@stream-io/video-react-native-sdk 1.29.0-beta.1 → 1.29.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 (198) hide show
  1. package/CHANGELOG.md +3114 -0
  2. package/android/src/main/AndroidManifest.xml +1 -8
  3. package/android/src/main/AndroidManifestNew.xml +0 -11
  4. package/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.kt +5 -42
  5. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/WebRtcAudioUtils.kt +6 -70
  6. package/android/src/main/java/com/streamvideo/reactnative/callmanager/StreamInCallManagerModule.kt +4 -6
  7. package/android/src/main/java/com/streamvideo/reactnative/util/CallAliveServiceChecker.kt +95 -0
  8. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js +160 -0
  9. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +1 -0
  10. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js +31 -18
  11. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
  12. package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js +97 -64
  13. package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
  14. package/dist/commonjs/index.js +0 -1
  15. package/dist/commonjs/index.js.map +1 -1
  16. package/dist/commonjs/modules/call-manager/CallManager.js +0 -26
  17. package/dist/commonjs/modules/call-manager/CallManager.js.map +1 -1
  18. package/dist/commonjs/providers/StreamCall/index.js +6 -6
  19. package/dist/commonjs/providers/StreamCall/index.js.map +1 -1
  20. package/dist/commonjs/utils/StreamVideoRN/index.js +21 -33
  21. package/dist/commonjs/utils/StreamVideoRN/index.js.map +1 -1
  22. package/dist/commonjs/utils/internal/registerSDKGlobals.js +3 -52
  23. package/dist/commonjs/utils/internal/registerSDKGlobals.js.map +1 -1
  24. package/dist/commonjs/utils/push/android.js +200 -145
  25. package/dist/commonjs/utils/push/android.js.map +1 -1
  26. package/dist/commonjs/utils/push/internal/ios.js +34 -16
  27. package/dist/commonjs/utils/push/internal/ios.js.map +1 -1
  28. package/dist/commonjs/utils/push/internal/rxSubjects.js +20 -1
  29. package/dist/commonjs/utils/push/internal/rxSubjects.js.map +1 -1
  30. package/dist/commonjs/utils/push/internal/utils.js +1 -17
  31. package/dist/commonjs/utils/push/internal/utils.js.map +1 -1
  32. package/dist/commonjs/utils/push/ios.js.map +1 -1
  33. package/dist/commonjs/utils/push/libs/callkeep.js +17 -0
  34. package/dist/commonjs/utils/push/libs/callkeep.js.map +1 -0
  35. package/dist/commonjs/utils/push/libs/index.js +19 -8
  36. package/dist/commonjs/utils/push/libs/index.js.map +1 -1
  37. package/dist/commonjs/utils/push/libs/notifee/index.js +19 -0
  38. package/dist/commonjs/utils/push/libs/notifee/index.js.map +1 -1
  39. package/dist/commonjs/utils/push/libs/voipPushNotification.js +17 -0
  40. package/dist/commonjs/utils/push/libs/voipPushNotification.js.map +1 -0
  41. package/dist/commonjs/utils/push/setupIosCallKeepEvents.js +205 -0
  42. package/dist/commonjs/utils/push/setupIosCallKeepEvents.js.map +1 -0
  43. package/dist/commonjs/utils/push/setupIosVoipPushEvents.js +6 -7
  44. package/dist/commonjs/utils/push/setupIosVoipPushEvents.js.map +1 -1
  45. package/dist/commonjs/version.js +1 -1
  46. package/dist/commonjs/version.js.map +1 -1
  47. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js +153 -0
  48. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +1 -0
  49. package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js +31 -18
  50. package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
  51. package/dist/module/hooks/useAndroidKeepCallAliveEffect.js +99 -66
  52. package/dist/module/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
  53. package/dist/module/index.js +0 -1
  54. package/dist/module/index.js.map +1 -1
  55. package/dist/module/modules/call-manager/CallManager.js +0 -26
  56. package/dist/module/modules/call-manager/CallManager.js.map +1 -1
  57. package/dist/module/providers/StreamCall/index.js +6 -6
  58. package/dist/module/providers/StreamCall/index.js.map +1 -1
  59. package/dist/module/utils/StreamVideoRN/index.js +21 -33
  60. package/dist/module/utils/StreamVideoRN/index.js.map +1 -1
  61. package/dist/module/utils/internal/registerSDKGlobals.js +4 -53
  62. package/dist/module/utils/internal/registerSDKGlobals.js.map +1 -1
  63. package/dist/module/utils/push/android.js +202 -147
  64. package/dist/module/utils/push/android.js.map +1 -1
  65. package/dist/module/utils/push/internal/ios.js +34 -16
  66. package/dist/module/utils/push/internal/ios.js.map +1 -1
  67. package/dist/module/utils/push/internal/rxSubjects.js +19 -0
  68. package/dist/module/utils/push/internal/rxSubjects.js.map +1 -1
  69. package/dist/module/utils/push/internal/utils.js +0 -14
  70. package/dist/module/utils/push/internal/utils.js.map +1 -1
  71. package/dist/module/utils/push/ios.js.map +1 -1
  72. package/dist/module/utils/push/libs/callkeep.js +11 -0
  73. package/dist/module/utils/push/libs/callkeep.js.map +1 -0
  74. package/dist/module/utils/push/libs/index.js +2 -1
  75. package/dist/module/utils/push/libs/index.js.map +1 -1
  76. package/dist/module/utils/push/libs/notifee/index.js +18 -0
  77. package/dist/module/utils/push/libs/notifee/index.js.map +1 -1
  78. package/dist/module/utils/push/libs/voipPushNotification.js +11 -0
  79. package/dist/module/utils/push/libs/voipPushNotification.js.map +1 -0
  80. package/dist/module/utils/push/setupIosCallKeepEvents.js +199 -0
  81. package/dist/module/utils/push/setupIosCallKeepEvents.js.map +1 -0
  82. package/dist/module/utils/push/setupIosVoipPushEvents.js +6 -7
  83. package/dist/module/utils/push/setupIosVoipPushEvents.js.map +1 -1
  84. package/dist/module/version.js +1 -1
  85. package/dist/module/version.js.map +1 -1
  86. package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts +5 -0
  87. package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts.map +1 -0
  88. package/dist/typescript/hooks/push/useIosVoipPushEventsSetupEffect.d.ts.map +1 -1
  89. package/dist/typescript/hooks/useAndroidKeepCallAliveEffect.d.ts.map +1 -1
  90. package/dist/typescript/index.d.ts +0 -1
  91. package/dist/typescript/index.d.ts.map +1 -1
  92. package/dist/typescript/modules/call-manager/CallManager.d.ts +0 -5
  93. package/dist/typescript/modules/call-manager/CallManager.d.ts.map +1 -1
  94. package/dist/typescript/utils/StreamVideoRN/index.d.ts +2 -20
  95. package/dist/typescript/utils/StreamVideoRN/index.d.ts.map +1 -1
  96. package/dist/typescript/utils/StreamVideoRN/types.d.ts +29 -54
  97. package/dist/typescript/utils/StreamVideoRN/types.d.ts.map +1 -1
  98. package/dist/typescript/utils/internal/registerSDKGlobals.d.ts.map +1 -1
  99. package/dist/typescript/utils/push/android.d.ts +2 -1
  100. package/dist/typescript/utils/push/android.d.ts.map +1 -1
  101. package/dist/typescript/utils/push/internal/ios.d.ts.map +1 -1
  102. package/dist/typescript/utils/push/internal/rxSubjects.d.ts +12 -0
  103. package/dist/typescript/utils/push/internal/rxSubjects.d.ts.map +1 -1
  104. package/dist/typescript/utils/push/internal/utils.d.ts +0 -4
  105. package/dist/typescript/utils/push/internal/utils.d.ts.map +1 -1
  106. package/dist/typescript/utils/push/ios.d.ts +2 -1
  107. package/dist/typescript/utils/push/ios.d.ts.map +1 -1
  108. package/dist/typescript/utils/push/libs/callkeep.d.ts +3 -0
  109. package/dist/typescript/utils/push/libs/callkeep.d.ts.map +1 -0
  110. package/dist/typescript/utils/push/libs/firebaseMessaging/index.d.ts +2 -16
  111. package/dist/typescript/utils/push/libs/firebaseMessaging/index.d.ts.map +1 -1
  112. package/dist/typescript/utils/push/libs/index.d.ts +2 -1
  113. package/dist/typescript/utils/push/libs/index.d.ts.map +1 -1
  114. package/dist/typescript/utils/push/libs/notifee/index.d.ts +1 -0
  115. package/dist/typescript/utils/push/libs/notifee/index.d.ts.map +1 -1
  116. package/dist/typescript/utils/push/libs/voipPushNotification.d.ts +3 -0
  117. package/dist/typescript/utils/push/libs/voipPushNotification.d.ts.map +1 -0
  118. package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts +6 -0
  119. package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts.map +1 -0
  120. package/dist/typescript/utils/push/setupIosVoipPushEvents.d.ts.map +1 -1
  121. package/dist/typescript/version.d.ts +1 -1
  122. package/dist/typescript/version.d.ts.map +1 -1
  123. package/expo-config-plugin/dist/withAndroidManifest.js +33 -1
  124. package/expo-config-plugin/dist/withAndroidPermissions.js +7 -2
  125. package/expo-config-plugin/dist/withAppDelegate.js +197 -19
  126. package/expo-config-plugin/dist/withMainActivity.js +1 -1
  127. package/expo-config-plugin/dist/withiOSInfoPlist.js +3 -2
  128. package/ios/StreamInCallManager.m +0 -2
  129. package/ios/StreamInCallManager.swift +5 -20
  130. package/ios/StreamVideoReactNative.h +4 -7
  131. package/ios/StreamVideoReactNative.m +82 -191
  132. package/package.json +17 -12
  133. package/src/hooks/push/useIosCallkeepWithCallingStateEffect.ts +235 -0
  134. package/src/hooks/push/useIosVoipPushEventsSetupEffect.ts +34 -21
  135. package/src/hooks/useAndroidKeepCallAliveEffect.ts +120 -94
  136. package/src/index.ts +0 -1
  137. package/src/modules/call-manager/CallManager.ts +0 -36
  138. package/src/modules/call-manager/native-module.d.ts +0 -7
  139. package/src/providers/StreamCall/index.tsx +6 -6
  140. package/src/utils/StreamVideoRN/index.ts +30 -40
  141. package/src/utils/StreamVideoRN/types.ts +29 -56
  142. package/src/utils/internal/registerSDKGlobals.ts +4 -47
  143. package/src/utils/push/android.ts +308 -223
  144. package/src/utils/push/internal/ios.ts +46 -25
  145. package/src/utils/push/internal/rxSubjects.ts +29 -0
  146. package/src/utils/push/internal/utils.ts +0 -25
  147. package/src/utils/push/ios.ts +6 -1
  148. package/src/utils/push/libs/callkeep.ts +16 -0
  149. package/src/utils/push/libs/index.ts +2 -1
  150. package/src/utils/push/libs/notifee/index.ts +27 -0
  151. package/src/utils/push/libs/voipPushNotification.ts +17 -0
  152. package/src/utils/push/setupIosCallKeepEvents.ts +252 -0
  153. package/src/utils/push/setupIosVoipPushEvents.ts +7 -11
  154. package/src/version.ts +1 -1
  155. package/android/src/main/java/com/streamvideo/reactnative/keepalive/KeepAliveNotification.kt +0 -83
  156. package/android/src/main/java/com/streamvideo/reactnative/keepalive/StreamCallKeepAliveHeadlessService.kt +0 -134
  157. package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js +0 -216
  158. package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js.map +0 -1
  159. package/dist/commonjs/utils/internal/audioSessionPromise.js +0 -46
  160. package/dist/commonjs/utils/internal/audioSessionPromise.js.map +0 -1
  161. package/dist/commonjs/utils/internal/callingx.js +0 -84
  162. package/dist/commonjs/utils/internal/callingx.js.map +0 -1
  163. package/dist/commonjs/utils/keepCallAliveHeadlessTask.js +0 -48
  164. package/dist/commonjs/utils/keepCallAliveHeadlessTask.js.map +0 -1
  165. package/dist/commonjs/utils/push/libs/callingx.js +0 -75
  166. package/dist/commonjs/utils/push/libs/callingx.js.map +0 -1
  167. package/dist/commonjs/utils/push/setupCallingExpEvents.js +0 -97
  168. package/dist/commonjs/utils/push/setupCallingExpEvents.js.map +0 -1
  169. package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js +0 -209
  170. package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js.map +0 -1
  171. package/dist/module/utils/internal/audioSessionPromise.js +0 -39
  172. package/dist/module/utils/internal/audioSessionPromise.js.map +0 -1
  173. package/dist/module/utils/internal/callingx.js +0 -75
  174. package/dist/module/utils/internal/callingx.js.map +0 -1
  175. package/dist/module/utils/keepCallAliveHeadlessTask.js +0 -42
  176. package/dist/module/utils/keepCallAliveHeadlessTask.js.map +0 -1
  177. package/dist/module/utils/push/libs/callingx.js +0 -67
  178. package/dist/module/utils/push/libs/callingx.js.map +0 -1
  179. package/dist/module/utils/push/setupCallingExpEvents.js +0 -91
  180. package/dist/module/utils/push/setupCallingExpEvents.js.map +0 -1
  181. package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts +0 -5
  182. package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts.map +0 -1
  183. package/dist/typescript/utils/internal/audioSessionPromise.d.ts +0 -16
  184. package/dist/typescript/utils/internal/audioSessionPromise.d.ts.map +0 -1
  185. package/dist/typescript/utils/internal/callingx.d.ts +0 -13
  186. package/dist/typescript/utils/internal/callingx.d.ts.map +0 -1
  187. package/dist/typescript/utils/keepCallAliveHeadlessTask.d.ts +0 -10
  188. package/dist/typescript/utils/keepCallAliveHeadlessTask.d.ts.map +0 -1
  189. package/dist/typescript/utils/push/libs/callingx.d.ts +0 -9
  190. package/dist/typescript/utils/push/libs/callingx.d.ts.map +0 -1
  191. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts +0 -8
  192. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts.map +0 -1
  193. package/src/hooks/push/useCallingExpWithCallingStateEffect.ts +0 -307
  194. package/src/utils/internal/audioSessionPromise.ts +0 -39
  195. package/src/utils/internal/callingx.ts +0 -108
  196. package/src/utils/keepCallAliveHeadlessTask.ts +0 -54
  197. package/src/utils/push/libs/callingx.ts +0 -90
  198. package/src/utils/push/setupCallingExpEvents.ts +0 -117
@@ -4,7 +4,6 @@
4
4
  #import <React/RCTUIManagerUtils.h>
5
5
  #import <UIKit/UIKit.h>
6
6
  #import <CallKit/CallKit.h>
7
- #import <PushKit/PushKit.h>
8
7
  #import "StreamVideoReactNative.h"
9
8
  #import "WebRTCModule.h"
10
9
  #import "WebRTCModuleOptions.h"
@@ -15,8 +14,12 @@
15
14
  NSNotificationName const kBroadcastStartedNotification = @"iOS_BroadcastStarted";
16
15
  NSNotificationName const kBroadcastStoppedNotification = @"iOS_BroadcastStopped";
17
16
 
17
+ static NSMutableDictionary *_incomingCallUUIDsByCallID = nil;
18
+ static NSMutableDictionary *_incomingCallCidsByUUID = nil;
18
19
  static dispatch_queue_t _dictionaryQueue = nil;
19
20
 
21
+ static BOOL _shouldRejectCallWhenBusy = NO;
22
+
20
23
  void broadcastNotificationCallback(CFNotificationCenterRef center,
21
24
  void *observer,
22
25
  CFStringRef name,
@@ -57,198 +60,11 @@ RCT_EXPORT_MODULE();
57
60
  static dispatch_once_t onceToken;
58
61
  dispatch_once(&onceToken, ^{
59
62
  _dictionaryQueue = dispatch_queue_create("com.stream.video.dictionary", DISPATCH_QUEUE_SERIAL);
63
+ _incomingCallUUIDsByCallID = [NSMutableDictionary dictionary];
64
+ _incomingCallCidsByUUID = [NSMutableDictionary dictionary];
60
65
  });
61
66
  }
62
67
 
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:fromPushKit: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
- BOOL fromPushKit = YES;
206
- void (^completionHandler)(void) = completion;
207
-
208
- NSMethodSignature *signature = [callingxClass methodSignatureForSelector:selector];
209
- NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
210
- [invocation setTarget:callingxClass];
211
- [invocation setSelector:selector];
212
- [invocation setArgument:&callCid atIndex:2];
213
- [invocation setArgument:&createdCallerName atIndex:3];
214
- [invocation setArgument:&handleType atIndex:4];
215
- [invocation setArgument:&hasVideo atIndex:5];
216
- [invocation setArgument:&createdCallerName atIndex:6];
217
- [invocation setArgument:&supportsHolding atIndex:7];
218
- [invocation setArgument:&supportsDTMF atIndex:8];
219
- [invocation setArgument:&supportsGrouping atIndex:9];
220
- [invocation setArgument:&supportsUngrouping atIndex:10];
221
- [invocation setArgument:&fromPushKit atIndex:11];
222
- [invocation setArgument:&streamPayload atIndex:12];
223
- [invocation setArgument:&completionHandler atIndex:13];
224
- [invocation invoke];
225
- }
226
-
227
- +(void)didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type {
228
- Class voipManagerClass = NSClassFromString(@"Callingx.VoipNotificationsManager");
229
- if (!voipManagerClass) {
230
- // Fallback: Try the unmangled name (might work depending on Swift version)
231
- voipManagerClass = NSClassFromString(@"VoipNotificationsManager");
232
- }
233
-
234
- if (!voipManagerClass) {
235
- #if DEBUG
236
- NSLog(@"[StreamVideoReactNative][didReceiveIncomingPushWithPayload] VoipNotificationsManager not available");
237
- #endif
238
- return;
239
- }
240
-
241
- SEL selector = @selector(didReceiveIncomingPushWithPayload:forType:);
242
- if (![voipManagerClass respondsToSelector:selector]) {
243
- #if DEBUG
244
- NSLog(@"[StreamVideoReactNative][didReceiveIncomingPushWithPayload] VoipNotificationsManager does not respond to didReceiveIncomingPushWithPayload:forType:");
245
- #endif
246
- return;
247
- }
248
-
249
- [voipManagerClass didReceiveIncomingPushWithPayload:payload forType:type];
250
- }
251
-
252
68
  -(instancetype)init {
253
69
  if ((self = [super init])) {
254
70
  _notificationCenter = CFNotificationCenterGetDarwinNotifyCenter();
@@ -375,6 +191,71 @@ RCT_EXPORT_METHOD(currentThermalState:(RCTPromiseResolveBlock)resolve rejecter:(
375
191
  }
376
192
  }
377
193
 
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
+
378
259
  RCT_EXPORT_METHOD(captureRef:(nonnull NSNumber *)reactTag
379
260
  options:(NSDictionary *)options
380
261
  resolver:(RCTPromiseResolveBlock)resolve
@@ -492,7 +373,17 @@ RCT_EXPORT_METHOD(getBatteryState:(RCTPromiseResolveBlock)resolve
492
373
  ];
493
374
  }
494
375
 
495
- //current implementation will return any registered calls not only stream calls
376
+ +(BOOL)shouldRejectCallWhenBusy {
377
+ return _shouldRejectCallWhenBusy;
378
+ }
379
+
380
+ RCT_EXPORT_METHOD(setShouldRejectCallWhenBusy:(BOOL)shouldReject) {
381
+ _shouldRejectCallWhenBusy = shouldReject;
382
+ #ifdef DEBUG
383
+ NSLog(@"setShouldRejectCallWhenBusy: %@", shouldReject ? @"YES" : @"NO");
384
+ #endif
385
+ }
386
+
496
387
  + (BOOL)hasAnyActiveCall
497
388
  {
498
389
  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.29.0-beta.1",
3
+ "version": "1.29.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.41.3",
54
- "@stream-io/video-react-bindings": "1.13.3",
53
+ "@stream-io/video-client": "1.42.0",
54
+ "@stream-io/video-react-bindings": "1.13.4",
55
55
  "intl-pluralrules": "2.0.1",
56
56
  "lodash.merge": "^4.6.2",
57
57
  "react-native-url-polyfill": "^3.0.0",
@@ -65,7 +65,6 @@
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-callingx": ">=0.1.0",
69
68
  "@stream-io/react-native-webrtc": ">=137.1.0",
70
69
  "@stream-io/video-filters-react-native": ">=0.1.0",
71
70
  "expo": ">=47.0.0",
@@ -73,9 +72,11 @@
73
72
  "expo-notifications": "*",
74
73
  "react": ">=17.0.0",
75
74
  "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"
78
+ "react-native-svg": ">=13.6.0",
79
+ "react-native-voip-push-notification": ">=3.3.1"
79
80
  },
80
81
  "peerDependenciesMeta": {
81
82
  "@notifee/react-native": {
@@ -93,9 +94,6 @@
93
94
  "@stream-io/noise-cancellation-react-native": {
94
95
  "optional": true
95
96
  },
96
- "@stream-io/react-native-callingx": {
97
- "optional": true
98
- },
99
97
  "@stream-io/video-filters-react-native": {
100
98
  "optional": true
101
99
  },
@@ -108,11 +106,17 @@
108
106
  "expo-notifications": {
109
107
  "optional": true
110
108
  },
109
+ "react-native-callkeep": {
110
+ "optional": true
111
+ },
111
112
  "react-native-gesture-handler": {
112
113
  "optional": true
113
114
  },
114
115
  "react-native-reanimated": {
115
116
  "optional": true
117
+ },
118
+ "react-native-voip-push-notification": {
119
+ "optional": true
116
120
  }
117
121
  },
118
122
  "devDependencies": {
@@ -126,10 +130,9 @@
126
130
  "@react-native-firebase/app": "^23.4.0",
127
131
  "@react-native-firebase/messaging": "^23.4.0",
128
132
  "@react-native/babel-preset": "^0.81.5",
129
- "@stream-io/noise-cancellation-react-native": "0.5.0",
130
- "@stream-io/react-native-callingx": "0.1.0-beta.1",
133
+ "@stream-io/noise-cancellation-react-native": "^0.5.0",
131
134
  "@stream-io/react-native-webrtc": "137.1.0",
132
- "@stream-io/video-filters-react-native": "0.10.0",
135
+ "@stream-io/video-filters-react-native": "^0.10.0",
133
136
  "@testing-library/jest-native": "^5.4.3",
134
137
  "@testing-library/react-native": "13.3.3",
135
138
  "@tsconfig/node18": "^18.2.4",
@@ -145,9 +148,11 @@
145
148
  "react": "19.1.0",
146
149
  "react-native": "^0.81.5",
147
150
  "react-native-builder-bob": "~0.23",
151
+ "react-native-callkeep": "^4.3.16",
148
152
  "react-native-gesture-handler": "^2.28.0",
149
153
  "react-native-reanimated": "~4.1.2",
150
154
  "react-native-svg": "^15.14.0",
155
+ "react-native-voip-push-notification": "3.3.3",
151
156
  "react-native-worklets": "^0.5.0",
152
157
  "react-test-renderer": "19.1.0",
153
158
  "rimraf": "^6.0.1",
@@ -162,4 +167,4 @@
162
167
  "typescript"
163
168
  ]
164
169
  }
165
- }
170
+ }
@@ -0,0 +1,235 @@
1
+ import {
2
+ CallingState,
3
+ RxUtils,
4
+ videoLoggerSystem,
5
+ } from '@stream-io/video-client';
6
+ import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
7
+ import { NativeModules, Platform } from 'react-native';
8
+ import { useEffect, useState } from 'react';
9
+ import { StreamVideoRN } from '../../utils';
10
+ import { getCallKeepLib } from '../../utils/push/libs';
11
+ import {
12
+ voipCallkeepAcceptedCallOnNativeDialerMap$,
13
+ voipCallkeepCallOnForegroundMap$,
14
+ voipPushNotificationCallCId$,
15
+ } from '../../utils/push/internal/rxSubjects';
16
+
17
+ const isNonActiveCallingState = (callingState: CallingState) => {
18
+ return (
19
+ callingState === CallingState.IDLE ||
20
+ callingState === CallingState.UNKNOWN ||
21
+ callingState === CallingState.LEFT
22
+ );
23
+ };
24
+
25
+ const isAcceptedCallingState = (callingState: CallingState) => {
26
+ return (
27
+ callingState === CallingState.JOINING ||
28
+ callingState === CallingState.JOINED
29
+ );
30
+ };
31
+
32
+ const unsubscribeCallkeepEvents = async (activeCallCid: string | undefined) => {
33
+ const voipPushNotificationCallCId = RxUtils.getCurrentValue(
34
+ voipPushNotificationCallCId$,
35
+ );
36
+ if (activeCallCid && activeCallCid === voipPushNotificationCallCId) {
37
+ // callkeep events should not be listened anymore so clear the call cid
38
+ voipPushNotificationCallCId$.next(undefined);
39
+ }
40
+ return await NativeModules.StreamVideoReactNative?.removeIncomingCall(
41
+ activeCallCid,
42
+ );
43
+ };
44
+
45
+ const logger = videoLoggerSystem.getLogger(
46
+ 'useIosCallkeepWithCallingStateEffect',
47
+ );
48
+ const log = (message: string) => {
49
+ logger.warn(message);
50
+ };
51
+
52
+ /**
53
+ * This hook is used to inform the callkeep library that the call has been joined or ended.
54
+ */
55
+ export const useIosCallkeepWithCallingStateEffect = () => {
56
+ const activeCall = useCall();
57
+ const { useCallCallingState } = useCallStateHooks();
58
+ const callingState = useCallCallingState();
59
+ const [acceptedForegroundCallkeepMap, setAcceptedForegroundCallkeepMap] =
60
+ useState<{
61
+ uuid: string;
62
+ cid: string;
63
+ }>();
64
+
65
+ useEffect(() => {
66
+ return () => {
67
+ const pushConfig = StreamVideoRN.getConfig().push;
68
+ if (
69
+ Platform.OS !== 'ios' ||
70
+ !pushConfig ||
71
+ !pushConfig.ios?.pushProviderName
72
+ ) {
73
+ return;
74
+ }
75
+ if (!pushConfig.android.incomingCallChannel) {
76
+ // TODO: remove this check and find a better way once we have telecom integration for android
77
+ return;
78
+ }
79
+
80
+ const callkeep = getCallKeepLib();
81
+ // if the component is unmounted and the callID was not reported to callkeep, then report it now
82
+ if (acceptedForegroundCallkeepMap) {
83
+ log(
84
+ `Ending call in callkeep: ${acceptedForegroundCallkeepMap.cid}, reason: component unmounted and call was present in acceptedForegroundCallkeepMap`,
85
+ );
86
+ unsubscribeCallkeepEvents(acceptedForegroundCallkeepMap.cid).then(() =>
87
+ callkeep.endCall(acceptedForegroundCallkeepMap.uuid),
88
+ );
89
+ }
90
+ };
91
+ }, [acceptedForegroundCallkeepMap]);
92
+
93
+ const activeCallCid = activeCall?.cid;
94
+
95
+ useEffect(() => {
96
+ return () => {
97
+ const pushConfig = StreamVideoRN.getConfig().push;
98
+ if (
99
+ Platform.OS !== 'ios' ||
100
+ !pushConfig ||
101
+ !pushConfig.ios?.pushProviderName ||
102
+ !activeCallCid
103
+ ) {
104
+ return;
105
+ }
106
+ if (!pushConfig.android.incomingCallChannel) {
107
+ // TODO: remove this check and find a better way once we have telecom integration for android
108
+ return;
109
+ }
110
+ const nativeDialerAcceptedCallMap = RxUtils.getCurrentValue(
111
+ voipCallkeepAcceptedCallOnNativeDialerMap$,
112
+ );
113
+ const foregroundIncomingCallkeepMap = RxUtils.getCurrentValue(
114
+ voipCallkeepCallOnForegroundMap$,
115
+ );
116
+ const callkeep = getCallKeepLib();
117
+ if (activeCallCid === nativeDialerAcceptedCallMap?.cid) {
118
+ log(
119
+ `Ending call in callkeep: ${activeCallCid}, reason: activeCallCid changed or was removed and call was present in nativeDialerAcceptedCallMap`,
120
+ );
121
+ unsubscribeCallkeepEvents(activeCallCid).then(() =>
122
+ callkeep.endCall(nativeDialerAcceptedCallMap.uuid),
123
+ );
124
+ // no need to keep this reference anymore
125
+ voipCallkeepAcceptedCallOnNativeDialerMap$.next(undefined);
126
+ } else if (activeCallCid === foregroundIncomingCallkeepMap?.cid) {
127
+ log(
128
+ `Ending call in callkeep: ${activeCallCid}, reason: activeCallCid changed or was removed and call was present in foregroundIncomingCallkeepMap`,
129
+ );
130
+ unsubscribeCallkeepEvents(activeCallCid).then(() =>
131
+ callkeep.endCall(foregroundIncomingCallkeepMap.uuid),
132
+ );
133
+ }
134
+ };
135
+ }, [activeCallCid]);
136
+
137
+ const pushConfig = StreamVideoRN.getConfig().push;
138
+ if (
139
+ Platform.OS !== 'ios' ||
140
+ !pushConfig ||
141
+ !pushConfig.ios.pushProviderName ||
142
+ !activeCallCid
143
+ ) {
144
+ return;
145
+ }
146
+ if (!pushConfig.android.incomingCallChannel) {
147
+ // TODO: remove this check and find a better way once we have telecom integration for android
148
+ return;
149
+ }
150
+
151
+ /**
152
+ * Check if current call is still needed to be accepted in callkeep
153
+ */
154
+ if (
155
+ isAcceptedCallingState(callingState) &&
156
+ acceptedForegroundCallkeepMap?.cid !== activeCallCid
157
+ ) {
158
+ const callkeep = getCallKeepLib();
159
+ // push notification was displayed
160
+ // but the call has been accepted through the app and not through the native dialer
161
+ const foregroundCallkeepMap = RxUtils.getCurrentValue(
162
+ voipCallkeepCallOnForegroundMap$,
163
+ );
164
+ if (foregroundCallkeepMap && foregroundCallkeepMap.cid === activeCallCid) {
165
+ log(
166
+ // @ts-expect-error - types issue
167
+ `Accepting call in callkeep: ${activeCallCid}, reason: callingstate went to ${CallingState[callingState]} and call was present in foregroundCallkeepMap`,
168
+ );
169
+ // no need to keep this reference anymore
170
+ voipCallkeepCallOnForegroundMap$.next(undefined);
171
+ NativeModules.StreamVideoReactNative?.removeIncomingCall(
172
+ activeCallCid,
173
+ ).then(() => callkeep.answerIncomingCall(foregroundCallkeepMap.uuid));
174
+ // this call should be accepted in callkeep
175
+ setAcceptedForegroundCallkeepMap(foregroundCallkeepMap);
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Check if current call is still needed to be ended in callkeep
181
+ */
182
+ if (isNonActiveCallingState(callingState)) {
183
+ const callkeep = getCallKeepLib();
184
+
185
+ // this was a previously joined call which had push notification displayed
186
+ // the call was accepted through the app and not through native dialer
187
+ // the call was left using the leave button in the app and not through native dialer
188
+ if (activeCallCid === acceptedForegroundCallkeepMap?.cid) {
189
+ log(
190
+ // @ts-expect-error - types issue
191
+ `Ending call in callkeep: ${activeCallCid}, reason: callingstate went to ${CallingState[callingState]} and call was present in acceptedForegroundCallkeepMap`,
192
+ );
193
+ unsubscribeCallkeepEvents(activeCallCid).then(() =>
194
+ callkeep.endCall(acceptedForegroundCallkeepMap.uuid),
195
+ );
196
+ setAcceptedForegroundCallkeepMap(undefined);
197
+ return;
198
+ }
199
+ // this was a call which had push notification displayed but never joined
200
+ // the user rejected in the app and not from native dialer
201
+ const foregroundIncomingCallkeepMap = RxUtils.getCurrentValue(
202
+ voipCallkeepCallOnForegroundMap$,
203
+ );
204
+ if (activeCallCid === foregroundIncomingCallkeepMap?.cid) {
205
+ log(
206
+ // @ts-expect-error - types issue
207
+ `Ending call in callkeep: ${activeCallCid}, reason: callingstate went to ${CallingState[callingState]} and call was present in foregroundIncomingCallkeepMap`,
208
+ );
209
+ unsubscribeCallkeepEvents(activeCallCid).then(() =>
210
+ callkeep.endCall(foregroundIncomingCallkeepMap.uuid),
211
+ );
212
+ // no need to keep this reference anymore
213
+ voipCallkeepCallOnForegroundMap$.next(undefined);
214
+ return;
215
+ }
216
+ // this was a previously joined call
217
+ // it was an accepted call from native dialer and not from the app
218
+ // the user left using the leave button in the app
219
+ const nativeDialerAcceptedCallMap = RxUtils.getCurrentValue(
220
+ voipCallkeepAcceptedCallOnNativeDialerMap$,
221
+ );
222
+ if (activeCallCid === nativeDialerAcceptedCallMap?.cid) {
223
+ log(
224
+ // @ts-expect-error - types issue
225
+ `Ending call in callkeep: ${activeCallCid}, reason: callingstate went to ${CallingState[callingState]} and call was present in nativeDialerAcceptedCallMap`,
226
+ );
227
+ unsubscribeCallkeepEvents(activeCallCid).then(() =>
228
+ callkeep.endCall(nativeDialerAcceptedCallMap.uuid),
229
+ );
230
+ // no need to keep this reference anymore
231
+ voipCallkeepAcceptedCallOnNativeDialerMap$.next(undefined);
232
+ return;
233
+ }
234
+ }
235
+ };