@stream-io/video-react-native-sdk 1.34.0 → 1.36.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 (184) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/commonjs/components/Call/RingingCallContent/IncomingCall.js +9 -2
  3. package/dist/commonjs/components/Call/RingingCallContent/IncomingCall.js.map +1 -1
  4. package/dist/commonjs/components/Call/RingingCallContent/OutgoingCall.js +9 -2
  5. package/dist/commonjs/components/Call/RingingCallContent/OutgoingCall.js.map +1 -1
  6. package/dist/commonjs/components/Call/RingingCallContent/RingingCallContent.js +11 -12
  7. package/dist/commonjs/components/Call/RingingCallContent/RingingCallContent.js.map +1 -1
  8. package/dist/commonjs/components/Call/RingingCallContent/TextBasedIndicator.js +7 -2
  9. package/dist/commonjs/components/Call/RingingCallContent/TextBasedIndicator.js.map +1 -1
  10. package/dist/commonjs/components/Livestream/ViewerLivestream/ViewerLivestream.js +7 -3
  11. package/dist/commonjs/components/Livestream/ViewerLivestream/ViewerLivestream.js.map +1 -1
  12. package/dist/commonjs/components/Participant/ParticipantView/VideoRenderer/TrackSubscriber.js +1 -1
  13. package/dist/commonjs/components/Participant/ParticipantView/VideoRenderer/TrackSubscriber.js.map +1 -1
  14. package/dist/commonjs/hooks/push/index.js +0 -4
  15. package/dist/commonjs/hooks/push/index.js.map +1 -1
  16. package/dist/commonjs/modules/call-manager/CallManager.js +6 -0
  17. package/dist/commonjs/modules/call-manager/CallManager.js.map +1 -1
  18. package/dist/commonjs/utils/StreamVideoRN/index.js +0 -17
  19. package/dist/commonjs/utils/StreamVideoRN/index.js.map +1 -1
  20. package/dist/commonjs/utils/internal/callingx/callingx.js +55 -32
  21. package/dist/commonjs/utils/internal/callingx/callingx.js.map +1 -1
  22. package/dist/commonjs/utils/internal/registerSDKGlobals.js +2 -0
  23. package/dist/commonjs/utils/internal/registerSDKGlobals.js.map +1 -1
  24. package/dist/commonjs/utils/push/android.js +10 -93
  25. package/dist/commonjs/utils/push/android.js.map +1 -1
  26. package/dist/commonjs/utils/push/index.js +0 -11
  27. package/dist/commonjs/utils/push/index.js.map +1 -1
  28. package/dist/commonjs/utils/push/internal/utils.js +2 -31
  29. package/dist/commonjs/utils/push/internal/utils.js.map +1 -1
  30. package/dist/commonjs/utils/push/libs/callingx.js +9 -0
  31. package/dist/commonjs/utils/push/libs/callingx.js.map +1 -1
  32. package/dist/commonjs/utils/push/libs/index.js +0 -33
  33. package/dist/commonjs/utils/push/libs/index.js.map +1 -1
  34. package/dist/commonjs/utils/push/utils.js +0 -28
  35. package/dist/commonjs/utils/push/utils.js.map +1 -1
  36. package/dist/commonjs/version.js +1 -1
  37. package/dist/module/components/Call/RingingCallContent/IncomingCall.js +9 -2
  38. package/dist/module/components/Call/RingingCallContent/IncomingCall.js.map +1 -1
  39. package/dist/module/components/Call/RingingCallContent/OutgoingCall.js +9 -2
  40. package/dist/module/components/Call/RingingCallContent/OutgoingCall.js.map +1 -1
  41. package/dist/module/components/Call/RingingCallContent/RingingCallContent.js +11 -12
  42. package/dist/module/components/Call/RingingCallContent/RingingCallContent.js.map +1 -1
  43. package/dist/module/components/Call/RingingCallContent/TextBasedIndicator.js +7 -2
  44. package/dist/module/components/Call/RingingCallContent/TextBasedIndicator.js.map +1 -1
  45. package/dist/module/components/Livestream/ViewerLivestream/ViewerLivestream.js +7 -3
  46. package/dist/module/components/Livestream/ViewerLivestream/ViewerLivestream.js.map +1 -1
  47. package/dist/module/components/Participant/ParticipantView/VideoRenderer/TrackSubscriber.js +1 -1
  48. package/dist/module/components/Participant/ParticipantView/VideoRenderer/TrackSubscriber.js.map +1 -1
  49. package/dist/module/hooks/push/index.js +0 -4
  50. package/dist/module/hooks/push/index.js.map +1 -1
  51. package/dist/module/modules/call-manager/CallManager.js +6 -0
  52. package/dist/module/modules/call-manager/CallManager.js.map +1 -1
  53. package/dist/module/utils/StreamVideoRN/index.js +0 -17
  54. package/dist/module/utils/StreamVideoRN/index.js.map +1 -1
  55. package/dist/module/utils/internal/callingx/callingx.js +56 -33
  56. package/dist/module/utils/internal/callingx/callingx.js.map +1 -1
  57. package/dist/module/utils/internal/registerSDKGlobals.js +2 -0
  58. package/dist/module/utils/internal/registerSDKGlobals.js.map +1 -1
  59. package/dist/module/utils/push/android.js +11 -92
  60. package/dist/module/utils/push/android.js.map +1 -1
  61. package/dist/module/utils/push/index.js +0 -1
  62. package/dist/module/utils/push/index.js.map +1 -1
  63. package/dist/module/utils/push/internal/utils.js +0 -28
  64. package/dist/module/utils/push/internal/utils.js.map +1 -1
  65. package/dist/module/utils/push/libs/callingx.js +9 -0
  66. package/dist/module/utils/push/libs/callingx.js.map +1 -1
  67. package/dist/module/utils/push/libs/index.js +0 -3
  68. package/dist/module/utils/push/libs/index.js.map +1 -1
  69. package/dist/module/utils/push/utils.js +0 -25
  70. package/dist/module/utils/push/utils.js.map +1 -1
  71. package/dist/module/version.js +1 -1
  72. package/dist/typescript/components/Call/RingingCallContent/IncomingCall.d.ts.map +1 -1
  73. package/dist/typescript/components/Call/RingingCallContent/OutgoingCall.d.ts.map +1 -1
  74. package/dist/typescript/components/Call/RingingCallContent/RingingCallContent.d.ts.map +1 -1
  75. package/dist/typescript/components/Call/RingingCallContent/TextBasedIndicator.d.ts.map +1 -1
  76. package/dist/typescript/components/Livestream/ViewerLivestream/ViewerLivestream.d.ts.map +1 -1
  77. package/dist/typescript/hooks/push/index.d.ts.map +1 -1
  78. package/dist/typescript/modules/call-manager/CallManager.d.ts.map +1 -1
  79. package/dist/typescript/utils/StreamVideoRN/index.d.ts +0 -7
  80. package/dist/typescript/utils/StreamVideoRN/index.d.ts.map +1 -1
  81. package/dist/typescript/utils/StreamVideoRN/types.d.ts +19 -40
  82. package/dist/typescript/utils/StreamVideoRN/types.d.ts.map +1 -1
  83. package/dist/typescript/utils/internal/callingx/callingx.d.ts.map +1 -1
  84. package/dist/typescript/utils/internal/registerSDKGlobals.d.ts.map +1 -1
  85. package/dist/typescript/utils/push/android.d.ts +1 -6
  86. package/dist/typescript/utils/push/android.d.ts.map +1 -1
  87. package/dist/typescript/utils/push/index.d.ts +0 -1
  88. package/dist/typescript/utils/push/index.d.ts.map +1 -1
  89. package/dist/typescript/utils/push/internal/utils.d.ts +2 -10
  90. package/dist/typescript/utils/push/internal/utils.d.ts.map +1 -1
  91. package/dist/typescript/utils/push/libs/callingx.d.ts.map +1 -1
  92. package/dist/typescript/utils/push/libs/firebaseMessaging/index.d.ts +16 -2
  93. package/dist/typescript/utils/push/libs/firebaseMessaging/index.d.ts.map +1 -1
  94. package/dist/typescript/utils/push/libs/index.d.ts +0 -3
  95. package/dist/typescript/utils/push/libs/index.d.ts.map +1 -1
  96. package/dist/typescript/utils/push/utils.d.ts +0 -6
  97. package/dist/typescript/utils/push/utils.d.ts.map +1 -1
  98. package/dist/typescript/version.d.ts +1 -1
  99. package/expo-config-plugin/dist/withAppDelegate.js +56 -0
  100. package/ios/StreamVideoReactNative.h +14 -0
  101. package/ios/StreamVideoReactNative.m +129 -7
  102. package/package.json +4 -14
  103. package/src/components/Call/RingingCallContent/IncomingCall.tsx +14 -2
  104. package/src/components/Call/RingingCallContent/OutgoingCall.tsx +14 -2
  105. package/src/components/Call/RingingCallContent/RingingCallContent.tsx +7 -12
  106. package/src/components/Call/RingingCallContent/TextBasedIndicator.tsx +13 -2
  107. package/src/components/Livestream/ViewerLivestream/ViewerLivestream.tsx +10 -2
  108. package/src/components/Participant/ParticipantView/VideoRenderer/TrackSubscriber.tsx +1 -1
  109. package/src/hooks/push/index.ts +0 -4
  110. package/src/modules/call-manager/CallManager.ts +6 -0
  111. package/src/utils/StreamVideoRN/index.ts +0 -22
  112. package/src/utils/StreamVideoRN/types.ts +19 -46
  113. package/src/utils/internal/callingx/callingx.ts +60 -29
  114. package/src/utils/internal/registerSDKGlobals.ts +2 -0
  115. package/src/utils/push/android.ts +11 -117
  116. package/src/utils/push/index.ts +0 -1
  117. package/src/utils/push/internal/utils.ts +1 -41
  118. package/src/utils/push/libs/callingx.ts +12 -0
  119. package/src/utils/push/libs/index.ts +0 -3
  120. package/src/utils/push/utils.ts +0 -37
  121. package/src/version.ts +1 -1
  122. package/dist/commonjs/hooks/push/useIosInitRemoteNotifications.js +0 -33
  123. package/dist/commonjs/hooks/push/useIosInitRemoteNotifications.js.map +0 -1
  124. package/dist/commonjs/hooks/push/useProcessPushNonRingingCallEffect.js +0 -49
  125. package/dist/commonjs/hooks/push/useProcessPushNonRingingCallEffect.js.map +0 -1
  126. package/dist/commonjs/utils/internal/newNotificationCallbacks.js +0 -17
  127. package/dist/commonjs/utils/internal/newNotificationCallbacks.js.map +0 -1
  128. package/dist/commonjs/utils/push/internal/rxSubjects.js +0 -13
  129. package/dist/commonjs/utils/push/internal/rxSubjects.js.map +0 -1
  130. package/dist/commonjs/utils/push/ios.js +0 -158
  131. package/dist/commonjs/utils/push/ios.js.map +0 -1
  132. package/dist/commonjs/utils/push/libs/expoNotifications.js +0 -25
  133. package/dist/commonjs/utils/push/libs/expoNotifications.js.map +0 -1
  134. package/dist/commonjs/utils/push/libs/iosPushNotification.js +0 -17
  135. package/dist/commonjs/utils/push/libs/iosPushNotification.js.map +0 -1
  136. package/dist/commonjs/utils/push/libs/notifee/index.js +0 -38
  137. package/dist/commonjs/utils/push/libs/notifee/index.js.map +0 -1
  138. package/dist/commonjs/utils/push/libs/notifee/lib.js +0 -16
  139. package/dist/commonjs/utils/push/libs/notifee/lib.js.map +0 -1
  140. package/dist/module/hooks/push/useIosInitRemoteNotifications.js +0 -27
  141. package/dist/module/hooks/push/useIosInitRemoteNotifications.js.map +0 -1
  142. package/dist/module/hooks/push/useProcessPushNonRingingCallEffect.js +0 -43
  143. package/dist/module/hooks/push/useProcessPushNonRingingCallEffect.js.map +0 -1
  144. package/dist/module/utils/internal/newNotificationCallbacks.js +0 -10
  145. package/dist/module/utils/internal/newNotificationCallbacks.js.map +0 -1
  146. package/dist/module/utils/push/internal/rxSubjects.js +0 -7
  147. package/dist/module/utils/push/internal/rxSubjects.js.map +0 -1
  148. package/dist/module/utils/push/ios.js +0 -148
  149. package/dist/module/utils/push/ios.js.map +0 -1
  150. package/dist/module/utils/push/libs/expoNotifications.js +0 -18
  151. package/dist/module/utils/push/libs/expoNotifications.js.map +0 -1
  152. package/dist/module/utils/push/libs/iosPushNotification.js +0 -11
  153. package/dist/module/utils/push/libs/iosPushNotification.js.map +0 -1
  154. package/dist/module/utils/push/libs/notifee/index.js +0 -31
  155. package/dist/module/utils/push/libs/notifee/index.js.map +0 -1
  156. package/dist/module/utils/push/libs/notifee/lib.js +0 -11
  157. package/dist/module/utils/push/libs/notifee/lib.js.map +0 -1
  158. package/dist/typescript/hooks/push/useIosInitRemoteNotifications.d.ts +0 -5
  159. package/dist/typescript/hooks/push/useIosInitRemoteNotifications.d.ts.map +0 -1
  160. package/dist/typescript/hooks/push/useProcessPushNonRingingCallEffect.d.ts +0 -7
  161. package/dist/typescript/hooks/push/useProcessPushNonRingingCallEffect.d.ts.map +0 -1
  162. package/dist/typescript/utils/internal/newNotificationCallbacks.d.ts +0 -10
  163. package/dist/typescript/utils/internal/newNotificationCallbacks.d.ts.map +0 -1
  164. package/dist/typescript/utils/push/internal/rxSubjects.d.ts +0 -11
  165. package/dist/typescript/utils/push/internal/rxSubjects.d.ts.map +0 -1
  166. package/dist/typescript/utils/push/ios.d.ts +0 -14
  167. package/dist/typescript/utils/push/ios.d.ts.map +0 -1
  168. package/dist/typescript/utils/push/libs/expoNotifications.d.ts +0 -6
  169. package/dist/typescript/utils/push/libs/expoNotifications.d.ts.map +0 -1
  170. package/dist/typescript/utils/push/libs/iosPushNotification.d.ts +0 -5
  171. package/dist/typescript/utils/push/libs/iosPushNotification.d.ts.map +0 -1
  172. package/dist/typescript/utils/push/libs/notifee/index.d.ts +0 -23
  173. package/dist/typescript/utils/push/libs/notifee/index.d.ts.map +0 -1
  174. package/dist/typescript/utils/push/libs/notifee/lib.d.ts +0 -4
  175. package/dist/typescript/utils/push/libs/notifee/lib.d.ts.map +0 -1
  176. package/src/hooks/push/useIosInitRemoteNotifications.ts +0 -29
  177. package/src/hooks/push/useProcessPushNonRingingCallEffect.ts +0 -50
  178. package/src/utils/internal/newNotificationCallbacks.ts +0 -29
  179. package/src/utils/push/internal/rxSubjects.ts +0 -10
  180. package/src/utils/push/ios.ts +0 -207
  181. package/src/utils/push/libs/expoNotifications.ts +0 -32
  182. package/src/utils/push/libs/iosPushNotification.ts +0 -22
  183. package/src/utils/push/libs/notifee/index.ts +0 -41
  184. package/src/utils/push/libs/notifee/lib.ts +0 -14
@@ -148,11 +148,19 @@ export const ViewerLivestream = ({
148
148
  ]);
149
149
 
150
150
  if (endedAt != null) {
151
- return <CallEndedView />;
151
+ return (
152
+ <View style={[styles.container, viewerLivestream.container]}>
153
+ <CallEndedView />
154
+ </View>
155
+ );
152
156
  }
153
157
 
154
158
  if (!canJoinLive || callingState !== CallingState.JOINED) {
155
- return <ViewerLobby isLive={canJoinLive} />;
159
+ return (
160
+ <View style={[styles.container, viewerLivestream.container]}>
161
+ <ViewerLobby isLive={canJoinLive} />
162
+ </View>
163
+ );
156
164
  }
157
165
 
158
166
  return (
@@ -63,7 +63,7 @@ const TrackSubscriber = forwardRef<TrackSubscriberHandle, TrackSubscriberProps>(
63
63
  call.state.updateParticipantTracks(trackType, {
64
64
  [participantSessionId]: { dimension },
65
65
  });
66
- call.dynascaleManager.applyTrackSubscriptions(debounceType);
66
+ call.trackSubscriptionManager.apply(debounceType);
67
67
  };
68
68
  const isPublishingTrack$ = call.state.participants$.pipe(
69
69
  map((ps) => ps.find((p) => p.sessionId === participantSessionId)),
@@ -1,15 +1,11 @@
1
1
  import { useIosVoipPushEventsSetupEffect } from './useIosVoipPushEventsSetupEffect';
2
2
  import { useInitAndroidTokenAndRest } from './useInitAndroidTokenAndRest';
3
- import { useIosInitRemoteNotifications } from './useIosInitRemoteNotifications';
4
- import { useProcessPushNonRingingCallEffect } from './useProcessPushNonRingingCallEffect';
5
3
 
6
4
  /**
7
5
  * This hook is used to do the initial setup for push notifications.
8
6
  * It must be used in a component which is a child of StreamVideo from bindings
9
7
  */
10
8
  export const usePushRegisterEffect = () => {
11
- useIosInitRemoteNotifications();
12
9
  useIosVoipPushEventsSetupEffect();
13
- useProcessPushNonRingingCallEffect();
14
10
  useInitAndroidTokenAndRest();
15
11
  };
@@ -112,6 +112,12 @@ export class CallManager {
112
112
  */
113
113
  start = (config?: StreamInCallManagerConfig): void => {
114
114
  if (shouldBypassForCallKit()) {
115
+ // Forward only the passive endpoint preference; callingx reads it when
116
+ // CallKit drives session activation.
117
+ if (config?.audioRole === 'communicator' && CallingxModule) {
118
+ const type = config.deviceEndpointType ?? 'speaker';
119
+ CallingxModule.setDefaultAudioDeviceEndpointType(type);
120
+ }
115
121
  videoLoggerSystem
116
122
  .getLogger('CallManager')
117
123
  .debug(
@@ -1,8 +1,5 @@
1
1
  import type { StreamVideoConfig } from './types';
2
2
  import pushLogoutCallbacks from '../internal/pushLogoutCallback';
3
- import newNotificationCallbacks, {
4
- type NewCallNotificationCallback,
5
- } from '../internal/newNotificationCallbacks';
6
3
  import { setupIosVoipPushEvents } from '../push/setupIosVoipPushEvents';
7
4
  import { setupCallingExpEvents } from '../push/setupCallingExpEvents';
8
5
  import {
@@ -160,25 +157,6 @@ export class StreamVideoRN {
160
157
  pushLogoutCallbacks.current = [];
161
158
  }
162
159
 
163
- /**
164
- * This function is used to add a callback to be called when a new call notification is received.
165
- * @param callback
166
- * @returns Unsubscribe function
167
- */
168
- static addOnNewCallNotificationListener(
169
- callback: NewCallNotificationCallback,
170
- ) {
171
- if (!newNotificationCallbacks.current) {
172
- newNotificationCallbacks.current = [callback];
173
- } else {
174
- newNotificationCallbacks.current.push(callback);
175
- }
176
- return () => {
177
- newNotificationCallbacks.current =
178
- newNotificationCallbacks.current?.filter((cb) => cb !== callback);
179
- };
180
- }
181
-
182
160
  /**
183
161
  * Play native busy tone for call rejection
184
162
  */
@@ -3,7 +3,6 @@ import {
3
3
  StreamVideoClient,
4
4
  type Call,
5
5
  } from '@stream-io/video-client';
6
- import type { AndroidChannel } from '@notifee/react-native';
7
6
 
8
7
  export type AndroidChannelConfig = {
9
8
  id: string;
@@ -70,6 +69,21 @@ export type StreamVideoConfig = {
70
69
  * @default false
71
70
  */
72
71
  enableOngoingCalls?: boolean;
72
+ /**
73
+ * When true, ringing pushes that arrive while the app is in the
74
+ * foreground are not shown by CallKit. The push is still delivered to
75
+ * JS, so the app must show its own ringing UI. Background pushes are unaffected.
76
+ * Requires iOS 26.4 or newer version of iOS.
77
+ * @default false
78
+ */
79
+ skipIncomingPushInForeground?: boolean;
80
+ /**
81
+ * Default audio endpoint for CallKit-managed calls on iOS.
82
+ * `'earpiece'` routes voice-only / phone-style calls to the built-in receiver.
83
+ * Set via `setPushConfig` so it's in place before CallKit's `CXAnswerCallAction`.
84
+ * @default 'speaker'
85
+ */
86
+ defaultDeviceEndpointType?: 'speaker' | 'earpiece';
73
87
  };
74
88
  android?: {
75
89
  /**
@@ -84,17 +98,6 @@ export type StreamVideoConfig = {
84
98
  * @example "production-fcm-video" or "staging-fcm-video" based on the environment
85
99
  */
86
100
  pushProviderName?: string;
87
- /**
88
- * The notification channel to be used for non ringing calls for Android.
89
- * @example
90
- * {
91
- * id: 'stream_call_notifications',
92
- * name: 'Call notifications',
93
- * importance: AndroidImportance.HIGH,
94
- * sound: 'default',
95
- * }
96
- */
97
- callChannel?: AndroidChannel;
98
101
  /**
99
102
  * The notification channel to be used for incoming calls for Android.
100
103
  * @example
@@ -123,38 +126,13 @@ export type StreamVideoConfig = {
123
126
  * The transformer to be used to transform the call title in the notification for ringing and ongoing calls for Android.
124
127
  */
125
128
  titleTransformer?: (memberName: string, incoming: boolean) => string;
129
+ enableOngoingCalls?: boolean;
126
130
  /**
127
- * Functions to create the texts shown in the notification for non ringing calls in Android.
128
- * @example
129
- * getTitle(type, createdUserName) {
130
- if (type === 'call.live_started') {
131
- return `Call went live, it was started by ${createdUserName}`;
132
- } else if (type === 'call.missed') {
133
- return `Missed call from ${createdUserName}`;
134
- } else {
135
- return `${createdUserName} is notifying you about a call`;
136
- }
137
- },
138
- getBody(type, _createdUserName) {
139
- if (type === 'call.missed') {
140
- return 'Missed call!';
141
- } else {
142
- return 'Tap to open the call';
143
- }
144
- },
145
- */
146
- callNotificationTextGetters?: {
147
- getTitle: (
148
- type: NonRingingPushEvent,
149
- createdUserName: string,
150
- ) => string;
151
- getBody: (type: NonRingingPushEvent, createdUserName: string) => string;
152
- };
153
- /**
154
- * Whether to enable ongoing calls.
131
+ * When true, incoming call push notifications (call.ring) will not be displayed
132
+ * as a notification when the app is in the foreground.
155
133
  * @default false
156
134
  */
157
- enableOngoingCalls?: boolean;
135
+ skipIncomingPushInForeground?: boolean;
158
136
  };
159
137
  /**
160
138
  * Whether to reject calls when the user is busy.
@@ -180,11 +158,6 @@ export type StreamVideoConfig = {
180
158
  * }
181
159
  */
182
160
  createStreamVideoClient: () => Promise<StreamVideoClient | undefined>;
183
- /** Callback that is called when a non ringing push notification was tapped */
184
- onTapNonRingingCallNotification?: (
185
- call_cid: string,
186
- type: NonRingingPushEvent,
187
- ) => void;
188
161
  };
189
162
  foregroundService: {
190
163
  android: {
@@ -2,7 +2,7 @@
2
2
  * Internal utils for callingx library usage from video-client.
3
3
  * See @./registerSDKGlobals.ts for more usage details.
4
4
  */
5
- import { Platform } from 'react-native';
5
+ import { AppState, NativeModules, Platform } from 'react-native';
6
6
  import type { EndCallReason } from '@stream-io/react-native-callingx';
7
7
  import { getCallingxLibIfAvailable } from '../../push/libs/callingx';
8
8
  import { waitForAudioSessionActivation } from './audioSessionPromise';
@@ -12,8 +12,18 @@ import type {
12
12
  StreamVideoParticipant,
13
13
  } from '@stream-io/video-client';
14
14
  import { CallingState, videoLoggerSystem } from '@stream-io/video-client';
15
+ import { StreamVideoRN } from '../../StreamVideoRN';
15
16
  const CallingxModule = getCallingxLibIfAvailable();
16
17
 
18
+ async function isAppInForeground(): Promise<boolean> {
19
+ if (Platform.OS === 'android') {
20
+ const nativeModule = NativeModules.StreamVideoAppLifecycle;
21
+ const state = await nativeModule.getCurrentAppState();
22
+ return state === 'active';
23
+ }
24
+ return AppState.currentState !== 'background';
25
+ }
26
+
17
27
  /**
18
28
  * Gets the call display name. To be used for display in native call screen.
19
29
  */
@@ -78,10 +88,11 @@ export async function registerOutgoingCall(call: Call) {
78
88
 
79
89
  try {
80
90
  logger.debug(`registerOutgoingCall: Registering outgoing call ${call.cid}`);
91
+ const callDisplayName = getCallDisplayNameFromCall(call);
81
92
  await CallingxModule.startCall(
82
93
  call.cid, // unique id for call
83
- call.state.createdBy?.id ?? getCallDisplayNameFromCall(call), // handle for native call UI (prefer createdBy user id, fallback to call display name)
84
- getCallDisplayNameFromCall(call), // display name for display in call screen
94
+ call.state.createdBy?.id ?? callDisplayName, // handle for native call UI (prefer createdBy user id, fallback to call display name)
95
+ callDisplayName, // display name for display in call screen
85
96
  call.state.settings?.video?.enabled ?? false, // is video call?
86
97
  );
87
98
  } catch (error) {
@@ -109,23 +120,26 @@ export async function joinCallingxCall(call: Call, activeCalls: Call[]) {
109
120
  const isOutcomingCall = call.ringing && call.isCreatedByMe;
110
121
  const isIncomingCall = call.ringing && !call.isCreatedByMe;
111
122
 
123
+ const startCallInCallingx = async () => {
124
+ logger.debug(`joinCallingxCall: Joining call ${call.cid}`);
125
+ const callDisplayName = getCallDisplayNameFromCall(call);
126
+ await CallingxModule.startCall(
127
+ call.cid, // unique id for call
128
+ call.state.createdBy?.id ?? callDisplayName, // handle for native call UI (prefer createdBy user id, fallback to call display name)
129
+ callDisplayName, // display name for display in call screen
130
+ call.state.settings?.video?.enabled ?? false, // is video call?
131
+ );
132
+ if (Platform.OS === 'ios') {
133
+ await waitForAudioSessionActivation();
134
+ }
135
+ };
136
+
112
137
  if (
113
138
  isOutcomingCall ||
114
139
  (!call.ringing && CallingxModule.isOngoingCallsEnabled)
115
140
  ) {
116
141
  try {
117
- logger.debug(`joinCallingxCall: Joining call ${call.cid}`);
118
- await CallingxModule.startCall(
119
- call.cid, // unique id for call
120
- call.state.createdBy?.id ?? getCallDisplayNameFromCall(call), // handle for native call UI (prefer createdBy user id, fallback to call display name)
121
- getCallDisplayNameFromCall(call), // display name for display in call screen
122
- call.state.settings?.video?.enabled ?? false, // is video call?
123
- );
124
-
125
- // Wait for audio session activation on iOS only
126
- if (Platform.OS === 'ios') {
127
- await waitForAudioSessionActivation();
128
- }
142
+ await startCallInCallingx();
129
143
  } catch (error) {
130
144
  logger.error(
131
145
  `startCallingxCall: Error starting call in callingx: ${call.cid}`,
@@ -134,6 +148,19 @@ export async function joinCallingxCall(call: Call, activeCalls: Call[]) {
134
148
  }
135
149
  } else if (isIncomingCall) {
136
150
  logger.debug(`joinCallingxCall: Joining incoming call ${call.cid}`);
151
+ let skipIncomingPushInForeground = false;
152
+ if (Platform.OS === 'ios') {
153
+ skipIncomingPushInForeground =
154
+ StreamVideoRN.getConfig().push?.ios?.skipIncomingPushInForeground ??
155
+ false;
156
+ } else {
157
+ skipIncomingPushInForeground =
158
+ StreamVideoRN.getConfig().push?.android?.skipIncomingPushInForeground ??
159
+ false;
160
+ }
161
+ const shouldSkipDisplayIncoming = skipIncomingPushInForeground
162
+ ? await isAppInForeground()
163
+ : false;
137
164
  try {
138
165
  // Leave any existing active ringing calls before joining a new ringing call
139
166
  const activeCallsToLeave = activeCalls.filter(
@@ -150,25 +177,29 @@ export async function joinCallingxCall(call: Call, activeCalls: Call[]) {
150
177
  logger.error(`failed to leave active call ${activeCall.cid}`, e);
151
178
  });
152
179
  }
180
+ if (shouldSkipDisplayIncoming) {
181
+ await startCallInCallingx();
182
+ } else {
183
+ // Awaits native CallKit/Telecom registration before answering.
184
+ // Safe to call even if the call is already registered (e.g. from VoIP push) --
185
+ // iOS early-returns with no error, Android sends the registered broadcast.
186
+ const callDisplayName = getCallDisplayNameFromCall(call);
187
+ await CallingxModule.displayIncomingCall(
188
+ call.cid, // unique id for call
189
+ call.state.createdBy?.id ?? callDisplayName, // handle for native call UI (prefer createdBy user id, fallback to call display name)
190
+ callDisplayName, // display name for display in call screen
191
+ call.state.settings?.video?.enabled ?? false, // is video call?
192
+ );
153
193
 
154
- // Awaits native CallKit/Telecom registration before answering.
155
- // Safe to call even if the call is already registered (e.g. from VoIP push) --
156
- // iOS early-returns with no error, Android sends the registered broadcast.
157
- await CallingxModule.displayIncomingCall(
158
- call.cid, // unique id for call
159
- call.state.createdBy?.id ?? getCallDisplayNameFromCall(call), // handle for native call UI (prefer createdBy user id, fallback to call display name)
160
- getCallDisplayNameFromCall(call), // display name for display in call screen
161
- call.state.settings?.video?.enabled ?? false, // is video call?
162
- );
163
-
164
- await CallingxModule.answerIncomingCall(call.cid);
194
+ await CallingxModule.answerIncomingCall(call.cid);
165
195
 
166
- if (Platform.OS === 'ios') {
167
- await waitForAudioSessionActivation();
196
+ if (Platform.OS === 'ios') {
197
+ await waitForAudioSessionActivation();
198
+ }
168
199
  }
169
200
  } catch (error) {
170
201
  logger.error(
171
- `Error displaying incoming call in callingx: ${call.cid}`,
202
+ `Error joining incoming call in callingx: ${call.cid} shouldSkipDisplayIncoming: ${shouldSkipDisplayIncoming}`,
172
203
  error,
173
204
  );
174
205
  }
@@ -50,6 +50,8 @@ const streamRNVideoSDKGlobals: StreamRNVideoSDKGlobals = {
50
50
  callManager: {
51
51
  setup: ({ defaultDevice, isRingingTypeCall }) => {
52
52
  if (shouldBypassForCallKit({ isRingingTypeCall })) {
53
+ // Forward the sticky preference; callingx reads it on next CallKit activation.
54
+ CallingxModule?.setDefaultAudioDeviceEndpointType(defaultDevice);
53
55
  return;
54
56
  }
55
57
  StreamInCallManagerNativeModule.setDefaultAudioDeviceEndpointType(
@@ -4,20 +4,12 @@ import {
4
4
  videoLoggerSystem,
5
5
  } from '@stream-io/video-client';
6
6
  import { AppState, Platform } from 'react-native';
7
- import type {
8
- NonRingingPushEvent,
9
- StreamVideoConfig,
10
- } from '../StreamVideoRN/types';
7
+ import type { StreamVideoConfig } from '../StreamVideoRN/types';
11
8
  import {
12
9
  type FirebaseMessagingTypes,
13
- getExpoNotificationsLib,
14
- getExpoNotificationsLibNoThrow,
15
10
  getFirebaseMessagingLib,
16
11
  getFirebaseMessagingLibNoThrow,
17
- getNotifeeLibThrowIfNotInstalledForPush,
18
- type NotifeeLib,
19
12
  } from './libs';
20
- import { pushNonRingingCallData$ } from './internal/rxSubjects';
21
13
  import { pushUnsubscriptionCallbacks } from './internal/constants';
22
14
  import { canListenToWS, shouldCallBeClosed } from './internal/utils';
23
15
  import { setPushLogoutCallback } from '../internal/pushLogoutCallback';
@@ -26,12 +18,6 @@ import { getCallingxLib } from './libs/callingx';
26
18
 
27
19
  type PushConfig = NonNullable<StreamVideoConfig['push']>;
28
20
 
29
- type onBackgroundEventFunctionParams = Parameters<
30
- NotifeeLib['default']['onBackgroundEvent']
31
- >[0];
32
-
33
- type Event = Parameters<onBackgroundEventFunctionParams>[0];
34
-
35
21
  let lastFirebaseToken = { token: '', userId: '' };
36
22
 
37
23
  /** Send token to stream */
@@ -73,24 +59,6 @@ export async function initAndroidPushToken(
73
59
  logger.debug(`sending firebase token: ${token} for userId: ${userId}`);
74
60
  await client.addDevice(token, 'firebase', push_provider_name);
75
61
  };
76
- if (pushConfig.isExpo) {
77
- const expoNotificationsLib = pushConfig.onTapNonRingingCallNotification
78
- ? getExpoNotificationsLib()
79
- : getExpoNotificationsLibNoThrow();
80
- if (expoNotificationsLib) {
81
- logger.debug(`setting expo notification token listeners`);
82
- const subscription = expoNotificationsLib.addPushTokenListener(
83
- (devicePushToken) => {
84
- setDeviceToken(devicePushToken.data);
85
- },
86
- );
87
- setUnsubscribeListener(() => subscription.remove());
88
- const devicePushToken =
89
- await expoNotificationsLib.getDevicePushTokenAsync();
90
- const token = devicePushToken.data;
91
- await setDeviceToken(token);
92
- }
93
- }
94
62
 
95
63
  const messaging = pushConfig.isExpo
96
64
  ? getFirebaseMessagingLibNoThrow(true)
@@ -193,6 +161,11 @@ export const firebaseDataHandler = async (
193
161
  'debug',
194
162
  );
195
163
  callingx.endCallWithReason(call_cid, endCallReason);
164
+ callFromPush.leave({ reject: false }).catch((error) => {
165
+ logger.error(
166
+ `Failed to leave already-ended ringing call ${call_cid}: ${error}`,
167
+ );
168
+ });
196
169
  resolve(undefined);
197
170
  return;
198
171
  }
@@ -323,90 +296,11 @@ export const firebaseDataHandler = async (
323
296
  `Removing incoming call notification immediately with callCid: ${call_cid} as it should be closed`,
324
297
  );
325
298
  callingx.endCallWithReason(call_cid, endCallReason);
299
+ callFromPush.leave({ reject: false }).catch((error) => {
300
+ logger.error(
301
+ `Failed to leave already-ended ringing call ${call_cid}: ${error}`,
302
+ );
303
+ });
326
304
  }
327
- } else {
328
- const notifeeLib = getNotifeeLibThrowIfNotInstalledForPush();
329
- const notifee = notifeeLib.default;
330
- const settings = await notifee.getNotificationSettings();
331
- if (settings.authorizationStatus !== 1) {
332
- logger.debug(
333
- `Notification permission not granted, unable to post ${data.type} notifications`,
334
- );
335
- return;
336
- }
337
-
338
- // the other types are call.live_started and call.notification
339
- const callChannel = pushConfig.android?.callChannel;
340
- const callNotificationTextGetters =
341
- pushConfig.android?.callNotificationTextGetters;
342
- if (!callChannel || !callNotificationTextGetters) {
343
- logger.debug(
344
- "Can't show call notification as either or both callChannel and callNotificationTextGetters is not provided",
345
- );
346
- return;
347
- }
348
- await notifee.createChannel(callChannel);
349
- const channelId = callChannel.id;
350
- const { getTitle, getBody } = callNotificationTextGetters;
351
- const createdUserName = data.created_by_display_name as string;
352
- // we can safely cast to string because the data is from "stream.video"
353
- const type = data.type as NonRingingPushEvent;
354
-
355
- const title = getTitle(type, createdUserName);
356
- const body = getBody(type, createdUserName);
357
-
358
- logger.debug(
359
- `Displaying NonRingingPushEvent ${type} notification with title: ${title} body: ${body}`,
360
- );
361
- await notifee.displayNotification({
362
- title,
363
- body,
364
- data,
365
- android: {
366
- sound: callChannel.sound,
367
- smallIcon: pushConfig.android?.smallIcon,
368
- vibrationPattern: callChannel.vibrationPattern,
369
- channelId,
370
- importance: 4, // high importance
371
- pressAction: {
372
- id: 'default',
373
- launchActivity: 'default', // open the app when the notification is pressed
374
- },
375
- timeoutAfter: 60000, // 60 seconds, after which the notification will be dismissed automatically
376
- },
377
- });
378
- const cid = data.call_cid as string;
379
- pushNonRingingCallData$.next({ cid, type });
380
- }
381
- };
382
-
383
- export const onAndroidNotifeeEvent = async ({ event }: { event: Event }) => {
384
- if (Platform.OS !== 'android') return;
385
- const { type, detail } = event;
386
- const { notification } = detail;
387
- const notificationId = notification?.id;
388
- const data = notification?.data;
389
- const pushConfig = StreamVideoRN.getConfig().push;
390
- if (
391
- !pushConfig ||
392
- !data ||
393
- !notificationId ||
394
- data.sender !== 'stream.video'
395
- ) {
396
- return;
397
- }
398
-
399
- // we can safely cast to string because the data is from "stream.video"
400
- const call_cid = data.call_cid as string;
401
-
402
- const notifeeLib = getNotifeeLibThrowIfNotInstalledForPush();
403
- if (type === notifeeLib.EventType.PRESS) {
404
- videoLoggerSystem
405
- .getLogger('onAndroidNotifeeEvent')
406
- .debug(`onTapNonRingingCallNotification with callCId: ${call_cid}`);
407
- pushConfig.onTapNonRingingCallNotification?.(
408
- call_cid,
409
- data.type as NonRingingPushEvent,
410
- );
411
305
  }
412
306
  };
@@ -1,3 +1,2 @@
1
1
  export * from './android';
2
- export * from './ios';
3
2
  export * from './utils';
@@ -4,11 +4,7 @@ import {
4
4
  StreamVideoClient,
5
5
  videoLoggerSystem,
6
6
  } from '@stream-io/video-client';
7
- import type {
8
- NonRingingPushEvent,
9
- StreamVideoConfig,
10
- } from '../../StreamVideoRN/types';
11
- import { onNewCallNotification } from '../../internal/newNotificationCallbacks';
7
+ import type { StreamVideoConfig } from '../../StreamVideoRN/types';
12
8
  import { pushUnsubscriptionCallbacks } from './constants';
13
9
  import { AppState } from 'react-native';
14
10
  import type { EndCallReason } from '@stream-io/react-native-callingx';
@@ -162,42 +158,6 @@ export const processCallFromPushInBackground = async (
162
158
  }
163
159
  };
164
160
 
165
- /**
166
- * This function is used process the call from push notifications due to non ringing calls
167
- * It does the following steps:
168
- * 1. Get the call from the client if present or create a new call
169
- * 2. Fetch the latest state of the call from the server
170
- * 3. Call all the callbacks to inform the app about the call
171
- */
172
- export const processNonIncomingCallFromPush = async (
173
- client: StreamVideoClient,
174
- call_cid: string,
175
- nonRingingNotificationType: NonRingingPushEvent,
176
- ) => {
177
- let callFromPush: Call;
178
- try {
179
- const _callFromPush = client.state.calls.find((c) => c.cid === call_cid);
180
- if (_callFromPush) {
181
- callFromPush = _callFromPush;
182
- } else {
183
- // if not it means that WS is not alive when receiving the push notifications and we need to fetch the call
184
- const [callType, callId] = call_cid.split(':');
185
- callFromPush = client.call(callType as string, callId as string);
186
- await callFromPush.get();
187
- }
188
- } catch (e) {
189
- const nonRingingCallLogger = videoLoggerSystem.getLogger(
190
- 'processNonIncomingCallFromPush',
191
- );
192
- nonRingingCallLogger.error(
193
- 'failed to fetch call from push notification',
194
- e,
195
- );
196
- return;
197
- }
198
- onNewCallNotification(callFromPush, nonRingingNotificationType);
199
- };
200
-
201
161
  /**
202
162
  * This function is used to clear all the push related WS subscriptions
203
163
  * note: events are subscribed in push for accept/decline through WS
@@ -52,6 +52,14 @@ export function extractCallingExpOptions(
52
52
  if (pushConfig.ios.enableOngoingCalls !== undefined) {
53
53
  iosOptions.enableOngoingCalls = pushConfig.ios.enableOngoingCalls;
54
54
  }
55
+ if (pushConfig.ios.skipIncomingPushInForeground !== undefined) {
56
+ iosOptions.skipIncomingPushInForeground =
57
+ pushConfig.ios.skipIncomingPushInForeground;
58
+ }
59
+ if (pushConfig.ios.defaultDeviceEndpointType !== undefined) {
60
+ iosOptions.defaultDeviceEndpointType =
61
+ pushConfig.ios.defaultDeviceEndpointType;
62
+ }
55
63
 
56
64
  if (Object.keys(iosOptions).length > 0) {
57
65
  callingExpOptions.ios = iosOptions;
@@ -72,6 +80,10 @@ export function extractCallingExpOptions(
72
80
  if (pushConfig.android.enableOngoingCalls !== undefined) {
73
81
  androidOptions.enableOngoingCalls = pushConfig.android.enableOngoingCalls;
74
82
  }
83
+ if (pushConfig.android.skipIncomingPushInForeground !== undefined) {
84
+ androidOptions.skipIncomingPushInForeground =
85
+ pushConfig.android.skipIncomingPushInForeground;
86
+ }
75
87
  }
76
88
 
77
89
  if (foregroundServiceConfig.android.channel) {
@@ -1,7 +1,4 @@
1
- export * from './expoNotifications';
2
1
  export * from './firebaseMessaging';
3
- export * from './iosPushNotification';
4
- export * from './notifee';
5
2
  export * from './callingx';
6
3
 
7
4
  /*
@@ -1,8 +1,5 @@
1
- import type { Event } from '@notifee/react-native';
2
1
  import type { FirebaseMessagingTypes } from './libs/firebaseMessaging';
3
- import type { ExpoNotification } from './libs/expoNotifications';
4
2
  import type { NonRingingPushEvent } from '../StreamVideoRN/types';
5
- import type { PushNotificationiOSType } from './libs/iosPushNotification';
6
3
 
7
4
  export type StreamPushPayload =
8
5
  | {
@@ -17,37 +14,3 @@ export function isFirebaseStreamVideoMessage(
17
14
  ) {
18
15
  return message.data?.sender === 'stream.video';
19
16
  }
20
-
21
- export function isNotifeeStreamVideoEvent(event: Event) {
22
- const { detail } = event;
23
- const { notification } = detail;
24
- return notification?.data?.sender === 'stream.video';
25
- }
26
-
27
- export function isExpoNotificationStreamVideoEvent(event: ExpoNotification) {
28
- const trigger = event.request.trigger;
29
- if (
30
- trigger &&
31
- typeof trigger === 'object' &&
32
- 'type' in trigger &&
33
- trigger.type === 'push'
34
- ) {
35
- // iOS
36
- const streamPayload = trigger.payload?.stream as StreamPushPayload;
37
- // Android
38
- const remoteMessageData = trigger.remoteMessage?.data;
39
- return (
40
- streamPayload?.sender === 'stream.video' ||
41
- remoteMessageData?.sender === 'stream.video'
42
- );
43
- }
44
- return false;
45
- }
46
-
47
- export function isPushNotificationiOSStreamVideoEvent(
48
- notification: PushNotificationiOSType,
49
- ) {
50
- const data = notification.getData();
51
- const streamPayload = data?.stream as StreamPushPayload;
52
- return streamPayload?.sender === 'stream.video';
53
- }
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '1.34.0';
1
+ export const version = '1.36.0';