@stream-io/video-react-native-sdk 1.21.2 → 1.22.1-alpha.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 (219) hide show
  1. package/android/gradle.properties +3 -3
  2. package/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.kt +10 -0
  3. package/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativePackage.kt +2 -1
  4. package/android/src/main/java/com/streamvideo/reactnative/audio/AudioDeviceManager.kt +592 -0
  5. package/android/src/main/java/com/streamvideo/reactnative/audio/BluetoothManager.kt +755 -0
  6. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/AudioDeviceEndpointUtils.kt +192 -0
  7. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/AudioFocusUtil.kt +62 -0
  8. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/AudioManagerUtil.kt +159 -0
  9. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/AudioSetupStoreUtil.kt +41 -0
  10. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/WebRtcAudioUtils.kt +250 -0
  11. package/android/src/main/java/com/streamvideo/reactnative/callmanager/StreamInCallManagerModule.kt +191 -0
  12. package/android/src/main/java/com/streamvideo/reactnative/model/AudioDeviceEndpoint.kt +136 -0
  13. package/android/src/main/java/org/webrtc/audio/WebRtcAudioTrackHelper.kt +12 -0
  14. package/dist/commonjs/components/Call/CallContent/CallContent.js +13 -9
  15. package/dist/commonjs/components/Call/CallContent/CallContent.js.map +1 -1
  16. package/dist/commonjs/components/Call/CallContent/RTCViewPipIOS.js +9 -2
  17. package/dist/commonjs/components/Call/CallContent/RTCViewPipIOS.js.map +1 -1
  18. package/dist/commonjs/components/Call/CallContent/RTCViewPipNative.js +3 -0
  19. package/dist/commonjs/components/Call/CallContent/RTCViewPipNative.js.map +1 -1
  20. package/dist/commonjs/components/Livestream/HostLivestream/HostLivestream.js +10 -6
  21. package/dist/commonjs/components/Livestream/HostLivestream/HostLivestream.js.map +1 -1
  22. package/dist/commonjs/components/Livestream/LivestreamControls/ViewerLivestreamControls.js +8 -4
  23. package/dist/commonjs/components/Livestream/LivestreamControls/ViewerLivestreamControls.js.map +1 -1
  24. package/dist/commonjs/components/Livestream/LivestreamLayout/LivestreamLayout.js +26 -27
  25. package/dist/commonjs/components/Livestream/LivestreamLayout/LivestreamLayout.js.map +1 -1
  26. package/dist/commonjs/components/Livestream/ViewerLivestream/ViewerLivestream.js +10 -6
  27. package/dist/commonjs/components/Livestream/ViewerLivestream/ViewerLivestream.js.map +1 -1
  28. package/dist/commonjs/hooks/useIsInPiPMode.js +3 -3
  29. package/dist/commonjs/hooks/useIsInPiPMode.js.map +1 -1
  30. package/dist/commonjs/hooks/usePermissionNotification.js +5 -5
  31. package/dist/commonjs/hooks/usePermissionNotification.js.map +1 -1
  32. package/dist/commonjs/index.js +12 -0
  33. package/dist/commonjs/index.js.map +1 -1
  34. package/dist/commonjs/modules/call-manager/CallManager.js +113 -0
  35. package/dist/commonjs/modules/call-manager/CallManager.js.map +1 -0
  36. package/dist/commonjs/modules/call-manager/PrevLibDetection.js +18 -0
  37. package/dist/commonjs/modules/call-manager/PrevLibDetection.js.map +1 -0
  38. package/dist/commonjs/modules/call-manager/index.js +24 -0
  39. package/dist/commonjs/modules/call-manager/index.js.map +1 -0
  40. package/dist/commonjs/modules/call-manager/native-module.d.js +4 -0
  41. package/dist/commonjs/modules/call-manager/native-module.d.js.map +1 -0
  42. package/dist/commonjs/modules/call-manager/types.js +2 -0
  43. package/dist/commonjs/modules/call-manager/types.js.map +1 -0
  44. package/dist/commonjs/providers/StreamCall/AppStateListener.js +5 -5
  45. package/dist/commonjs/providers/StreamCall/AppStateListener.js.map +1 -1
  46. package/dist/commonjs/theme/theme.js.map +1 -1
  47. package/dist/commonjs/utils/internal/rxSubjects.js +2 -2
  48. package/dist/commonjs/utils/internal/rxSubjects.js.map +1 -1
  49. package/dist/commonjs/version.js +1 -1
  50. package/dist/commonjs/version.js.map +1 -1
  51. package/dist/module/components/Call/CallContent/CallContent.js +14 -9
  52. package/dist/module/components/Call/CallContent/CallContent.js.map +1 -1
  53. package/dist/module/components/Call/CallContent/RTCViewPipIOS.js +9 -2
  54. package/dist/module/components/Call/CallContent/RTCViewPipIOS.js.map +1 -1
  55. package/dist/module/components/Call/CallContent/RTCViewPipNative.js +3 -0
  56. package/dist/module/components/Call/CallContent/RTCViewPipNative.js.map +1 -1
  57. package/dist/module/components/Livestream/HostLivestream/HostLivestream.js +10 -5
  58. package/dist/module/components/Livestream/HostLivestream/HostLivestream.js.map +1 -1
  59. package/dist/module/components/Livestream/LivestreamControls/ViewerLivestreamControls.js +9 -4
  60. package/dist/module/components/Livestream/LivestreamControls/ViewerLivestreamControls.js.map +1 -1
  61. package/dist/module/components/Livestream/LivestreamLayout/LivestreamLayout.js +26 -27
  62. package/dist/module/components/Livestream/LivestreamLayout/LivestreamLayout.js.map +1 -1
  63. package/dist/module/components/Livestream/ViewerLivestream/ViewerLivestream.js +10 -5
  64. package/dist/module/components/Livestream/ViewerLivestream/ViewerLivestream.js.map +1 -1
  65. package/dist/module/hooks/useIsInPiPMode.js +4 -4
  66. package/dist/module/hooks/useIsInPiPMode.js.map +1 -1
  67. package/dist/module/hooks/usePermissionNotification.js +7 -6
  68. package/dist/module/hooks/usePermissionNotification.js.map +1 -1
  69. package/dist/module/icons/Back.js +1 -1
  70. package/dist/module/icons/Back.js.map +1 -1
  71. package/dist/module/icons/CameraSwitch.js +1 -1
  72. package/dist/module/icons/CameraSwitch.js.map +1 -1
  73. package/dist/module/icons/Mic.js +1 -1
  74. package/dist/module/icons/Mic.js.map +1 -1
  75. package/dist/module/icons/MicOff.js +1 -1
  76. package/dist/module/icons/MicOff.js.map +1 -1
  77. package/dist/module/icons/Phone.js +1 -1
  78. package/dist/module/icons/Phone.js.map +1 -1
  79. package/dist/module/icons/PinVertical.js +1 -1
  80. package/dist/module/icons/PinVertical.js.map +1 -1
  81. package/dist/module/icons/Reaction.js +1 -1
  82. package/dist/module/icons/Reaction.js.map +1 -1
  83. package/dist/module/icons/Spotlight.js +1 -1
  84. package/dist/module/icons/Spotlight.js.map +1 -1
  85. package/dist/module/icons/Video.js +1 -1
  86. package/dist/module/icons/Video.js.map +1 -1
  87. package/dist/module/icons/VideoSlash.js +1 -1
  88. package/dist/module/icons/VideoSlash.js.map +1 -1
  89. package/dist/module/index.js +1 -0
  90. package/dist/module/index.js.map +1 -1
  91. package/dist/module/modules/call-manager/CallManager.js +106 -0
  92. package/dist/module/modules/call-manager/CallManager.js.map +1 -0
  93. package/dist/module/modules/call-manager/PrevLibDetection.js +12 -0
  94. package/dist/module/modules/call-manager/PrevLibDetection.js.map +1 -0
  95. package/dist/module/modules/call-manager/index.js +4 -0
  96. package/dist/module/modules/call-manager/index.js.map +1 -0
  97. package/dist/module/modules/call-manager/native-module.d.js +2 -0
  98. package/dist/module/modules/call-manager/native-module.d.js.map +1 -0
  99. package/dist/module/modules/call-manager/types.js +2 -0
  100. package/dist/module/modules/call-manager/types.js.map +1 -0
  101. package/dist/module/providers/StreamCall/AppStateListener.js +6 -6
  102. package/dist/module/providers/StreamCall/AppStateListener.js.map +1 -1
  103. package/dist/module/theme/theme.js.map +1 -1
  104. package/dist/module/utils/internal/rxSubjects.js +1 -1
  105. package/dist/module/utils/internal/rxSubjects.js.map +1 -1
  106. package/dist/module/version.js +1 -1
  107. package/dist/module/version.js.map +1 -1
  108. package/dist/typescript/components/Call/CallContent/CallContent.d.ts +3 -2
  109. package/dist/typescript/components/Call/CallContent/CallContent.d.ts.map +1 -1
  110. package/dist/typescript/components/Call/CallContent/RTCViewPipIOS.d.ts +5 -0
  111. package/dist/typescript/components/Call/CallContent/RTCViewPipIOS.d.ts.map +1 -1
  112. package/dist/typescript/components/Call/CallContent/RTCViewPipNative.d.ts +6 -0
  113. package/dist/typescript/components/Call/CallContent/RTCViewPipNative.d.ts.map +1 -1
  114. package/dist/typescript/components/Livestream/HostLivestream/HostLivestream.d.ts.map +1 -1
  115. package/dist/typescript/components/Livestream/LivestreamControls/ViewerLivestreamControls.d.ts.map +1 -1
  116. package/dist/typescript/components/Livestream/LivestreamLayout/LivestreamLayout.d.ts.map +1 -1
  117. package/dist/typescript/components/Livestream/ViewerLivestream/ViewerLivestream.d.ts.map +1 -1
  118. package/dist/typescript/hooks/usePermissionNotification.d.ts.map +1 -1
  119. package/dist/typescript/icons/Back.d.ts +1 -1
  120. package/dist/typescript/icons/Back.d.ts.map +1 -1
  121. package/dist/typescript/icons/BadNetwork.d.ts +1 -1
  122. package/dist/typescript/icons/BadNetwork.d.ts.map +1 -1
  123. package/dist/typescript/icons/CameraSwitch.d.ts +1 -1
  124. package/dist/typescript/icons/CameraSwitch.d.ts.map +1 -1
  125. package/dist/typescript/icons/LivestreamControls.d.ts +1 -1
  126. package/dist/typescript/icons/LivestreamControls.d.ts.map +1 -1
  127. package/dist/typescript/icons/Lock.d.ts +1 -1
  128. package/dist/typescript/icons/Lock.d.ts.map +1 -1
  129. package/dist/typescript/icons/Maximize.d.ts +1 -1
  130. package/dist/typescript/icons/Maximize.d.ts.map +1 -1
  131. package/dist/typescript/icons/Mic.d.ts +1 -1
  132. package/dist/typescript/icons/Mic.d.ts.map +1 -1
  133. package/dist/typescript/icons/MicOff.d.ts +1 -1
  134. package/dist/typescript/icons/MicOff.d.ts.map +1 -1
  135. package/dist/typescript/icons/Phone.d.ts +1 -1
  136. package/dist/typescript/icons/Phone.d.ts.map +1 -1
  137. package/dist/typescript/icons/PhoneDown.d.ts +1 -1
  138. package/dist/typescript/icons/PhoneDown.d.ts.map +1 -1
  139. package/dist/typescript/icons/PinVertical.d.ts +1 -1
  140. package/dist/typescript/icons/PinVertical.d.ts.map +1 -1
  141. package/dist/typescript/icons/Reaction.d.ts +1 -1
  142. package/dist/typescript/icons/Reaction.d.ts.map +1 -1
  143. package/dist/typescript/icons/ScreenShare.d.ts +1 -1
  144. package/dist/typescript/icons/ScreenShare.d.ts.map +1 -1
  145. package/dist/typescript/icons/ScreenShareIndicator.d.ts +1 -1
  146. package/dist/typescript/icons/ScreenShareIndicator.d.ts.map +1 -1
  147. package/dist/typescript/icons/Spotlight.d.ts +1 -1
  148. package/dist/typescript/icons/Spotlight.d.ts.map +1 -1
  149. package/dist/typescript/icons/StopScreenShare.d.ts +1 -1
  150. package/dist/typescript/icons/StopScreenShare.d.ts.map +1 -1
  151. package/dist/typescript/icons/Video.d.ts +1 -1
  152. package/dist/typescript/icons/Video.d.ts.map +1 -1
  153. package/dist/typescript/icons/VideoSlash.d.ts +1 -1
  154. package/dist/typescript/icons/VideoSlash.d.ts.map +1 -1
  155. package/dist/typescript/index.d.ts +1 -0
  156. package/dist/typescript/index.d.ts.map +1 -1
  157. package/dist/typescript/modules/call-manager/CallManager.d.ts +67 -0
  158. package/dist/typescript/modules/call-manager/CallManager.d.ts.map +1 -0
  159. package/dist/typescript/modules/call-manager/PrevLibDetection.d.ts +13 -0
  160. package/dist/typescript/modules/call-manager/PrevLibDetection.d.ts.map +1 -0
  161. package/dist/typescript/modules/call-manager/index.d.ts +4 -0
  162. package/dist/typescript/modules/call-manager/index.d.ts.map +1 -0
  163. package/dist/typescript/modules/call-manager/types.d.ts +15 -0
  164. package/dist/typescript/modules/call-manager/types.d.ts.map +1 -0
  165. package/dist/typescript/providers/StreamCall/AppStateListener.d.ts.map +1 -1
  166. package/dist/typescript/theme/theme.d.ts +1 -2
  167. package/dist/typescript/theme/theme.d.ts.map +1 -1
  168. package/dist/typescript/utils/internal/rxSubjects.d.ts +1 -1
  169. package/dist/typescript/utils/internal/rxSubjects.d.ts.map +1 -1
  170. package/dist/typescript/version.d.ts +1 -1
  171. package/dist/typescript/version.d.ts.map +1 -1
  172. package/ios/PictureInPicture/StreamPictureInPictureController.swift +5 -0
  173. package/ios/RTCViewPip.swift +15 -0
  174. package/ios/RTCViewPipManager.mm +1 -0
  175. package/ios/StreamInCallManager.m +26 -0
  176. package/ios/StreamInCallManager.swift +303 -0
  177. package/ios/StreamVideoReactNative-Bridging-Header.h +1 -0
  178. package/ios/StreamVideoReactNative.m +6 -5
  179. package/ios/StreamVideoReactNative.xcodeproj/project.xcworkspace/xcuserdata/santhoshvaiyapuri.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  180. package/ios/StreamVideoReactNative.xcodeproj/xcuserdata/santhoshvaiyapuri.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  181. package/package.json +33 -35
  182. package/src/components/Call/CallContent/CallContent.tsx +14 -10
  183. package/src/components/Call/CallContent/RTCViewPipIOS.tsx +17 -2
  184. package/src/components/Call/CallContent/RTCViewPipNative.tsx +8 -0
  185. package/src/components/Livestream/HostLivestream/HostLivestream.tsx +8 -3
  186. package/src/components/Livestream/LivestreamControls/ViewerLivestreamControls.tsx +11 -5
  187. package/src/components/Livestream/LivestreamLayout/LivestreamLayout.tsx +38 -29
  188. package/src/components/Livestream/ViewerLivestream/ViewerLivestream.tsx +8 -3
  189. package/src/hooks/useIsInPiPMode.tsx +4 -4
  190. package/src/hooks/usePermissionNotification.tsx +7 -12
  191. package/src/icons/Back.tsx +2 -2
  192. package/src/icons/BadNetwork.tsx +1 -1
  193. package/src/icons/CameraSwitch.tsx +2 -2
  194. package/src/icons/LivestreamControls.tsx +1 -1
  195. package/src/icons/Lock.tsx +1 -1
  196. package/src/icons/Maximize.tsx +1 -1
  197. package/src/icons/Mic.tsx +2 -2
  198. package/src/icons/MicOff.tsx +2 -2
  199. package/src/icons/Phone.tsx +2 -2
  200. package/src/icons/PhoneDown.tsx +1 -1
  201. package/src/icons/PinVertical.tsx +2 -2
  202. package/src/icons/Reaction.tsx +2 -2
  203. package/src/icons/ScreenShare.tsx +1 -1
  204. package/src/icons/ScreenShareIndicator.tsx +1 -1
  205. package/src/icons/Spotlight.tsx +2 -2
  206. package/src/icons/StopScreenShare.tsx +1 -1
  207. package/src/icons/Video.tsx +2 -2
  208. package/src/icons/VideoSlash.tsx +2 -2
  209. package/src/index.ts +1 -0
  210. package/src/modules/call-manager/CallManager.ts +116 -0
  211. package/src/modules/call-manager/PrevLibDetection.ts +27 -0
  212. package/src/modules/call-manager/index.ts +5 -0
  213. package/src/modules/call-manager/native-module.d.ts +80 -0
  214. package/src/modules/call-manager/types.ts +25 -0
  215. package/src/providers/StreamCall/AppStateListener.tsx +6 -9
  216. package/src/theme/theme.ts +2 -2
  217. package/src/utils/internal/rxSubjects.ts +1 -1
  218. package/src/version.ts +1 -1
  219. package/CHANGELOG.md +0 -2783
@@ -10,6 +10,7 @@ import {
10
10
  ViewerLeaveStreamButton as DefaultViewerLeaveStreamButton,
11
11
  type ViewerLeaveStreamButtonProps,
12
12
  } from './ViewerLeaveStreamButton';
13
+ import { callManager } from '../../../modules/call-manager';
13
14
  import { useTheme } from '../../../contexts';
14
15
  import { Z_INDEX } from '../../../constants';
15
16
  import {
@@ -18,12 +19,11 @@ import {
18
19
  LiveIndicator,
19
20
  } from '../LivestreamTopView';
20
21
  import { IconWrapper, Maximize } from '../../../icons';
21
- import InCallManager from 'react-native-incall-manager';
22
22
  import {
23
- VolumeOff,
24
- VolumeOn,
25
23
  PauseIcon,
26
24
  PlayIcon,
25
+ VolumeOff,
26
+ VolumeOn,
27
27
  } from '../../../icons/LivestreamControls';
28
28
 
29
29
  /**
@@ -104,10 +104,16 @@ export const ViewerLivestreamControls = ({
104
104
  };
105
105
 
106
106
  const toggleAudio = () => {
107
- setIsMuted(!isMuted);
108
- InCallManager.setForceSpeakerphoneOn(isMuted);
107
+ const shouldMute = !isMuted;
108
+ callManager.speaker.setMute(shouldMute);
109
+ setIsMuted(shouldMute);
109
110
  };
110
111
 
112
+ useEffect(() => {
113
+ // always unmute audio output on mount for consistency
114
+ callManager.speaker.setMute(false);
115
+ }, []);
116
+
111
117
  const togglePlayPause = () => {
112
118
  setIsPlaying(!isPlaying);
113
119
  showPlayPauseButtonWithTimeout();
@@ -1,5 +1,9 @@
1
1
  import React, { useCallback, useEffect, useState } from 'react';
2
- import { hasScreenShare, SfuModels } from '@stream-io/video-client';
2
+ import {
3
+ hasScreenShare,
4
+ SfuModels,
5
+ StreamVideoParticipant,
6
+ } from '@stream-io/video-client';
3
7
  import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
4
8
  import { StyleSheet, View, type ViewStyle } from 'react-native';
5
9
  import { usePaginatedLayoutSortPreset } from '../../../hooks/usePaginatedLayoutSortPreset';
@@ -9,6 +13,7 @@ import {
9
13
  type VideoRendererProps,
10
14
  } from '../../Participant';
11
15
  import type { ScreenShareOverlayProps } from '../../utility/ScreenShareOverlay';
16
+ import { useTrackDimensions } from '../../../hooks';
12
17
 
13
18
  /**
14
19
  * Props for the LivestreamLayout component.
@@ -56,11 +61,6 @@ export const LivestreamLayout = ({
56
61
  React.ComponentProps<NonNullable<typeof VideoRenderer>>['objectFit']
57
62
  >();
58
63
 
59
- // no need to pass object fit for local participant as the dimensions are for remote tracks
60
- const objectFitToBeSet = currentSpeaker?.isLocalParticipant
61
- ? undefined
62
- : objectFit;
63
-
64
64
  const onDimensionsChange = useCallback(
65
65
  (d: SfuModels.VideoDimension | undefined) => {
66
66
  if (d) {
@@ -84,48 +84,57 @@ export const LivestreamLayout = ({
84
84
  livestreamLayout.container,
85
85
  ]}
86
86
  >
87
- <RemoteVideoTrackDimensionsRenderLessComponent
88
- onDimensionsChange={onDimensionsChange}
89
- />
90
87
  {VideoRenderer &&
91
88
  hasOngoingScreenShare &&
92
89
  presenter &&
93
90
  (presenter.isLocalParticipant && ScreenShareOverlay ? (
94
91
  <ScreenShareOverlay />
95
92
  ) : (
96
- <VideoRenderer trackType="screenShareTrack" participant={presenter} />
93
+ <>
94
+ <VideoRenderer
95
+ trackType="screenShareTrack"
96
+ objectFit={objectFit}
97
+ participant={presenter}
98
+ />
99
+ <VideoTrackDimensionsRenderLessComponent
100
+ onDimensionsChange={onDimensionsChange}
101
+ participant={presenter}
102
+ trackType="screenShareTrack"
103
+ />
104
+ </>
97
105
  ))}
98
106
  {VideoRenderer && !hasOngoingScreenShare && currentSpeaker && (
99
- <VideoRenderer
100
- participant={currentSpeaker}
101
- objectFit={objectFitToBeSet}
102
- trackType="videoTrack"
103
- />
107
+ <>
108
+ <VideoRenderer
109
+ participant={currentSpeaker}
110
+ objectFit={objectFit}
111
+ trackType="videoTrack"
112
+ />
113
+ <VideoTrackDimensionsRenderLessComponent
114
+ onDimensionsChange={onDimensionsChange}
115
+ participant={currentSpeaker}
116
+ trackType="videoTrack"
117
+ />
118
+ </>
104
119
  )}
105
120
  </View>
106
121
  );
107
122
  };
108
123
 
109
- const RemoteVideoTrackDimensionsRenderLessComponent = ({
124
+ const VideoTrackDimensionsRenderLessComponent = ({
110
125
  onDimensionsChange,
126
+ participant,
127
+ trackType,
111
128
  }: {
112
129
  onDimensionsChange: (d: SfuModels.VideoDimension | undefined) => void;
130
+ participant: StreamVideoParticipant;
131
+ trackType: 'videoTrack' | 'screenShareTrack';
113
132
  }) => {
114
- const [dimension, setDimension] = useState<SfuModels.VideoDimension>();
115
- const { useCallStatsReport } = useCallStateHooks();
116
- const statsReport = useCallStatsReport();
117
- const highestFrameHeight = statsReport?.subscriberStats?.highestFrameHeight;
118
- const highestFrameWidth = statsReport?.subscriberStats?.highestFrameWidth;
119
-
120
- useEffect(() => {
121
- if (highestFrameHeight && highestFrameWidth) {
122
- setDimension({ height: highestFrameHeight, width: highestFrameWidth });
123
- }
124
- }, [highestFrameHeight, highestFrameWidth]);
133
+ const { width, height } = useTrackDimensions(participant, trackType);
125
134
 
126
135
  useEffect(() => {
127
- onDimensionsChange(dimension);
128
- }, [dimension, onDimensionsChange]);
136
+ onDimensionsChange({ width, height });
137
+ }, [width, height, onDimensionsChange]);
129
138
 
130
139
  return null;
131
140
  };
@@ -1,6 +1,5 @@
1
1
  import React, { useEffect, useMemo, useState } from 'react';
2
2
  import { StyleSheet, View } from 'react-native';
3
- import InCallManager from 'react-native-incall-manager';
4
3
  import { useTheme } from '../../../contexts';
5
4
  import { type ViewerLivestreamTopViewProps } from '../LivestreamTopView/ViewerLivestreamTopView';
6
5
  import {
@@ -20,6 +19,7 @@ import {
20
19
  import { CallingState, hasVideo } from '@stream-io/video-client';
21
20
  import { CallEndedView } from '../LivestreamPlayer/LivestreamEnded';
22
21
  import { ViewerLobby } from './ViewerLobby';
22
+ import { getRNInCallManagerLibNoThrow } from '../../../modules/call-manager/PrevLibDetection';
23
23
 
24
24
  /**
25
25
  * Props for the ViewerLivestream component.
@@ -102,8 +102,13 @@ export const ViewerLivestream = ({
102
102
 
103
103
  // Automatically route audio to speaker devices as relevant for watching videos.
104
104
  useEffect(() => {
105
- InCallManager.start({ media: 'video' });
106
- return () => InCallManager.stop();
105
+ const prevInCallManager = getRNInCallManagerLibNoThrow();
106
+ if (prevInCallManager) {
107
+ prevInCallManager.start({ media: 'video' });
108
+ return () => {
109
+ prevInCallManager.stop();
110
+ };
111
+ }
107
112
  }, []);
108
113
 
109
114
  useEffect(() => {
@@ -1,17 +1,17 @@
1
1
  import { useEffect, useState } from 'react';
2
2
  import { RxUtils } from '@stream-io/video-client';
3
- import { isInPiPModeAndroid$ } from '../utils/internal/rxSubjects';
3
+ import { isInPiPMode$ } from '../utils/internal/rxSubjects';
4
4
 
5
5
  export function useIsInPiPMode() {
6
6
  const [value, setValue] = useState<boolean>(() => {
7
- return RxUtils.getCurrentValue(isInPiPModeAndroid$);
7
+ return RxUtils.getCurrentValue(isInPiPMode$);
8
8
  });
9
9
 
10
10
  useEffect(() => {
11
- const subscription = isInPiPModeAndroid$.subscribe({
11
+ const subscription = isInPiPMode$.subscribe({
12
12
  next: setValue,
13
13
  error: (err) => {
14
- console.log('An error occurred while reading isInPiPModeAndroid$', err);
14
+ console.log('An error occurred while reading isInPiPMode$', err);
15
15
  setValue(false);
16
16
  },
17
17
  });
@@ -1,8 +1,9 @@
1
1
  import { CallingState, OwnCapability } from '@stream-io/video-client';
2
2
  import { useCallStateHooks } from '@stream-io/video-react-bindings';
3
- import { useCallback, useEffect } from 'react';
3
+ import { useEffect } from 'react';
4
4
  import { Alert } from 'react-native';
5
5
  import { usePrevious } from '../utils/hooks/usePrevious';
6
+ import { useEffectEvent } from '@stream-io/video-react-bindings';
6
7
 
7
8
  export type PermissionNotificationProps = {
8
9
  /**
@@ -32,13 +33,13 @@ export const usePermissionNotification = (
32
33
  const previousHasPermission = usePrevious(hasPermission);
33
34
  const callingState = useCallCallingState();
34
35
 
35
- const showGrantedNotification = useCallback(() => {
36
+ const showGrantedNotification = useEffectEvent(() => {
36
37
  Alert.alert(messageApproved);
37
- }, [messageApproved]);
38
+ });
38
39
 
39
- const showRevokedNotification = useCallback(() => {
40
+ const showRevokedNotification = useEffectEvent(() => {
40
41
  Alert.alert(messageRevoked);
41
- }, [messageRevoked]);
42
+ });
42
43
 
43
44
  useEffect(() => {
44
45
  // Permission state is not reliable before the call is joined,
@@ -51,11 +52,5 @@ export const usePermissionNotification = (
51
52
  } else if (!hasPermission && previousHasPermission) {
52
53
  showRevokedNotification();
53
54
  }
54
- }, [
55
- callingState,
56
- hasPermission,
57
- previousHasPermission,
58
- showGrantedNotification,
59
- showRevokedNotification,
60
- ]);
55
+ }, [callingState, hasPermission, previousHasPermission]);
61
56
  };
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import { Svg, Path } from 'react-native-svg';
3
- import { type ColorValue } from 'react-native/types';
2
+ import { Path, Svg } from 'react-native-svg';
3
+ import { type ColorValue } from 'react-native';
4
4
 
5
5
  type Props = {
6
6
  color: ColorValue;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { Path, Svg } from 'react-native-svg';
3
- import { type ColorValue } from 'react-native/types';
3
+ import { type ColorValue } from 'react-native';
4
4
 
5
5
  type Props = {
6
6
  color: ColorValue;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import { Svg, Path } from 'react-native-svg';
3
- import { type ColorValue } from 'react-native/types';
2
+ import { Path, Svg } from 'react-native-svg';
3
+ import { type ColorValue } from 'react-native';
4
4
 
5
5
  type Props = {
6
6
  color: ColorValue;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { Path, Svg } from 'react-native-svg';
3
- import { ColorValue } from 'react-native/types';
3
+ import { ColorValue } from 'react-native';
4
4
 
5
5
  type IconProps = {
6
6
  color: ColorValue;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import Svg, { Path } from 'react-native-svg';
3
- import { type ColorValue } from 'react-native/types';
3
+ import { type ColorValue } from 'react-native';
4
4
 
5
5
  type Props = {
6
6
  color: ColorValue;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { type ColorValue } from 'react-native/types';
2
+ import { type ColorValue } from 'react-native';
3
3
  import Svg, { Path } from 'react-native-svg';
4
4
 
5
5
  type IconProps = {
package/src/icons/Mic.tsx CHANGED
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import { Svg, Path } from 'react-native-svg';
3
- import { type ColorValue } from 'react-native/types';
2
+ import { Path, Svg } from 'react-native-svg';
3
+ import { type ColorValue } from 'react-native';
4
4
 
5
5
  type Props = {
6
6
  color: ColorValue;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import { Svg, Path } from 'react-native-svg';
3
- import { type ColorValue } from 'react-native/types';
2
+ import { Path, Svg } from 'react-native-svg';
3
+ import { type ColorValue } from 'react-native';
4
4
 
5
5
  type Props = {
6
6
  color: ColorValue;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import { Svg, Path } from 'react-native-svg';
3
- import { type ColorValue } from 'react-native/types';
2
+ import { Path, Svg } from 'react-native-svg';
3
+ import { type ColorValue } from 'react-native';
4
4
  import { IconTestIds } from '../constants/TestIds';
5
5
 
6
6
  type Props = {
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { Path, Svg } from 'react-native-svg';
3
- import { type ColorValue } from 'react-native/types';
3
+ import { type ColorValue } from 'react-native';
4
4
  import { IconTestIds } from '../constants/TestIds';
5
5
 
6
6
  type Props = {
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import { Svg, Path } from 'react-native-svg';
3
- import { type ColorValue } from 'react-native/types';
2
+ import { Path, Svg } from 'react-native-svg';
3
+ import { type ColorValue } from 'react-native';
4
4
 
5
5
  type Props = {
6
6
  color: ColorValue;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import { Svg, Path } from 'react-native-svg';
3
- import { type ColorValue } from 'react-native/types';
2
+ import { Path, Svg } from 'react-native-svg';
3
+ import { type ColorValue } from 'react-native';
4
4
 
5
5
  type Props = {
6
6
  color: ColorValue;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import Svg, { Path } from 'react-native-svg';
3
- import { type ColorValue } from 'react-native/types';
3
+ import { type ColorValue } from 'react-native';
4
4
  import { IconTestIds } from '../constants/TestIds';
5
5
 
6
6
  type Props = {
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import Svg, { Mask, Path } from 'react-native-svg';
3
- import { type ColorValue } from 'react-native/types';
3
+ import { type ColorValue } from 'react-native';
4
4
  import { IconTestIds } from '../constants/TestIds';
5
5
 
6
6
  type Props = {
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import { Svg, Path } from 'react-native-svg';
3
- import { type ColorValue } from 'react-native/types';
2
+ import { Path, Svg } from 'react-native-svg';
3
+ import { type ColorValue } from 'react-native';
4
4
 
5
5
  type Props = {
6
6
  color: ColorValue;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import Svg, { Path } from 'react-native-svg';
3
- import { type ColorValue } from 'react-native/types';
3
+ import { type ColorValue } from 'react-native';
4
4
 
5
5
  type Props = {
6
6
  color: ColorValue;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import { Svg, Path } from 'react-native-svg';
3
- import { type ColorValue } from 'react-native/types';
2
+ import { Path, Svg } from 'react-native-svg';
3
+ import { type ColorValue } from 'react-native';
4
4
 
5
5
  type Props = {
6
6
  color: ColorValue;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import { Svg, Path } from 'react-native-svg';
3
- import { type ColorValue } from 'react-native/types';
2
+ import { Path, Svg } from 'react-native-svg';
3
+ import { type ColorValue } from 'react-native';
4
4
  import { IconTestIds } from '../constants/TestIds';
5
5
 
6
6
  type Props = {
package/src/index.ts CHANGED
@@ -27,6 +27,7 @@ export * from './hooks';
27
27
  export * from './theme';
28
28
  export * from './utils';
29
29
  export * from './translations';
30
+ export * from './modules/call-manager';
30
31
 
31
32
  // Overriding 'StreamVideo' and 'StreamCall' from '@stream-io/video-react-bindings'
32
33
  // Explicitly re-exporting to resolve ambiguity.
@@ -0,0 +1,116 @@
1
+ import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
2
+ import { AudioDeviceStatus, StreamInCallManagerConfig } from './types';
3
+
4
+ const NativeManager = NativeModules.StreamInCallManager;
5
+
6
+ const invariant = (condition: boolean, message: string) => {
7
+ if (!condition) throw new Error(message);
8
+ };
9
+
10
+ class AndroidCallManager {
11
+ private eventEmitter?: NativeEventEmitter;
12
+
13
+ /**
14
+ * Get the current audio device status.
15
+ */
16
+ getAudioDeviceStatus = async (): Promise<AudioDeviceStatus> => {
17
+ invariant(Platform.OS === 'android', 'Supported only on Android');
18
+ return NativeManager.getAudioDeviceStatus();
19
+ };
20
+
21
+ /**
22
+ * Switches the audio device to the specified endpoint.
23
+ *
24
+ * @param endpointName the device name.
25
+ */
26
+ selectAudioDevice = (endpointName: string): void => {
27
+ invariant(Platform.OS === 'android', 'Supported only on Android');
28
+ NativeManager.chooseAudioDeviceEndpoint(endpointName);
29
+ };
30
+
31
+ /**
32
+ * Register a listener for audio device changes.
33
+ * @param onChange callback to be called when the audio device changes.
34
+ */
35
+ addAudioDeviceChangeListener = (
36
+ onChange: (audioDeviceStatus: AudioDeviceStatus) => void,
37
+ ): (() => void) => {
38
+ invariant(Platform.OS === 'android', 'Supported only on Android');
39
+ this.eventEmitter ??= new NativeEventEmitter(NativeManager);
40
+ const s = this.eventEmitter.addListener('onAudioDeviceChanged', onChange);
41
+ return () => s.remove();
42
+ };
43
+ }
44
+
45
+ class IOSCallManager {
46
+ /**
47
+ * Will trigger the iOS device selector.
48
+ */
49
+ showDeviceSelector = (): void => {
50
+ invariant(Platform.OS === 'ios', 'Supported only on iOS');
51
+ NativeManager.showAudioRoutePicker();
52
+ };
53
+ }
54
+
55
+ class SpeakerManager {
56
+ /**
57
+ * Mutes or unmutes the speaker.
58
+ */
59
+ setMute = (mute: boolean): void => {
60
+ if (mute) {
61
+ NativeManager.muteAudioOutput();
62
+ } else {
63
+ NativeManager.unmuteAudioOutput();
64
+ }
65
+ };
66
+
67
+ /**
68
+ * Forces speakerphone on/off.
69
+ */
70
+ setForceSpeakerphoneOn = (force: boolean): void => {
71
+ NativeManager.setForceSpeakerphoneOn(force);
72
+ };
73
+ }
74
+
75
+ export class CallManager {
76
+ android = new AndroidCallManager();
77
+ ios = new IOSCallManager();
78
+ speaker = new SpeakerManager();
79
+
80
+ /**
81
+ * Starts the in call manager.
82
+ *
83
+ * @param config.audioRole The audio role to set. It can be one of the following:
84
+ * - `'communicator'`: (Default) For use cases like video or voice calls.
85
+ * It prioritizes low latency and allows manual audio device switching.
86
+ * Audio routing is controlled by the SDK.
87
+ * - `'listener'`: For use cases like livestream viewing.
88
+ * It prioritizes high-quality stereo audio streaming.
89
+ * Audio routing is controlled by the OS, and manual switching is not supported.
90
+ *
91
+ * @param config.deviceEndpointType The default audio device endpoint type to set. It can be one of the following:
92
+ * - `'speaker'`: (Default) For normal video or voice calls.
93
+ * - `'earpiece'`: For voice-only mobile call type scenarios.
94
+ */
95
+ start = (config?: StreamInCallManagerConfig): void => {
96
+ NativeManager.setAudioRole(config?.audioRole ?? 'communicator');
97
+ if (config?.audioRole === 'communicator') {
98
+ const type = config.deviceEndpointType ?? 'speaker';
99
+ NativeManager.setDefaultAudioDeviceEndpointType(type);
100
+ }
101
+ NativeManager.start();
102
+ };
103
+
104
+ /**
105
+ * Stops the in call manager.
106
+ */
107
+ stop = (): void => {
108
+ NativeManager.stop();
109
+ };
110
+
111
+ /**
112
+ * For debugging purposes, will emit a log event with the current audio state.
113
+ * in the native layer.
114
+ */
115
+ logAudioState = (): void => NativeManager.logAudioState();
116
+ }
@@ -0,0 +1,27 @@
1
+ import { getLogger } from '@stream-io/video-client';
2
+
3
+ declare class RNInCallManagerLib {
4
+ start(setup?: {
5
+ auto?: boolean;
6
+ media?: 'video' | 'audio';
7
+ ringback?: string;
8
+ }): void;
9
+
10
+ stop(setup?: { busytone?: string }): void;
11
+ }
12
+
13
+ let rnInCallManagerLib: RNInCallManagerLib | undefined;
14
+
15
+ try {
16
+ rnInCallManagerLib = require('react-native-incall-manager').default;
17
+ } catch {}
18
+
19
+ export function getRNInCallManagerLibNoThrow() {
20
+ if (rnInCallManagerLib) {
21
+ getLogger(['getRNInCallManagerLibNoThrow'])(
22
+ 'debug',
23
+ 'react-native-incall-manager library is not required to be installed from 1.22.0 version of the @stream-io/video-react-native-sdk. Please check the migration documentation at https://getstream.io/video/docs/react-native/migration-guides/1.22.0/ for more details.',
24
+ );
25
+ }
26
+ return rnInCallManagerLib;
27
+ }
@@ -0,0 +1,5 @@
1
+ import { CallManager } from './CallManager';
2
+
3
+ export * from './types';
4
+
5
+ export const callManager = new CallManager();
@@ -0,0 +1,80 @@
1
+ import 'react-native';
2
+ import type { NativeModule } from 'react-native';
3
+ import type { AudioDeviceStatus, AudioRole, DeviceEndpointType } from './types';
4
+
5
+ export interface CallManager extends NativeModule {
6
+ /**
7
+ * Sets the audio role for the call. This should be done before calling **start()**.
8
+ *
9
+ * @param role The audio role to set. It can be one of the following:
10
+ * - `'communicator'`: (Default) For use cases like video or voice calls.
11
+ * It prioritizes low latency and allows manual audio device switching.
12
+ * Audio routing is controlled by the SDK.
13
+ * - `'listener'`: For use cases like livestream viewing.
14
+ * It prioritizes high-quality stereo audio streaming.
15
+ * Audio routing is controlled by the OS and manual switching is not supported.
16
+ */
17
+ setAudioRole: (role: AudioRole) => void;
18
+
19
+ /**
20
+ * Sets the default audio device endpoint type for the call. This should be done before calling **start()**.
21
+ * @param type The default audio device endpoint type to set. It can be one of the following:
22
+ * - `'speaker'`: (Default) For normal video or voice calls.
23
+ * - `'earpiece'`: For voice only mobile call type scenarios.
24
+ */
25
+ setDefaultAudioDeviceEndpointType: (type: DeviceEndpointType) => void;
26
+
27
+ /**
28
+ * Choose an audio device endpoint.
29
+ * @param endpointName - The name of the audio device endpoint to choose.
30
+ */
31
+ chooseAudioDeviceEndpoint: (endpoint: string) => void;
32
+
33
+ /**
34
+ * Get the current audio device status.
35
+ * @returns The audio device status.
36
+ */
37
+ getAudioDeviceStatus: () => Promise<AudioDeviceStatus>;
38
+
39
+ /**
40
+ * Shows the iOS audio route picker.
41
+ */
42
+ showAudioRoutePicker: () => void;
43
+
44
+ /**
45
+ * Start the in call manager.
46
+ */
47
+ start: () => void;
48
+
49
+ /**
50
+ * Stop the in call manager.
51
+ */
52
+ stop: () => void;
53
+
54
+ /**
55
+ * Mutes the speaker
56
+ */
57
+ muteAudioOutput: () => void;
58
+
59
+ /**
60
+ * Unmutes the speaker
61
+ */
62
+ unmuteAudioOutput: () => void;
63
+
64
+ /**
65
+ * Forces speakerphone on/off.
66
+ */
67
+ setForceSpeakerphoneOn: (boolean) => void;
68
+
69
+ /**
70
+ * Log the current audio state natively.
71
+ * Meant for debugging purposes.
72
+ */
73
+ logAudioState: () => void;
74
+ }
75
+
76
+ declare module 'react-native' {
77
+ interface NativeModulesStatic {
78
+ StreamInCallManager: CallManager;
79
+ }
80
+ }