@stream-io/video-react-native-sdk 1.31.1 → 1.32.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 (207) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/android/src/main/AndroidManifest.xml +8 -1
  3. package/android/src/main/AndroidManifestNew.xml +11 -0
  4. package/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.kt +42 -5
  5. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/WebRtcAudioUtils.kt +70 -6
  6. package/android/src/main/java/com/streamvideo/reactnative/callmanager/StreamInCallManagerModule.kt +6 -4
  7. package/android/src/main/java/com/streamvideo/reactnative/keepalive/KeepAliveNotification.kt +83 -0
  8. package/android/src/main/java/com/streamvideo/reactnative/keepalive/StreamCallKeepAliveHeadlessService.kt +149 -0
  9. package/dist/commonjs/hooks/push/index.js +0 -2
  10. package/dist/commonjs/hooks/push/index.js.map +1 -1
  11. package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js +146 -0
  12. package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js.map +1 -0
  13. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js +18 -31
  14. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
  15. package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js +41 -106
  16. package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
  17. package/dist/commonjs/index.js +1 -0
  18. package/dist/commonjs/index.js.map +1 -1
  19. package/dist/commonjs/modules/call-manager/CallManager.js +26 -0
  20. package/dist/commonjs/modules/call-manager/CallManager.js.map +1 -1
  21. package/dist/commonjs/providers/StreamCall/index.js +6 -6
  22. package/dist/commonjs/providers/StreamCall/index.js.map +1 -1
  23. package/dist/commonjs/utils/StreamVideoRN/index.js +35 -21
  24. package/dist/commonjs/utils/StreamVideoRN/index.js.map +1 -1
  25. package/dist/commonjs/utils/internal/callingx/audioSessionPromise.js +68 -0
  26. package/dist/commonjs/utils/internal/callingx/audioSessionPromise.js.map +1 -0
  27. package/dist/commonjs/utils/internal/callingx/callingx.js +150 -0
  28. package/dist/commonjs/utils/internal/callingx/callingx.js.map +1 -0
  29. package/dist/commonjs/utils/internal/registerSDKGlobals.js +53 -3
  30. package/dist/commonjs/utils/internal/registerSDKGlobals.js.map +1 -1
  31. package/dist/commonjs/utils/keepCallAliveHeadlessTask.js +48 -0
  32. package/dist/commonjs/utils/keepCallAliveHeadlessTask.js.map +1 -0
  33. package/dist/commonjs/utils/push/android.js +135 -202
  34. package/dist/commonjs/utils/push/android.js.map +1 -1
  35. package/dist/commonjs/utils/push/internal/ios.js +17 -34
  36. package/dist/commonjs/utils/push/internal/ios.js.map +1 -1
  37. package/dist/commonjs/utils/push/internal/rxSubjects.js +1 -45
  38. package/dist/commonjs/utils/push/internal/rxSubjects.js.map +1 -1
  39. package/dist/commonjs/utils/push/internal/utils.js +71 -53
  40. package/dist/commonjs/utils/push/internal/utils.js.map +1 -1
  41. package/dist/commonjs/utils/push/ios.js.map +1 -1
  42. package/dist/commonjs/utils/push/libs/callingx.js +75 -0
  43. package/dist/commonjs/utils/push/libs/callingx.js.map +1 -0
  44. package/dist/commonjs/utils/push/libs/index.js +8 -19
  45. package/dist/commonjs/utils/push/libs/index.js.map +1 -1
  46. package/dist/commonjs/utils/push/libs/notifee/index.js +0 -23
  47. package/dist/commonjs/utils/push/libs/notifee/index.js.map +1 -1
  48. package/dist/commonjs/utils/push/setupCallingExpEvents.js +105 -0
  49. package/dist/commonjs/utils/push/setupCallingExpEvents.js.map +1 -0
  50. package/dist/commonjs/utils/push/setupIosVoipPushEvents.js +7 -6
  51. package/dist/commonjs/utils/push/setupIosVoipPushEvents.js.map +1 -1
  52. package/dist/commonjs/version.js +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 +139 -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 +42 -107
  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 +35 -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 +140 -0
  72. package/dist/module/utils/internal/callingx/callingx.js.map +1 -0
  73. package/dist/module/utils/internal/registerSDKGlobals.js +53 -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 +67 -50
  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 +67 -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 -21
  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/typescript/hooks/push/index.d.ts.map +1 -1
  98. package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts +5 -0
  99. package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts.map +1 -0
  100. package/dist/typescript/hooks/push/useIosVoipPushEventsSetupEffect.d.ts.map +1 -1
  101. package/dist/typescript/hooks/useAndroidKeepCallAliveEffect.d.ts.map +1 -1
  102. package/dist/typescript/index.d.ts +1 -0
  103. package/dist/typescript/index.d.ts.map +1 -1
  104. package/dist/typescript/modules/call-manager/CallManager.d.ts +5 -0
  105. package/dist/typescript/modules/call-manager/CallManager.d.ts.map +1 -1
  106. package/dist/typescript/utils/StreamVideoRN/index.d.ts +22 -2
  107. package/dist/typescript/utils/StreamVideoRN/index.d.ts.map +1 -1
  108. package/dist/typescript/utils/StreamVideoRN/types.d.ts +59 -25
  109. package/dist/typescript/utils/StreamVideoRN/types.d.ts.map +1 -1
  110. package/dist/typescript/utils/internal/callingx/audioSessionPromise.d.ts +16 -0
  111. package/dist/typescript/utils/internal/callingx/audioSessionPromise.d.ts.map +1 -0
  112. package/dist/typescript/utils/internal/callingx/callingx.d.ts +18 -0
  113. package/dist/typescript/utils/internal/callingx/callingx.d.ts.map +1 -0
  114. package/dist/typescript/utils/internal/registerSDKGlobals.d.ts.map +1 -1
  115. package/dist/typescript/utils/keepCallAliveHeadlessTask.d.ts +10 -0
  116. package/dist/typescript/utils/keepCallAliveHeadlessTask.d.ts.map +1 -0
  117. package/dist/typescript/utils/push/android.d.ts +1 -2
  118. package/dist/typescript/utils/push/android.d.ts.map +1 -1
  119. package/dist/typescript/utils/push/internal/ios.d.ts.map +1 -1
  120. package/dist/typescript/utils/push/internal/rxSubjects.d.ts +0 -33
  121. package/dist/typescript/utils/push/internal/rxSubjects.d.ts.map +1 -1
  122. package/dist/typescript/utils/push/internal/utils.d.ts +14 -8
  123. package/dist/typescript/utils/push/internal/utils.d.ts.map +1 -1
  124. package/dist/typescript/utils/push/ios.d.ts +1 -2
  125. package/dist/typescript/utils/push/ios.d.ts.map +1 -1
  126. package/dist/typescript/utils/push/libs/callingx.d.ts +9 -0
  127. package/dist/typescript/utils/push/libs/callingx.d.ts.map +1 -0
  128. package/dist/typescript/utils/push/libs/index.d.ts +1 -2
  129. package/dist/typescript/utils/push/libs/index.d.ts.map +1 -1
  130. package/dist/typescript/utils/push/libs/notifee/index.d.ts +0 -2
  131. package/dist/typescript/utils/push/libs/notifee/index.d.ts.map +1 -1
  132. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts +8 -0
  133. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts.map +1 -0
  134. package/dist/typescript/utils/push/setupIosVoipPushEvents.d.ts.map +1 -1
  135. package/dist/typescript/version.d.ts +1 -1
  136. package/expo-config-plugin/dist/withAndroidManifest.js +1 -33
  137. package/expo-config-plugin/dist/withAndroidPermissions.js +2 -7
  138. package/expo-config-plugin/dist/withAppDelegate.js +19 -197
  139. package/expo-config-plugin/dist/withMainActivity.js +1 -1
  140. package/expo-config-plugin/dist/withiOSInfoPlist.js +2 -3
  141. package/ios/StreamInCallManager.m +2 -0
  142. package/ios/StreamInCallManager.swift +19 -7
  143. package/ios/StreamVideoReactNative-Bridging-Header.h +3 -1
  144. package/ios/StreamVideoReactNative.h +7 -4
  145. package/ios/StreamVideoReactNative.m +199 -84
  146. package/package.json +11 -16
  147. package/src/hooks/push/index.ts +0 -2
  148. package/src/hooks/push/useCallingExpWithCallingStateEffect.ts +193 -0
  149. package/src/hooks/push/useIosVoipPushEventsSetupEffect.ts +21 -34
  150. package/src/hooks/useAndroidKeepCallAliveEffect.ts +63 -129
  151. package/src/index.ts +1 -0
  152. package/src/modules/call-manager/CallManager.ts +36 -0
  153. package/src/modules/call-manager/native-module.d.ts +7 -0
  154. package/src/providers/StreamCall/index.tsx +6 -6
  155. package/src/utils/StreamVideoRN/index.ts +42 -30
  156. package/src/utils/StreamVideoRN/types.ts +61 -25
  157. package/src/utils/internal/callingx/audioSessionPromise.ts +65 -0
  158. package/src/utils/internal/callingx/callingx.ts +197 -0
  159. package/src/utils/internal/registerSDKGlobals.ts +52 -4
  160. package/src/utils/keepCallAliveHeadlessTask.ts +54 -0
  161. package/src/utils/push/android.ts +198 -311
  162. package/src/utils/push/internal/ios.ts +28 -44
  163. package/src/utils/push/internal/rxSubjects.ts +0 -61
  164. package/src/utils/push/internal/utils.ts +108 -64
  165. package/src/utils/push/ios.ts +1 -6
  166. package/src/utils/push/libs/callingx.ts +89 -0
  167. package/src/utils/push/libs/index.ts +1 -2
  168. package/src/utils/push/libs/notifee/index.ts +0 -31
  169. package/src/utils/push/setupCallingExpEvents.ts +135 -0
  170. package/src/utils/push/setupIosVoipPushEvents.ts +11 -7
  171. package/src/version.ts +1 -1
  172. package/android/src/main/java/com/streamvideo/reactnative/util/CallAliveServiceChecker.kt +0 -95
  173. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js +0 -160
  174. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +0 -1
  175. package/dist/commonjs/hooks/push/useProcessPushCallEffect.js +0 -67
  176. package/dist/commonjs/hooks/push/useProcessPushCallEffect.js.map +0 -1
  177. package/dist/commonjs/utils/push/libs/callkeep.js +0 -17
  178. package/dist/commonjs/utils/push/libs/callkeep.js.map +0 -1
  179. package/dist/commonjs/utils/push/libs/voipPushNotification.js +0 -17
  180. package/dist/commonjs/utils/push/libs/voipPushNotification.js.map +0 -1
  181. package/dist/commonjs/utils/push/setupIosCallKeepEvents.js +0 -205
  182. package/dist/commonjs/utils/push/setupIosCallKeepEvents.js.map +0 -1
  183. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js +0 -153
  184. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +0 -1
  185. package/dist/module/hooks/push/useProcessPushCallEffect.js +0 -60
  186. package/dist/module/hooks/push/useProcessPushCallEffect.js.map +0 -1
  187. package/dist/module/utils/push/libs/callkeep.js +0 -11
  188. package/dist/module/utils/push/libs/callkeep.js.map +0 -1
  189. package/dist/module/utils/push/libs/voipPushNotification.js +0 -11
  190. package/dist/module/utils/push/libs/voipPushNotification.js.map +0 -1
  191. package/dist/module/utils/push/setupIosCallKeepEvents.js +0 -199
  192. package/dist/module/utils/push/setupIosCallKeepEvents.js.map +0 -1
  193. package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts +0 -5
  194. package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts.map +0 -1
  195. package/dist/typescript/hooks/push/useProcessPushCallEffect.d.ts +0 -8
  196. package/dist/typescript/hooks/push/useProcessPushCallEffect.d.ts.map +0 -1
  197. package/dist/typescript/utils/push/libs/callkeep.d.ts +0 -3
  198. package/dist/typescript/utils/push/libs/callkeep.d.ts.map +0 -1
  199. package/dist/typescript/utils/push/libs/voipPushNotification.d.ts +0 -3
  200. package/dist/typescript/utils/push/libs/voipPushNotification.d.ts.map +0 -1
  201. package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts +0 -6
  202. package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts.map +0 -1
  203. package/src/hooks/push/useIosCallkeepWithCallingStateEffect.ts +0 -235
  204. package/src/hooks/push/useProcessPushCallEffect.ts +0 -108
  205. package/src/utils/push/libs/callkeep.ts +0 -16
  206. package/src/utils/push/libs/voipPushNotification.ts +0 -17
  207. package/src/utils/push/setupIosCallKeepEvents.ts +0 -252
@@ -4,6 +4,7 @@
4
4
  #import <React/RCTUIManagerUtils.h>
5
5
  #import <UIKit/UIKit.h>
6
6
  #import <CallKit/CallKit.h>
7
+ #import <PushKit/PushKit.h>
7
8
  #import "StreamVideoReactNative.h"
8
9
  #import "WebRTCModule.h"
9
10
  #import "WebRTCModuleOptions.h"
@@ -12,21 +13,21 @@
12
13
  #import <AudioToolbox/AudioToolbox.h>
13
14
 
14
15
  // Import Swift-generated header for ScreenShareAudioMixer
15
- #if __has_include(<stream_react_native_webrtc/stream_react_native_webrtc-Swift.h>)
16
- #import <stream_react_native_webrtc/stream_react_native_webrtc-Swift.h>
16
+ #if __has_feature(modules)
17
+ @import stream_react_native_webrtc.Swift;
17
18
  #elif __has_include("stream_react_native_webrtc-Swift.h")
18
19
  #import "stream_react_native_webrtc-Swift.h"
20
+ #elif __has_include(<stream_react_native_webrtc/stream_react_native_webrtc-Swift.h>)
21
+ #import <stream_react_native_webrtc/stream_react_native_webrtc-Swift.h>
19
22
  #endif
20
23
 
21
24
  // Do not change these consts, it is what is used react-native-webrtc
22
25
  NSNotificationName const kBroadcastStartedNotification = @"iOS_BroadcastStarted";
23
26
  NSNotificationName const kBroadcastStoppedNotification = @"iOS_BroadcastStopped";
24
27
 
25
- static NSMutableDictionary *_incomingCallUUIDsByCallID = nil;
26
- static NSMutableDictionary *_incomingCallCidsByUUID = nil;
27
- static dispatch_queue_t _dictionaryQueue = nil;
28
+ static NSString *const DEFAULT_DISPLAY_NAME = @"Unknown Caller";
28
29
 
29
- static BOOL _shouldRejectCallWhenBusy = NO;
30
+ static dispatch_queue_t _dictionaryQueue = nil;
30
31
 
31
32
  void broadcastNotificationCallback(CFNotificationCenterRef center,
32
33
  void *observer,
@@ -68,11 +69,200 @@ RCT_EXPORT_MODULE();
68
69
  static dispatch_once_t onceToken;
69
70
  dispatch_once(&onceToken, ^{
70
71
  _dictionaryQueue = dispatch_queue_create("com.stream.video.dictionary", DISPATCH_QUEUE_SERIAL);
71
- _incomingCallUUIDsByCallID = [NSMutableDictionary dictionary];
72
- _incomingCallCidsByUUID = [NSMutableDictionary dictionary];
73
72
  });
74
73
  }
75
74
 
75
+ +(BOOL)canRegisterCall {
76
+ Class callingxClass = NSClassFromString(@"Callingx");
77
+ if (!callingxClass) {
78
+ #if DEBUG
79
+ NSLog(@"[StreamVideoReactNative][canRegisterCall] Callingx not available");
80
+ #endif
81
+ return YES;
82
+ }
83
+
84
+ SEL selector = @selector(canRegisterCall);
85
+ if (![callingxClass respondsToSelector:selector]) {
86
+ #if DEBUG
87
+ NSLog(@"[StreamVideoReactNative][canRegisterCall] Callingx does not respond to canRegisterCall selector");
88
+ #endif
89
+ return YES;
90
+ }
91
+
92
+ NSMethodSignature *signature = [callingxClass methodSignatureForSelector:selector];
93
+ NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
94
+ [invocation setTarget:callingxClass];
95
+ [invocation setSelector:selector];
96
+ [invocation invoke];
97
+
98
+ BOOL canRegister = NO;
99
+ [invocation getReturnValue:&canRegister];
100
+
101
+ #if DEBUG
102
+ NSLog(@"[StreamVideoReactNative][canRegisterCall] canRegisterCall = %@", canRegister ? @"YES" : @"NO");
103
+ #endif
104
+
105
+ return canRegister;
106
+ }
107
+
108
+ +(void)voipRegistration {
109
+ Class voipManagerClass = NSClassFromString(@"Callingx.VoipNotificationsManager");
110
+ if (!voipManagerClass) {
111
+ // Fallback: Try the unmangled name (might work depending on Swift version)
112
+ voipManagerClass = NSClassFromString(@"VoipNotificationsManager");
113
+ }
114
+
115
+ if (!voipManagerClass) {
116
+ #if DEBUG
117
+ NSLog(@"[StreamVideoReactNative][voipRegistration] VoipNotificationsManager not available");
118
+ #endif
119
+ return;
120
+ }
121
+
122
+ SEL selector = @selector(voipRegistration);
123
+ if (![voipManagerClass respondsToSelector:selector]) {
124
+ #if DEBUG
125
+ NSLog(@"[StreamVideoReactNative][voipRegistration] VoipNotificationsManager does not respond to voipRegistration");
126
+ #endif
127
+ return;
128
+ }
129
+
130
+ [voipManagerClass voipRegistration];
131
+ }
132
+
133
+ +(void)didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type {
134
+ Class voipManagerClass = NSClassFromString(@"Callingx.VoipNotificationsManager");
135
+ if (!voipManagerClass) {
136
+ // Fallback: Try the unmangled name (might work depending on Swift version)
137
+ voipManagerClass = NSClassFromString(@"VoipNotificationsManager");
138
+ }
139
+
140
+ if (!voipManagerClass) {
141
+ #if DEBUG
142
+ NSLog(@"[StreamVideoReactNative][didUpdatePushCredentials] VoipNotificationsManager not available");
143
+ #endif
144
+ return;
145
+ }
146
+
147
+ SEL selector = @selector(didUpdatePushCredentials:forType:);
148
+ if (![voipManagerClass respondsToSelector:selector]) {
149
+ #if DEBUG
150
+ NSLog(@"[StreamVideoReactNative][didUpdatePushCredentials] VoipNotificationsManager does not respond to didUpdatePushCredentials:forType:");
151
+ #endif
152
+ return;
153
+ }
154
+
155
+ [voipManagerClass didUpdatePushCredentials:credentials forType:type];
156
+ }
157
+
158
+ +(void)didReceiveIncomingPush:(PKPushPayload *)payload forType:(NSString *)type completionHandler: (void (^_Nullable)(void)) completion {
159
+ NSDictionary *streamPayload = payload.dictionaryPayload[@"stream"];
160
+ if (!streamPayload) {
161
+ #if DEBUG
162
+ NSLog(@"[StreamVideoReactNative][didReceiveIncomingPush] Stream payload not found");
163
+ #endif
164
+ if (completion) {
165
+ completion();
166
+ }
167
+ return;
168
+ }
169
+
170
+ NSString *callCid = streamPayload[@"call_cid"];
171
+ if (!callCid) {
172
+ #if DEBUG
173
+ NSLog(@"[StreamVideoReactNative][didReceiveIncomingPush] Missing required field: call_cid");
174
+ #endif
175
+ if (completion) {
176
+ completion();
177
+ }
178
+ return;
179
+ }
180
+
181
+ if (![StreamVideoReactNative canRegisterCall]) {
182
+ if (completion) {
183
+ completion();
184
+ }
185
+ return;
186
+ }
187
+
188
+ [StreamVideoReactNative reportNewIncomingCall:streamPayload forType:type completionHandler:completion];
189
+ [StreamVideoReactNative didReceiveIncomingPushWithPayload:payload forType:type];
190
+ }
191
+
192
+ +(void)reportNewIncomingCall:(NSDictionary *)streamPayload forType:(NSString *)type completionHandler: (void (^_Nullable)(void)) completion {
193
+ Class callingxClass = NSClassFromString(@"Callingx");
194
+ if (!callingxClass) {
195
+ NSLog(@"[StreamVideoReactNative][didReceiveIncomingPush] Callingx not available");
196
+ return;
197
+ }
198
+
199
+ SEL selector = @selector(reportNewIncomingCall:handle:handleType:hasVideo:localizedCallerName:supportsHolding:supportsDTMF:supportsGrouping:supportsUngrouping:payload:withCompletionHandler:);
200
+ if (![callingxClass respondsToSelector:selector]) {
201
+ #if DEBUG
202
+ NSLog(@"[StreamVideoReactNative][didReceiveIncomingPush] Callingx does not respond to selector");
203
+ #endif
204
+ return;
205
+ }
206
+
207
+ NSString *callCid = streamPayload[@"call_cid"];
208
+ NSString *callDisplayName = streamPayload[@"call_display_name"];
209
+ NSString *createdByDisplayName = streamPayload[@"created_by_display_name"];
210
+ NSString *createdCallerName = callDisplayName.length > 0 ? callDisplayName : createdByDisplayName;
211
+ NSString *localizedCallerName = createdCallerName.length > 0 ? createdCallerName : DEFAULT_DISPLAY_NAME;
212
+ NSString *createdById = streamPayload[@"created_by_id"];
213
+ NSString *handle = createdById.length > 0 ? createdById : localizedCallerName;
214
+ NSString *videoIncluded = streamPayload[@"video"];
215
+ BOOL hasVideo = [videoIncluded isEqualToString:@"false"] ? NO : YES;
216
+ NSString *handleType = @"generic";
217
+ BOOL supportsHolding = NO;
218
+ BOOL supportsDTMF = NO;
219
+ BOOL supportsGrouping = NO;
220
+ BOOL supportsUngrouping = NO;
221
+ void (^completionHandler)(void) = completion;
222
+
223
+ NSMethodSignature *signature = [callingxClass methodSignatureForSelector:selector];
224
+ NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
225
+ [invocation setTarget:callingxClass];
226
+ [invocation setSelector:selector];
227
+ [invocation setArgument:&callCid atIndex:2];
228
+ [invocation setArgument:&handle atIndex:3];
229
+ [invocation setArgument:&handleType atIndex:4];
230
+ [invocation setArgument:&hasVideo atIndex:5];
231
+ [invocation setArgument:&localizedCallerName atIndex:6];
232
+ [invocation setArgument:&supportsHolding atIndex:7];
233
+ [invocation setArgument:&supportsDTMF atIndex:8];
234
+ [invocation setArgument:&supportsGrouping atIndex:9];
235
+ [invocation setArgument:&supportsUngrouping atIndex:10];
236
+ [invocation setArgument:&streamPayload atIndex:11];
237
+ [invocation setArgument:&completionHandler atIndex:12];
238
+ [invocation invoke];
239
+ }
240
+
241
+ +(void)didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type {
242
+ Class voipManagerClass = NSClassFromString(@"Callingx.VoipNotificationsManager");
243
+ if (!voipManagerClass) {
244
+ // Fallback: Try the unmangled name (might work depending on Swift version)
245
+ voipManagerClass = NSClassFromString(@"VoipNotificationsManager");
246
+ }
247
+
248
+ if (!voipManagerClass) {
249
+ #if DEBUG
250
+ NSLog(@"[StreamVideoReactNative][didReceiveIncomingPushWithPayload] VoipNotificationsManager not available");
251
+ #endif
252
+ return;
253
+ }
254
+
255
+ SEL selector = @selector(didReceiveIncomingPushWithPayload:forType:);
256
+ if (![voipManagerClass respondsToSelector:selector]) {
257
+ #if DEBUG
258
+ NSLog(@"[StreamVideoReactNative][didReceiveIncomingPushWithPayload] VoipNotificationsManager does not respond to didReceiveIncomingPushWithPayload:forType:");
259
+ #endif
260
+ return;
261
+ }
262
+
263
+ [voipManagerClass didReceiveIncomingPushWithPayload:payload forType:type];
264
+ }
265
+
76
266
  -(instancetype)init {
77
267
  if ((self = [super init])) {
78
268
  _notificationCenter = CFNotificationCenterGetDarwinNotifyCenter();
@@ -199,71 +389,6 @@ RCT_EXPORT_METHOD(currentThermalState:(RCTPromiseResolveBlock)resolve rejecter:(
199
389
  }
200
390
  }
201
391
 
202
- +(void)registerIncomingCall:(NSString *)cid uuid:(NSString *)uuid {
203
- [StreamVideoReactNative initializeSharedDictionaries];
204
- dispatch_sync(_dictionaryQueue, ^{
205
-
206
- #ifdef DEBUG
207
- NSLog(@"registerIncomingCall cid:%@ -> uuid:%@",cid,uuid);
208
- #endif
209
- NSString *lowercaseUUID = [uuid lowercaseString];
210
- _incomingCallUUIDsByCallID[cid] = lowercaseUUID;
211
- _incomingCallCidsByUUID[lowercaseUUID] = cid;
212
- });
213
- }
214
-
215
- RCT_EXPORT_METHOD(getIncomingCallUUid:(NSString *)cid
216
- resolver:(RCTPromiseResolveBlock)resolve
217
- rejecter:(RCTPromiseRejectBlock)reject)
218
- {
219
- dispatch_sync(_dictionaryQueue, ^{
220
- NSString *uuid = _incomingCallUUIDsByCallID[cid];
221
- if (uuid) {
222
- resolve(uuid);
223
- } else {
224
- NSString *errorString = [NSString stringWithFormat:@"requested incoming call not found for cid: %@", cid];
225
- reject(@"access_failure", errorString, nil);
226
- }
227
- });
228
- }
229
-
230
- RCT_EXPORT_METHOD(getIncomingCallCid:(NSString *)uuid
231
- resolver:(RCTPromiseResolveBlock)resolve
232
- rejecter:(RCTPromiseRejectBlock)reject)
233
- {
234
- dispatch_sync(_dictionaryQueue, ^{
235
- NSString *lowercaseUUID = [uuid lowercaseString];
236
- NSString *foundCid = _incomingCallCidsByUUID[lowercaseUUID];
237
-
238
- if (foundCid) {
239
- resolve(foundCid);
240
- } else {
241
- NSString *errorString = [NSString stringWithFormat:@"requested incoming call not found for uuid: %@", uuid];
242
- reject(@"access_failure", errorString, nil);
243
- }
244
- });
245
- }
246
-
247
- RCT_EXPORT_METHOD(removeIncomingCall:(NSString *)cid
248
- resolver:(RCTPromiseResolveBlock)resolve
249
- rejecter:(RCTPromiseRejectBlock)reject)
250
- {
251
- dispatch_sync(_dictionaryQueue, ^{
252
- NSString *uuid = _incomingCallUUIDsByCallID[cid];
253
- if (uuid) {
254
- #ifdef DEBUG
255
- NSLog(@"removeIncomingCall cid:%@ -> uuid:%@",cid,uuid);
256
- #endif
257
-
258
- [_incomingCallUUIDsByCallID removeObjectForKey:cid];
259
- [_incomingCallCidsByUUID removeObjectForKey:uuid];
260
- resolve(@YES);
261
- } else {
262
- resolve(@NO);
263
- }
264
- });
265
- }
266
-
267
392
  RCT_EXPORT_METHOD(captureRef:(nonnull NSNumber *)reactTag
268
393
  options:(NSDictionary *)options
269
394
  resolver:(RCTPromiseResolveBlock)resolve
@@ -401,17 +526,7 @@ RCT_EXPORT_METHOD(checkPermission:(NSString *)permission
401
526
  ];
402
527
  }
403
528
 
404
- +(BOOL)shouldRejectCallWhenBusy {
405
- return _shouldRejectCallWhenBusy;
406
- }
407
-
408
- RCT_EXPORT_METHOD(setShouldRejectCallWhenBusy:(BOOL)shouldReject) {
409
- _shouldRejectCallWhenBusy = shouldReject;
410
- #ifdef DEBUG
411
- NSLog(@"setShouldRejectCallWhenBusy: %@", shouldReject ? @"YES" : @"NO");
412
- #endif
413
- }
414
-
529
+ //current implementation will return any registered calls not only stream calls
415
530
  + (BOOL)hasAnyActiveCall
416
531
  {
417
532
  CXCallObserver *callObserver = [[CXCallObserver alloc] init];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-io/video-react-native-sdk",
3
- "version": "1.31.1",
3
+ "version": "1.32.0",
4
4
  "description": "Stream Video SDK for React Native",
5
5
  "author": "https://getstream.io",
6
6
  "homepage": "https://getstream.io/video/docs/react-native/",
@@ -50,8 +50,8 @@
50
50
  "!**/.*"
51
51
  ],
52
52
  "dependencies": {
53
- "@stream-io/video-client": "1.45.0",
54
- "@stream-io/video-react-bindings": "1.13.15",
53
+ "@stream-io/video-client": "1.46.0",
54
+ "@stream-io/video-react-bindings": "1.14.0",
55
55
  "intl-pluralrules": "2.0.1",
56
56
  "react-native-url-polyfill": "^3.0.0",
57
57
  "rxjs": "~7.8.2",
@@ -64,6 +64,7 @@
64
64
  "@react-native-firebase/app": ">=17.5.0",
65
65
  "@react-native-firebase/messaging": ">=17.5.0",
66
66
  "@stream-io/noise-cancellation-react-native": ">=0.1.0",
67
+ "@stream-io/react-native-callingx": ">=0.1.0",
67
68
  "@stream-io/react-native-webrtc": ">=137.1.3",
68
69
  "@stream-io/video-filters-react-native": ">=0.1.0",
69
70
  "expo": ">=47.0.0",
@@ -71,11 +72,9 @@
71
72
  "expo-notifications": "*",
72
73
  "react": ">=17.0.0",
73
74
  "react-native": ">=0.73.0",
74
- "react-native-callkeep": ">=4.3.11",
75
75
  "react-native-gesture-handler": ">=2.8.0",
76
76
  "react-native-reanimated": ">=2.7.0",
77
- "react-native-svg": ">=13.6.0",
78
- "react-native-voip-push-notification": ">=3.3.1"
77
+ "react-native-svg": ">=13.6.0"
79
78
  },
80
79
  "peerDependenciesMeta": {
81
80
  "@notifee/react-native": {
@@ -93,6 +92,9 @@
93
92
  "@stream-io/noise-cancellation-react-native": {
94
93
  "optional": true
95
94
  },
95
+ "@stream-io/react-native-callingx": {
96
+ "optional": true
97
+ },
96
98
  "@stream-io/video-filters-react-native": {
97
99
  "optional": true
98
100
  },
@@ -105,17 +107,11 @@
105
107
  "expo-notifications": {
106
108
  "optional": true
107
109
  },
108
- "react-native-callkeep": {
109
- "optional": true
110
- },
111
110
  "react-native-gesture-handler": {
112
111
  "optional": true
113
112
  },
114
113
  "react-native-reanimated": {
115
114
  "optional": true
116
- },
117
- "react-native-voip-push-notification": {
118
- "optional": true
119
115
  }
120
116
  },
121
117
  "devDependencies": {
@@ -129,9 +125,10 @@
129
125
  "@react-native-firebase/app": "^23.4.0",
130
126
  "@react-native-firebase/messaging": "^23.4.0",
131
127
  "@react-native/babel-preset": "^0.81.5",
132
- "@stream-io/noise-cancellation-react-native": "^0.6.0",
128
+ "@stream-io/noise-cancellation-react-native": "^0.7.0",
129
+ "@stream-io/react-native-callingx": "^0.1.0",
133
130
  "@stream-io/react-native-webrtc": "137.1.3",
134
- "@stream-io/video-filters-react-native": "^0.11.0",
131
+ "@stream-io/video-filters-react-native": "^0.12.0",
135
132
  "@testing-library/jest-native": "^5.4.3",
136
133
  "@testing-library/react-native": "13.3.3",
137
134
  "@tsconfig/node18": "^18.2.4",
@@ -146,11 +143,9 @@
146
143
  "react": "19.1.0",
147
144
  "react-native": "^0.81.5",
148
145
  "react-native-builder-bob": "~0.23",
149
- "react-native-callkeep": "^4.3.16",
150
146
  "react-native-gesture-handler": "^2.28.0",
151
147
  "react-native-reanimated": "~4.1.2",
152
148
  "react-native-svg": "^15.14.0",
153
- "react-native-voip-push-notification": "3.3.3",
154
149
  "react-native-worklets": "^0.5.0",
155
150
  "react-test-renderer": "19.1.0",
156
151
  "rimraf": "^6.0.1",
@@ -1,5 +1,4 @@
1
1
  import { useIosVoipPushEventsSetupEffect } from './useIosVoipPushEventsSetupEffect';
2
- import { useProcessPushCallEffect } from './useProcessPushCallEffect';
3
2
  import { useInitAndroidTokenAndRest } from './useInitAndroidTokenAndRest';
4
3
  import { useIosInitRemoteNotifications } from './useIosInitRemoteNotifications';
5
4
  import { useProcessPushNonRingingCallEffect } from './useProcessPushNonRingingCallEffect';
@@ -12,6 +11,5 @@ export const usePushRegisterEffect = () => {
12
11
  useIosInitRemoteNotifications();
13
12
  useIosVoipPushEventsSetupEffect();
14
13
  useProcessPushNonRingingCallEffect();
15
- useProcessPushCallEffect();
16
14
  useInitAndroidTokenAndRest();
17
15
  };
@@ -0,0 +1,193 @@
1
+ import { Call, CallingState, videoLoggerSystem } from '@stream-io/video-client';
2
+ import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
3
+ import { useEffect, useMemo } from 'react';
4
+ import { filter, take } from 'rxjs/operators';
5
+ import { getCallDisplayName } from '../../utils/internal/callingx/callingx';
6
+ import { getCallingxLibIfAvailable } from '../../utils/push/libs/callingx';
7
+
8
+ const logger = videoLoggerSystem.getLogger('callingx');
9
+
10
+ /**
11
+ * This hook is used to inform sync call state with CallKit/Telecom (i.e. start call, end call, mute/unmute call).
12
+ */
13
+ export const useCallingExpWithCallingStateEffect = () => {
14
+ const { useMicrophoneState, useParticipants, useCallMembers } =
15
+ useCallStateHooks();
16
+
17
+ const activeCall = useCall();
18
+ const { isMute, microphone } = useMicrophoneState();
19
+ const callMembers = useCallMembers();
20
+ const participants = useParticipants();
21
+
22
+ const activeCallCid = activeCall?.cid;
23
+ const createdByUserId = activeCall?.state.createdBy?.id;
24
+ const callCustomDisplayName = activeCall?.state.custom?.display_name;
25
+ const currentUserId = activeCall?.currentUserId;
26
+ const isIncoming =
27
+ (activeCall?.ringing && !activeCall?.isCreatedByMe) || false;
28
+
29
+ const callDisplayName = useMemo(
30
+ () =>
31
+ callCustomDisplayName ??
32
+ getCallDisplayName(callMembers, participants, currentUserId),
33
+ [callMembers, participants, currentUserId, callCustomDisplayName],
34
+ );
35
+
36
+ useEffect(() => {
37
+ const callingx = getCallingxLibIfAvailable();
38
+ if (!callingx?.isSetup || !activeCall) {
39
+ return;
40
+ }
41
+ // need to capture RINGING -> Joining -> Joined state change for the first time
42
+ // and inform callingx that the call is active
43
+ const shouldMakeCallActive = (call: Call): boolean => {
44
+ // only for outgoing calls or non-ringing ongoing calls in callingx
45
+ // Note: incoming calls are handled by callingx pending states instead
46
+ return (
47
+ (call.ringing && call.isCreatedByMe) ||
48
+ (!call.ringing && callingx.isOngoingCallsEnabled)
49
+ );
50
+ };
51
+ const subscription = activeCall.state.callingState$
52
+ .pipe(
53
+ filter(
54
+ (callingState) =>
55
+ shouldMakeCallActive(activeCall) &&
56
+ callingState === CallingState.JOINED &&
57
+ callingx.isCallTracked(activeCall.cid),
58
+ ),
59
+ take(1), // only need to capture the first joined state for outgoing calls
60
+ // then subscription completes and is automatically unsubscribed
61
+ )
62
+ .subscribe(() => {
63
+ callingx.setCurrentCallActive(activeCall.cid);
64
+ });
65
+ return () => {
66
+ subscription.unsubscribe();
67
+ };
68
+ }, [activeCall]);
69
+
70
+ useEffect(() => {
71
+ return () => {
72
+ const callingx = getCallingxLibIfAvailable();
73
+ if (!callingx?.isSetup || !activeCallCid) {
74
+ return;
75
+ }
76
+
77
+ const isCallTracked = callingx.isCallTracked(activeCallCid);
78
+ if (!isCallTracked) {
79
+ logger.debug(
80
+ `useCallingExpWithCallingStateEffect:No active call cid to end in calling exp: ${activeCallCid} isCallTracked: ${isCallTracked}`,
81
+ );
82
+ return;
83
+ }
84
+ //if incoming stream call was unmounted, we need to end the call in CallKit/Telecom
85
+ logger.debug(
86
+ `useCallingExpWithCallingStateEffect: Ending call in callingx: ${activeCallCid}`,
87
+ );
88
+ callingx
89
+ .endCallWithReason(activeCallCid, 'local')
90
+ .catch((error: unknown) => {
91
+ logger.error(
92
+ `useCallingExpWithCallingStateEffect: Error ending call in callingx: ${activeCallCid}`,
93
+ error,
94
+ );
95
+ });
96
+ };
97
+ }, [activeCallCid]);
98
+
99
+ useEffect(() => {
100
+ const callingx = getCallingxLibIfAvailable();
101
+ if (!callingx?.isSetup || !activeCallCid) {
102
+ return;
103
+ }
104
+
105
+ const isCallTracked = callingx.isCallTracked(activeCallCid);
106
+ if (!isCallTracked) {
107
+ logger.debug(
108
+ `useCallingExpWithCallingStateEffect:No active call cid to update callingx: ${activeCallCid} isCallTracked: ${isCallTracked}`,
109
+ );
110
+ return;
111
+ }
112
+
113
+ callingx.updateDisplay(
114
+ activeCallCid,
115
+ createdByUserId ?? callDisplayName,
116
+ callDisplayName,
117
+ isIncoming,
118
+ );
119
+ }, [activeCallCid, createdByUserId, callDisplayName, isIncoming]);
120
+
121
+ // Sync microphone mute state from app → CallKit
122
+ useEffect(() => {
123
+ const callingx = getCallingxLibIfAvailable();
124
+ if (!callingx?.isSetup || !activeCallCid) {
125
+ return;
126
+ }
127
+
128
+ const isCallTracked = callingx.isCallTracked(activeCallCid);
129
+ if (!isCallTracked) {
130
+ logger.debug(
131
+ `useCallingExpWithCallingStateEffect: No active call cid to set muted in calling exp: ${activeCallCid} isCallTracked: ${isCallTracked}`,
132
+ );
133
+ return;
134
+ }
135
+
136
+ callingx.setMutedCall(activeCallCid, isMute);
137
+ }, [activeCallCid, isMute]);
138
+
139
+ // Sync mute state from CallKit → app (only for system-initiated mute actions)
140
+ useEffect(() => {
141
+ const callingx = getCallingxLibIfAvailable();
142
+ if (!callingx?.isSetup || !activeCallCid) {
143
+ logger.debug(
144
+ `useCallingExpWithCallingStateEffect: No active call cid to set muted in calling exp: ${activeCallCid} callingx isSetup: ${callingx?.isSetup}`,
145
+ );
146
+ return;
147
+ }
148
+
149
+ // Listen to mic toggle events from CallKit/Telecom and update stream call microphone state.
150
+ // Only system-initiated mute actions (e.g. user tapped mute on the native CallKit UI)
151
+ // are sent here — app-initiated actions are filtered out on the native side to prevent
152
+ // the feedback loop: app mutes mic → setMutedCall → CallKit delegate → event to JS → loop.
153
+ const subscription = callingx.addEventListener(
154
+ 'didPerformSetMutedCallAction',
155
+ async (event: { callId: string; muted: boolean }) => {
156
+ const { callId, muted } = event;
157
+
158
+ const isCallTracked = callingx.isCallTracked(activeCallCid);
159
+ if (!isCallTracked || callId !== activeCallCid) {
160
+ logger.debug(
161
+ `useCallingExpWithCallingStateEffect: No active call cid to set muted in calling exp: ${activeCallCid} isCallTracked: ${isCallTracked} callId: ${callId}`,
162
+ );
163
+ return;
164
+ }
165
+
166
+ const isCurrentlyMuted = microphone.state.status === 'disabled';
167
+ if (isCurrentlyMuted === muted) {
168
+ logger.debug(
169
+ `useCallingExpWithCallingStateEffect: Mic toggle is already in the desired state: ${muted} for call: ${activeCallCid}`,
170
+ );
171
+ return;
172
+ }
173
+
174
+ try {
175
+ if (muted) {
176
+ await microphone.disable();
177
+ } else {
178
+ await microphone.enable();
179
+ }
180
+ } catch (error: unknown) {
181
+ logger.error(
182
+ `useCallingExpWithCallingStateEffect: Error toggling mic in calling exp: ${activeCallCid}`,
183
+ error,
184
+ );
185
+ }
186
+ },
187
+ );
188
+
189
+ return () => {
190
+ subscription.remove();
191
+ };
192
+ }, [activeCallCid, microphone]);
193
+ };