@stream-io/video-react-native-sdk 1.29.4-beta.0 → 1.30.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 (276) hide show
  1. package/CHANGELOG.md +3162 -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/components/Call/CallContent/CallContent.js +13 -7
  9. package/dist/commonjs/components/Call/CallContent/CallContent.js.map +1 -1
  10. package/dist/commonjs/components/Call/CallContent/RTCViewPipIOS.js +50 -14
  11. package/dist/commonjs/components/Call/CallContent/RTCViewPipIOS.js.map +1 -1
  12. package/dist/commonjs/components/Call/CallContent/RTCViewPipNative.js +27 -0
  13. package/dist/commonjs/components/Call/CallContent/RTCViewPipNative.js.map +1 -1
  14. package/dist/commonjs/components/Call/CallLayout/CallParticipantsGrid.js +19 -10
  15. package/dist/commonjs/components/Call/CallLayout/CallParticipantsGrid.js.map +1 -1
  16. package/dist/commonjs/components/Call/CallLayout/CallParticipantsSpotlight.js +12 -9
  17. package/dist/commonjs/components/Call/CallLayout/CallParticipantsSpotlight.js.map +1 -1
  18. package/dist/commonjs/components/Call/CallParticipantsList/CallParticipantsList.js +19 -4
  19. package/dist/commonjs/components/Call/CallParticipantsList/CallParticipantsList.js.map +1 -1
  20. package/dist/commonjs/hooks/push/index.js +2 -0
  21. package/dist/commonjs/hooks/push/index.js.map +1 -1
  22. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js +160 -0
  23. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +1 -0
  24. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js +31 -18
  25. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
  26. package/dist/commonjs/hooks/push/useProcessPushCallEffect.js +67 -0
  27. package/dist/commonjs/hooks/push/useProcessPushCallEffect.js.map +1 -0
  28. package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js +97 -64
  29. package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
  30. package/dist/commonjs/index.js +0 -1
  31. package/dist/commonjs/index.js.map +1 -1
  32. package/dist/commonjs/modules/call-manager/CallManager.js +0 -26
  33. package/dist/commonjs/modules/call-manager/CallManager.js.map +1 -1
  34. package/dist/commonjs/providers/StreamCall/index.js +6 -6
  35. package/dist/commonjs/providers/StreamCall/index.js.map +1 -1
  36. package/dist/commonjs/utils/StreamVideoRN/index.js +21 -33
  37. package/dist/commonjs/utils/StreamVideoRN/index.js.map +1 -1
  38. package/dist/commonjs/utils/hooks/index.js +0 -11
  39. package/dist/commonjs/utils/hooks/index.js.map +1 -1
  40. package/dist/commonjs/utils/internal/registerSDKGlobals.js +3 -52
  41. package/dist/commonjs/utils/internal/registerSDKGlobals.js.map +1 -1
  42. package/dist/commonjs/utils/push/android.js +202 -151
  43. package/dist/commonjs/utils/push/android.js.map +1 -1
  44. package/dist/commonjs/utils/push/internal/ios.js +34 -17
  45. package/dist/commonjs/utils/push/internal/ios.js.map +1 -1
  46. package/dist/commonjs/utils/push/internal/rxSubjects.js +45 -1
  47. package/dist/commonjs/utils/push/internal/rxSubjects.js.map +1 -1
  48. package/dist/commonjs/utils/push/internal/utils.js +20 -32
  49. package/dist/commonjs/utils/push/internal/utils.js.map +1 -1
  50. package/dist/commonjs/utils/push/ios.js.map +1 -1
  51. package/dist/commonjs/utils/push/libs/callkeep.js +17 -0
  52. package/dist/commonjs/utils/push/libs/callkeep.js.map +1 -0
  53. package/dist/commonjs/utils/push/libs/index.js +19 -8
  54. package/dist/commonjs/utils/push/libs/index.js.map +1 -1
  55. package/dist/commonjs/utils/push/libs/notifee/index.js +19 -0
  56. package/dist/commonjs/utils/push/libs/notifee/index.js.map +1 -1
  57. package/dist/commonjs/utils/push/libs/voipPushNotification.js +17 -0
  58. package/dist/commonjs/utils/push/libs/voipPushNotification.js.map +1 -0
  59. package/dist/commonjs/utils/push/setupIosCallKeepEvents.js +205 -0
  60. package/dist/commonjs/utils/push/setupIosCallKeepEvents.js.map +1 -0
  61. package/dist/commonjs/utils/push/setupIosVoipPushEvents.js +6 -7
  62. package/dist/commonjs/utils/push/setupIosVoipPushEvents.js.map +1 -1
  63. package/dist/commonjs/version.js +1 -1
  64. package/dist/commonjs/version.js.map +1 -1
  65. package/dist/module/components/Call/CallContent/CallContent.js +10 -4
  66. package/dist/module/components/Call/CallContent/CallContent.js.map +1 -1
  67. package/dist/module/components/Call/CallContent/RTCViewPipIOS.js +52 -16
  68. package/dist/module/components/Call/CallContent/RTCViewPipIOS.js.map +1 -1
  69. package/dist/module/components/Call/CallContent/RTCViewPipNative.js +27 -0
  70. package/dist/module/components/Call/CallContent/RTCViewPipNative.js.map +1 -1
  71. package/dist/module/components/Call/CallLayout/CallParticipantsGrid.js +19 -10
  72. package/dist/module/components/Call/CallLayout/CallParticipantsGrid.js.map +1 -1
  73. package/dist/module/components/Call/CallLayout/CallParticipantsSpotlight.js +15 -12
  74. package/dist/module/components/Call/CallLayout/CallParticipantsSpotlight.js.map +1 -1
  75. package/dist/module/components/Call/CallParticipantsList/CallParticipantsList.js +20 -5
  76. package/dist/module/components/Call/CallParticipantsList/CallParticipantsList.js.map +1 -1
  77. package/dist/module/hooks/push/index.js +2 -0
  78. package/dist/module/hooks/push/index.js.map +1 -1
  79. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js +153 -0
  80. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +1 -0
  81. package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js +31 -18
  82. package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
  83. package/dist/module/hooks/push/useProcessPushCallEffect.js +60 -0
  84. package/dist/module/hooks/push/useProcessPushCallEffect.js.map +1 -0
  85. package/dist/module/hooks/useAndroidKeepCallAliveEffect.js +99 -66
  86. package/dist/module/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
  87. package/dist/module/index.js +0 -1
  88. package/dist/module/index.js.map +1 -1
  89. package/dist/module/modules/call-manager/CallManager.js +0 -26
  90. package/dist/module/modules/call-manager/CallManager.js.map +1 -1
  91. package/dist/module/providers/StreamCall/index.js +6 -6
  92. package/dist/module/providers/StreamCall/index.js.map +1 -1
  93. package/dist/module/utils/StreamVideoRN/index.js +21 -33
  94. package/dist/module/utils/StreamVideoRN/index.js.map +1 -1
  95. package/dist/module/utils/hooks/index.js +0 -1
  96. package/dist/module/utils/hooks/index.js.map +1 -1
  97. package/dist/module/utils/internal/registerSDKGlobals.js +3 -52
  98. package/dist/module/utils/internal/registerSDKGlobals.js.map +1 -1
  99. package/dist/module/utils/push/android.js +204 -153
  100. package/dist/module/utils/push/android.js.map +1 -1
  101. package/dist/module/utils/push/internal/ios.js +34 -17
  102. package/dist/module/utils/push/internal/ios.js.map +1 -1
  103. package/dist/module/utils/push/internal/rxSubjects.js +44 -0
  104. package/dist/module/utils/push/internal/rxSubjects.js.map +1 -1
  105. package/dist/module/utils/push/internal/utils.js +19 -29
  106. package/dist/module/utils/push/internal/utils.js.map +1 -1
  107. package/dist/module/utils/push/ios.js.map +1 -1
  108. package/dist/module/utils/push/libs/callkeep.js +11 -0
  109. package/dist/module/utils/push/libs/callkeep.js.map +1 -0
  110. package/dist/module/utils/push/libs/index.js +2 -1
  111. package/dist/module/utils/push/libs/index.js.map +1 -1
  112. package/dist/module/utils/push/libs/notifee/index.js +18 -0
  113. package/dist/module/utils/push/libs/notifee/index.js.map +1 -1
  114. package/dist/module/utils/push/libs/voipPushNotification.js +11 -0
  115. package/dist/module/utils/push/libs/voipPushNotification.js.map +1 -0
  116. package/dist/module/utils/push/setupIosCallKeepEvents.js +199 -0
  117. package/dist/module/utils/push/setupIosCallKeepEvents.js.map +1 -0
  118. package/dist/module/utils/push/setupIosVoipPushEvents.js +6 -7
  119. package/dist/module/utils/push/setupIosVoipPushEvents.js.map +1 -1
  120. package/dist/module/version.js +1 -1
  121. package/dist/module/version.js.map +1 -1
  122. package/dist/typescript/components/Call/CallContent/CallContent.d.ts.map +1 -1
  123. package/dist/typescript/components/Call/CallContent/RTCViewPipIOS.d.ts.map +1 -1
  124. package/dist/typescript/components/Call/CallContent/RTCViewPipNative.d.ts +18 -0
  125. package/dist/typescript/components/Call/CallContent/RTCViewPipNative.d.ts.map +1 -1
  126. package/dist/typescript/components/Call/CallLayout/CallParticipantsGrid.d.ts.map +1 -1
  127. package/dist/typescript/components/Call/CallLayout/CallParticipantsSpotlight.d.ts.map +1 -1
  128. package/dist/typescript/components/Call/CallParticipantsList/CallParticipantsList.d.ts.map +1 -1
  129. package/dist/typescript/hooks/push/index.d.ts.map +1 -1
  130. package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts +5 -0
  131. package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts.map +1 -0
  132. package/dist/typescript/hooks/push/useIosVoipPushEventsSetupEffect.d.ts.map +1 -1
  133. package/dist/typescript/hooks/push/useProcessPushCallEffect.d.ts +8 -0
  134. package/dist/typescript/hooks/push/useProcessPushCallEffect.d.ts.map +1 -0
  135. package/dist/typescript/hooks/useAndroidKeepCallAliveEffect.d.ts.map +1 -1
  136. package/dist/typescript/index.d.ts +0 -1
  137. package/dist/typescript/index.d.ts.map +1 -1
  138. package/dist/typescript/modules/call-manager/CallManager.d.ts +0 -5
  139. package/dist/typescript/modules/call-manager/CallManager.d.ts.map +1 -1
  140. package/dist/typescript/utils/StreamVideoRN/index.d.ts +2 -20
  141. package/dist/typescript/utils/StreamVideoRN/index.d.ts.map +1 -1
  142. package/dist/typescript/utils/StreamVideoRN/types.d.ts +29 -54
  143. package/dist/typescript/utils/StreamVideoRN/types.d.ts.map +1 -1
  144. package/dist/typescript/utils/hooks/index.d.ts +0 -1
  145. package/dist/typescript/utils/hooks/index.d.ts.map +1 -1
  146. package/dist/typescript/utils/internal/registerSDKGlobals.d.ts.map +1 -1
  147. package/dist/typescript/utils/push/android.d.ts +2 -1
  148. package/dist/typescript/utils/push/android.d.ts.map +1 -1
  149. package/dist/typescript/utils/push/internal/ios.d.ts.map +1 -1
  150. package/dist/typescript/utils/push/internal/rxSubjects.d.ts +33 -0
  151. package/dist/typescript/utils/push/internal/rxSubjects.d.ts.map +1 -1
  152. package/dist/typescript/utils/push/internal/utils.d.ts +1 -8
  153. package/dist/typescript/utils/push/internal/utils.d.ts.map +1 -1
  154. package/dist/typescript/utils/push/ios.d.ts +2 -1
  155. package/dist/typescript/utils/push/ios.d.ts.map +1 -1
  156. package/dist/typescript/utils/push/libs/callkeep.d.ts +3 -0
  157. package/dist/typescript/utils/push/libs/callkeep.d.ts.map +1 -0
  158. package/dist/typescript/utils/push/libs/index.d.ts +2 -1
  159. package/dist/typescript/utils/push/libs/index.d.ts.map +1 -1
  160. package/dist/typescript/utils/push/libs/notifee/index.d.ts +1 -0
  161. package/dist/typescript/utils/push/libs/notifee/index.d.ts.map +1 -1
  162. package/dist/typescript/utils/push/libs/voipPushNotification.d.ts +3 -0
  163. package/dist/typescript/utils/push/libs/voipPushNotification.d.ts.map +1 -0
  164. package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts +6 -0
  165. package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts.map +1 -0
  166. package/dist/typescript/utils/push/setupIosVoipPushEvents.d.ts.map +1 -1
  167. package/dist/typescript/version.d.ts +1 -1
  168. package/dist/typescript/version.d.ts.map +1 -1
  169. package/expo-config-plugin/dist/withAndroidManifest.js +33 -1
  170. package/expo-config-plugin/dist/withAndroidPermissions.js +7 -2
  171. package/expo-config-plugin/dist/withAppDelegate.js +197 -19
  172. package/expo-config-plugin/dist/withMainActivity.js +1 -1
  173. package/expo-config-plugin/dist/withiOSInfoPlist.js +3 -2
  174. package/ios/PictureInPicture/PictureInPictureAvatarView.swift +273 -0
  175. package/ios/PictureInPicture/PictureInPictureConnectionQualityIndicator.swift +162 -0
  176. package/ios/PictureInPicture/PictureInPictureContent.swift +173 -0
  177. package/ios/PictureInPicture/PictureInPictureContentState.swift +123 -0
  178. package/ios/PictureInPicture/PictureInPictureDelegateProxy.swift +89 -0
  179. package/ios/PictureInPicture/PictureInPictureEnforcedStopAdapter.swift +166 -0
  180. package/ios/PictureInPicture/PictureInPictureLogger.swift +16 -0
  181. package/ios/PictureInPicture/PictureInPictureParticipantOverlayView.swift +217 -0
  182. package/ios/PictureInPicture/PictureInPictureReconnectionView.swift +193 -0
  183. package/ios/PictureInPicture/StreamAVPictureInPictureVideoCallViewController.swift +125 -7
  184. package/ios/PictureInPicture/StreamPictureInPictureController.swift +237 -63
  185. package/ios/PictureInPicture/StreamPictureInPictureControllerProtocol.swift +30 -0
  186. package/ios/PictureInPicture/StreamPictureInPictureVideoRenderer.swift +384 -12
  187. package/ios/RTCViewPip.swift +187 -21
  188. package/ios/RTCViewPipManager.mm +9 -0
  189. package/ios/RTCViewPipManager.swift +3 -3
  190. package/ios/StreamInCallManager.m +0 -2
  191. package/ios/StreamInCallManager.swift +7 -19
  192. package/ios/StreamVideoReactNative.h +4 -7
  193. package/ios/StreamVideoReactNative.m +82 -189
  194. package/package.json +19 -14
  195. package/src/components/Call/CallContent/CallContent.tsx +16 -8
  196. package/src/components/Call/CallContent/RTCViewPipIOS.tsx +81 -15
  197. package/src/components/Call/CallContent/RTCViewPipNative.tsx +36 -0
  198. package/src/components/Call/CallLayout/CallParticipantsGrid.tsx +28 -14
  199. package/src/components/Call/CallLayout/CallParticipantsSpotlight.tsx +19 -10
  200. package/src/components/Call/CallParticipantsList/CallParticipantsList.tsx +20 -5
  201. package/src/hooks/push/index.ts +2 -0
  202. package/src/hooks/push/useIosCallkeepWithCallingStateEffect.ts +235 -0
  203. package/src/hooks/push/useIosVoipPushEventsSetupEffect.ts +34 -21
  204. package/src/hooks/push/useProcessPushCallEffect.ts +108 -0
  205. package/src/hooks/useAndroidKeepCallAliveEffect.ts +120 -94
  206. package/src/index.ts +0 -1
  207. package/src/modules/call-manager/CallManager.ts +0 -36
  208. package/src/modules/call-manager/native-module.d.ts +0 -7
  209. package/src/providers/StreamCall/index.tsx +6 -6
  210. package/src/utils/StreamVideoRN/index.ts +30 -40
  211. package/src/utils/StreamVideoRN/types.ts +29 -56
  212. package/src/utils/hooks/index.ts +0 -1
  213. package/src/utils/internal/registerSDKGlobals.ts +4 -47
  214. package/src/utils/push/android.ts +309 -227
  215. package/src/utils/push/internal/ios.ts +44 -28
  216. package/src/utils/push/internal/rxSubjects.ts +61 -0
  217. package/src/utils/push/internal/utils.ts +26 -45
  218. package/src/utils/push/ios.ts +6 -1
  219. package/src/utils/push/libs/callkeep.ts +16 -0
  220. package/src/utils/push/libs/index.ts +2 -1
  221. package/src/utils/push/libs/notifee/index.ts +27 -0
  222. package/src/utils/push/libs/voipPushNotification.ts +17 -0
  223. package/src/utils/push/setupIosCallKeepEvents.ts +252 -0
  224. package/src/utils/push/setupIosVoipPushEvents.ts +7 -11
  225. package/src/version.ts +1 -1
  226. package/android/src/main/java/com/streamvideo/reactnative/keepalive/KeepAliveNotification.kt +0 -83
  227. package/android/src/main/java/com/streamvideo/reactnative/keepalive/StreamCallKeepAliveHeadlessService.kt +0 -149
  228. package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js +0 -121
  229. package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js.map +0 -1
  230. package/dist/commonjs/utils/hooks/useDebouncedValue.js +0 -24
  231. package/dist/commonjs/utils/hooks/useDebouncedValue.js.map +0 -1
  232. package/dist/commonjs/utils/internal/callingx/audioSessionPromise.js +0 -58
  233. package/dist/commonjs/utils/internal/callingx/audioSessionPromise.js.map +0 -1
  234. package/dist/commonjs/utils/internal/callingx/callingx.js +0 -109
  235. package/dist/commonjs/utils/internal/callingx/callingx.js.map +0 -1
  236. package/dist/commonjs/utils/keepCallAliveHeadlessTask.js +0 -48
  237. package/dist/commonjs/utils/keepCallAliveHeadlessTask.js.map +0 -1
  238. package/dist/commonjs/utils/push/libs/callingx.js +0 -75
  239. package/dist/commonjs/utils/push/libs/callingx.js.map +0 -1
  240. package/dist/commonjs/utils/push/setupCallingExpEvents.js +0 -108
  241. package/dist/commonjs/utils/push/setupCallingExpEvents.js.map +0 -1
  242. package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js +0 -114
  243. package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js.map +0 -1
  244. package/dist/module/utils/hooks/useDebouncedValue.js +0 -19
  245. package/dist/module/utils/hooks/useDebouncedValue.js.map +0 -1
  246. package/dist/module/utils/internal/callingx/audioSessionPromise.js +0 -51
  247. package/dist/module/utils/internal/callingx/audioSessionPromise.js.map +0 -1
  248. package/dist/module/utils/internal/callingx/callingx.js +0 -100
  249. package/dist/module/utils/internal/callingx/callingx.js.map +0 -1
  250. package/dist/module/utils/keepCallAliveHeadlessTask.js +0 -42
  251. package/dist/module/utils/keepCallAliveHeadlessTask.js.map +0 -1
  252. package/dist/module/utils/push/libs/callingx.js +0 -67
  253. package/dist/module/utils/push/libs/callingx.js.map +0 -1
  254. package/dist/module/utils/push/setupCallingExpEvents.js +0 -102
  255. package/dist/module/utils/push/setupCallingExpEvents.js.map +0 -1
  256. package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts +0 -5
  257. package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts.map +0 -1
  258. package/dist/typescript/utils/hooks/useDebouncedValue.d.ts +0 -8
  259. package/dist/typescript/utils/hooks/useDebouncedValue.d.ts.map +0 -1
  260. package/dist/typescript/utils/internal/callingx/audioSessionPromise.d.ts +0 -16
  261. package/dist/typescript/utils/internal/callingx/audioSessionPromise.d.ts.map +0 -1
  262. package/dist/typescript/utils/internal/callingx/callingx.d.ts +0 -14
  263. package/dist/typescript/utils/internal/callingx/callingx.d.ts.map +0 -1
  264. package/dist/typescript/utils/keepCallAliveHeadlessTask.d.ts +0 -10
  265. package/dist/typescript/utils/keepCallAliveHeadlessTask.d.ts.map +0 -1
  266. package/dist/typescript/utils/push/libs/callingx.d.ts +0 -9
  267. package/dist/typescript/utils/push/libs/callingx.d.ts.map +0 -1
  268. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts +0 -8
  269. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts.map +0 -1
  270. package/src/hooks/push/useCallingExpWithCallingStateEffect.ts +0 -147
  271. package/src/utils/hooks/useDebouncedValue.ts +0 -21
  272. package/src/utils/internal/callingx/audioSessionPromise.ts +0 -53
  273. package/src/utils/internal/callingx/callingx.ts +0 -146
  274. package/src/utils/keepCallAliveHeadlessTask.ts +0 -54
  275. package/src/utils/push/libs/callingx.ts +0 -90
  276. package/src/utils/push/setupCallingExpEvents.ts +0 -130
@@ -1,7 +1,7 @@
1
- import React from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import { StyleSheet, View, type ViewStyle } from 'react-native';
3
- import { useCallStateHooks } from '@stream-io/video-react-bindings';
4
- import { useDebouncedValue } from '../../../utils/hooks/useDebouncedValue';
3
+ import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
4
+ import { debounceTime } from 'rxjs';
5
5
  import {
6
6
  CallParticipantsList as DefaultCallParticipantsList,
7
7
  type CallParticipantsListComponentProps,
@@ -49,19 +49,33 @@ export const CallParticipantsGrid = ({
49
49
  const {
50
50
  theme: { colors, callParticipantsGrid },
51
51
  } = useTheme();
52
- const {
53
- useRemoteParticipants,
54
- useParticipants,
55
- useLocalParticipant,
56
- useDominantSpeaker,
57
- } = useCallStateHooks();
58
- const _remoteParticipants = useRemoteParticipants();
52
+ const call = useCall();
53
+ const { useLocalParticipant, useDominantSpeaker } = useCallStateHooks();
59
54
  const localParticipant = useLocalParticipant();
60
- const _allParticipants = useParticipants();
61
55
  const dominantSpeaker = useDominantSpeaker();
62
- // we debounce the participants arrays to avoid unnecessary rerenders that happen when participant tracks are all subscribed simultaneously
63
- const remoteParticipants = useDebouncedValue(_remoteParticipants, 300);
64
- const allParticipants = useDebouncedValue(_allParticipants, 300);
56
+ const [remoteParticipants, setRemoteParticipants] = useState<
57
+ StreamVideoParticipant[]
58
+ >(() => call?.state.remoteParticipants ?? []);
59
+ const [allParticipants, setAllParticipants] = useState<
60
+ StreamVideoParticipant[]
61
+ >(() => call?.state.participants ?? []);
62
+ useEffect(() => {
63
+ if (!call) {
64
+ setRemoteParticipants([]);
65
+ setAllParticipants([]);
66
+ return;
67
+ }
68
+ const sub1 = call.state.remoteParticipants$
69
+ .pipe(debounceTime(300))
70
+ .subscribe(setRemoteParticipants);
71
+ const sub2 = call.state.participants$
72
+ .pipe(debounceTime(300))
73
+ .subscribe(setAllParticipants);
74
+ return () => {
75
+ sub1.unsubscribe();
76
+ sub2.unsubscribe();
77
+ };
78
+ }, [call]);
65
79
  const landscapeStyles: ViewStyle = {
66
80
  flexDirection: landscape ? 'row' : 'column',
67
81
  };
@@ -1,11 +1,11 @@
1
- import React, { useMemo } from 'react';
1
+ import React, { useEffect, useMemo, useState } from 'react';
2
2
  import {
3
3
  hasScreenShare,
4
- speakerLayoutSortPreset,
4
+ type StreamVideoParticipant,
5
5
  } from '@stream-io/video-client';
6
- import { useCallStateHooks } from '@stream-io/video-react-bindings';
6
+ import { useCall } from '@stream-io/video-react-bindings';
7
7
  import { StyleSheet, View, type ViewStyle } from 'react-native';
8
- import { useDebouncedValue } from '../../../utils/hooks/useDebouncedValue';
8
+ import { debounceTime } from 'rxjs';
9
9
  import { ComponentTestIds } from '../../../constants/TestIds';
10
10
  import {
11
11
  CallParticipantsList as DefaultCallParticipantsList,
@@ -56,15 +56,24 @@ export const CallParticipantsSpotlight = ({
56
56
  theme: { callParticipantsSpotlight, variants },
57
57
  } = useTheme();
58
58
  const styles = useStyles();
59
- const { useParticipants } = useCallStateHooks();
60
- const _allParticipants = useParticipants({
61
- sortBy: speakerLayoutSortPreset,
62
- });
63
- const allParticipants = useDebouncedValue(_allParticipants, 300); // we debounce the participants to avoid unnecessary rerenders that happen when participant tracks are all subscribed simultaneously
59
+ const call = useCall();
60
+ const [allParticipants, setAllParticipants] = useState<
61
+ StreamVideoParticipant[]
62
+ >(() => call?.state.participants ?? []);
63
+ useEffect(() => {
64
+ if (!call) {
65
+ setAllParticipants([]);
66
+ return;
67
+ }
68
+ const sub = call.state.participants$
69
+ .pipe(debounceTime(300))
70
+ .subscribe(setAllParticipants);
71
+ return () => sub.unsubscribe();
72
+ }, [call]);
64
73
  const [participantInSpotlight, ...otherParticipants] = allParticipants;
65
74
  const isScreenShareOnSpotlight =
66
75
  participantInSpotlight && hasScreenShare(participantInSpotlight);
67
- const isUserAloneInCall = _allParticipants?.length === 1;
76
+ const isUserAloneInCall = allParticipants.length === 1;
68
77
 
69
78
  const isInPiP = useIsInPiPMode();
70
79
 
@@ -1,7 +1,7 @@
1
1
  import React, {
2
2
  useCallback,
3
+ useEffect,
3
4
  useMemo,
4
- useReducer,
5
5
  useRef,
6
6
  useState,
7
7
  } from 'react';
@@ -17,7 +17,7 @@ import {
17
17
  type StreamVideoParticipantPatches,
18
18
  VisibilityState,
19
19
  } from '@stream-io/video-client';
20
- import { useDebouncedValue } from '../../../utils/hooks/useDebouncedValue';
20
+ import { Subject, debounceTime } from 'rxjs';
21
21
  import { useCall } from '@stream-io/video-react-bindings';
22
22
  import { ComponentTestIds } from '../../../constants/TestIds';
23
23
  import {
@@ -104,9 +104,24 @@ export const CallParticipantsList = ({
104
104
  // we use a HashSet to track the currently viewable participants
105
105
  // and a separate force update state to rerender the component to inform that the HashSet has changed
106
106
  // NOTE: we use set instead of array or object for O(1) lookup, add and delete
107
- const viewableParticipantSessionIds = useRef<Set<string>>(new Set());
108
- const [_forceUpdateValue, forceUpdate] = useReducer((x) => x + 1, 0);
109
- const forceUpdateValue = useDebouncedValue(_forceUpdateValue, 500); // we debounce forced value to avoid multiple viewability change continuous rerenders due to callbacks that occurs simultaneously during a large list scroll or when scrolling is completed
107
+ // Lazy ref init: avoids recreating instances on every render (useRef doesn't support initializer fns)
108
+ const viewableParticipantSessionIds = useRef<Set<string>>(null!);
109
+ if (!viewableParticipantSessionIds.current) {
110
+ viewableParticipantSessionIds.current = new Set();
111
+ }
112
+ const forceUpdate$Ref = useRef<Subject<void>>(null!);
113
+ if (!forceUpdate$Ref.current) {
114
+ forceUpdate$Ref.current = new Subject<void>();
115
+ }
116
+ const forceUpdate$ = forceUpdate$Ref.current;
117
+ const [forceUpdateValue, setForceUpdateValue] = useState(0);
118
+ useEffect(() => {
119
+ const sub = forceUpdate$.pipe(debounceTime(500)).subscribe(() => {
120
+ setForceUpdateValue((v) => v + 1);
121
+ });
122
+ return () => sub.unsubscribe();
123
+ }, [forceUpdate$]);
124
+ const forceUpdate = useCallback(() => forceUpdate$.next(), [forceUpdate$]);
110
125
 
111
126
  // we use a ref to store the active call object
112
127
  // so that it can be used in the onViewableItemsChanged callback
@@ -1,4 +1,5 @@
1
1
  import { useIosVoipPushEventsSetupEffect } from './useIosVoipPushEventsSetupEffect';
2
+ import { useProcessPushCallEffect } from './useProcessPushCallEffect';
2
3
  import { useInitAndroidTokenAndRest } from './useInitAndroidTokenAndRest';
3
4
  import { useIosInitRemoteNotifications } from './useIosInitRemoteNotifications';
4
5
  import { useProcessPushNonRingingCallEffect } from './useProcessPushNonRingingCallEffect';
@@ -11,5 +12,6 @@ export const usePushRegisterEffect = () => {
11
12
  useIosInitRemoteNotifications();
12
13
  useIosVoipPushEventsSetupEffect();
13
14
  useProcessPushNonRingingCallEffect();
15
+ useProcessPushCallEffect();
14
16
  useInitAndroidTokenAndRest();
15
17
  };
@@ -0,0 +1,235 @@
1
+ import {
2
+ CallingState,
3
+ RxUtils,
4
+ videoLoggerSystem,
5
+ } from '@stream-io/video-client';
6
+ import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
7
+ import { NativeModules, Platform } from 'react-native';
8
+ import { useEffect, useState } from 'react';
9
+ import { StreamVideoRN } from '../../utils';
10
+ import { getCallKeepLib } from '../../utils/push/libs';
11
+ import {
12
+ voipCallkeepAcceptedCallOnNativeDialerMap$,
13
+ voipCallkeepCallOnForegroundMap$,
14
+ voipPushNotificationCallCId$,
15
+ } from '../../utils/push/internal/rxSubjects';
16
+
17
+ const isNonActiveCallingState = (callingState: CallingState) => {
18
+ return (
19
+ callingState === CallingState.IDLE ||
20
+ callingState === CallingState.UNKNOWN ||
21
+ callingState === CallingState.LEFT
22
+ );
23
+ };
24
+
25
+ const isAcceptedCallingState = (callingState: CallingState) => {
26
+ return (
27
+ callingState === CallingState.JOINING ||
28
+ callingState === CallingState.JOINED
29
+ );
30
+ };
31
+
32
+ const unsubscribeCallkeepEvents = async (activeCallCid: string | undefined) => {
33
+ const voipPushNotificationCallCId = RxUtils.getCurrentValue(
34
+ voipPushNotificationCallCId$,
35
+ );
36
+ if (activeCallCid && activeCallCid === voipPushNotificationCallCId) {
37
+ // callkeep events should not be listened anymore so clear the call cid
38
+ voipPushNotificationCallCId$.next(undefined);
39
+ }
40
+ return await NativeModules.StreamVideoReactNative?.removeIncomingCall(
41
+ activeCallCid,
42
+ );
43
+ };
44
+
45
+ const logger = videoLoggerSystem.getLogger(
46
+ 'useIosCallkeepWithCallingStateEffect',
47
+ );
48
+ const log = (message: string) => {
49
+ logger.warn(message);
50
+ };
51
+
52
+ /**
53
+ * This hook is used to inform the callkeep library that the call has been joined or ended.
54
+ */
55
+ export const useIosCallkeepWithCallingStateEffect = () => {
56
+ const activeCall = useCall();
57
+ const { useCallCallingState } = useCallStateHooks();
58
+ const callingState = useCallCallingState();
59
+ const [acceptedForegroundCallkeepMap, setAcceptedForegroundCallkeepMap] =
60
+ useState<{
61
+ uuid: string;
62
+ cid: string;
63
+ }>();
64
+
65
+ useEffect(() => {
66
+ return () => {
67
+ const pushConfig = StreamVideoRN.getConfig().push;
68
+ if (
69
+ Platform.OS !== 'ios' ||
70
+ !pushConfig ||
71
+ !pushConfig.ios?.pushProviderName
72
+ ) {
73
+ return;
74
+ }
75
+ if (!pushConfig.android.incomingCallChannel) {
76
+ // TODO: remove this check and find a better way once we have telecom integration for android
77
+ return;
78
+ }
79
+
80
+ const callkeep = getCallKeepLib();
81
+ // if the component is unmounted and the callID was not reported to callkeep, then report it now
82
+ if (acceptedForegroundCallkeepMap) {
83
+ log(
84
+ `Ending call in callkeep: ${acceptedForegroundCallkeepMap.cid}, reason: component unmounted and call was present in acceptedForegroundCallkeepMap`,
85
+ );
86
+ unsubscribeCallkeepEvents(acceptedForegroundCallkeepMap.cid).then(() =>
87
+ callkeep.endCall(acceptedForegroundCallkeepMap.uuid),
88
+ );
89
+ }
90
+ };
91
+ }, [acceptedForegroundCallkeepMap]);
92
+
93
+ const activeCallCid = activeCall?.cid;
94
+
95
+ useEffect(() => {
96
+ return () => {
97
+ const pushConfig = StreamVideoRN.getConfig().push;
98
+ if (
99
+ Platform.OS !== 'ios' ||
100
+ !pushConfig ||
101
+ !pushConfig.ios?.pushProviderName ||
102
+ !activeCallCid
103
+ ) {
104
+ return;
105
+ }
106
+ if (!pushConfig.android.incomingCallChannel) {
107
+ // TODO: remove this check and find a better way once we have telecom integration for android
108
+ return;
109
+ }
110
+ const nativeDialerAcceptedCallMap = RxUtils.getCurrentValue(
111
+ voipCallkeepAcceptedCallOnNativeDialerMap$,
112
+ );
113
+ const foregroundIncomingCallkeepMap = RxUtils.getCurrentValue(
114
+ voipCallkeepCallOnForegroundMap$,
115
+ );
116
+ const callkeep = getCallKeepLib();
117
+ if (activeCallCid === nativeDialerAcceptedCallMap?.cid) {
118
+ log(
119
+ `Ending call in callkeep: ${activeCallCid}, reason: activeCallCid changed or was removed and call was present in nativeDialerAcceptedCallMap`,
120
+ );
121
+ unsubscribeCallkeepEvents(activeCallCid).then(() =>
122
+ callkeep.endCall(nativeDialerAcceptedCallMap.uuid),
123
+ );
124
+ // no need to keep this reference anymore
125
+ voipCallkeepAcceptedCallOnNativeDialerMap$.next(undefined);
126
+ } else if (activeCallCid === foregroundIncomingCallkeepMap?.cid) {
127
+ log(
128
+ `Ending call in callkeep: ${activeCallCid}, reason: activeCallCid changed or was removed and call was present in foregroundIncomingCallkeepMap`,
129
+ );
130
+ unsubscribeCallkeepEvents(activeCallCid).then(() =>
131
+ callkeep.endCall(foregroundIncomingCallkeepMap.uuid),
132
+ );
133
+ }
134
+ };
135
+ }, [activeCallCid]);
136
+
137
+ const pushConfig = StreamVideoRN.getConfig().push;
138
+ if (
139
+ Platform.OS !== 'ios' ||
140
+ !pushConfig ||
141
+ !pushConfig.ios.pushProviderName ||
142
+ !activeCallCid
143
+ ) {
144
+ return;
145
+ }
146
+ if (!pushConfig.android.incomingCallChannel) {
147
+ // TODO: remove this check and find a better way once we have telecom integration for android
148
+ return;
149
+ }
150
+
151
+ /**
152
+ * Check if current call is still needed to be accepted in callkeep
153
+ */
154
+ if (
155
+ isAcceptedCallingState(callingState) &&
156
+ acceptedForegroundCallkeepMap?.cid !== activeCallCid
157
+ ) {
158
+ const callkeep = getCallKeepLib();
159
+ // push notification was displayed
160
+ // but the call has been accepted through the app and not through the native dialer
161
+ const foregroundCallkeepMap = RxUtils.getCurrentValue(
162
+ voipCallkeepCallOnForegroundMap$,
163
+ );
164
+ if (foregroundCallkeepMap && foregroundCallkeepMap.cid === activeCallCid) {
165
+ log(
166
+ // @ts-expect-error - types issue
167
+ `Accepting call in callkeep: ${activeCallCid}, reason: callingstate went to ${CallingState[callingState]} and call was present in foregroundCallkeepMap`,
168
+ );
169
+ // no need to keep this reference anymore
170
+ voipCallkeepCallOnForegroundMap$.next(undefined);
171
+ NativeModules.StreamVideoReactNative?.removeIncomingCall(
172
+ activeCallCid,
173
+ ).then(() => callkeep.answerIncomingCall(foregroundCallkeepMap.uuid));
174
+ // this call should be accepted in callkeep
175
+ setAcceptedForegroundCallkeepMap(foregroundCallkeepMap);
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Check if current call is still needed to be ended in callkeep
181
+ */
182
+ if (isNonActiveCallingState(callingState)) {
183
+ const callkeep = getCallKeepLib();
184
+
185
+ // this was a previously joined call which had push notification displayed
186
+ // the call was accepted through the app and not through native dialer
187
+ // the call was left using the leave button in the app and not through native dialer
188
+ if (activeCallCid === acceptedForegroundCallkeepMap?.cid) {
189
+ log(
190
+ // @ts-expect-error - types issue
191
+ `Ending call in callkeep: ${activeCallCid}, reason: callingstate went to ${CallingState[callingState]} and call was present in acceptedForegroundCallkeepMap`,
192
+ );
193
+ unsubscribeCallkeepEvents(activeCallCid).then(() =>
194
+ callkeep.endCall(acceptedForegroundCallkeepMap.uuid),
195
+ );
196
+ setAcceptedForegroundCallkeepMap(undefined);
197
+ return;
198
+ }
199
+ // this was a call which had push notification displayed but never joined
200
+ // the user rejected in the app and not from native dialer
201
+ const foregroundIncomingCallkeepMap = RxUtils.getCurrentValue(
202
+ voipCallkeepCallOnForegroundMap$,
203
+ );
204
+ if (activeCallCid === foregroundIncomingCallkeepMap?.cid) {
205
+ log(
206
+ // @ts-expect-error - types issue
207
+ `Ending call in callkeep: ${activeCallCid}, reason: callingstate went to ${CallingState[callingState]} and call was present in foregroundIncomingCallkeepMap`,
208
+ );
209
+ unsubscribeCallkeepEvents(activeCallCid).then(() =>
210
+ callkeep.endCall(foregroundIncomingCallkeepMap.uuid),
211
+ );
212
+ // no need to keep this reference anymore
213
+ voipCallkeepCallOnForegroundMap$.next(undefined);
214
+ return;
215
+ }
216
+ // this was a previously joined call
217
+ // it was an accepted call from native dialer and not from the app
218
+ // the user left using the leave button in the app
219
+ const nativeDialerAcceptedCallMap = RxUtils.getCurrentValue(
220
+ voipCallkeepAcceptedCallOnNativeDialerMap$,
221
+ );
222
+ if (activeCallCid === nativeDialerAcceptedCallMap?.cid) {
223
+ log(
224
+ // @ts-expect-error - types issue
225
+ `Ending call in callkeep: ${activeCallCid}, reason: callingstate went to ${CallingState[callingState]} and call was present in nativeDialerAcceptedCallMap`,
226
+ );
227
+ unsubscribeCallkeepEvents(activeCallCid).then(() =>
228
+ callkeep.endCall(nativeDialerAcceptedCallMap.uuid),
229
+ );
230
+ // no need to keep this reference anymore
231
+ voipCallkeepAcceptedCallOnNativeDialerMap$.next(undefined);
232
+ return;
233
+ }
234
+ }
235
+ };
@@ -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
  };
@@ -0,0 +1,108 @@
1
+ import {
2
+ pushAcceptedIncomingCallCId$,
3
+ pushAndroidBackgroundDeliveredIncomingCallCId$,
4
+ pushRejectedIncomingCallCId$,
5
+ pushTappedIncomingCallCId$,
6
+ } from '../../utils/push/internal/rxSubjects';
7
+ import { useEffect } from 'react';
8
+ import { StreamVideoRN } from '../../utils';
9
+ import {
10
+ useConnectedUser,
11
+ useStreamVideoClient,
12
+ } from '@stream-io/video-react-bindings';
13
+ import { BehaviorSubject } from 'rxjs';
14
+ import { distinctUntilChanged, filter } from 'rxjs/operators';
15
+ import { processCallFromPush } from '../../utils/push/internal/utils';
16
+ import { StreamVideoClient, videoLoggerSystem } from '@stream-io/video-client';
17
+ import type { StreamVideoConfig } from '../../utils/StreamVideoRN/types';
18
+
19
+ /**
20
+ * This hook is used to process the incoming call data via push notifications using the relevant rxjs subjects
21
+ * It either joins or leaves the call based on the user's action.
22
+ * Note: this effect cannot work when push notifications are received when the app is in quit state or in other words when the client is not connected with a websocket.
23
+ * So we essentially run this effect only when the client is connected with a websocket.
24
+ */
25
+ export const useProcessPushCallEffect = () => {
26
+ const client = useStreamVideoClient();
27
+ const connectedUserId = useConnectedUser()?.id;
28
+ // The Effect to join/reject call automatically when incoming call was received and processed from push notification
29
+ useEffect(() => {
30
+ const pushConfig = StreamVideoRN.getConfig().push;
31
+ if (!pushConfig || !client || !connectedUserId) {
32
+ return;
33
+ }
34
+
35
+ videoLoggerSystem
36
+ .getLogger('useProcessPushCallEffect')
37
+ .debug(
38
+ `Adding subscriptions to process incoming call from push notification`,
39
+ );
40
+
41
+ // if the user accepts the call from push notification we join the call
42
+ const acceptedCallSubscription = createCallSubscription(
43
+ pushAcceptedIncomingCallCId$,
44
+ client,
45
+ pushConfig,
46
+ 'accept',
47
+ );
48
+
49
+ // if the user rejects the call from push notification we leave the call
50
+ const declinedCallSubscription = createCallSubscription(
51
+ pushRejectedIncomingCallCId$,
52
+ client,
53
+ pushConfig,
54
+ 'decline',
55
+ );
56
+
57
+ // if the user taps the call from push notification we do nothing as the only thing is to get the call which adds it to the client
58
+ const pressedCallSubscription = createCallSubscription(
59
+ pushTappedIncomingCallCId$,
60
+ client,
61
+ pushConfig,
62
+ 'pressed',
63
+ );
64
+
65
+ const backgroundIncomingDeliveredCallSubscription = createCallSubscription(
66
+ pushAndroidBackgroundDeliveredIncomingCallCId$,
67
+ client,
68
+ pushConfig,
69
+ 'backgroundDelivered',
70
+ );
71
+
72
+ return () => {
73
+ acceptedCallSubscription.unsubscribe();
74
+ declinedCallSubscription.unsubscribe();
75
+ pressedCallSubscription.unsubscribe();
76
+ backgroundIncomingDeliveredCallSubscription.unsubscribe();
77
+ };
78
+ }, [client, connectedUserId]);
79
+ };
80
+
81
+ /**
82
+ * A type guard to check if the cid is not undefined
83
+ */
84
+ function cidIsNotUndefined(cid: string | undefined): cid is string {
85
+ return cid !== undefined;
86
+ }
87
+
88
+ /**
89
+ * The common logic to create a subscription for the given call cid and action
90
+ */
91
+ const createCallSubscription = (
92
+ behaviourSubjectWithCallCid: BehaviorSubject<string | undefined>,
93
+ client: StreamVideoClient,
94
+ pushConfig: NonNullable<StreamVideoConfig['push']>,
95
+ action: 'accept' | 'decline' | 'pressed' | 'backgroundDelivered',
96
+ ) => {
97
+ return behaviourSubjectWithCallCid
98
+ .pipe(distinctUntilChanged(), filter(cidIsNotUndefined))
99
+ .subscribe(async (callCId) => {
100
+ videoLoggerSystem
101
+ .getLogger('useProcessPushCallEffect')
102
+ .debug(
103
+ `Processing call from push notification with action: ${action} and callCId: ${callCId}`,
104
+ );
105
+ await processCallFromPush(client, callCId, action, pushConfig);
106
+ behaviourSubjectWithCallCid.next(undefined); // remove the current call id to avoid processing again
107
+ });
108
+ };