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

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 (208) hide show
  1. package/android/src/main/AndroidManifest.xml +8 -1
  2. package/android/src/main/AndroidManifestNew.xml +11 -0
  3. package/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.kt +42 -5
  4. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/WebRtcAudioUtils.kt +70 -6
  5. package/android/src/main/java/com/streamvideo/reactnative/callmanager/StreamInCallManagerModule.kt +6 -4
  6. package/android/src/main/java/com/streamvideo/reactnative/keepalive/KeepAliveNotification.kt +83 -0
  7. package/android/src/main/java/com/streamvideo/reactnative/keepalive/StreamCallKeepAliveHeadlessService.kt +149 -0
  8. package/dist/commonjs/hooks/push/index.js +0 -2
  9. package/dist/commonjs/hooks/push/index.js.map +1 -1
  10. package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js +121 -0
  11. package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js.map +1 -0
  12. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js +18 -31
  13. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
  14. package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js +64 -97
  15. package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
  16. package/dist/commonjs/index.js +1 -0
  17. package/dist/commonjs/index.js.map +1 -1
  18. package/dist/commonjs/modules/call-manager/CallManager.js +26 -0
  19. package/dist/commonjs/modules/call-manager/CallManager.js.map +1 -1
  20. package/dist/commonjs/providers/StreamCall/index.js +6 -6
  21. package/dist/commonjs/providers/StreamCall/index.js.map +1 -1
  22. package/dist/commonjs/utils/StreamVideoRN/index.js +33 -21
  23. package/dist/commonjs/utils/StreamVideoRN/index.js.map +1 -1
  24. package/dist/commonjs/utils/internal/callingx/audioSessionPromise.js +68 -0
  25. package/dist/commonjs/utils/internal/callingx/audioSessionPromise.js.map +1 -0
  26. package/dist/commonjs/utils/internal/callingx/callingx.js +123 -0
  27. package/dist/commonjs/utils/internal/callingx/callingx.js.map +1 -0
  28. package/dist/commonjs/utils/internal/registerSDKGlobals.js +52 -3
  29. package/dist/commonjs/utils/internal/registerSDKGlobals.js.map +1 -1
  30. package/dist/commonjs/utils/keepCallAliveHeadlessTask.js +48 -0
  31. package/dist/commonjs/utils/keepCallAliveHeadlessTask.js.map +1 -0
  32. package/dist/commonjs/utils/push/android.js +135 -202
  33. package/dist/commonjs/utils/push/android.js.map +1 -1
  34. package/dist/commonjs/utils/push/internal/ios.js +17 -34
  35. package/dist/commonjs/utils/push/internal/ios.js.map +1 -1
  36. package/dist/commonjs/utils/push/internal/rxSubjects.js +1 -45
  37. package/dist/commonjs/utils/push/internal/rxSubjects.js.map +1 -1
  38. package/dist/commonjs/utils/push/internal/utils.js +67 -52
  39. package/dist/commonjs/utils/push/internal/utils.js.map +1 -1
  40. package/dist/commonjs/utils/push/ios.js.map +1 -1
  41. package/dist/commonjs/utils/push/libs/callingx.js +78 -0
  42. package/dist/commonjs/utils/push/libs/callingx.js.map +1 -0
  43. package/dist/commonjs/utils/push/libs/index.js +8 -19
  44. package/dist/commonjs/utils/push/libs/index.js.map +1 -1
  45. package/dist/commonjs/utils/push/libs/notifee/index.js +0 -19
  46. package/dist/commonjs/utils/push/libs/notifee/index.js.map +1 -1
  47. package/dist/commonjs/utils/push/setupCallingExpEvents.js +105 -0
  48. package/dist/commonjs/utils/push/setupCallingExpEvents.js.map +1 -0
  49. package/dist/commonjs/utils/push/setupIosVoipPushEvents.js +7 -6
  50. package/dist/commonjs/utils/push/setupIosVoipPushEvents.js.map +1 -1
  51. package/dist/commonjs/version.js +1 -1
  52. package/dist/commonjs/version.js.map +1 -1
  53. package/dist/module/hooks/push/index.js +0 -2
  54. package/dist/module/hooks/push/index.js.map +1 -1
  55. package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js +114 -0
  56. package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js.map +1 -0
  57. package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js +18 -31
  58. package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
  59. package/dist/module/hooks/useAndroidKeepCallAliveEffect.js +66 -99
  60. package/dist/module/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
  61. package/dist/module/index.js +1 -0
  62. package/dist/module/index.js.map +1 -1
  63. package/dist/module/modules/call-manager/CallManager.js +26 -0
  64. package/dist/module/modules/call-manager/CallManager.js.map +1 -1
  65. package/dist/module/providers/StreamCall/index.js +6 -6
  66. package/dist/module/providers/StreamCall/index.js.map +1 -1
  67. package/dist/module/utils/StreamVideoRN/index.js +33 -21
  68. package/dist/module/utils/StreamVideoRN/index.js.map +1 -1
  69. package/dist/module/utils/internal/callingx/audioSessionPromise.js +61 -0
  70. package/dist/module/utils/internal/callingx/audioSessionPromise.js.map +1 -0
  71. package/dist/module/utils/internal/callingx/callingx.js +114 -0
  72. package/dist/module/utils/internal/callingx/callingx.js.map +1 -0
  73. package/dist/module/utils/internal/registerSDKGlobals.js +52 -3
  74. package/dist/module/utils/internal/registerSDKGlobals.js.map +1 -1
  75. package/dist/module/utils/keepCallAliveHeadlessTask.js +42 -0
  76. package/dist/module/utils/keepCallAliveHeadlessTask.js.map +1 -0
  77. package/dist/module/utils/push/android.js +137 -204
  78. package/dist/module/utils/push/android.js.map +1 -1
  79. package/dist/module/utils/push/internal/ios.js +17 -34
  80. package/dist/module/utils/push/internal/ios.js.map +1 -1
  81. package/dist/module/utils/push/internal/rxSubjects.js +0 -44
  82. package/dist/module/utils/push/internal/rxSubjects.js.map +1 -1
  83. package/dist/module/utils/push/internal/utils.js +63 -49
  84. package/dist/module/utils/push/internal/utils.js.map +1 -1
  85. package/dist/module/utils/push/ios.js.map +1 -1
  86. package/dist/module/utils/push/libs/callingx.js +70 -0
  87. package/dist/module/utils/push/libs/callingx.js.map +1 -0
  88. package/dist/module/utils/push/libs/index.js +1 -2
  89. package/dist/module/utils/push/libs/index.js.map +1 -1
  90. package/dist/module/utils/push/libs/notifee/index.js +0 -18
  91. package/dist/module/utils/push/libs/notifee/index.js.map +1 -1
  92. package/dist/module/utils/push/setupCallingExpEvents.js +99 -0
  93. package/dist/module/utils/push/setupCallingExpEvents.js.map +1 -0
  94. package/dist/module/utils/push/setupIosVoipPushEvents.js +7 -6
  95. package/dist/module/utils/push/setupIosVoipPushEvents.js.map +1 -1
  96. package/dist/module/version.js +1 -1
  97. package/dist/module/version.js.map +1 -1
  98. package/dist/typescript/hooks/push/index.d.ts.map +1 -1
  99. package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts +5 -0
  100. package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts.map +1 -0
  101. package/dist/typescript/hooks/push/useIosVoipPushEventsSetupEffect.d.ts.map +1 -1
  102. package/dist/typescript/hooks/useAndroidKeepCallAliveEffect.d.ts.map +1 -1
  103. package/dist/typescript/index.d.ts +1 -0
  104. package/dist/typescript/index.d.ts.map +1 -1
  105. package/dist/typescript/modules/call-manager/CallManager.d.ts +5 -0
  106. package/dist/typescript/modules/call-manager/CallManager.d.ts.map +1 -1
  107. package/dist/typescript/utils/StreamVideoRN/index.d.ts +20 -2
  108. package/dist/typescript/utils/StreamVideoRN/index.d.ts.map +1 -1
  109. package/dist/typescript/utils/StreamVideoRN/types.d.ts +63 -25
  110. package/dist/typescript/utils/StreamVideoRN/types.d.ts.map +1 -1
  111. package/dist/typescript/utils/internal/callingx/audioSessionPromise.d.ts +16 -0
  112. package/dist/typescript/utils/internal/callingx/audioSessionPromise.d.ts.map +1 -0
  113. package/dist/typescript/utils/internal/callingx/callingx.d.ts +17 -0
  114. package/dist/typescript/utils/internal/callingx/callingx.d.ts.map +1 -0
  115. package/dist/typescript/utils/internal/registerSDKGlobals.d.ts.map +1 -1
  116. package/dist/typescript/utils/keepCallAliveHeadlessTask.d.ts +10 -0
  117. package/dist/typescript/utils/keepCallAliveHeadlessTask.d.ts.map +1 -0
  118. package/dist/typescript/utils/push/android.d.ts +1 -2
  119. package/dist/typescript/utils/push/android.d.ts.map +1 -1
  120. package/dist/typescript/utils/push/internal/ios.d.ts.map +1 -1
  121. package/dist/typescript/utils/push/internal/rxSubjects.d.ts +0 -33
  122. package/dist/typescript/utils/push/internal/rxSubjects.d.ts.map +1 -1
  123. package/dist/typescript/utils/push/internal/utils.d.ts +14 -8
  124. package/dist/typescript/utils/push/internal/utils.d.ts.map +1 -1
  125. package/dist/typescript/utils/push/ios.d.ts +1 -2
  126. package/dist/typescript/utils/push/ios.d.ts.map +1 -1
  127. package/dist/typescript/utils/push/libs/callingx.d.ts +9 -0
  128. package/dist/typescript/utils/push/libs/callingx.d.ts.map +1 -0
  129. package/dist/typescript/utils/push/libs/index.d.ts +1 -2
  130. package/dist/typescript/utils/push/libs/index.d.ts.map +1 -1
  131. package/dist/typescript/utils/push/libs/notifee/index.d.ts +0 -1
  132. package/dist/typescript/utils/push/libs/notifee/index.d.ts.map +1 -1
  133. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts +8 -0
  134. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts.map +1 -0
  135. package/dist/typescript/utils/push/setupIosVoipPushEvents.d.ts.map +1 -1
  136. package/dist/typescript/version.d.ts +1 -1
  137. package/dist/typescript/version.d.ts.map +1 -1
  138. package/expo-config-plugin/dist/withAndroidManifest.js +1 -33
  139. package/expo-config-plugin/dist/withAndroidPermissions.js +2 -7
  140. package/expo-config-plugin/dist/withAppDelegate.js +19 -197
  141. package/expo-config-plugin/dist/withMainActivity.js +1 -1
  142. package/expo-config-plugin/dist/withiOSInfoPlist.js +2 -3
  143. package/ios/StreamInCallManager.m +2 -0
  144. package/ios/StreamInCallManager.swift +19 -7
  145. package/ios/StreamVideoReactNative.h +7 -4
  146. package/ios/StreamVideoReactNative.m +189 -82
  147. package/package.json +13 -18
  148. package/src/hooks/push/index.ts +0 -2
  149. package/src/hooks/push/useCallingExpWithCallingStateEffect.ts +147 -0
  150. package/src/hooks/push/useIosVoipPushEventsSetupEffect.ts +21 -34
  151. package/src/hooks/useAndroidKeepCallAliveEffect.ts +94 -120
  152. package/src/index.ts +1 -0
  153. package/src/modules/call-manager/CallManager.ts +36 -0
  154. package/src/modules/call-manager/native-module.d.ts +7 -0
  155. package/src/providers/StreamCall/index.tsx +6 -6
  156. package/src/utils/StreamVideoRN/index.ts +40 -30
  157. package/src/utils/StreamVideoRN/types.ts +65 -25
  158. package/src/utils/internal/callingx/audioSessionPromise.ts +65 -0
  159. package/src/utils/internal/callingx/callingx.ts +165 -0
  160. package/src/utils/internal/registerSDKGlobals.ts +47 -4
  161. package/src/utils/keepCallAliveHeadlessTask.ts +54 -0
  162. package/src/utils/push/android.ts +196 -311
  163. package/src/utils/push/internal/ios.ts +28 -44
  164. package/src/utils/push/internal/rxSubjects.ts +0 -61
  165. package/src/utils/push/internal/utils.ts +104 -63
  166. package/src/utils/push/ios.ts +1 -6
  167. package/src/utils/push/libs/callingx.ts +93 -0
  168. package/src/utils/push/libs/index.ts +1 -2
  169. package/src/utils/push/libs/notifee/index.ts +0 -27
  170. package/src/utils/push/setupCallingExpEvents.ts +135 -0
  171. package/src/utils/push/setupIosVoipPushEvents.ts +11 -7
  172. package/src/version.ts +1 -1
  173. package/android/src/main/java/com/streamvideo/reactnative/util/CallAliveServiceChecker.kt +0 -95
  174. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js +0 -160
  175. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +0 -1
  176. package/dist/commonjs/hooks/push/useProcessPushCallEffect.js +0 -67
  177. package/dist/commonjs/hooks/push/useProcessPushCallEffect.js.map +0 -1
  178. package/dist/commonjs/utils/push/libs/callkeep.js +0 -17
  179. package/dist/commonjs/utils/push/libs/callkeep.js.map +0 -1
  180. package/dist/commonjs/utils/push/libs/voipPushNotification.js +0 -17
  181. package/dist/commonjs/utils/push/libs/voipPushNotification.js.map +0 -1
  182. package/dist/commonjs/utils/push/setupIosCallKeepEvents.js +0 -205
  183. package/dist/commonjs/utils/push/setupIosCallKeepEvents.js.map +0 -1
  184. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js +0 -153
  185. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +0 -1
  186. package/dist/module/hooks/push/useProcessPushCallEffect.js +0 -60
  187. package/dist/module/hooks/push/useProcessPushCallEffect.js.map +0 -1
  188. package/dist/module/utils/push/libs/callkeep.js +0 -11
  189. package/dist/module/utils/push/libs/callkeep.js.map +0 -1
  190. package/dist/module/utils/push/libs/voipPushNotification.js +0 -11
  191. package/dist/module/utils/push/libs/voipPushNotification.js.map +0 -1
  192. package/dist/module/utils/push/setupIosCallKeepEvents.js +0 -199
  193. package/dist/module/utils/push/setupIosCallKeepEvents.js.map +0 -1
  194. package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts +0 -5
  195. package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts.map +0 -1
  196. package/dist/typescript/hooks/push/useProcessPushCallEffect.d.ts +0 -8
  197. package/dist/typescript/hooks/push/useProcessPushCallEffect.d.ts.map +0 -1
  198. package/dist/typescript/utils/push/libs/callkeep.d.ts +0 -3
  199. package/dist/typescript/utils/push/libs/callkeep.d.ts.map +0 -1
  200. package/dist/typescript/utils/push/libs/voipPushNotification.d.ts +0 -3
  201. package/dist/typescript/utils/push/libs/voipPushNotification.d.ts.map +0 -1
  202. package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts +0 -6
  203. package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts.map +0 -1
  204. package/src/hooks/push/useIosCallkeepWithCallingStateEffect.ts +0 -235
  205. package/src/hooks/push/useProcessPushCallEffect.ts +0 -108
  206. package/src/utils/push/libs/callkeep.ts +0 -16
  207. package/src/utils/push/libs/voipPushNotification.ts +0 -17
  208. package/src/utils/push/setupIosCallKeepEvents.ts +0 -252
@@ -1,10 +1,9 @@
1
- import { AppState, NativeModules, Platform } from 'react-native';
2
- import { getCallKeepLib, getVoipPushNotificationLib } from '../libs';
3
- import { voipPushNotificationCallCId$ } from './rxSubjects';
1
+ import { Platform } from 'react-native';
4
2
  import { pushUnsubscriptionCallbacks } from './constants';
5
- import { canAddPushWSSubscriptionsRef, shouldCallBeEnded } from './utils';
3
+ import { canListenToWS, shouldCallBeClosed } from './utils';
6
4
  import { StreamVideoConfig } from '../../StreamVideoRN/types';
7
5
  import { videoLoggerSystem } from '@stream-io/video-client';
6
+ import { getCallingxLib } from '../libs/callingx';
8
7
 
9
8
  export const onVoipNotificationReceived = async (
10
9
  notification: any,
@@ -32,71 +31,57 @@ export const onVoipNotificationReceived = async (
32
31
  "version": "v2"
33
32
  }
34
33
  } */
34
+ const logger = videoLoggerSystem.getLogger(
35
+ 'callingx - onVoipNotificationReceived',
36
+ );
37
+
35
38
  const sender = notification?.stream?.sender;
36
39
  const type = notification?.stream?.type;
37
40
  // do not process any other notifications other than stream.video or ringing
38
41
  if (sender !== 'stream.video' && type !== 'call.ring') {
39
42
  return;
40
43
  }
44
+
41
45
  const call_cid = notification?.stream?.call_cid;
42
46
  if (!call_cid || Platform.OS !== 'ios' || !pushConfig.ios.pushProviderName) {
43
47
  return;
44
48
  }
45
- const logger = videoLoggerSystem.getLogger('setupIosVoipPushEvents');
46
- const client = await pushConfig.createStreamVideoClient();
47
49
 
48
- if (!client) {
50
+ const callingx = getCallingxLib();
51
+ if (callingx.isCallTracked(call_cid)) {
52
+ //same call_cid is already tracked, so we skip the notification
49
53
  logger.debug(
50
- 'client not found, not processing call.ring voip push notification',
54
+ `the same call_cid ${call_cid} is already tracked, skipping the call.ring notification`,
51
55
  );
52
56
  return;
53
57
  }
54
- const shouldRejectCallWhenBusy = client['rejectCallWhenBusy'] ?? false;
55
- if (shouldRejectCallWhenBusy) {
56
- // inform the iOS native module that we should reject call when busy
57
- NativeModules.StreamVideoReactNative.setShouldRejectCallWhenBusy(
58
- shouldRejectCallWhenBusy,
59
- );
60
- }
61
- const callFromPush = await client.onRingingCall(call_cid);
62
- let uuid = '';
63
- try {
64
- uuid =
65
- await NativeModules?.StreamVideoReactNative?.getIncomingCallUUid(
66
- call_cid,
67
- );
68
- } catch (error) {
69
- logger.error('Error in getting call uuid from native module', error);
70
- }
71
- if (!uuid) {
72
- logger.error(
73
- `Not processing call.ring push notification, as no uuid found for call_cid: ${call_cid}`,
58
+
59
+ const client = await pushConfig.createStreamVideoClient();
60
+ if (!client) {
61
+ logger.debug(
62
+ 'client not found, not processing call.ring voip push notification',
74
63
  );
75
64
  return;
76
65
  }
77
- const created_by_id = notification?.stream?.created_by_id;
78
- const receiver_id = notification?.stream?.receiver_id;
66
+
67
+ const callFromPush = await client.onRingingCall(call_cid);
68
+
79
69
  function closeCallIfNecessary() {
80
- const { mustEndCall, callkeepReason } = shouldCallBeEnded(
70
+ const { mustEndCall, endCallReason } = shouldCallBeClosed(
81
71
  callFromPush,
82
- created_by_id,
83
- receiver_id,
72
+ notification?.stream,
84
73
  );
85
74
  if (mustEndCall) {
86
- const callkeep = getCallKeepLib();
87
75
  logger.debug(
88
- `callkeep.reportEndCallWithUUID for uuid: ${uuid}, call_cid: ${call_cid}, reason: ${callkeepReason}`,
76
+ `callingx.endCallWithReason for call_cid: ${call_cid} endCallReason: ${endCallReason}`,
89
77
  );
90
- callkeep.reportEndCallWithUUID(uuid, callkeepReason);
91
- const voipPushNotification = getVoipPushNotificationLib();
92
- voipPushNotification.onVoipNotificationCompleted(uuid);
78
+ callingx.endCallWithReason(call_cid, endCallReason);
93
79
  return true;
94
80
  }
95
81
  return false;
96
82
  }
83
+
97
84
  const closed = closeCallIfNecessary();
98
- const canListenToWS = () =>
99
- canAddPushWSSubscriptionsRef.current && AppState.currentState !== 'active';
100
85
  if (!closed && canListenToWS()) {
101
86
  const unsubscribe = callFromPush.on('all', (event) => {
102
87
  const _canListenToWS = canListenToWS();
@@ -121,10 +106,9 @@ export const onVoipNotificationReceived = async (
121
106
  pushUnsubscriptionCallbacks.get(call_cid)?.forEach((cb) => cb());
122
107
  pushUnsubscriptionCallbacks.set(call_cid, [unsubscribe]);
123
108
  }
124
- // send the info to this subject, it is listened by callkeep events
125
- // callkeep events will then accept/reject the call
109
+
110
+ // callingx event listeners (setupCallingExpEvents) will handle accept/reject
126
111
  logger.debug(
127
- `call_cid:${call_cid} uuid:${uuid} received and processed from call.ring push notification`,
112
+ `call_cid:${call_cid} received and processed from call.ring push notification`,
128
113
  );
129
- voipPushNotificationCallCId$.next(call_cid);
130
114
  };
@@ -8,64 +8,3 @@ import type { NonRingingPushEvent } from '../../StreamVideoRN/types';
8
8
  export const pushNonRingingCallData$ = new BehaviorSubject<
9
9
  { cid: string; type: NonRingingPushEvent } | undefined
10
10
  >(undefined);
11
-
12
- /**
13
- * This rxjs subject is used to store the call cid of the accepted incoming call from push notification
14
- * Note: it is should be subscribed only when a user has connected to the websocket of Stream
15
- */
16
- export const pushAcceptedIncomingCallCId$ = new BehaviorSubject<
17
- string | undefined
18
- >(undefined);
19
-
20
- /**
21
- * This rxjs subject is used to store the call cid of the tapped incoming call from push notification it is neither accepted nor rejected yet
22
- * Note: it should be subscribed only when a user has connected to the websocket of Stream
23
- */
24
- export const pushTappedIncomingCallCId$ = new BehaviorSubject<
25
- string | undefined
26
- >(undefined);
27
-
28
- /**
29
- * This rxjs subject is used to store the call cid of the delivered incoming call from push notification it is neither accepted nor rejected yet
30
- * Used so that the call is navigated to when app is open from being killed
31
- * Note: it should be subscribed only when a user has connected to the websocket of Stream
32
- */
33
- export const pushAndroidBackgroundDeliveredIncomingCallCId$ =
34
- new BehaviorSubject<string | undefined>(undefined);
35
-
36
- /**
37
- * This rxjs subject is used to store the call cid of the accepted incoming call from push notification
38
- * Note: it should be subscribed only when a user has connected to the websocket of Stream
39
- */
40
- export const pushRejectedIncomingCallCId$ = new BehaviorSubject<
41
- string | undefined
42
- >(undefined);
43
-
44
- /**
45
- * This rxjs subject is used to store the call cid of the incoming call from ios voip pushkit notification
46
- */
47
- export const voipPushNotificationCallCId$ = new BehaviorSubject<
48
- string | undefined
49
- >(undefined);
50
-
51
- /** The pair of cid of a call and its corresponding uuid created in the native side */
52
- type CallkeepMap = {
53
- uuid: string;
54
- cid: string;
55
- };
56
-
57
- /*
58
- * This rxjs subject should only used to store the CallkeepMap
59
- * for the incoming call when on foreground
60
- * or in other words, when we get didDisplayIncomingCall from callkeep lib
61
- */
62
- export const voipCallkeepCallOnForegroundMap$ = new BehaviorSubject<
63
- CallkeepMap | undefined
64
- >(undefined);
65
-
66
- /*
67
- * This rxjs subject should only used to store the CallkeepMap when it was accepted in the native dialer
68
- */
69
- export const voipCallkeepAcceptedCallOnNativeDialerMap$ = new BehaviorSubject<
70
- CallkeepMap | undefined
71
- >(undefined);
@@ -10,9 +10,12 @@ import type {
10
10
  } from '../../StreamVideoRN/types';
11
11
  import { onNewCallNotification } from '../../internal/newNotificationCallbacks';
12
12
  import { pushUnsubscriptionCallbacks } from './constants';
13
+ import { AppState } from 'react-native';
14
+ import type { EndCallReason } from '@stream-io/react-native-callingx';
13
15
 
14
16
  type PushConfig = NonNullable<StreamVideoConfig['push']>;
15
17
 
18
+ const logger = videoLoggerSystem.getLogger('callingx');
16
19
  type CanAddPushWSSubscriptionsRef = { current: boolean };
17
20
 
18
21
  /**
@@ -24,44 +27,37 @@ export const shouldCallBeEnded = (
24
27
  created_by_id: string | undefined,
25
28
  receiver_id: string | undefined,
26
29
  ) => {
27
- /* callkeep reasons for ending a call
28
- FAILED: 1,
29
- REMOTE_ENDED: 2,
30
- UNANSWERED: 3,
31
- ANSWERED_ELSEWHERE: 4,
32
- DECLINED_ELSEWHERE: 5,
33
- MISSED: 6
34
- */
35
30
  const callSession = callFromPush.state.session;
36
31
  const rejected_by = callSession?.rejected_by;
37
32
  const accepted_by = callSession?.accepted_by;
38
33
  let mustEndCall = false;
39
- let callkeepReason = 0;
34
+ let endCallReason: EndCallReason = 'unknown';
35
+
40
36
  if (created_by_id && rejected_by) {
41
37
  if (rejected_by[created_by_id]) {
42
- // call was cancelled by the caller
38
+ // call was cancelled by the caller before the receiver could answer
43
39
  mustEndCall = true;
44
- callkeepReason = 2;
40
+ endCallReason = 'canceled';
45
41
  }
46
42
  } else if (receiver_id && rejected_by) {
47
43
  if (rejected_by[receiver_id]) {
48
44
  // call was rejected by the receiver in some other device
49
45
  mustEndCall = true;
50
- callkeepReason = 5;
46
+ endCallReason = 'rejected';
51
47
  }
52
48
  } else if (receiver_id && accepted_by) {
53
49
  if (accepted_by[receiver_id]) {
54
50
  // call was accepted by the receiver in some other device
55
51
  mustEndCall = true;
56
- callkeepReason = 4;
52
+ endCallReason = 'answeredElsewhere';
57
53
  }
58
54
  }
59
55
  videoLoggerSystem
60
56
  .getLogger('shouldCallBeEnded')
61
57
  .debug(
62
- `callCid: ${callFromPush.cid} mustEndCall: ${mustEndCall} callkeepReason: ${callkeepReason}`,
58
+ `callCid: ${callFromPush.cid} mustEndCall: ${mustEndCall} endCallReason: ${endCallReason}`,
63
59
  );
64
- return { mustEndCall, callkeepReason };
60
+ return { mustEndCall, endCallReason };
65
61
  };
66
62
 
67
63
  /* An action for the notification or callkeep and app does not have JS context setup yet, so we need to do two steps:
@@ -71,71 +67,95 @@ export const shouldCallBeEnded = (
71
67
  export const processCallFromPushInBackground = async (
72
68
  pushConfig: PushConfig,
73
69
  call_cid: string,
74
- action: Parameters<typeof processCallFromPush>[2],
70
+ action: 'accept' | 'decline' | 'pressed' | 'backgroundDelivered',
71
+ /**
72
+ * Callback to inform iOS CallKit that the action can be fulfilled
73
+ * Needed for iOS CallKit fullfillment of action
74
+ * as per ios docs "Instead, wait until you establish a connection and then fulfill the object."
75
+ * This means we wait until call.get() is done and call.join() or call.leave() is invoked (not completed) to fulfill the action
76
+ */
77
+ onIOSActionCanBeFulfilled: (didFail: boolean) => void,
75
78
  ) => {
76
79
  let videoClient: StreamVideoClient | undefined;
77
80
 
78
81
  try {
79
82
  videoClient = await pushConfig.createStreamVideoClient();
80
83
  if (!videoClient) {
81
- return;
84
+ throw new Error('createStreamVideoClient returned null');
82
85
  }
83
86
  } catch (e) {
84
- const logger = videoLoggerSystem.getLogger(
85
- 'processCallFromPushInBackground',
87
+ logger.error(
88
+ 'processCallFromPushInBackground: failed to create video client',
89
+ e,
86
90
  );
87
- logger.error('failed to create video client', e);
91
+ onIOSActionCanBeFulfilled(true);
88
92
  return;
89
93
  }
90
- await processCallFromPush(videoClient, call_cid, action, pushConfig);
91
- };
92
94
 
93
- /**
94
- * This function is used process the call from push notifications due to incoming call
95
- * It does the following steps:
96
- * 1. Get the call from the client if present or create a new call
97
- * 2. Fetch the latest state of the call from the server if its not already in ringing state
98
- * 3. Join or leave the call based on the user's action.
99
- */
100
- export const processCallFromPush = async (
101
- client: StreamVideoClient,
102
- call_cid: string,
103
- action: 'accept' | 'decline' | 'pressed' | 'backgroundDelivered',
104
- pushConfig: PushConfig,
105
- ) => {
106
95
  let callFromPush: Call;
107
96
  try {
108
- callFromPush = await client.onRingingCall(call_cid);
97
+ callFromPush = await videoClient.onRingingCall(call_cid);
109
98
  } catch (e) {
110
- const logger = videoLoggerSystem.getLogger('processCallFromPush');
111
- logger.error('failed to fetch call from push notification', e);
99
+ logger.error(
100
+ 'processCallFromPushInBackground: failed to fetch call from push notification',
101
+ e,
102
+ );
103
+ onIOSActionCanBeFulfilled(true);
112
104
  return;
113
105
  }
114
- // note: when action was pressed or delivered, we dont need to do anything as the only thing is to do is to get the call which adds it to the client
115
- try {
116
- if (action === 'accept') {
117
- if (pushConfig.publishOptions) {
118
- callFromPush.updatePublishOptions(pushConfig.publishOptions);
119
- }
120
- videoLoggerSystem
121
- .getLogger('processCallFromPush')
122
- .debug(
123
- `joining call from push notification with callCid: ${callFromPush.cid}`,
124
- );
106
+ if (action === 'accept') {
107
+ if (pushConfig.publishOptions) {
108
+ callFromPush.updatePublishOptions(pushConfig.publishOptions);
109
+ }
110
+ logger.debug(
111
+ `joining call from push notification with callCid: ${callFromPush.cid}`,
112
+ );
113
+ const callingState = callFromPush.state.callingState;
114
+ if (
115
+ callingState !== CallingState.RINGING &&
116
+ callingState !== CallingState.IDLE
117
+ ) {
118
+ logger.debug(
119
+ `skipping join call as it is not in ringing or idle state from push notification. callCid: ${callFromPush.cid}`,
120
+ );
121
+ onIOSActionCanBeFulfilled(true);
122
+ return;
123
+ }
124
+ try {
125
+ onIOSActionCanBeFulfilled(false);
125
126
  await callFromPush.join();
126
- } else if (action === 'decline') {
127
- const canReject =
128
- callFromPush.state.callingState === CallingState.RINGING;
129
- videoLoggerSystem
130
- .getLogger('processCallFromPush')
131
- .debug(
132
- `declining call from push notification with callCid: ${callFromPush.cid} reject: ${canReject}`,
133
- );
134
- await callFromPush.leave({ reject: canReject, reason: 'decline' });
127
+ } catch (e) {
128
+ logger.warn(
129
+ 'processCallFromPushInBackground: failed to join call from push notification',
130
+ e,
131
+ );
132
+ }
133
+ } else if (action === 'decline') {
134
+ const alreadyLeft = callFromPush.state.callingState === CallingState.LEFT;
135
+ if (alreadyLeft) {
136
+ onIOSActionCanBeFulfilled(false);
137
+ return;
138
+ }
139
+ const canReject =
140
+ callFromPush.state.callingState === CallingState.RINGING ||
141
+ callFromPush.state.callingState === CallingState.IDLE;
142
+ const isCurrentUserMember = callFromPush.state.members.some(
143
+ (member) => member.user_id === callFromPush.currentUserId,
144
+ );
145
+ const reject = canReject && isCurrentUserMember;
146
+ logger.debug(
147
+ `declining call from push notification with callCid: ${callFromPush.cid} reject: ${reject}`,
148
+ );
149
+ try {
150
+ await callFromPush.leave({ reject, reason: 'decline' });
151
+ onIOSActionCanBeFulfilled(false);
152
+ } catch (e) {
153
+ logger.warn(
154
+ 'processCallFromPushInBackground: failed to decline call from push notification',
155
+ e,
156
+ );
157
+ onIOSActionCanBeFulfilled(true);
135
158
  }
136
- } catch (e) {
137
- const logger = videoLoggerSystem.getLogger('processCallFromPush');
138
- logger.warn(`failed to process ${action} call from push notification`, e);
139
159
  }
140
160
  };
141
161
 
@@ -163,10 +183,13 @@ export const processNonIncomingCallFromPush = async (
163
183
  await callFromPush.get();
164
184
  }
165
185
  } catch (e) {
166
- const logger = videoLoggerSystem.getLogger(
186
+ const nonRingingCallLogger = videoLoggerSystem.getLogger(
167
187
  'processNonIncomingCallFromPush',
168
188
  );
169
- logger.error('failed to fetch call from push notification', e);
189
+ nonRingingCallLogger.error(
190
+ 'failed to fetch call from push notification',
191
+ e,
192
+ );
170
193
  return;
171
194
  }
172
195
  onNewCallNotification(callFromPush, nonRingingNotificationType);
@@ -191,3 +214,21 @@ export const clearPushWSEventSubscriptions = (call_cid: string) => {
191
214
  export const canAddPushWSSubscriptionsRef: CanAddPushWSSubscriptionsRef = {
192
215
  current: true,
193
216
  };
217
+
218
+ export const canListenToWS = () =>
219
+ canAddPushWSSubscriptionsRef.current && AppState.currentState !== 'active';
220
+
221
+ export const shouldCallBeClosed = (
222
+ call: Call,
223
+ pushData: { [key: string]: string | object },
224
+ ) => {
225
+ const created_by_id = pushData?.created_by_id as string;
226
+ const receiver_id = pushData?.receiver_id as string;
227
+
228
+ const { mustEndCall, endCallReason } = shouldCallBeEnded(
229
+ call,
230
+ created_by_id,
231
+ receiver_id,
232
+ );
233
+ return { mustEndCall, endCallReason };
234
+ };
@@ -62,12 +62,7 @@ export const oniOSExpoNotificationEvent = (event: ExpoNotification) => {
62
62
  }
63
63
  };
64
64
 
65
- export const oniOSNotifeeEvent = ({
66
- event,
67
- }: {
68
- event: Event;
69
- isBackground: boolean;
70
- }) => {
65
+ export const oniOSNotifeeEvent = ({ event }: { event: Event }) => {
71
66
  if (Platform.OS !== 'ios') return;
72
67
  const pushConfig = StreamVideoRN.getConfig().push;
73
68
  const { type, detail } = event;
@@ -0,0 +1,93 @@
1
+ import { StreamVideoConfig } from '../../StreamVideoRN/types';
2
+
3
+ export type RNCallingxType =
4
+ import('@stream-io/react-native-callingx').ICallingxModule;
5
+ export type EventData = import('@stream-io/react-native-callingx').EventData;
6
+ export type EventParams =
7
+ import('@stream-io/react-native-callingx').EventParams;
8
+ export type CallingExpOptions =
9
+ import('@stream-io/react-native-callingx').CallingExpOptions;
10
+
11
+ let callingx: RNCallingxType | undefined;
12
+
13
+ try {
14
+ callingx = require('@stream-io/react-native-callingx').CallingxModule;
15
+ } catch {}
16
+
17
+ export function getCallingxLib() {
18
+ if (!callingx) {
19
+ throw Error('react-native-callingx library is not installed.');
20
+ }
21
+ return callingx;
22
+ }
23
+
24
+ export function getCallingxLibIfAvailable() {
25
+ return callingx ?? undefined;
26
+ }
27
+
28
+ export function extractCallingExpOptions(
29
+ config: StreamVideoConfig,
30
+ ): CallingExpOptions {
31
+ const { push: pushConfig, foregroundService: foregroundServiceConfig } =
32
+ config;
33
+ const callingExpOptions: CallingExpOptions = {};
34
+
35
+ if (pushConfig?.ios) {
36
+ const iosOptions: CallingExpOptions['ios'] = {};
37
+ if (pushConfig.ios.supportsVideo !== undefined) {
38
+ iosOptions.supportsVideo = pushConfig.ios.supportsVideo;
39
+ }
40
+ if (pushConfig.ios.sound !== undefined) {
41
+ iosOptions.sound = pushConfig.ios.sound;
42
+ }
43
+ if (pushConfig.ios.imageName !== undefined) {
44
+ iosOptions.imageName = pushConfig.ios.imageName;
45
+ }
46
+ if (pushConfig.ios.callsHistory !== undefined) {
47
+ iosOptions.callsHistory = pushConfig.ios.callsHistory;
48
+ }
49
+ if (pushConfig.ios.displayCallTimeout !== undefined) {
50
+ iosOptions.displayCallTimeout = pushConfig.ios.displayCallTimeout;
51
+ }
52
+
53
+ if (Object.keys(iosOptions).length > 0) {
54
+ callingExpOptions.ios = iosOptions;
55
+ }
56
+ }
57
+
58
+ const androidOptions: CallingExpOptions['android'] = {};
59
+ if (pushConfig?.android) {
60
+ if (pushConfig.android.incomingChannel) {
61
+ androidOptions.incomingChannel = pushConfig.android.incomingChannel;
62
+ }
63
+ if (pushConfig.android.titleTransformer) {
64
+ androidOptions.titleTransformer = pushConfig.android.titleTransformer;
65
+ }
66
+ if (pushConfig.android.subtitleTransformer) {
67
+ androidOptions.subtitleTransformer =
68
+ pushConfig.android.subtitleTransformer;
69
+ }
70
+ if (pushConfig.android.notificationTexts) {
71
+ androidOptions.notificationTexts = pushConfig.android.notificationTexts;
72
+ }
73
+ }
74
+
75
+ if (foregroundServiceConfig.android.channel) {
76
+ androidOptions.ongoingChannel = foregroundServiceConfig.android.channel;
77
+ }
78
+
79
+ if (Object.keys(androidOptions).length > 0) {
80
+ callingExpOptions.android = androidOptions;
81
+ }
82
+
83
+ if (pushConfig?.shouldRejectCallWhenBusy !== undefined) {
84
+ callingExpOptions.shouldRejectCallWhenBusy =
85
+ pushConfig.shouldRejectCallWhenBusy;
86
+ }
87
+
88
+ if (pushConfig?.enableOngoingCalls !== undefined) {
89
+ callingExpOptions.enableOngoingCalls = pushConfig?.enableOngoingCalls;
90
+ }
91
+
92
+ return callingExpOptions;
93
+ }
@@ -1,9 +1,8 @@
1
1
  export * from './expoNotifications';
2
2
  export * from './firebaseMessaging';
3
3
  export * from './iosPushNotification';
4
- export * from './voipPushNotification';
5
- export * from './callkeep';
6
4
  export * from './notifee';
5
+ export * from './callingx';
7
6
 
8
7
  /*
9
8
  NOTE: must keep each libs in different files
@@ -1,6 +1,4 @@
1
- import { PermissionsAndroid } from 'react-native';
2
1
  import { lib, type Type } from './lib';
3
- import { videoLoggerSystem } from '@stream-io/video-client';
4
2
 
5
3
  export type NotifeeLib = Type;
6
4
 
@@ -36,34 +34,9 @@ export function getNotifeeLibThrowIfNotInstalledForPush() {
36
34
  }
37
35
 
38
36
  export function getNotifeeLibNoThrowForKeepCallAlive() {
39
- if (!lib) {
40
- const logger = videoLoggerSystem.getLogger('getNotifeeLibNoThrow');
41
- logger.info(
42
- `${'@notifee/react-native library not installed. It is required to keep call alive in the background for Android. '}${INSTALLATION_INSTRUCTION}`,
43
- );
44
- }
45
37
  return lib;
46
38
  }
47
39
 
48
- export async function getKeepCallAliveForegroundServiceTypes() {
49
- const types: AndroidForegroundServiceType[] = [
50
- AndroidForegroundServiceType.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK,
51
- ];
52
- const hasCameraPermission = await PermissionsAndroid.check(
53
- PermissionsAndroid.PERMISSIONS.CAMERA!,
54
- );
55
- if (hasCameraPermission) {
56
- types.push(AndroidForegroundServiceType.FOREGROUND_SERVICE_TYPE_CAMERA);
57
- }
58
- const hasMicrophonePermission = await PermissionsAndroid.check(
59
- PermissionsAndroid.PERMISSIONS.RECORD_AUDIO!,
60
- );
61
- if (hasMicrophonePermission) {
62
- types.push(AndroidForegroundServiceType.FOREGROUND_SERVICE_TYPE_MICROPHONE);
63
- }
64
- return types;
65
- }
66
-
67
40
  export function getIncomingCallForegroundServiceTypes() {
68
41
  const types: AndroidForegroundServiceType[] = [
69
42
  AndroidForegroundServiceType.FOREGROUND_SERVICE_TYPE_SHORT_SERVICE,