@stream-io/video-react-native-sdk 1.31.0 → 1.31.1-beta.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 (210) 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 +144 -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 +35 -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 +150 -0
  27. package/dist/commonjs/utils/internal/callingx/callingx.js.map +1 -0
  28. package/dist/commonjs/utils/internal/registerSDKGlobals.js +53 -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 +71 -53
  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 +75 -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 +137 -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 +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 -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 +22 -2
  108. package/dist/typescript/utils/StreamVideoRN/index.d.ts.map +1 -1
  109. package/dist/typescript/utils/StreamVideoRN/types.d.ts +59 -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 +18 -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/firebaseMessaging/index.d.ts +16 -2
  130. package/dist/typescript/utils/push/libs/firebaseMessaging/index.d.ts.map +1 -1
  131. package/dist/typescript/utils/push/libs/index.d.ts +1 -2
  132. package/dist/typescript/utils/push/libs/index.d.ts.map +1 -1
  133. package/dist/typescript/utils/push/libs/notifee/index.d.ts +0 -1
  134. package/dist/typescript/utils/push/libs/notifee/index.d.ts.map +1 -1
  135. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts +8 -0
  136. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts.map +1 -0
  137. package/dist/typescript/utils/push/setupIosVoipPushEvents.d.ts.map +1 -1
  138. package/dist/typescript/version.d.ts +1 -1
  139. package/dist/typescript/version.d.ts.map +1 -1
  140. package/expo-config-plugin/dist/withAndroidManifest.js +1 -33
  141. package/expo-config-plugin/dist/withAndroidPermissions.js +2 -7
  142. package/expo-config-plugin/dist/withAppDelegate.js +19 -197
  143. package/expo-config-plugin/dist/withMainActivity.js +1 -1
  144. package/expo-config-plugin/dist/withiOSInfoPlist.js +2 -3
  145. package/ios/StreamInCallManager.m +2 -0
  146. package/ios/StreamInCallManager.swift +19 -7
  147. package/ios/StreamVideoReactNative.h +7 -4
  148. package/ios/StreamVideoReactNative.m +189 -82
  149. package/package.json +11 -16
  150. package/src/hooks/push/index.ts +0 -2
  151. package/src/hooks/push/useCallingExpWithCallingStateEffect.ts +189 -0
  152. package/src/hooks/push/useIosVoipPushEventsSetupEffect.ts +21 -34
  153. package/src/hooks/useAndroidKeepCallAliveEffect.ts +94 -120
  154. package/src/index.ts +1 -0
  155. package/src/modules/call-manager/CallManager.ts +36 -0
  156. package/src/modules/call-manager/native-module.d.ts +7 -0
  157. package/src/providers/StreamCall/index.tsx +6 -6
  158. package/src/utils/StreamVideoRN/index.ts +42 -30
  159. package/src/utils/StreamVideoRN/types.ts +61 -25
  160. package/src/utils/internal/callingx/audioSessionPromise.ts +65 -0
  161. package/src/utils/internal/callingx/callingx.ts +194 -0
  162. package/src/utils/internal/registerSDKGlobals.ts +52 -4
  163. package/src/utils/keepCallAliveHeadlessTask.ts +54 -0
  164. package/src/utils/push/android.ts +198 -311
  165. package/src/utils/push/internal/ios.ts +28 -44
  166. package/src/utils/push/internal/rxSubjects.ts +0 -61
  167. package/src/utils/push/internal/utils.ts +108 -64
  168. package/src/utils/push/ios.ts +1 -6
  169. package/src/utils/push/libs/callingx.ts +89 -0
  170. package/src/utils/push/libs/index.ts +1 -2
  171. package/src/utils/push/libs/notifee/index.ts +0 -27
  172. package/src/utils/push/setupCallingExpEvents.ts +135 -0
  173. package/src/utils/push/setupIosVoipPushEvents.ts +11 -7
  174. package/src/version.ts +1 -1
  175. package/android/src/main/java/com/streamvideo/reactnative/util/CallAliveServiceChecker.kt +0 -95
  176. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js +0 -160
  177. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +0 -1
  178. package/dist/commonjs/hooks/push/useProcessPushCallEffect.js +0 -67
  179. package/dist/commonjs/hooks/push/useProcessPushCallEffect.js.map +0 -1
  180. package/dist/commonjs/utils/push/libs/callkeep.js +0 -17
  181. package/dist/commonjs/utils/push/libs/callkeep.js.map +0 -1
  182. package/dist/commonjs/utils/push/libs/voipPushNotification.js +0 -17
  183. package/dist/commonjs/utils/push/libs/voipPushNotification.js.map +0 -1
  184. package/dist/commonjs/utils/push/setupIosCallKeepEvents.js +0 -205
  185. package/dist/commonjs/utils/push/setupIosCallKeepEvents.js.map +0 -1
  186. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js +0 -153
  187. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +0 -1
  188. package/dist/module/hooks/push/useProcessPushCallEffect.js +0 -60
  189. package/dist/module/hooks/push/useProcessPushCallEffect.js.map +0 -1
  190. package/dist/module/utils/push/libs/callkeep.js +0 -11
  191. package/dist/module/utils/push/libs/callkeep.js.map +0 -1
  192. package/dist/module/utils/push/libs/voipPushNotification.js +0 -11
  193. package/dist/module/utils/push/libs/voipPushNotification.js.map +0 -1
  194. package/dist/module/utils/push/setupIosCallKeepEvents.js +0 -199
  195. package/dist/module/utils/push/setupIosCallKeepEvents.js.map +0 -1
  196. package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts +0 -5
  197. package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts.map +0 -1
  198. package/dist/typescript/hooks/push/useProcessPushCallEffect.d.ts +0 -8
  199. package/dist/typescript/hooks/push/useProcessPushCallEffect.d.ts.map +0 -1
  200. package/dist/typescript/utils/push/libs/callkeep.d.ts +0 -3
  201. package/dist/typescript/utils/push/libs/callkeep.d.ts.map +0 -1
  202. package/dist/typescript/utils/push/libs/voipPushNotification.d.ts +0 -3
  203. package/dist/typescript/utils/push/libs/voipPushNotification.d.ts.map +0 -1
  204. package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts +0 -6
  205. package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts.map +0 -1
  206. package/src/hooks/push/useIosCallkeepWithCallingStateEffect.ts +0 -235
  207. package/src/hooks/push/useProcessPushCallEffect.ts +0 -108
  208. package/src/utils/push/libs/callkeep.ts +0 -16
  209. package/src/utils/push/libs/voipPushNotification.ts +0 -17
  210. 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"
@@ -22,12 +23,8 @@
22
23
  NSNotificationName const kBroadcastStartedNotification = @"iOS_BroadcastStarted";
23
24
  NSNotificationName const kBroadcastStoppedNotification = @"iOS_BroadcastStopped";
24
25
 
25
- static NSMutableDictionary *_incomingCallUUIDsByCallID = nil;
26
- static NSMutableDictionary *_incomingCallCidsByUUID = nil;
27
26
  static dispatch_queue_t _dictionaryQueue = nil;
28
27
 
29
- static BOOL _shouldRejectCallWhenBusy = NO;
30
-
31
28
  void broadcastNotificationCallback(CFNotificationCenterRef center,
32
29
  void *observer,
33
30
  CFStringRef name,
@@ -68,11 +65,196 @@ RCT_EXPORT_MODULE();
68
65
  static dispatch_once_t onceToken;
69
66
  dispatch_once(&onceToken, ^{
70
67
  _dictionaryQueue = dispatch_queue_create("com.stream.video.dictionary", DISPATCH_QUEUE_SERIAL);
71
- _incomingCallUUIDsByCallID = [NSMutableDictionary dictionary];
72
- _incomingCallCidsByUUID = [NSMutableDictionary dictionary];
73
68
  });
74
69
  }
75
70
 
71
+ +(BOOL)canRegisterCall {
72
+ Class callingxClass = NSClassFromString(@"Callingx");
73
+ if (!callingxClass) {
74
+ #if DEBUG
75
+ NSLog(@"[StreamVideoReactNative][canRegisterCall] Callingx not available");
76
+ #endif
77
+ return YES;
78
+ }
79
+
80
+ SEL selector = @selector(canRegisterCall);
81
+ if (![callingxClass respondsToSelector:selector]) {
82
+ #if DEBUG
83
+ NSLog(@"[StreamVideoReactNative][canRegisterCall] Callingx does not respond to canRegisterCall selector");
84
+ #endif
85
+ return YES;
86
+ }
87
+
88
+ NSMethodSignature *signature = [callingxClass methodSignatureForSelector:selector];
89
+ NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
90
+ [invocation setTarget:callingxClass];
91
+ [invocation setSelector:selector];
92
+ [invocation invoke];
93
+
94
+ BOOL canRegister = NO;
95
+ [invocation getReturnValue:&canRegister];
96
+
97
+ #if DEBUG
98
+ NSLog(@"[StreamVideoReactNative][canRegisterCall] canRegisterCall = %@", canRegister ? @"YES" : @"NO");
99
+ #endif
100
+
101
+ return canRegister;
102
+ }
103
+
104
+ +(void)voipRegistration {
105
+ Class voipManagerClass = NSClassFromString(@"Callingx.VoipNotificationsManager");
106
+ if (!voipManagerClass) {
107
+ // Fallback: Try the unmangled name (might work depending on Swift version)
108
+ voipManagerClass = NSClassFromString(@"VoipNotificationsManager");
109
+ }
110
+
111
+ if (!voipManagerClass) {
112
+ #if DEBUG
113
+ NSLog(@"[StreamVideoReactNative][voipRegistration] VoipNotificationsManager not available");
114
+ #endif
115
+ return;
116
+ }
117
+
118
+ SEL selector = @selector(voipRegistration);
119
+ if (![voipManagerClass respondsToSelector:selector]) {
120
+ #if DEBUG
121
+ NSLog(@"[StreamVideoReactNative][voipRegistration] VoipNotificationsManager does not respond to voipRegistration");
122
+ #endif
123
+ return;
124
+ }
125
+
126
+ [voipManagerClass voipRegistration];
127
+ }
128
+
129
+ +(void)didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type {
130
+ Class voipManagerClass = NSClassFromString(@"Callingx.VoipNotificationsManager");
131
+ if (!voipManagerClass) {
132
+ // Fallback: Try the unmangled name (might work depending on Swift version)
133
+ voipManagerClass = NSClassFromString(@"VoipNotificationsManager");
134
+ }
135
+
136
+ if (!voipManagerClass) {
137
+ #if DEBUG
138
+ NSLog(@"[StreamVideoReactNative][didUpdatePushCredentials] VoipNotificationsManager not available");
139
+ #endif
140
+ return;
141
+ }
142
+
143
+ SEL selector = @selector(didUpdatePushCredentials:forType:);
144
+ if (![voipManagerClass respondsToSelector:selector]) {
145
+ #if DEBUG
146
+ NSLog(@"[StreamVideoReactNative][didUpdatePushCredentials] VoipNotificationsManager does not respond to didUpdatePushCredentials:forType:");
147
+ #endif
148
+ return;
149
+ }
150
+
151
+ [voipManagerClass didUpdatePushCredentials:credentials forType:type];
152
+ }
153
+
154
+ +(void)didReceiveIncomingPush:(PKPushPayload *)payload forType:(NSString *)type completionHandler: (void (^_Nullable)(void)) completion {
155
+ NSDictionary *streamPayload = payload.dictionaryPayload[@"stream"];
156
+ if (!streamPayload) {
157
+ #if DEBUG
158
+ NSLog(@"[StreamVideoReactNative][didReceiveIncomingPush] Stream payload not found");
159
+ #endif
160
+ if (completion) {
161
+ completion();
162
+ }
163
+ return;
164
+ }
165
+
166
+ NSString *createdCallerName = streamPayload[@"created_by_display_name"];
167
+ NSString *callCid = streamPayload[@"call_cid"];
168
+ if (!createdCallerName || !callCid) {
169
+ #if DEBUG
170
+ NSLog(@"[StreamVideoReactNative][didReceiveIncomingPush] Missing required fields: created_by_display_name or call_cid");
171
+ #endif
172
+ if (completion) {
173
+ completion();
174
+ }
175
+ return;
176
+ }
177
+
178
+ if (![StreamVideoReactNative canRegisterCall]) {
179
+ if (completion) {
180
+ completion();
181
+ }
182
+ return;
183
+ }
184
+
185
+ [StreamVideoReactNative reportNewIncomingCall:streamPayload forType:type completionHandler:completion];
186
+ [StreamVideoReactNative didReceiveIncomingPushWithPayload:payload forType:type];
187
+ }
188
+
189
+ +(void)reportNewIncomingCall:(NSDictionary *)streamPayload forType:(NSString *)type completionHandler: (void (^_Nullable)(void)) completion {
190
+ Class callingxClass = NSClassFromString(@"Callingx");
191
+ if (!callingxClass) {
192
+ NSLog(@"[StreamVideoReactNative][didReceiveIncomingPush] Callingx not available");
193
+ return;
194
+ }
195
+
196
+ SEL selector = @selector(reportNewIncomingCall:handle:handleType:hasVideo:localizedCallerName:supportsHolding:supportsDTMF:supportsGrouping:supportsUngrouping:payload:withCompletionHandler:);
197
+ if (![callingxClass respondsToSelector:selector]) {
198
+ #if DEBUG
199
+ NSLog(@"[StreamVideoReactNative][didReceiveIncomingPush] Callingx does not respond to selector");
200
+ #endif
201
+ return;
202
+ }
203
+
204
+ NSString *callCid = streamPayload[@"call_cid"];
205
+ NSString *createdCallerName = streamPayload[@"created_by_display_name"];
206
+ NSString *videoIncluded = streamPayload[@"video"];
207
+ BOOL hasVideo = [videoIncluded isEqualToString:@"false"] ? NO : YES;
208
+ NSString *handleType = @"generic";
209
+ BOOL supportsHolding = NO;
210
+ BOOL supportsDTMF = NO;
211
+ BOOL supportsGrouping = NO;
212
+ BOOL supportsUngrouping = NO;
213
+ void (^completionHandler)(void) = completion;
214
+
215
+ NSMethodSignature *signature = [callingxClass methodSignatureForSelector:selector];
216
+ NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
217
+ [invocation setTarget:callingxClass];
218
+ [invocation setSelector:selector];
219
+ [invocation setArgument:&callCid atIndex:2];
220
+ [invocation setArgument:&createdCallerName atIndex:3];
221
+ [invocation setArgument:&handleType atIndex:4];
222
+ [invocation setArgument:&hasVideo atIndex:5];
223
+ [invocation setArgument:&createdCallerName atIndex:6];
224
+ [invocation setArgument:&supportsHolding atIndex:7];
225
+ [invocation setArgument:&supportsDTMF atIndex:8];
226
+ [invocation setArgument:&supportsGrouping atIndex:9];
227
+ [invocation setArgument:&supportsUngrouping atIndex:10];
228
+ [invocation setArgument:&streamPayload atIndex:11];
229
+ [invocation setArgument:&completionHandler atIndex:12];
230
+ [invocation invoke];
231
+ }
232
+
233
+ +(void)didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type {
234
+ Class voipManagerClass = NSClassFromString(@"Callingx.VoipNotificationsManager");
235
+ if (!voipManagerClass) {
236
+ // Fallback: Try the unmangled name (might work depending on Swift version)
237
+ voipManagerClass = NSClassFromString(@"VoipNotificationsManager");
238
+ }
239
+
240
+ if (!voipManagerClass) {
241
+ #if DEBUG
242
+ NSLog(@"[StreamVideoReactNative][didReceiveIncomingPushWithPayload] VoipNotificationsManager not available");
243
+ #endif
244
+ return;
245
+ }
246
+
247
+ SEL selector = @selector(didReceiveIncomingPushWithPayload:forType:);
248
+ if (![voipManagerClass respondsToSelector:selector]) {
249
+ #if DEBUG
250
+ NSLog(@"[StreamVideoReactNative][didReceiveIncomingPushWithPayload] VoipNotificationsManager does not respond to didReceiveIncomingPushWithPayload:forType:");
251
+ #endif
252
+ return;
253
+ }
254
+
255
+ [voipManagerClass didReceiveIncomingPushWithPayload:payload forType:type];
256
+ }
257
+
76
258
  -(instancetype)init {
77
259
  if ((self = [super init])) {
78
260
  _notificationCenter = CFNotificationCenterGetDarwinNotifyCenter();
@@ -199,71 +381,6 @@ RCT_EXPORT_METHOD(currentThermalState:(RCTPromiseResolveBlock)resolve rejecter:(
199
381
  }
200
382
  }
201
383
 
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
384
  RCT_EXPORT_METHOD(captureRef:(nonnull NSNumber *)reactTag
268
385
  options:(NSDictionary *)options
269
386
  resolver:(RCTPromiseResolveBlock)resolve
@@ -401,17 +518,7 @@ RCT_EXPORT_METHOD(checkPermission:(NSString *)permission
401
518
  ];
402
519
  }
403
520
 
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
-
521
+ //current implementation will return any registered calls not only stream calls
415
522
  + (BOOL)hasAnyActiveCall
416
523
  {
417
524
  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.0",
3
+ "version": "1.31.1-beta.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.44.5",
54
- "@stream-io/video-react-bindings": "1.13.14",
53
+ "@stream-io/video-client": "1.44.6-beta.0",
54
+ "@stream-io/video-react-bindings": "1.13.15-beta.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.6.1-beta.0",
129
+ "@stream-io/react-native-callingx": "0.1.1-beta.1",
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.11.1-beta.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,189 @@
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 currentUserId = activeCall?.currentUserId;
24
+ const isIncoming =
25
+ (activeCall?.ringing && !activeCall?.isCreatedByMe) || false;
26
+
27
+ const callDisplayName = useMemo(
28
+ () => getCallDisplayName(callMembers, participants, currentUserId),
29
+ [callMembers, participants, currentUserId],
30
+ );
31
+
32
+ useEffect(() => {
33
+ const callingx = getCallingxLibIfAvailable();
34
+ if (!callingx?.isSetup || !activeCall) {
35
+ return;
36
+ }
37
+ // need to capture RINGING -> Joining -> Joined state change for the first time
38
+ // and inform callingx that the call is active
39
+ const shouldMakeCallActive = (call: Call): boolean => {
40
+ // only for outgoing calls or non-ringing ongoing calls in callingx
41
+ // Note: incoming calls are handled by callingx pending states instead
42
+ return (
43
+ (call.ringing && call.isCreatedByMe) ||
44
+ (!call.ringing && callingx.isOngoingCallsEnabled)
45
+ );
46
+ };
47
+ const subscription = activeCall.state.callingState$
48
+ .pipe(
49
+ filter(
50
+ (callingState) =>
51
+ shouldMakeCallActive(activeCall) &&
52
+ callingState === CallingState.JOINED &&
53
+ callingx.isCallTracked(activeCall.cid),
54
+ ),
55
+ take(1), // only need to capture the first joined state for outgoing calls
56
+ // then subscription completes and is automatically unsubscribed
57
+ )
58
+ .subscribe(() => {
59
+ callingx.setCurrentCallActive(activeCall.cid);
60
+ });
61
+ return () => {
62
+ subscription.unsubscribe();
63
+ };
64
+ }, [activeCall]);
65
+
66
+ useEffect(() => {
67
+ return () => {
68
+ const callingx = getCallingxLibIfAvailable();
69
+ if (!callingx?.isSetup || !activeCallCid) {
70
+ return;
71
+ }
72
+
73
+ const isCallTracked = callingx.isCallTracked(activeCallCid);
74
+ if (!isCallTracked) {
75
+ logger.debug(
76
+ `useCallingExpWithCallingStateEffect:No active call cid to end in calling exp: ${activeCallCid} isCallTracked: ${isCallTracked}`,
77
+ );
78
+ return;
79
+ }
80
+ //if incoming stream call was unmounted, we need to end the call in CallKit/Telecom
81
+ logger.debug(
82
+ `useCallingExpWithCallingStateEffect: Ending call in callingx: ${activeCallCid}`,
83
+ );
84
+ callingx
85
+ .endCallWithReason(activeCallCid, 'local')
86
+ .catch((error: unknown) => {
87
+ logger.error(
88
+ `useCallingExpWithCallingStateEffect: Error ending call in callingx: ${activeCallCid}`,
89
+ error,
90
+ );
91
+ });
92
+ };
93
+ }, [activeCallCid]);
94
+
95
+ useEffect(() => {
96
+ const callingx = getCallingxLibIfAvailable();
97
+ if (!callingx?.isSetup || !activeCallCid) {
98
+ return;
99
+ }
100
+
101
+ const isCallTracked = callingx.isCallTracked(activeCallCid);
102
+ if (!isCallTracked) {
103
+ logger.debug(
104
+ `useCallingExpWithCallingStateEffect:No active call cid to update callingx: ${activeCallCid} isCallTracked: ${isCallTracked}`,
105
+ );
106
+ return;
107
+ }
108
+
109
+ callingx.updateDisplay(
110
+ activeCallCid,
111
+ activeCallCid,
112
+ callDisplayName,
113
+ isIncoming,
114
+ );
115
+ }, [activeCallCid, callDisplayName, isIncoming]);
116
+
117
+ // Sync microphone mute state from app → CallKit
118
+ useEffect(() => {
119
+ const callingx = getCallingxLibIfAvailable();
120
+ if (!callingx?.isSetup || !activeCallCid) {
121
+ return;
122
+ }
123
+
124
+ const isCallTracked = callingx.isCallTracked(activeCallCid);
125
+ if (!isCallTracked) {
126
+ logger.debug(
127
+ `useCallingExpWithCallingStateEffect: No active call cid to set muted in calling exp: ${activeCallCid} isCallTracked: ${isCallTracked}`,
128
+ );
129
+ return;
130
+ }
131
+
132
+ callingx.setMutedCall(activeCallCid, isMute);
133
+ }, [activeCallCid, isMute]);
134
+
135
+ // Sync mute state from CallKit → app (only for system-initiated mute actions)
136
+ useEffect(() => {
137
+ const callingx = getCallingxLibIfAvailable();
138
+ if (!callingx?.isSetup || !activeCallCid) {
139
+ logger.debug(
140
+ `useCallingExpWithCallingStateEffect: No active call cid to set muted in calling exp: ${activeCallCid} callingx isSetup: ${callingx?.isSetup}`,
141
+ );
142
+ return;
143
+ }
144
+
145
+ // Listen to mic toggle events from CallKit/Telecom and update stream call microphone state.
146
+ // Only system-initiated mute actions (e.g. user tapped mute on the native CallKit UI)
147
+ // are sent here — app-initiated actions are filtered out on the native side to prevent
148
+ // the feedback loop: app mutes mic → setMutedCall → CallKit delegate → event to JS → loop.
149
+ const subscription = callingx.addEventListener(
150
+ 'didPerformSetMutedCallAction',
151
+ async (event: { callId: string; muted: boolean }) => {
152
+ const { callId, muted } = event;
153
+
154
+ const isCallTracked = callingx.isCallTracked(activeCallCid);
155
+ if (!isCallTracked || callId !== activeCallCid) {
156
+ logger.debug(
157
+ `useCallingExpWithCallingStateEffect: No active call cid to set muted in calling exp: ${activeCallCid} isCallTracked: ${isCallTracked} callId: ${callId}`,
158
+ );
159
+ return;
160
+ }
161
+
162
+ const isCurrentlyMuted = microphone.state.status === 'disabled';
163
+ if (isCurrentlyMuted === muted) {
164
+ logger.debug(
165
+ `useCallingExpWithCallingStateEffect: Mic toggle is already in the desired state: ${muted} for call: ${activeCallCid}`,
166
+ );
167
+ return;
168
+ }
169
+
170
+ try {
171
+ if (muted) {
172
+ await microphone.disable();
173
+ } else {
174
+ await microphone.enable();
175
+ }
176
+ } catch (error: unknown) {
177
+ logger.error(
178
+ `useCallingExpWithCallingStateEffect: Error toggling mic in calling exp: ${activeCallCid}`,
179
+ error,
180
+ );
181
+ }
182
+ },
183
+ );
184
+
185
+ return () => {
186
+ subscription.remove();
187
+ };
188
+ }, [activeCallCid, microphone]);
189
+ };