@stream-io/video-react-native-sdk 1.29.0-beta.1 → 1.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/CHANGELOG.md +3114 -0
  2. package/android/src/main/AndroidManifest.xml +1 -8
  3. package/android/src/main/AndroidManifestNew.xml +0 -11
  4. package/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.kt +5 -42
  5. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/WebRtcAudioUtils.kt +6 -70
  6. package/android/src/main/java/com/streamvideo/reactnative/callmanager/StreamInCallManagerModule.kt +4 -6
  7. package/android/src/main/java/com/streamvideo/reactnative/util/CallAliveServiceChecker.kt +95 -0
  8. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js +160 -0
  9. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +1 -0
  10. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js +31 -18
  11. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
  12. package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js +97 -64
  13. package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
  14. package/dist/commonjs/index.js +0 -1
  15. package/dist/commonjs/index.js.map +1 -1
  16. package/dist/commonjs/modules/call-manager/CallManager.js +0 -26
  17. package/dist/commonjs/modules/call-manager/CallManager.js.map +1 -1
  18. package/dist/commonjs/providers/StreamCall/index.js +6 -6
  19. package/dist/commonjs/providers/StreamCall/index.js.map +1 -1
  20. package/dist/commonjs/utils/StreamVideoRN/index.js +21 -33
  21. package/dist/commonjs/utils/StreamVideoRN/index.js.map +1 -1
  22. package/dist/commonjs/utils/internal/registerSDKGlobals.js +3 -52
  23. package/dist/commonjs/utils/internal/registerSDKGlobals.js.map +1 -1
  24. package/dist/commonjs/utils/push/android.js +200 -145
  25. package/dist/commonjs/utils/push/android.js.map +1 -1
  26. package/dist/commonjs/utils/push/internal/ios.js +34 -16
  27. package/dist/commonjs/utils/push/internal/ios.js.map +1 -1
  28. package/dist/commonjs/utils/push/internal/rxSubjects.js +20 -1
  29. package/dist/commonjs/utils/push/internal/rxSubjects.js.map +1 -1
  30. package/dist/commonjs/utils/push/internal/utils.js +1 -17
  31. package/dist/commonjs/utils/push/internal/utils.js.map +1 -1
  32. package/dist/commonjs/utils/push/ios.js.map +1 -1
  33. package/dist/commonjs/utils/push/libs/callkeep.js +17 -0
  34. package/dist/commonjs/utils/push/libs/callkeep.js.map +1 -0
  35. package/dist/commonjs/utils/push/libs/index.js +19 -8
  36. package/dist/commonjs/utils/push/libs/index.js.map +1 -1
  37. package/dist/commonjs/utils/push/libs/notifee/index.js +19 -0
  38. package/dist/commonjs/utils/push/libs/notifee/index.js.map +1 -1
  39. package/dist/commonjs/utils/push/libs/voipPushNotification.js +17 -0
  40. package/dist/commonjs/utils/push/libs/voipPushNotification.js.map +1 -0
  41. package/dist/commonjs/utils/push/setupIosCallKeepEvents.js +205 -0
  42. package/dist/commonjs/utils/push/setupIosCallKeepEvents.js.map +1 -0
  43. package/dist/commonjs/utils/push/setupIosVoipPushEvents.js +6 -7
  44. package/dist/commonjs/utils/push/setupIosVoipPushEvents.js.map +1 -1
  45. package/dist/commonjs/version.js +1 -1
  46. package/dist/commonjs/version.js.map +1 -1
  47. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js +153 -0
  48. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +1 -0
  49. package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js +31 -18
  50. package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
  51. package/dist/module/hooks/useAndroidKeepCallAliveEffect.js +99 -66
  52. package/dist/module/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
  53. package/dist/module/index.js +0 -1
  54. package/dist/module/index.js.map +1 -1
  55. package/dist/module/modules/call-manager/CallManager.js +0 -26
  56. package/dist/module/modules/call-manager/CallManager.js.map +1 -1
  57. package/dist/module/providers/StreamCall/index.js +6 -6
  58. package/dist/module/providers/StreamCall/index.js.map +1 -1
  59. package/dist/module/utils/StreamVideoRN/index.js +21 -33
  60. package/dist/module/utils/StreamVideoRN/index.js.map +1 -1
  61. package/dist/module/utils/internal/registerSDKGlobals.js +4 -53
  62. package/dist/module/utils/internal/registerSDKGlobals.js.map +1 -1
  63. package/dist/module/utils/push/android.js +202 -147
  64. package/dist/module/utils/push/android.js.map +1 -1
  65. package/dist/module/utils/push/internal/ios.js +34 -16
  66. package/dist/module/utils/push/internal/ios.js.map +1 -1
  67. package/dist/module/utils/push/internal/rxSubjects.js +19 -0
  68. package/dist/module/utils/push/internal/rxSubjects.js.map +1 -1
  69. package/dist/module/utils/push/internal/utils.js +0 -14
  70. package/dist/module/utils/push/internal/utils.js.map +1 -1
  71. package/dist/module/utils/push/ios.js.map +1 -1
  72. package/dist/module/utils/push/libs/callkeep.js +11 -0
  73. package/dist/module/utils/push/libs/callkeep.js.map +1 -0
  74. package/dist/module/utils/push/libs/index.js +2 -1
  75. package/dist/module/utils/push/libs/index.js.map +1 -1
  76. package/dist/module/utils/push/libs/notifee/index.js +18 -0
  77. package/dist/module/utils/push/libs/notifee/index.js.map +1 -1
  78. package/dist/module/utils/push/libs/voipPushNotification.js +11 -0
  79. package/dist/module/utils/push/libs/voipPushNotification.js.map +1 -0
  80. package/dist/module/utils/push/setupIosCallKeepEvents.js +199 -0
  81. package/dist/module/utils/push/setupIosCallKeepEvents.js.map +1 -0
  82. package/dist/module/utils/push/setupIosVoipPushEvents.js +6 -7
  83. package/dist/module/utils/push/setupIosVoipPushEvents.js.map +1 -1
  84. package/dist/module/version.js +1 -1
  85. package/dist/module/version.js.map +1 -1
  86. package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts +5 -0
  87. package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts.map +1 -0
  88. package/dist/typescript/hooks/push/useIosVoipPushEventsSetupEffect.d.ts.map +1 -1
  89. package/dist/typescript/hooks/useAndroidKeepCallAliveEffect.d.ts.map +1 -1
  90. package/dist/typescript/index.d.ts +0 -1
  91. package/dist/typescript/index.d.ts.map +1 -1
  92. package/dist/typescript/modules/call-manager/CallManager.d.ts +0 -5
  93. package/dist/typescript/modules/call-manager/CallManager.d.ts.map +1 -1
  94. package/dist/typescript/utils/StreamVideoRN/index.d.ts +2 -20
  95. package/dist/typescript/utils/StreamVideoRN/index.d.ts.map +1 -1
  96. package/dist/typescript/utils/StreamVideoRN/types.d.ts +29 -54
  97. package/dist/typescript/utils/StreamVideoRN/types.d.ts.map +1 -1
  98. package/dist/typescript/utils/internal/registerSDKGlobals.d.ts.map +1 -1
  99. package/dist/typescript/utils/push/android.d.ts +2 -1
  100. package/dist/typescript/utils/push/android.d.ts.map +1 -1
  101. package/dist/typescript/utils/push/internal/ios.d.ts.map +1 -1
  102. package/dist/typescript/utils/push/internal/rxSubjects.d.ts +12 -0
  103. package/dist/typescript/utils/push/internal/rxSubjects.d.ts.map +1 -1
  104. package/dist/typescript/utils/push/internal/utils.d.ts +0 -4
  105. package/dist/typescript/utils/push/internal/utils.d.ts.map +1 -1
  106. package/dist/typescript/utils/push/ios.d.ts +2 -1
  107. package/dist/typescript/utils/push/ios.d.ts.map +1 -1
  108. package/dist/typescript/utils/push/libs/callkeep.d.ts +3 -0
  109. package/dist/typescript/utils/push/libs/callkeep.d.ts.map +1 -0
  110. package/dist/typescript/utils/push/libs/firebaseMessaging/index.d.ts +2 -16
  111. package/dist/typescript/utils/push/libs/firebaseMessaging/index.d.ts.map +1 -1
  112. package/dist/typescript/utils/push/libs/index.d.ts +2 -1
  113. package/dist/typescript/utils/push/libs/index.d.ts.map +1 -1
  114. package/dist/typescript/utils/push/libs/notifee/index.d.ts +1 -0
  115. package/dist/typescript/utils/push/libs/notifee/index.d.ts.map +1 -1
  116. package/dist/typescript/utils/push/libs/voipPushNotification.d.ts +3 -0
  117. package/dist/typescript/utils/push/libs/voipPushNotification.d.ts.map +1 -0
  118. package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts +6 -0
  119. package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts.map +1 -0
  120. package/dist/typescript/utils/push/setupIosVoipPushEvents.d.ts.map +1 -1
  121. package/dist/typescript/version.d.ts +1 -1
  122. package/dist/typescript/version.d.ts.map +1 -1
  123. package/expo-config-plugin/dist/withAndroidManifest.js +33 -1
  124. package/expo-config-plugin/dist/withAndroidPermissions.js +7 -2
  125. package/expo-config-plugin/dist/withAppDelegate.js +197 -19
  126. package/expo-config-plugin/dist/withMainActivity.js +1 -1
  127. package/expo-config-plugin/dist/withiOSInfoPlist.js +3 -2
  128. package/ios/StreamInCallManager.m +0 -2
  129. package/ios/StreamInCallManager.swift +5 -20
  130. package/ios/StreamVideoReactNative.h +4 -7
  131. package/ios/StreamVideoReactNative.m +82 -191
  132. package/package.json +17 -12
  133. package/src/hooks/push/useIosCallkeepWithCallingStateEffect.ts +235 -0
  134. package/src/hooks/push/useIosVoipPushEventsSetupEffect.ts +34 -21
  135. package/src/hooks/useAndroidKeepCallAliveEffect.ts +120 -94
  136. package/src/index.ts +0 -1
  137. package/src/modules/call-manager/CallManager.ts +0 -36
  138. package/src/modules/call-manager/native-module.d.ts +0 -7
  139. package/src/providers/StreamCall/index.tsx +6 -6
  140. package/src/utils/StreamVideoRN/index.ts +30 -40
  141. package/src/utils/StreamVideoRN/types.ts +29 -56
  142. package/src/utils/internal/registerSDKGlobals.ts +4 -47
  143. package/src/utils/push/android.ts +308 -223
  144. package/src/utils/push/internal/ios.ts +46 -25
  145. package/src/utils/push/internal/rxSubjects.ts +29 -0
  146. package/src/utils/push/internal/utils.ts +0 -25
  147. package/src/utils/push/ios.ts +6 -1
  148. package/src/utils/push/libs/callkeep.ts +16 -0
  149. package/src/utils/push/libs/index.ts +2 -1
  150. package/src/utils/push/libs/notifee/index.ts +27 -0
  151. package/src/utils/push/libs/voipPushNotification.ts +17 -0
  152. package/src/utils/push/setupIosCallKeepEvents.ts +252 -0
  153. package/src/utils/push/setupIosVoipPushEvents.ts +7 -11
  154. package/src/version.ts +1 -1
  155. package/android/src/main/java/com/streamvideo/reactnative/keepalive/KeepAliveNotification.kt +0 -83
  156. package/android/src/main/java/com/streamvideo/reactnative/keepalive/StreamCallKeepAliveHeadlessService.kt +0 -134
  157. package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js +0 -216
  158. package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js.map +0 -1
  159. package/dist/commonjs/utils/internal/audioSessionPromise.js +0 -46
  160. package/dist/commonjs/utils/internal/audioSessionPromise.js.map +0 -1
  161. package/dist/commonjs/utils/internal/callingx.js +0 -84
  162. package/dist/commonjs/utils/internal/callingx.js.map +0 -1
  163. package/dist/commonjs/utils/keepCallAliveHeadlessTask.js +0 -48
  164. package/dist/commonjs/utils/keepCallAliveHeadlessTask.js.map +0 -1
  165. package/dist/commonjs/utils/push/libs/callingx.js +0 -75
  166. package/dist/commonjs/utils/push/libs/callingx.js.map +0 -1
  167. package/dist/commonjs/utils/push/setupCallingExpEvents.js +0 -97
  168. package/dist/commonjs/utils/push/setupCallingExpEvents.js.map +0 -1
  169. package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js +0 -209
  170. package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js.map +0 -1
  171. package/dist/module/utils/internal/audioSessionPromise.js +0 -39
  172. package/dist/module/utils/internal/audioSessionPromise.js.map +0 -1
  173. package/dist/module/utils/internal/callingx.js +0 -75
  174. package/dist/module/utils/internal/callingx.js.map +0 -1
  175. package/dist/module/utils/keepCallAliveHeadlessTask.js +0 -42
  176. package/dist/module/utils/keepCallAliveHeadlessTask.js.map +0 -1
  177. package/dist/module/utils/push/libs/callingx.js +0 -67
  178. package/dist/module/utils/push/libs/callingx.js.map +0 -1
  179. package/dist/module/utils/push/setupCallingExpEvents.js +0 -91
  180. package/dist/module/utils/push/setupCallingExpEvents.js.map +0 -1
  181. package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts +0 -5
  182. package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts.map +0 -1
  183. package/dist/typescript/utils/internal/audioSessionPromise.d.ts +0 -16
  184. package/dist/typescript/utils/internal/audioSessionPromise.d.ts.map +0 -1
  185. package/dist/typescript/utils/internal/callingx.d.ts +0 -13
  186. package/dist/typescript/utils/internal/callingx.d.ts.map +0 -1
  187. package/dist/typescript/utils/keepCallAliveHeadlessTask.d.ts +0 -10
  188. package/dist/typescript/utils/keepCallAliveHeadlessTask.d.ts.map +0 -1
  189. package/dist/typescript/utils/push/libs/callingx.d.ts +0 -9
  190. package/dist/typescript/utils/push/libs/callingx.d.ts.map +0 -1
  191. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts +0 -8
  192. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts.map +0 -1
  193. package/src/hooks/push/useCallingExpWithCallingStateEffect.ts +0 -307
  194. package/src/utils/internal/audioSessionPromise.ts +0 -39
  195. package/src/utils/internal/callingx.ts +0 -108
  196. package/src/utils/keepCallAliveHeadlessTask.ts +0 -54
  197. package/src/utils/push/libs/callingx.ts +0 -90
  198. package/src/utils/push/setupCallingExpEvents.ts +0 -117
@@ -1,4 +1,6 @@
1
1
  import { type MutableRefObject, useEffect, useRef, useState } from 'react';
2
+ import { getVoipPushNotificationLib } from '../../utils/push/libs';
3
+
2
4
  import { Platform } from 'react-native';
3
5
  import { StreamVideoRN } from '../../utils';
4
6
  import { onVoipNotificationReceived } from '../../utils/push/internal/ios';
@@ -8,7 +10,6 @@ import {
8
10
  } from '@stream-io/video-react-bindings';
9
11
  import { setPushLogoutCallback } from '../../utils/internal/pushLogoutCallback';
10
12
  import { StreamVideoClient, videoLoggerSystem } from '@stream-io/video-client';
11
- import { getCallingxLibIfAvailable } from '../../utils/push/libs';
12
13
 
13
14
  const logger = videoLoggerSystem.getLogger('useIosVoipPushEventsSetupEffect');
14
15
 
@@ -27,7 +28,6 @@ function setLogoutCallback(
27
28
  lastVoipTokenRef.current = { token: '', userId: '' };
28
29
  try {
29
30
  await client.removeDevice(token);
30
- logger.debug('PushLogoutCallback - Removed voip token', token);
31
31
  } catch (err) {
32
32
  logger.warn('PushLogoutCallback - Failed to remove voip token', err);
33
33
  }
@@ -89,12 +89,24 @@ export const useIosVoipPushEventsSetupEffect = () => {
89
89
  useEffect(() => {
90
90
  const pushConfig = StreamVideoRN.getConfig().push;
91
91
  const pushProviderName = pushConfig?.ios.pushProviderName;
92
- const callingx = getCallingxLibIfAvailable();
93
-
94
- if (Platform.OS !== 'ios' || !client || !pushProviderName || !callingx) {
92
+ if (Platform.OS !== 'ios' || !client || !pushProviderName) {
93
+ return;
94
+ }
95
+ if (!pushConfig.android.incomingCallChannel) {
96
+ // TODO: remove this check and find a better way once we have telecom integration for android
97
+ logger.debug(
98
+ 'android incomingCallChannel is not defined, so skipping the useIosVoipPushEventsSetupEffect',
99
+ );
95
100
  return;
96
101
  }
97
102
 
103
+ const voipPushNotification = getVoipPushNotificationLib();
104
+
105
+ // even though we do this natively, we have to still register here again
106
+ // natively this will make sure "register" event for JS is sent with the last push token
107
+ // Necessary if client changed before we got the event here or user logged out and logged in again
108
+ voipPushNotification.registerVoipToken();
109
+
98
110
  const onTokenReceived = (token: string) => {
99
111
  const userId = client.streamClient._user?.id ?? '';
100
112
  if (client.streamClient.anonymous || !token || !userId) {
@@ -133,24 +145,24 @@ export const useIosVoipPushEventsSetupEffect = () => {
133
145
  });
134
146
  };
135
147
  // fired when PushKit give us the latest token
136
- const voipRegisterListener = callingx.addEventListener(
137
- 'voipNotificationsRegistered',
138
- ({ token }) => {
139
- onTokenReceived(token);
140
- },
141
- );
148
+ voipPushNotification.addEventListener('register', (token) => {
149
+ onTokenReceived(token);
150
+ });
142
151
 
143
- // this will return events that were fired before js bridge initialized
144
- callingx.getInitialVoipEvents().forEach(({ eventName, params }) => {
145
- if (eventName === 'voipNotificationsRegistered' && 'token' in params) {
146
- onTokenReceived(params.token);
147
- } else if (eventName === 'voipNotificationReceived') {
148
- onVoipNotificationReceived(params, pushConfig);
152
+ // this will fire when there are events occured before js bridge initialized
153
+ voipPushNotification.addEventListener('didLoadWithEvents', (events) => {
154
+ if (!events || !Array.isArray(events) || events.length < 1) {
155
+ return;
156
+ }
157
+ for (const voipPushEvent of events) {
158
+ const { name, data } = voipPushEvent;
159
+ if (name === 'RNVoipPushRemoteNotificationsRegisteredEvent') {
160
+ onTokenReceived(data);
161
+ } else if (name === 'RNVoipPushRemoteNotificationReceivedEvent') {
162
+ onVoipNotificationReceived(data, pushConfig);
163
+ }
149
164
  }
150
165
  });
151
-
152
- callingx.registerVoipToken();
153
-
154
166
  lastListener.count += 1;
155
167
  const currentListenerCount = lastListener.count;
156
168
 
@@ -163,7 +175,8 @@ export const useIosVoipPushEventsSetupEffect = () => {
163
175
  return;
164
176
  }
165
177
  logger.debug(`Voip event listeners are removed for user: ${userId}`);
166
- voipRegisterListener.remove();
178
+ voipPushNotification.removeEventListener('didLoadWithEvents');
179
+ voipPushNotification.removeEventListener('register');
167
180
  };
168
181
  }, [client]);
169
182
  };
@@ -5,48 +5,76 @@ import {
5
5
  AppState,
6
6
  type AppStateStatus,
7
7
  NativeModules,
8
- PermissionsAndroid,
9
8
  Platform,
10
9
  } from 'react-native';
11
- import { CallingState, videoLoggerSystem } from '@stream-io/video-client';
12
- import { keepCallAliveCallRef } from '../utils/keepCallAliveHeadlessTask';
13
- import { getNotifeeLibNoThrowForKeepCallAlive } from '../utils/push/libs/notifee';
14
- import { getCallingxLibIfAvailable } from '../utils/push/libs';
10
+ import { Call, CallingState, videoLoggerSystem } from '@stream-io/video-client';
11
+ import {
12
+ getKeepCallAliveForegroundServiceTypes,
13
+ getNotifeeLibNoThrowForKeepCallAlive,
14
+ } from '../utils/push/libs/notifee';
15
15
 
16
16
  const notifeeLib = getNotifeeLibNoThrowForKeepCallAlive();
17
+ const callToPassToForegroundService: { current: Call | undefined } = {
18
+ current: undefined,
19
+ };
17
20
 
18
- async function stopForegroundServiceNoThrow() {
19
- const logger = videoLoggerSystem.getLogger('stopForegroundServiceNoThrow');
20
- try {
21
- await NativeModules.StreamVideoReactNative.stopKeepCallAliveService();
22
- } catch (e) {
23
- logger.warn('Failed to stop keep-call-alive foreground service', e);
24
- }
21
+ function setForegroundService() {
22
+ if (Platform.OS === 'ios' || !notifeeLib) return;
23
+ NativeModules.StreamVideoReactNative.isCallAliveConfigured().then(
24
+ (isConfigured: boolean) => {
25
+ if (!isConfigured) {
26
+ const logger = videoLoggerSystem.getLogger(
27
+ 'setForegroundService method',
28
+ );
29
+ logger.info(
30
+ 'KeepCallAlive is not configured. Skipping foreground service setup.',
31
+ );
32
+ return;
33
+ }
34
+ notifeeLib.default.registerForegroundService(() => {
35
+ const task = new Promise((resolve) => {
36
+ const logger = videoLoggerSystem.getLogger(
37
+ 'setForegroundService method',
38
+ );
39
+ logger.info('Foreground service running for call in progress');
40
+ // any task to run from SDK in the foreground service must be added
41
+ resolve(true);
42
+ });
43
+ const videoConfig = StreamVideoRN.getConfig();
44
+ const foregroundServiceConfig = videoConfig.foregroundService;
45
+ const { taskToRun } = foregroundServiceConfig.android;
46
+ const call = callToPassToForegroundService.current;
47
+ if (!call) {
48
+ const logger = videoLoggerSystem.getLogger(
49
+ 'setForegroundService method',
50
+ );
51
+ logger.warn('No call to pass to foreground service');
52
+ return task.then(() => new Promise(() => {}));
53
+ }
54
+ callToPassToForegroundService.current = undefined;
55
+ return task.then(() => taskToRun(call));
56
+ });
57
+ },
58
+ );
25
59
  }
26
60
 
27
61
  async function startForegroundService(call_cid: string) {
28
- const logger = videoLoggerSystem.getLogger('startForegroundService');
29
- const isCallAliveConfigured = await (async () => {
30
- try {
31
- return await NativeModules.StreamVideoReactNative.isCallAliveConfigured();
32
- } catch (e) {
33
- logger.warn('Failed to check whether KeepCallAlive is configured', e);
34
- return false;
35
- }
36
- })();
62
+ const isCallAliveConfigured =
63
+ await NativeModules.StreamVideoReactNative.isCallAliveConfigured();
37
64
  if (!isCallAliveConfigured) {
65
+ const logger = videoLoggerSystem.getLogger('startForegroundService');
38
66
  logger.info(
39
67
  'KeepCallAlive is not configured. Skipping foreground service setup.',
40
68
  );
41
69
  return;
42
70
  }
43
- // Check for notification permission (Android 13+) before starting the service.
44
- const hasPostNotificationsPermission =
45
- Number(Platform.Version) < 33 ||
46
- (await PermissionsAndroid.check(
47
- PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS,
48
- ));
49
- if (!hasPostNotificationsPermission) {
71
+ // check for notification permission and then start the foreground service
72
+ if (!notifeeLib) return;
73
+ const settings = await notifeeLib.default.getNotificationSettings();
74
+ if (
75
+ settings.authorizationStatus !== notifeeLib.AuthorizationStatus.AUTHORIZED
76
+ ) {
77
+ const logger = videoLoggerSystem.getLogger('startForegroundService');
50
78
  logger.info(
51
79
  'Notification permission not granted, can not start foreground service to keep the call alive',
52
80
  );
@@ -55,28 +83,38 @@ async function startForegroundService(call_cid: string) {
55
83
  const videoConfig = StreamVideoRN.getConfig();
56
84
  const foregroundServiceConfig = videoConfig.foregroundService;
57
85
  const notificationTexts = foregroundServiceConfig.android.notificationTexts;
58
- const channel = foregroundServiceConfig.android.channel;
59
- const smallIconName = videoConfig.push?.android.smallIcon;
60
-
86
+ const channelId = foregroundServiceConfig.android.channel.id;
87
+ await notifeeLib.default.createChannel(
88
+ foregroundServiceConfig.android.channel,
89
+ );
90
+ const foregroundServiceTypes = await getKeepCallAliveForegroundServiceTypes();
61
91
  // NOTE: we use requestAnimationFrame to ensure that the foreground service is started after all the current UI operations are done
62
92
  // this is a workaround for the crash - android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException: Context.startForegroundService() did not then call Service.startForeground()
63
93
  // this crash was reproducible only in some android devices
64
- requestAnimationFrame(async () => {
65
- try {
66
- await NativeModules.StreamVideoReactNative.startKeepCallAliveService(
67
- call_cid,
68
- channel.id,
69
- channel.name,
70
- notificationTexts.title,
71
- notificationTexts.body,
72
- smallIconName ?? null,
73
- );
74
- } catch (e) {
75
- logger.warn('Failed to start keep-call-alive foreground service', e);
76
- }
94
+ requestAnimationFrame(() => {
95
+ notifeeLib.default.displayNotification({
96
+ id: call_cid,
97
+ title: notificationTexts.title,
98
+ body: notificationTexts.body,
99
+ android: {
100
+ channelId,
101
+ smallIcon: videoConfig.push?.android.smallIcon,
102
+ foregroundServiceTypes,
103
+ asForegroundService: true,
104
+ ongoing: true, // user cannot dismiss the notification
105
+ colorized: true,
106
+ pressAction: {
107
+ id: 'default',
108
+ launchActivity: 'default', // open the app when the notification is pressed
109
+ },
110
+ },
111
+ });
77
112
  });
78
113
  }
79
114
 
115
+ // flag to check if setForegroundService has already been run once
116
+ let isSetForegroundServiceRan = false;
117
+
80
118
  /**
81
119
  * This hook is used to keep the call alive in the background for Android.
82
120
  * It starts a foreground service to keep the call alive as soon as the call is joined
@@ -87,7 +125,7 @@ export const useAndroidKeepCallAliveEffect = () => {
87
125
  const foregroundServiceStartedRef = useRef(false);
88
126
 
89
127
  const call = useCall();
90
- keepCallAliveCallRef.current = call;
128
+ callToPassToForegroundService.current = call;
91
129
  const activeCallCid = call?.cid;
92
130
  const { useCallCallingState } = useCallStateHooks();
93
131
  const callingState = useCallCallingState();
@@ -95,7 +133,6 @@ export const useAndroidKeepCallAliveEffect = () => {
95
133
  const isOutgoingCall =
96
134
  callingState === CallingState.RINGING && call?.isCreatedByMe;
97
135
  const isCallJoined = callingState === CallingState.JOINED;
98
- const isRingingCall = call?.ringing;
99
136
 
100
137
  const shouldStartForegroundService =
101
138
  !foregroundServiceStartedRef.current && (isOutgoingCall || isCallJoined);
@@ -104,14 +141,7 @@ export const useAndroidKeepCallAliveEffect = () => {
104
141
  if (Platform.OS === 'ios' || !activeCallCid) {
105
142
  return undefined;
106
143
  }
107
-
108
- const callingx = getCallingxLibIfAvailable();
109
- if (
110
- callingx?.isSetup &&
111
- (isRingingCall || (!isRingingCall && callingx?.isOngoingCallsEnabled))
112
- ) {
113
- return undefined;
114
- }
144
+ if (!notifeeLib) return undefined;
115
145
 
116
146
  // start foreground service as soon as the call is joined
117
147
  if (shouldStartForegroundService) {
@@ -119,21 +149,23 @@ export const useAndroidKeepCallAliveEffect = () => {
119
149
  if (foregroundServiceStartedRef.current) {
120
150
  return;
121
151
  }
122
- // Optional compatibility cleanup: if the app uses Notifee for ringing push,
123
- // we might have an incoming call notification running as a foreground service.
124
- if (notifeeLib) {
125
- const notifee = notifeeLib.default;
126
- const displayedNotifications =
127
- await notifee.getDisplayedNotifications();
128
- const activeCallNotification = displayedNotifications.find(
129
- (notification) => notification.id === activeCallCid,
130
- );
131
- if (activeCallNotification) {
132
- // this means that we have a incoming call notification shown as foreground service and we must stop it
133
- notifee.stopForegroundService();
134
- notifee.cancelDisplayedNotification(activeCallCid);
135
- }
152
+ if (!isSetForegroundServiceRan) {
153
+ isSetForegroundServiceRan = true;
154
+ setForegroundService();
155
+ }
156
+ const notifee = notifeeLib.default;
157
+ const displayedNotifications =
158
+ await notifee.getDisplayedNotifications();
159
+ const activeCallNotification = displayedNotifications.find(
160
+ (notification) => notification.id === activeCallCid,
161
+ );
162
+ if (activeCallNotification) {
163
+ callToPassToForegroundService.current = undefined;
164
+ // this means that we have a incoming call notification shown as foreground service and we must stop it
165
+ notifee.stopForegroundService();
166
+ notifee.cancelDisplayedNotification(activeCallCid);
136
167
  }
168
+ // check for notification permission and then start the foreground service
137
169
 
138
170
  await startForegroundService(activeCallCid);
139
171
  foregroundServiceStartedRef.current = true;
@@ -142,6 +174,7 @@ export const useAndroidKeepCallAliveEffect = () => {
142
174
  // ensure that app is active before running the function
143
175
  if (AppState.currentState === 'active') {
144
176
  run();
177
+ return undefined;
145
178
  }
146
179
  const sub = AppState.addEventListener(
147
180
  'change',
@@ -159,49 +192,42 @@ export const useAndroidKeepCallAliveEffect = () => {
159
192
  return () => {
160
193
  // cancel any notifee displayed notification when the call has transitioned out of ringing
161
194
  // NOTE: cancels only the non fg service notifications
162
- if (notifeeLib) {
163
- notifeeLib.default.cancelDisplayedNotification(activeCallCid);
164
- }
195
+ notifeeLib.default.cancelDisplayedNotification(activeCallCid);
165
196
  };
166
197
  } else if (
167
198
  callingState === CallingState.IDLE ||
168
199
  callingState === CallingState.LEFT
169
200
  ) {
170
201
  if (foregroundServiceStartedRef.current) {
171
- keepCallAliveCallRef.current = undefined;
202
+ callToPassToForegroundService.current = undefined;
172
203
  // stop foreground service when the call is not active
173
- stopForegroundServiceNoThrow();
204
+ notifeeLib.default.stopForegroundService();
174
205
  foregroundServiceStartedRef.current = false;
175
206
  } else {
176
- if (notifeeLib) {
177
- notifeeLib.default
178
- .getDisplayedNotifications()
179
- .then((displayedNotifications) => {
180
- const activeCallNotification = displayedNotifications.find(
181
- (notification) => notification.id === activeCallCid,
182
- );
183
- if (activeCallNotification) {
184
- // this means that we have a incoming call notification shown as foreground service and we must stop it
185
- notifeeLib.default.stopForegroundService();
186
- }
187
- });
188
- }
207
+ notifeeLib.default
208
+ .getDisplayedNotifications()
209
+ .then((displayedNotifications) => {
210
+ const activeCallNotification = displayedNotifications.find(
211
+ (notification) => notification.id === activeCallCid,
212
+ );
213
+ if (activeCallNotification) {
214
+ callToPassToForegroundService.current = undefined;
215
+ // this means that we have a incoming call notification shown as foreground service and we must stop it
216
+ notifeeLib.default.stopForegroundService();
217
+ }
218
+ });
189
219
  }
190
220
  }
191
221
  return undefined;
192
- }, [
193
- activeCallCid,
194
- callingState,
195
- shouldStartForegroundService,
196
- isRingingCall,
197
- ]);
222
+ }, [activeCallCid, callingState, shouldStartForegroundService]);
198
223
 
199
224
  useEffect(() => {
200
225
  return () => {
201
226
  // stop foreground service when this effect is unmounted
202
227
  if (foregroundServiceStartedRef.current) {
203
- keepCallAliveCallRef.current = undefined;
204
- stopForegroundServiceNoThrow();
228
+ if (!notifeeLib) return;
229
+ callToPassToForegroundService.current = undefined;
230
+ notifeeLib.default.stopForegroundService();
205
231
  foregroundServiceStartedRef.current = false;
206
232
  }
207
233
  };
package/src/index.ts CHANGED
@@ -9,7 +9,6 @@ import { registerGlobals } from '@stream-io/react-native-webrtc';
9
9
  import Logger from '@stream-io/react-native-webrtc/src/Logger';
10
10
  import { Platform } from 'react-native';
11
11
  import { registerSDKGlobals } from './utils/internal/registerSDKGlobals';
12
- import './utils/keepCallAliveHeadlessTask';
13
12
 
14
13
  // We're registering globals, because our video JS client is serving SDKs that use browser based webRTC functions.
15
14
  // This will result in creation of 2 global objects: `window` and `navigator`
@@ -1,10 +1,7 @@
1
1
  import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
2
2
  import { AudioDeviceStatus, StreamInCallManagerConfig } from './types';
3
- import { getCallingxLibIfAvailable } from '../../utils/push/libs/callingx';
4
- import { videoLoggerSystem } from '@stream-io/video-client';
5
3
 
6
4
  const NativeManager = NativeModules.StreamInCallManager;
7
- const CallingxModule = getCallingxLibIfAvailable();
8
5
 
9
6
  const invariant = (condition: boolean, message: string) => {
10
7
  if (!condition) throw new Error(message);
@@ -75,19 +72,6 @@ class SpeakerManager {
75
72
  };
76
73
  }
77
74
 
78
- const shouldBypassForCallKit = (): boolean => {
79
- if (Platform.OS !== 'ios') {
80
- return false;
81
- }
82
- if (!CallingxModule) {
83
- return false;
84
- }
85
- return (
86
- CallingxModule.isSetup &&
87
- (CallingxModule.hasRegisteredCall() || CallingxModule.isOngoingCallsEnabled)
88
- );
89
- };
90
-
91
75
  export class CallManager {
92
76
  android = new AndroidCallManager();
93
77
  ios = new IOSCallManager();
@@ -111,14 +95,6 @@ export class CallManager {
111
95
  * @param config.enableStereoAudioOutput Whether to enable stereo audio output. Only supported for listener audio role.
112
96
  */
113
97
  start = (config?: StreamInCallManagerConfig): void => {
114
- if (shouldBypassForCallKit()) {
115
- videoLoggerSystem
116
- .getLogger('CallManager')
117
- .debug(
118
- 'start: skipping start as callkit is handling the audio session',
119
- );
120
- return;
121
- }
122
98
  NativeManager.setAudioRole(config?.audioRole ?? 'communicator');
123
99
  if (config?.audioRole === 'communicator') {
124
100
  const type = config.deviceEndpointType ?? 'speaker';
@@ -134,12 +110,6 @@ export class CallManager {
134
110
  * Stops the in call manager.
135
111
  */
136
112
  stop = (): void => {
137
- if (shouldBypassForCallKit()) {
138
- videoLoggerSystem
139
- .getLogger('CallManager')
140
- .debug('stop: skipping stop as callkit is handling the audio session');
141
- return;
142
- }
143
113
  NativeManager.stop();
144
114
  };
145
115
 
@@ -148,10 +118,4 @@ export class CallManager {
148
118
  * in the native layer.
149
119
  */
150
120
  logAudioState = (): void => NativeManager.logAudioState();
151
-
152
- /**
153
- * For debugging purposes, returns the current audio state as a string.
154
- * @returns A string containing the current audio state information.
155
- */
156
- getAudioStateLog = (): string => NativeManager.getAudioStateLog();
157
121
  }
@@ -82,13 +82,6 @@ export interface CallManager extends NativeModule {
82
82
  * Meant for debugging purposes.
83
83
  */
84
84
  logAudioState: () => void;
85
-
86
- /**
87
- * Get the current audio state as a string.
88
- * Meant for debugging purposes.
89
- * @returns A string containing the current audio state information.
90
- */
91
- getAudioStateLog: () => string;
92
85
  }
93
86
 
94
87
  declare module 'react-native' {
@@ -1,12 +1,12 @@
1
1
  import { StreamCallProvider } from '@stream-io/video-react-bindings';
2
2
  import React, { type PropsWithChildren, useEffect } from 'react';
3
3
  import { Call } from '@stream-io/video-client';
4
+ import { useIosCallkeepWithCallingStateEffect } from '../../hooks/push/useIosCallkeepWithCallingStateEffect';
4
5
  import { canAddPushWSSubscriptionsRef } from '../../utils/push/internal/utils';
5
6
  import { useAndroidKeepCallAliveEffect } from '../../hooks/useAndroidKeepCallAliveEffect';
6
7
  import { AppStateListener } from './AppStateListener';
7
8
  import { DeviceStats } from './DeviceStats';
8
9
  import { pushUnsubscriptionCallbacks } from '../../utils/push/internal/constants';
9
- import { useCallingExpWithCallingStateEffect } from '../../hooks/push/useCallingExpWithCallingStateEffect';
10
10
 
11
11
  // const PIP_CHANGE_EVENT = 'StreamVideoReactNative_PIP_CHANGE_EVENT';
12
12
 
@@ -34,7 +34,7 @@ export const StreamCall = ({
34
34
  <StreamCallProvider call={call}>
35
35
  <AppStateListener />
36
36
  <AndroidKeepCallAlive />
37
- <CallingExpWithCallingState />
37
+ <IosInformCallkeepCallEnd />
38
38
  <ClearPushWSSubscriptions />
39
39
  <DeviceStats />
40
40
  {children}
@@ -52,11 +52,11 @@ const AndroidKeepCallAlive = () => {
52
52
  };
53
53
 
54
54
  /**
55
- * This is a renderless component to sync state between stream call and CallKit/Telecom.
56
- * useCallingExpWithCallingStateEffect needs to called inside a child of StreamCallProvider.
55
+ * This is a renderless component to end the call in callkeep for ios.
56
+ * useAndroidKeepCallAliveEffect needs to called inside a child of StreamCallProvider.
57
57
  */
58
- const CallingExpWithCallingState = () => {
59
- useCallingExpWithCallingStateEffect();
58
+ const IosInformCallkeepCallEnd = () => {
59
+ useIosCallkeepWithCallingStateEffect();
60
60
  return null;
61
61
  };
62
62
 
@@ -3,14 +3,9 @@ import pushLogoutCallbacks from '../internal/pushLogoutCallback';
3
3
  import newNotificationCallbacks, {
4
4
  type NewCallNotificationCallback,
5
5
  } from '../internal/newNotificationCallbacks';
6
+ import { setupIosCallKeepEvents } from '../push/setupIosCallKeepEvents';
6
7
  import { setupIosVoipPushEvents } from '../push/setupIosVoipPushEvents';
7
- import { setupCallingExpEvents } from '../push/setupCallingExpEvents';
8
- import {
9
- extractCallingExpOptions,
10
- getCallingxLib,
11
- } from '../push/libs/callingx';
12
8
  import { NativeModules, Platform } from 'react-native';
13
- import { videoLoggerSystem } from '@stream-io/video-client';
14
9
 
15
10
  // Utility type for deep partial
16
11
  type DeepPartial<T> = {
@@ -52,7 +47,10 @@ const DEFAULT_STREAM_VIDEO_CONFIG: StreamVideoConfig = {
52
47
  android: {
53
48
  channel: {
54
49
  id: 'stream_call_foreground_service',
55
- name: 'Ongoing calls',
50
+ name: 'To keep calls alive',
51
+ lights: false,
52
+ vibration: false,
53
+ importance: 3,
56
54
  },
57
55
  notificationTexts: {
58
56
  title: 'Call in progress',
@@ -78,6 +76,20 @@ export class StreamVideoRN {
78
76
  this.config = deepMerge(this.config, updateConfig);
79
77
  }
80
78
 
79
+ static updateAndroidIncomingCallChannel(
80
+ updateChannel: Partial<
81
+ NonNullable<StreamVideoConfig['push']>['android']['incomingCallChannel']
82
+ >,
83
+ ) {
84
+ const prevChannel = this.config.push?.android?.incomingCallChannel;
85
+ if (prevChannel) {
86
+ this.config.push!.android.incomingCallChannel = {
87
+ ...prevChannel,
88
+ ...updateChannel,
89
+ };
90
+ }
91
+ }
92
+
81
93
  /**
82
94
  * Set the push config for StreamVideoRN.
83
95
  * This method must be called **outside** of your application lifecycle, e.g. alongside your
@@ -90,26 +102,7 @@ export class StreamVideoRN {
90
102
  * import App from './App';
91
103
  * // Set push config
92
104
  * const pushConfig = {}; // construct your config
93
- * // Set CallKit/Android Telecom API integration options. All params are optional. If not provided, the default values will be used.
94
- * const callingExpOptions = {
95
- * ios: {
96
- * callsHistory: true,
97
- * displayCallTimeout: 60000,
98
- * sound: 'ringtone',
99
- * imageName: 'callkit_icon',
100
- * },
101
- * android: {
102
- * incomingChannel: {
103
- * id: 'stream_incoming_call_notifications',
104
- * name: 'Call notifications',
105
- * vibration: true,
106
- * sound: 'default',
107
- * },
108
- * titleTransformer: (text: string) => text,
109
- * subtitleTransformer: (text: string) => text,
110
- * },
111
- * };
112
- * StreamVideoRN.setPushConfig(pushConfig, callingExpOptions);
105
+ * StreamVideoRN.setPushConfig(pushConfig);
113
106
  * AppRegistry.registerComponent('app', () => App);
114
107
  */
115
108
  static setPushConfig(pushConfig: NonNullable<StreamVideoConfig['push']>) {
@@ -117,23 +110,20 @@ export class StreamVideoRN {
117
110
  // Ignoring this config as push config was already set
118
111
  return;
119
112
  }
120
-
121
- this.config.push = pushConfig;
122
-
123
- try {
124
- const callingx = getCallingxLib();
125
- videoLoggerSystem
126
- .getLogger('StreamVideoRN.setPushConfig')
127
- .info(JSON.stringify(this.config));
128
- const options = extractCallingExpOptions(this.config);
129
- callingx.setup(options);
130
- } catch {
113
+ if (
114
+ __DEV__ &&
115
+ (pushConfig.navigateAcceptCall || pushConfig.navigateToIncomingCall)
116
+ ) {
131
117
  throw new Error(
132
- 'react-native-callingx library is not installed. Please check the installation instructions: https://getstream.io/video/docs/react-native/incoming-calls/ringing-setup/react-native/.',
118
+ `Support for navigateAcceptCall or navigateToIncomingCall in pushConfig has been removed.
119
+ Please watch for incoming and outgoing calls in the root component of your app.
120
+ Please see https://getstream.io/video/docs/react-native/advanced/ringing-calls/#watch-for-incoming-and-outgoing-calls for more information.`,
133
121
  );
134
122
  }
135
123
 
136
- setupCallingExpEvents(pushConfig);
124
+ this.config.push = pushConfig;
125
+
126
+ setupIosCallKeepEvents(pushConfig);
137
127
  setupIosVoipPushEvents(pushConfig);
138
128
  }
139
129