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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/android/src/main/AndroidManifest.xml +8 -1
  2. package/android/src/main/AndroidManifestNew.xml +11 -0
  3. package/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.kt +42 -5
  4. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/WebRtcAudioUtils.kt +70 -6
  5. package/android/src/main/java/com/streamvideo/reactnative/callmanager/StreamInCallManagerModule.kt +6 -4
  6. package/android/src/main/java/com/streamvideo/reactnative/keepalive/KeepAliveNotification.kt +83 -0
  7. package/android/src/main/java/com/streamvideo/reactnative/keepalive/StreamCallKeepAliveHeadlessService.kt +149 -0
  8. package/dist/commonjs/hooks/push/index.js +0 -2
  9. package/dist/commonjs/hooks/push/index.js.map +1 -1
  10. package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js +121 -0
  11. package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js.map +1 -0
  12. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js +18 -31
  13. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
  14. package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js +64 -97
  15. package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
  16. package/dist/commonjs/index.js +1 -0
  17. package/dist/commonjs/index.js.map +1 -1
  18. package/dist/commonjs/modules/call-manager/CallManager.js +26 -0
  19. package/dist/commonjs/modules/call-manager/CallManager.js.map +1 -1
  20. package/dist/commonjs/providers/StreamCall/index.js +6 -6
  21. package/dist/commonjs/providers/StreamCall/index.js.map +1 -1
  22. package/dist/commonjs/utils/StreamVideoRN/index.js +33 -21
  23. package/dist/commonjs/utils/StreamVideoRN/index.js.map +1 -1
  24. package/dist/commonjs/utils/internal/callingx/audioSessionPromise.js +68 -0
  25. package/dist/commonjs/utils/internal/callingx/audioSessionPromise.js.map +1 -0
  26. package/dist/commonjs/utils/internal/callingx/callingx.js +123 -0
  27. package/dist/commonjs/utils/internal/callingx/callingx.js.map +1 -0
  28. package/dist/commonjs/utils/internal/registerSDKGlobals.js +52 -3
  29. package/dist/commonjs/utils/internal/registerSDKGlobals.js.map +1 -1
  30. package/dist/commonjs/utils/keepCallAliveHeadlessTask.js +48 -0
  31. package/dist/commonjs/utils/keepCallAliveHeadlessTask.js.map +1 -0
  32. package/dist/commonjs/utils/push/android.js +135 -202
  33. package/dist/commonjs/utils/push/android.js.map +1 -1
  34. package/dist/commonjs/utils/push/internal/ios.js +17 -34
  35. package/dist/commonjs/utils/push/internal/ios.js.map +1 -1
  36. package/dist/commonjs/utils/push/internal/rxSubjects.js +1 -45
  37. package/dist/commonjs/utils/push/internal/rxSubjects.js.map +1 -1
  38. package/dist/commonjs/utils/push/internal/utils.js +67 -52
  39. package/dist/commonjs/utils/push/internal/utils.js.map +1 -1
  40. package/dist/commonjs/utils/push/ios.js.map +1 -1
  41. package/dist/commonjs/utils/push/libs/callingx.js +78 -0
  42. package/dist/commonjs/utils/push/libs/callingx.js.map +1 -0
  43. package/dist/commonjs/utils/push/libs/index.js +8 -19
  44. package/dist/commonjs/utils/push/libs/index.js.map +1 -1
  45. package/dist/commonjs/utils/push/libs/notifee/index.js +0 -19
  46. package/dist/commonjs/utils/push/libs/notifee/index.js.map +1 -1
  47. package/dist/commonjs/utils/push/setupCallingExpEvents.js +105 -0
  48. package/dist/commonjs/utils/push/setupCallingExpEvents.js.map +1 -0
  49. package/dist/commonjs/utils/push/setupIosVoipPushEvents.js +7 -6
  50. package/dist/commonjs/utils/push/setupIosVoipPushEvents.js.map +1 -1
  51. package/dist/commonjs/version.js +1 -1
  52. package/dist/commonjs/version.js.map +1 -1
  53. package/dist/module/hooks/push/index.js +0 -2
  54. package/dist/module/hooks/push/index.js.map +1 -1
  55. package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js +114 -0
  56. package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js.map +1 -0
  57. package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js +18 -31
  58. package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
  59. package/dist/module/hooks/useAndroidKeepCallAliveEffect.js +66 -99
  60. package/dist/module/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
  61. package/dist/module/index.js +1 -0
  62. package/dist/module/index.js.map +1 -1
  63. package/dist/module/modules/call-manager/CallManager.js +26 -0
  64. package/dist/module/modules/call-manager/CallManager.js.map +1 -1
  65. package/dist/module/providers/StreamCall/index.js +6 -6
  66. package/dist/module/providers/StreamCall/index.js.map +1 -1
  67. package/dist/module/utils/StreamVideoRN/index.js +33 -21
  68. package/dist/module/utils/StreamVideoRN/index.js.map +1 -1
  69. package/dist/module/utils/internal/callingx/audioSessionPromise.js +61 -0
  70. package/dist/module/utils/internal/callingx/audioSessionPromise.js.map +1 -0
  71. package/dist/module/utils/internal/callingx/callingx.js +114 -0
  72. package/dist/module/utils/internal/callingx/callingx.js.map +1 -0
  73. package/dist/module/utils/internal/registerSDKGlobals.js +52 -3
  74. package/dist/module/utils/internal/registerSDKGlobals.js.map +1 -1
  75. package/dist/module/utils/keepCallAliveHeadlessTask.js +42 -0
  76. package/dist/module/utils/keepCallAliveHeadlessTask.js.map +1 -0
  77. package/dist/module/utils/push/android.js +137 -204
  78. package/dist/module/utils/push/android.js.map +1 -1
  79. package/dist/module/utils/push/internal/ios.js +17 -34
  80. package/dist/module/utils/push/internal/ios.js.map +1 -1
  81. package/dist/module/utils/push/internal/rxSubjects.js +0 -44
  82. package/dist/module/utils/push/internal/rxSubjects.js.map +1 -1
  83. package/dist/module/utils/push/internal/utils.js +63 -49
  84. package/dist/module/utils/push/internal/utils.js.map +1 -1
  85. package/dist/module/utils/push/ios.js.map +1 -1
  86. package/dist/module/utils/push/libs/callingx.js +70 -0
  87. package/dist/module/utils/push/libs/callingx.js.map +1 -0
  88. package/dist/module/utils/push/libs/index.js +1 -2
  89. package/dist/module/utils/push/libs/index.js.map +1 -1
  90. package/dist/module/utils/push/libs/notifee/index.js +0 -18
  91. package/dist/module/utils/push/libs/notifee/index.js.map +1 -1
  92. package/dist/module/utils/push/setupCallingExpEvents.js +99 -0
  93. package/dist/module/utils/push/setupCallingExpEvents.js.map +1 -0
  94. package/dist/module/utils/push/setupIosVoipPushEvents.js +7 -6
  95. package/dist/module/utils/push/setupIosVoipPushEvents.js.map +1 -1
  96. package/dist/module/version.js +1 -1
  97. package/dist/module/version.js.map +1 -1
  98. package/dist/typescript/hooks/push/index.d.ts.map +1 -1
  99. package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts +5 -0
  100. package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts.map +1 -0
  101. package/dist/typescript/hooks/push/useIosVoipPushEventsSetupEffect.d.ts.map +1 -1
  102. package/dist/typescript/hooks/useAndroidKeepCallAliveEffect.d.ts.map +1 -1
  103. package/dist/typescript/index.d.ts +1 -0
  104. package/dist/typescript/index.d.ts.map +1 -1
  105. package/dist/typescript/modules/call-manager/CallManager.d.ts +5 -0
  106. package/dist/typescript/modules/call-manager/CallManager.d.ts.map +1 -1
  107. package/dist/typescript/utils/StreamVideoRN/index.d.ts +20 -2
  108. package/dist/typescript/utils/StreamVideoRN/index.d.ts.map +1 -1
  109. package/dist/typescript/utils/StreamVideoRN/types.d.ts +63 -25
  110. package/dist/typescript/utils/StreamVideoRN/types.d.ts.map +1 -1
  111. package/dist/typescript/utils/internal/callingx/audioSessionPromise.d.ts +16 -0
  112. package/dist/typescript/utils/internal/callingx/audioSessionPromise.d.ts.map +1 -0
  113. package/dist/typescript/utils/internal/callingx/callingx.d.ts +17 -0
  114. package/dist/typescript/utils/internal/callingx/callingx.d.ts.map +1 -0
  115. package/dist/typescript/utils/internal/registerSDKGlobals.d.ts.map +1 -1
  116. package/dist/typescript/utils/keepCallAliveHeadlessTask.d.ts +10 -0
  117. package/dist/typescript/utils/keepCallAliveHeadlessTask.d.ts.map +1 -0
  118. package/dist/typescript/utils/push/android.d.ts +1 -2
  119. package/dist/typescript/utils/push/android.d.ts.map +1 -1
  120. package/dist/typescript/utils/push/internal/ios.d.ts.map +1 -1
  121. package/dist/typescript/utils/push/internal/rxSubjects.d.ts +0 -33
  122. package/dist/typescript/utils/push/internal/rxSubjects.d.ts.map +1 -1
  123. package/dist/typescript/utils/push/internal/utils.d.ts +14 -8
  124. package/dist/typescript/utils/push/internal/utils.d.ts.map +1 -1
  125. package/dist/typescript/utils/push/ios.d.ts +1 -2
  126. package/dist/typescript/utils/push/ios.d.ts.map +1 -1
  127. package/dist/typescript/utils/push/libs/callingx.d.ts +9 -0
  128. package/dist/typescript/utils/push/libs/callingx.d.ts.map +1 -0
  129. package/dist/typescript/utils/push/libs/index.d.ts +1 -2
  130. package/dist/typescript/utils/push/libs/index.d.ts.map +1 -1
  131. package/dist/typescript/utils/push/libs/notifee/index.d.ts +0 -1
  132. package/dist/typescript/utils/push/libs/notifee/index.d.ts.map +1 -1
  133. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts +8 -0
  134. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts.map +1 -0
  135. package/dist/typescript/utils/push/setupIosVoipPushEvents.d.ts.map +1 -1
  136. package/dist/typescript/version.d.ts +1 -1
  137. package/dist/typescript/version.d.ts.map +1 -1
  138. package/expo-config-plugin/dist/withAndroidManifest.js +1 -33
  139. package/expo-config-plugin/dist/withAndroidPermissions.js +2 -7
  140. package/expo-config-plugin/dist/withAppDelegate.js +19 -197
  141. package/expo-config-plugin/dist/withMainActivity.js +1 -1
  142. package/expo-config-plugin/dist/withiOSInfoPlist.js +2 -3
  143. package/ios/StreamInCallManager.m +2 -0
  144. package/ios/StreamInCallManager.swift +19 -7
  145. package/ios/StreamVideoReactNative.h +7 -4
  146. package/ios/StreamVideoReactNative.m +189 -82
  147. package/package.json +13 -18
  148. package/src/hooks/push/index.ts +0 -2
  149. package/src/hooks/push/useCallingExpWithCallingStateEffect.ts +147 -0
  150. package/src/hooks/push/useIosVoipPushEventsSetupEffect.ts +21 -34
  151. package/src/hooks/useAndroidKeepCallAliveEffect.ts +94 -120
  152. package/src/index.ts +1 -0
  153. package/src/modules/call-manager/CallManager.ts +36 -0
  154. package/src/modules/call-manager/native-module.d.ts +7 -0
  155. package/src/providers/StreamCall/index.tsx +6 -6
  156. package/src/utils/StreamVideoRN/index.ts +40 -30
  157. package/src/utils/StreamVideoRN/types.ts +65 -25
  158. package/src/utils/internal/callingx/audioSessionPromise.ts +65 -0
  159. package/src/utils/internal/callingx/callingx.ts +165 -0
  160. package/src/utils/internal/registerSDKGlobals.ts +47 -4
  161. package/src/utils/keepCallAliveHeadlessTask.ts +54 -0
  162. package/src/utils/push/android.ts +196 -311
  163. package/src/utils/push/internal/ios.ts +28 -44
  164. package/src/utils/push/internal/rxSubjects.ts +0 -61
  165. package/src/utils/push/internal/utils.ts +104 -63
  166. package/src/utils/push/ios.ts +1 -6
  167. package/src/utils/push/libs/callingx.ts +93 -0
  168. package/src/utils/push/libs/index.ts +1 -2
  169. package/src/utils/push/libs/notifee/index.ts +0 -27
  170. package/src/utils/push/setupCallingExpEvents.ts +135 -0
  171. package/src/utils/push/setupIosVoipPushEvents.ts +11 -7
  172. package/src/version.ts +1 -1
  173. package/android/src/main/java/com/streamvideo/reactnative/util/CallAliveServiceChecker.kt +0 -95
  174. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js +0 -160
  175. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +0 -1
  176. package/dist/commonjs/hooks/push/useProcessPushCallEffect.js +0 -67
  177. package/dist/commonjs/hooks/push/useProcessPushCallEffect.js.map +0 -1
  178. package/dist/commonjs/utils/push/libs/callkeep.js +0 -17
  179. package/dist/commonjs/utils/push/libs/callkeep.js.map +0 -1
  180. package/dist/commonjs/utils/push/libs/voipPushNotification.js +0 -17
  181. package/dist/commonjs/utils/push/libs/voipPushNotification.js.map +0 -1
  182. package/dist/commonjs/utils/push/setupIosCallKeepEvents.js +0 -205
  183. package/dist/commonjs/utils/push/setupIosCallKeepEvents.js.map +0 -1
  184. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js +0 -153
  185. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +0 -1
  186. package/dist/module/hooks/push/useProcessPushCallEffect.js +0 -60
  187. package/dist/module/hooks/push/useProcessPushCallEffect.js.map +0 -1
  188. package/dist/module/utils/push/libs/callkeep.js +0 -11
  189. package/dist/module/utils/push/libs/callkeep.js.map +0 -1
  190. package/dist/module/utils/push/libs/voipPushNotification.js +0 -11
  191. package/dist/module/utils/push/libs/voipPushNotification.js.map +0 -1
  192. package/dist/module/utils/push/setupIosCallKeepEvents.js +0 -199
  193. package/dist/module/utils/push/setupIosCallKeepEvents.js.map +0 -1
  194. package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts +0 -5
  195. package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts.map +0 -1
  196. package/dist/typescript/hooks/push/useProcessPushCallEffect.d.ts +0 -8
  197. package/dist/typescript/hooks/push/useProcessPushCallEffect.d.ts.map +0 -1
  198. package/dist/typescript/utils/push/libs/callkeep.d.ts +0 -3
  199. package/dist/typescript/utils/push/libs/callkeep.d.ts.map +0 -1
  200. package/dist/typescript/utils/push/libs/voipPushNotification.d.ts +0 -3
  201. package/dist/typescript/utils/push/libs/voipPushNotification.d.ts.map +0 -1
  202. package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts +0 -6
  203. package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts.map +0 -1
  204. package/src/hooks/push/useIosCallkeepWithCallingStateEffect.ts +0 -235
  205. package/src/hooks/push/useProcessPushCallEffect.ts +0 -108
  206. package/src/utils/push/libs/callkeep.ts +0 -16
  207. package/src/utils/push/libs/voipPushNotification.ts +0 -17
  208. package/src/utils/push/setupIosCallKeepEvents.ts +0 -252
@@ -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"
@@ -14,12 +15,8 @@
14
15
  NSNotificationName const kBroadcastStartedNotification = @"iOS_BroadcastStarted";
15
16
  NSNotificationName const kBroadcastStoppedNotification = @"iOS_BroadcastStopped";
16
17
 
17
- static NSMutableDictionary *_incomingCallUUIDsByCallID = nil;
18
- static NSMutableDictionary *_incomingCallCidsByUUID = nil;
19
18
  static dispatch_queue_t _dictionaryQueue = nil;
20
19
 
21
- static BOOL _shouldRejectCallWhenBusy = NO;
22
-
23
20
  void broadcastNotificationCallback(CFNotificationCenterRef center,
24
21
  void *observer,
25
22
  CFStringRef name,
@@ -60,11 +57,196 @@ RCT_EXPORT_MODULE();
60
57
  static dispatch_once_t onceToken;
61
58
  dispatch_once(&onceToken, ^{
62
59
  _dictionaryQueue = dispatch_queue_create("com.stream.video.dictionary", DISPATCH_QUEUE_SERIAL);
63
- _incomingCallUUIDsByCallID = [NSMutableDictionary dictionary];
64
- _incomingCallCidsByUUID = [NSMutableDictionary dictionary];
65
60
  });
66
61
  }
67
62
 
63
+ +(BOOL)canRegisterCall {
64
+ Class callingxClass = NSClassFromString(@"Callingx");
65
+ if (!callingxClass) {
66
+ #if DEBUG
67
+ NSLog(@"[StreamVideoReactNative][canRegisterCall] Callingx not available");
68
+ #endif
69
+ return YES;
70
+ }
71
+
72
+ SEL selector = @selector(canRegisterCall);
73
+ if (![callingxClass respondsToSelector:selector]) {
74
+ #if DEBUG
75
+ NSLog(@"[StreamVideoReactNative][canRegisterCall] Callingx does not respond to canRegisterCall selector");
76
+ #endif
77
+ return YES;
78
+ }
79
+
80
+ NSMethodSignature *signature = [callingxClass methodSignatureForSelector:selector];
81
+ NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
82
+ [invocation setTarget:callingxClass];
83
+ [invocation setSelector:selector];
84
+ [invocation invoke];
85
+
86
+ BOOL canRegister = NO;
87
+ [invocation getReturnValue:&canRegister];
88
+
89
+ #if DEBUG
90
+ NSLog(@"[StreamVideoReactNative][canRegisterCall] canRegisterCall = %@", canRegister ? @"YES" : @"NO");
91
+ #endif
92
+
93
+ return canRegister;
94
+ }
95
+
96
+ +(void)voipRegistration {
97
+ Class voipManagerClass = NSClassFromString(@"Callingx.VoipNotificationsManager");
98
+ if (!voipManagerClass) {
99
+ // Fallback: Try the unmangled name (might work depending on Swift version)
100
+ voipManagerClass = NSClassFromString(@"VoipNotificationsManager");
101
+ }
102
+
103
+ if (!voipManagerClass) {
104
+ #if DEBUG
105
+ NSLog(@"[StreamVideoReactNative][voipRegistration] VoipNotificationsManager not available");
106
+ #endif
107
+ return;
108
+ }
109
+
110
+ SEL selector = @selector(voipRegistration);
111
+ if (![voipManagerClass respondsToSelector:selector]) {
112
+ #if DEBUG
113
+ NSLog(@"[StreamVideoReactNative][voipRegistration] VoipNotificationsManager does not respond to voipRegistration");
114
+ #endif
115
+ return;
116
+ }
117
+
118
+ [voipManagerClass voipRegistration];
119
+ }
120
+
121
+ +(void)didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type {
122
+ Class voipManagerClass = NSClassFromString(@"Callingx.VoipNotificationsManager");
123
+ if (!voipManagerClass) {
124
+ // Fallback: Try the unmangled name (might work depending on Swift version)
125
+ voipManagerClass = NSClassFromString(@"VoipNotificationsManager");
126
+ }
127
+
128
+ if (!voipManagerClass) {
129
+ #if DEBUG
130
+ NSLog(@"[StreamVideoReactNative][didUpdatePushCredentials] VoipNotificationsManager not available");
131
+ #endif
132
+ return;
133
+ }
134
+
135
+ SEL selector = @selector(didUpdatePushCredentials:forType:);
136
+ if (![voipManagerClass respondsToSelector:selector]) {
137
+ #if DEBUG
138
+ NSLog(@"[StreamVideoReactNative][didUpdatePushCredentials] VoipNotificationsManager does not respond to didUpdatePushCredentials:forType:");
139
+ #endif
140
+ return;
141
+ }
142
+
143
+ [voipManagerClass didUpdatePushCredentials:credentials forType:type];
144
+ }
145
+
146
+ +(void)didReceiveIncomingPush:(PKPushPayload *)payload forType:(NSString *)type completionHandler: (void (^_Nullable)(void)) completion {
147
+ NSDictionary *streamPayload = payload.dictionaryPayload[@"stream"];
148
+ if (!streamPayload) {
149
+ #if DEBUG
150
+ NSLog(@"[StreamVideoReactNative][didReceiveIncomingPush] Stream payload not found");
151
+ #endif
152
+ if (completion) {
153
+ completion();
154
+ }
155
+ return;
156
+ }
157
+
158
+ NSString *createdCallerName = streamPayload[@"created_by_display_name"];
159
+ NSString *callCid = streamPayload[@"call_cid"];
160
+ if (!createdCallerName || !callCid) {
161
+ #if DEBUG
162
+ NSLog(@"[StreamVideoReactNative][didReceiveIncomingPush] Missing required fields: created_by_display_name or call_cid");
163
+ #endif
164
+ if (completion) {
165
+ completion();
166
+ }
167
+ return;
168
+ }
169
+
170
+ if (![StreamVideoReactNative canRegisterCall]) {
171
+ if (completion) {
172
+ completion();
173
+ }
174
+ return;
175
+ }
176
+
177
+ [StreamVideoReactNative reportNewIncomingCall:streamPayload forType:type completionHandler:completion];
178
+ [StreamVideoReactNative didReceiveIncomingPushWithPayload:payload forType:type];
179
+ }
180
+
181
+ +(void)reportNewIncomingCall:(NSDictionary *)streamPayload forType:(NSString *)type completionHandler: (void (^_Nullable)(void)) completion {
182
+ Class callingxClass = NSClassFromString(@"Callingx");
183
+ if (!callingxClass) {
184
+ NSLog(@"[StreamVideoReactNative][didReceiveIncomingPush] Callingx not available");
185
+ return;
186
+ }
187
+
188
+ SEL selector = @selector(reportNewIncomingCall:handle:handleType:hasVideo:localizedCallerName:supportsHolding:supportsDTMF:supportsGrouping:supportsUngrouping:payload:withCompletionHandler:);
189
+ if (![callingxClass respondsToSelector:selector]) {
190
+ #if DEBUG
191
+ NSLog(@"[StreamVideoReactNative][didReceiveIncomingPush] Callingx does not respond to selector");
192
+ #endif
193
+ return;
194
+ }
195
+
196
+ NSString *callCid = streamPayload[@"call_cid"];
197
+ NSString *createdCallerName = streamPayload[@"created_by_display_name"];
198
+ NSString *videoIncluded = streamPayload[@"video"];
199
+ BOOL hasVideo = [videoIncluded isEqualToString:@"false"] ? NO : YES;
200
+ NSString *handleType = @"generic";
201
+ BOOL supportsHolding = NO;
202
+ BOOL supportsDTMF = NO;
203
+ BOOL supportsGrouping = NO;
204
+ BOOL supportsUngrouping = NO;
205
+ void (^completionHandler)(void) = completion;
206
+
207
+ NSMethodSignature *signature = [callingxClass methodSignatureForSelector:selector];
208
+ NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
209
+ [invocation setTarget:callingxClass];
210
+ [invocation setSelector:selector];
211
+ [invocation setArgument:&callCid atIndex:2];
212
+ [invocation setArgument:&createdCallerName atIndex:3];
213
+ [invocation setArgument:&handleType atIndex:4];
214
+ [invocation setArgument:&hasVideo atIndex:5];
215
+ [invocation setArgument:&createdCallerName atIndex:6];
216
+ [invocation setArgument:&supportsHolding atIndex:7];
217
+ [invocation setArgument:&supportsDTMF atIndex:8];
218
+ [invocation setArgument:&supportsGrouping atIndex:9];
219
+ [invocation setArgument:&supportsUngrouping atIndex:10];
220
+ [invocation setArgument:&streamPayload atIndex:11];
221
+ [invocation setArgument:&completionHandler atIndex:12];
222
+ [invocation invoke];
223
+ }
224
+
225
+ +(void)didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type {
226
+ Class voipManagerClass = NSClassFromString(@"Callingx.VoipNotificationsManager");
227
+ if (!voipManagerClass) {
228
+ // Fallback: Try the unmangled name (might work depending on Swift version)
229
+ voipManagerClass = NSClassFromString(@"VoipNotificationsManager");
230
+ }
231
+
232
+ if (!voipManagerClass) {
233
+ #if DEBUG
234
+ NSLog(@"[StreamVideoReactNative][didReceiveIncomingPushWithPayload] VoipNotificationsManager not available");
235
+ #endif
236
+ return;
237
+ }
238
+
239
+ SEL selector = @selector(didReceiveIncomingPushWithPayload:forType:);
240
+ if (![voipManagerClass respondsToSelector:selector]) {
241
+ #if DEBUG
242
+ NSLog(@"[StreamVideoReactNative][didReceiveIncomingPushWithPayload] VoipNotificationsManager does not respond to didReceiveIncomingPushWithPayload:forType:");
243
+ #endif
244
+ return;
245
+ }
246
+
247
+ [voipManagerClass didReceiveIncomingPushWithPayload:payload forType:type];
248
+ }
249
+
68
250
  -(instancetype)init {
69
251
  if ((self = [super init])) {
70
252
  _notificationCenter = CFNotificationCenterGetDarwinNotifyCenter();
@@ -191,71 +373,6 @@ RCT_EXPORT_METHOD(currentThermalState:(RCTPromiseResolveBlock)resolve rejecter:(
191
373
  }
192
374
  }
193
375
 
194
- +(void)registerIncomingCall:(NSString *)cid uuid:(NSString *)uuid {
195
- [StreamVideoReactNative initializeSharedDictionaries];
196
- dispatch_sync(_dictionaryQueue, ^{
197
-
198
- #ifdef DEBUG
199
- NSLog(@"registerIncomingCall cid:%@ -> uuid:%@",cid,uuid);
200
- #endif
201
- NSString *lowercaseUUID = [uuid lowercaseString];
202
- _incomingCallUUIDsByCallID[cid] = lowercaseUUID;
203
- _incomingCallCidsByUUID[lowercaseUUID] = cid;
204
- });
205
- }
206
-
207
- RCT_EXPORT_METHOD(getIncomingCallUUid:(NSString *)cid
208
- resolver:(RCTPromiseResolveBlock)resolve
209
- rejecter:(RCTPromiseRejectBlock)reject)
210
- {
211
- dispatch_sync(_dictionaryQueue, ^{
212
- NSString *uuid = _incomingCallUUIDsByCallID[cid];
213
- if (uuid) {
214
- resolve(uuid);
215
- } else {
216
- NSString *errorString = [NSString stringWithFormat:@"requested incoming call not found for cid: %@", cid];
217
- reject(@"access_failure", errorString, nil);
218
- }
219
- });
220
- }
221
-
222
- RCT_EXPORT_METHOD(getIncomingCallCid:(NSString *)uuid
223
- resolver:(RCTPromiseResolveBlock)resolve
224
- rejecter:(RCTPromiseRejectBlock)reject)
225
- {
226
- dispatch_sync(_dictionaryQueue, ^{
227
- NSString *lowercaseUUID = [uuid lowercaseString];
228
- NSString *foundCid = _incomingCallCidsByUUID[lowercaseUUID];
229
-
230
- if (foundCid) {
231
- resolve(foundCid);
232
- } else {
233
- NSString *errorString = [NSString stringWithFormat:@"requested incoming call not found for uuid: %@", uuid];
234
- reject(@"access_failure", errorString, nil);
235
- }
236
- });
237
- }
238
-
239
- RCT_EXPORT_METHOD(removeIncomingCall:(NSString *)cid
240
- resolver:(RCTPromiseResolveBlock)resolve
241
- rejecter:(RCTPromiseRejectBlock)reject)
242
- {
243
- dispatch_sync(_dictionaryQueue, ^{
244
- NSString *uuid = _incomingCallUUIDsByCallID[cid];
245
- if (uuid) {
246
- #ifdef DEBUG
247
- NSLog(@"removeIncomingCall cid:%@ -> uuid:%@",cid,uuid);
248
- #endif
249
-
250
- [_incomingCallUUIDsByCallID removeObjectForKey:cid];
251
- [_incomingCallCidsByUUID removeObjectForKey:uuid];
252
- resolve(@YES);
253
- } else {
254
- resolve(@NO);
255
- }
256
- });
257
- }
258
-
259
376
  RCT_EXPORT_METHOD(captureRef:(nonnull NSNumber *)reactTag
260
377
  options:(NSDictionary *)options
261
378
  resolver:(RCTPromiseResolveBlock)resolve
@@ -393,17 +510,7 @@ RCT_EXPORT_METHOD(checkPermission:(NSString *)permission
393
510
  ];
394
511
  }
395
512
 
396
- +(BOOL)shouldRejectCallWhenBusy {
397
- return _shouldRejectCallWhenBusy;
398
- }
399
-
400
- RCT_EXPORT_METHOD(setShouldRejectCallWhenBusy:(BOOL)shouldReject) {
401
- _shouldRejectCallWhenBusy = shouldReject;
402
- #ifdef DEBUG
403
- NSLog(@"setShouldRejectCallWhenBusy: %@", shouldReject ? @"YES" : @"NO");
404
- #endif
405
- }
406
-
513
+ //current implementation will return any registered calls not only stream calls
407
514
  + (BOOL)hasAnyActiveCall
408
515
  {
409
516
  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.30.0",
3
+ "version": "1.30.1-beta.1",
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.0",
54
- "@stream-io/video-react-bindings": "1.13.9",
53
+ "@stream-io/video-client": "1.44.1-beta.2",
54
+ "@stream-io/video-react-bindings": "1.13.10-beta.2",
55
55
  "intl-pluralrules": "2.0.1",
56
56
  "lodash.merge": "^4.6.2",
57
57
  "react-native-url-polyfill": "^3.0.0",
@@ -65,18 +65,17 @@
65
65
  "@react-native-firebase/app": ">=17.5.0",
66
66
  "@react-native-firebase/messaging": ">=17.5.0",
67
67
  "@stream-io/noise-cancellation-react-native": ">=0.1.0",
68
- "@stream-io/react-native-webrtc": ">=137.1.0",
68
+ "@stream-io/react-native-callingx": ">=0.1.0",
69
+ "@stream-io/react-native-webrtc": ">=137.1.2",
69
70
  "@stream-io/video-filters-react-native": ">=0.1.0",
70
71
  "expo": ">=47.0.0",
71
72
  "expo-build-properties": "*",
72
73
  "expo-notifications": "*",
73
74
  "react": ">=17.0.0",
74
75
  "react-native": ">=0.73.0",
75
- "react-native-callkeep": ">=4.3.11",
76
76
  "react-native-gesture-handler": ">=2.8.0",
77
77
  "react-native-reanimated": ">=2.7.0",
78
- "react-native-svg": ">=13.6.0",
79
- "react-native-voip-push-notification": ">=3.3.1"
78
+ "react-native-svg": ">=13.6.0"
80
79
  },
81
80
  "peerDependenciesMeta": {
82
81
  "@notifee/react-native": {
@@ -94,6 +93,9 @@
94
93
  "@stream-io/noise-cancellation-react-native": {
95
94
  "optional": true
96
95
  },
96
+ "@stream-io/react-native-callingx": {
97
+ "optional": true
98
+ },
97
99
  "@stream-io/video-filters-react-native": {
98
100
  "optional": true
99
101
  },
@@ -106,17 +108,11 @@
106
108
  "expo-notifications": {
107
109
  "optional": true
108
110
  },
109
- "react-native-callkeep": {
110
- "optional": true
111
- },
112
111
  "react-native-gesture-handler": {
113
112
  "optional": true
114
113
  },
115
114
  "react-native-reanimated": {
116
115
  "optional": true
117
- },
118
- "react-native-voip-push-notification": {
119
- "optional": true
120
116
  }
121
117
  },
122
118
  "devDependencies": {
@@ -130,9 +126,10 @@
130
126
  "@react-native-firebase/app": "^23.4.0",
131
127
  "@react-native-firebase/messaging": "^23.4.0",
132
128
  "@react-native/babel-preset": "^0.81.5",
133
- "@stream-io/noise-cancellation-react-native": "^0.5.0",
134
- "@stream-io/react-native-webrtc": "137.1.0",
135
- "@stream-io/video-filters-react-native": "^0.10.0",
129
+ "@stream-io/noise-cancellation-react-native": "0.5.1-beta.0",
130
+ "@stream-io/react-native-callingx": "0.1.1-beta.0",
131
+ "@stream-io/react-native-webrtc": "137.1.2",
132
+ "@stream-io/video-filters-react-native": "0.10.1-beta.0",
136
133
  "@testing-library/jest-native": "^5.4.3",
137
134
  "@testing-library/react-native": "13.3.3",
138
135
  "@tsconfig/node18": "^18.2.4",
@@ -148,11 +145,9 @@
148
145
  "react": "19.1.0",
149
146
  "react-native": "^0.81.5",
150
147
  "react-native-builder-bob": "~0.23",
151
- "react-native-callkeep": "^4.3.16",
152
148
  "react-native-gesture-handler": "^2.28.0",
153
149
  "react-native-reanimated": "~4.1.2",
154
150
  "react-native-svg": "^15.14.0",
155
- "react-native-voip-push-notification": "3.3.3",
156
151
  "react-native-worklets": "^0.5.0",
157
152
  "react-test-renderer": "19.1.0",
158
153
  "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,147 @@
1
+ import { videoLoggerSystem } from '@stream-io/video-client';
2
+ import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
3
+ import { useEffect, useMemo } from 'react';
4
+ import { getCallDisplayName } from '../../utils/internal/callingx/callingx';
5
+ import { getCallingxLibIfAvailable } from '../../utils/push/libs/callingx';
6
+
7
+ const logger = videoLoggerSystem.getLogger('callingx');
8
+
9
+ /**
10
+ * This hook is used to inform sync call state with CallKit/Telecom (i.e. start call, end call, mute/unmute call).
11
+ */
12
+ export const useCallingExpWithCallingStateEffect = () => {
13
+ const { useMicrophoneState, useParticipants, useCallMembers } =
14
+ useCallStateHooks();
15
+
16
+ const activeCall = useCall();
17
+ const { isMute, microphone } = useMicrophoneState();
18
+ const callMembers = useCallMembers();
19
+ const participants = useParticipants();
20
+
21
+ const activeCallCid = activeCall?.cid;
22
+ const currentUserId = activeCall?.currentUserId;
23
+
24
+ const callDisplayName = useMemo(
25
+ () => getCallDisplayName(callMembers, participants, currentUserId),
26
+ [callMembers, participants, currentUserId],
27
+ );
28
+
29
+ useEffect(() => {
30
+ return () => {
31
+ const callingx = getCallingxLibIfAvailable();
32
+ if (!callingx?.isSetup || !activeCallCid) {
33
+ return;
34
+ }
35
+
36
+ const isCallTracked = callingx.isCallTracked(activeCallCid);
37
+ if (!isCallTracked) {
38
+ logger.debug(
39
+ `useCallingExpWithCallingStateEffect:No active call cid to end in calling exp: ${activeCallCid} isCallTracked: ${isCallTracked}`,
40
+ );
41
+ return;
42
+ }
43
+ //if incoming stream call was unmounted, we need to end the call in CallKit/Telecom
44
+ logger.debug(
45
+ `useCallingExpWithCallingStateEffect: Ending call in callingx: ${activeCallCid}`,
46
+ );
47
+ callingx
48
+ .endCallWithReason(activeCallCid, 'local')
49
+ .catch((error: unknown) => {
50
+ logger.error(
51
+ `useCallingExpWithCallingStateEffect: Error ending call in callingx: ${activeCallCid}`,
52
+ error,
53
+ );
54
+ });
55
+ };
56
+ }, [activeCallCid]);
57
+
58
+ useEffect(() => {
59
+ const callingx = getCallingxLibIfAvailable();
60
+ if (!callingx?.isSetup || !activeCallCid) {
61
+ return;
62
+ }
63
+
64
+ const isCallTracked = callingx.isCallTracked(activeCallCid);
65
+ if (!isCallTracked) {
66
+ logger.debug(
67
+ `useCallingExpWithCallingStateEffect:No active call cid to update callingx: ${activeCallCid} isCallTracked: ${isCallTracked}`,
68
+ );
69
+ return;
70
+ }
71
+
72
+ callingx.updateDisplay(activeCallCid, activeCallCid, callDisplayName);
73
+ }, [activeCallCid, callDisplayName]);
74
+
75
+ // Sync microphone mute state from app → CallKit
76
+ useEffect(() => {
77
+ const callingx = getCallingxLibIfAvailable();
78
+ if (!callingx?.isSetup || !activeCallCid) {
79
+ return;
80
+ }
81
+
82
+ const isCallTracked = callingx.isCallTracked(activeCallCid);
83
+ if (!isCallTracked) {
84
+ logger.debug(
85
+ `useCallingExpWithCallingStateEffect: No active call cid to set muted in calling exp: ${activeCallCid} isCallTracked: ${isCallTracked}`,
86
+ );
87
+ return;
88
+ }
89
+
90
+ callingx.setMutedCall(activeCallCid, isMute);
91
+ }, [activeCallCid, isMute]);
92
+
93
+ // Sync mute state from CallKit → app (only for system-initiated mute actions)
94
+ useEffect(() => {
95
+ const callingx = getCallingxLibIfAvailable();
96
+ if (!callingx?.isSetup || !activeCallCid) {
97
+ logger.debug(
98
+ `useCallingExpWithCallingStateEffect: No active call cid to set muted in calling exp: ${activeCallCid} callingx isSetup: ${callingx?.isSetup}`,
99
+ );
100
+ return;
101
+ }
102
+
103
+ // Listen to mic toggle events from CallKit/Telecom and update stream call microphone state.
104
+ // Only system-initiated mute actions (e.g. user tapped mute on the native CallKit UI)
105
+ // are sent here — app-initiated actions are filtered out on the native side to prevent
106
+ // the feedback loop: app mutes mic → setMutedCall → CallKit delegate → event to JS → loop.
107
+ const subscription = callingx.addEventListener(
108
+ 'didPerformSetMutedCallAction',
109
+ async (event: { callId: string; muted: boolean }) => {
110
+ const { callId, muted } = event;
111
+
112
+ const isCallTracked = callingx.isCallTracked(activeCallCid);
113
+ if (!isCallTracked || callId !== activeCallCid) {
114
+ logger.debug(
115
+ `useCallingExpWithCallingStateEffect: No active call cid to set muted in calling exp: ${activeCallCid} isCallTracked: ${isCallTracked} callId: ${callId}`,
116
+ );
117
+ return;
118
+ }
119
+
120
+ const isCurrentlyMuted = microphone.state.status === 'disabled';
121
+ if (isCurrentlyMuted === muted) {
122
+ logger.debug(
123
+ `useCallingExpWithCallingStateEffect: Mic toggle is already in the desired state: ${muted} for call: ${activeCallCid}`,
124
+ );
125
+ return;
126
+ }
127
+
128
+ try {
129
+ if (muted) {
130
+ await microphone.disable();
131
+ } else {
132
+ await microphone.enable();
133
+ }
134
+ } catch (error: unknown) {
135
+ logger.error(
136
+ `useCallingExpWithCallingStateEffect: Error toggling mic in calling exp: ${activeCallCid}`,
137
+ error,
138
+ );
139
+ }
140
+ },
141
+ );
142
+
143
+ return () => {
144
+ subscription.remove();
145
+ };
146
+ }, [activeCallCid, microphone]);
147
+ };
@@ -1,6 +1,4 @@
1
1
  import { type MutableRefObject, useEffect, useRef, useState } from 'react';
2
- import { getVoipPushNotificationLib } from '../../utils/push/libs';
3
-
4
2
  import { Platform } from 'react-native';
5
3
  import { StreamVideoRN } from '../../utils';
6
4
  import { onVoipNotificationReceived } from '../../utils/push/internal/ios';
@@ -10,6 +8,7 @@ import {
10
8
  } from '@stream-io/video-react-bindings';
11
9
  import { setPushLogoutCallback } from '../../utils/internal/pushLogoutCallback';
12
10
  import { StreamVideoClient, videoLoggerSystem } from '@stream-io/video-client';
11
+ import { getCallingxLibIfAvailable } from '../../utils/push/libs';
13
12
 
14
13
  const logger = videoLoggerSystem.getLogger('useIosVoipPushEventsSetupEffect');
15
14
 
@@ -28,6 +27,7 @@ function setLogoutCallback(
28
27
  lastVoipTokenRef.current = { token: '', userId: '' };
29
28
  try {
30
29
  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,24 +89,12 @@ export const useIosVoipPushEventsSetupEffect = () => {
89
89
  useEffect(() => {
90
90
  const pushConfig = StreamVideoRN.getConfig().push;
91
91
  const pushProviderName = pushConfig?.ios.pushProviderName;
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
- );
92
+ const callingx = getCallingxLibIfAvailable();
93
+
94
+ if (Platform.OS !== 'ios' || !client || !pushProviderName || !callingx) {
100
95
  return;
101
96
  }
102
97
 
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
-
110
98
  const onTokenReceived = (token: string) => {
111
99
  const userId = client.streamClient._user?.id ?? '';
112
100
  if (client.streamClient.anonymous || !token || !userId) {
@@ -145,24 +133,24 @@ export const useIosVoipPushEventsSetupEffect = () => {
145
133
  });
146
134
  };
147
135
  // fired when PushKit give us the latest token
148
- voipPushNotification.addEventListener('register', (token) => {
149
- onTokenReceived(token);
150
- });
136
+ const voipRegisterListener = callingx.addEventListener(
137
+ 'voipNotificationsRegistered',
138
+ ({ token }) => {
139
+ onTokenReceived(token);
140
+ },
141
+ );
151
142
 
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
- }
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);
164
149
  }
165
150
  });
151
+
152
+ callingx.registerVoipToken();
153
+
166
154
  lastListener.count += 1;
167
155
  const currentListenerCount = lastListener.count;
168
156
 
@@ -175,8 +163,7 @@ export const useIosVoipPushEventsSetupEffect = () => {
175
163
  return;
176
164
  }
177
165
  logger.debug(`Voip event listeners are removed for user: ${userId}`);
178
- voipPushNotification.removeEventListener('didLoadWithEvents');
179
- voipPushNotification.removeEventListener('register');
166
+ voipRegisterListener.remove();
180
167
  };
181
168
  }, [client]);
182
169
  };