@stream-io/video-react-native-sdk 1.27.4 → 1.28.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 (36) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/android/src/main/java/com/streamvideo/reactnative/audio/AudioDeviceManager.kt +19 -11
  3. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/AudioFocusUtil.kt +23 -9
  4. package/android/src/main/java/com/streamvideo/reactnative/callmanager/StreamInCallManagerModule.kt +48 -14
  5. package/dist/commonjs/index.js +2 -0
  6. package/dist/commonjs/index.js.map +1 -1
  7. package/dist/commonjs/modules/call-manager/CallManager.js +5 -0
  8. package/dist/commonjs/modules/call-manager/CallManager.js.map +1 -1
  9. package/dist/commonjs/utils/internal/registerSDKGlobals.js +34 -0
  10. package/dist/commonjs/utils/internal/registerSDKGlobals.js.map +1 -0
  11. package/dist/commonjs/version.js +1 -1
  12. package/dist/module/index.js +2 -0
  13. package/dist/module/index.js.map +1 -1
  14. package/dist/module/modules/call-manager/CallManager.js +5 -0
  15. package/dist/module/modules/call-manager/CallManager.js.map +1 -1
  16. package/dist/module/utils/internal/registerSDKGlobals.js +28 -0
  17. package/dist/module/utils/internal/registerSDKGlobals.js.map +1 -0
  18. package/dist/module/version.js +1 -1
  19. package/dist/typescript/index.d.ts.map +1 -1
  20. package/dist/typescript/modules/call-manager/CallManager.d.ts +2 -0
  21. package/dist/typescript/modules/call-manager/CallManager.d.ts.map +1 -1
  22. package/dist/typescript/modules/call-manager/types.d.ts +1 -0
  23. package/dist/typescript/modules/call-manager/types.d.ts.map +1 -1
  24. package/dist/typescript/utils/internal/registerSDKGlobals.d.ts +2 -0
  25. package/dist/typescript/utils/internal/registerSDKGlobals.d.ts.map +1 -0
  26. package/dist/typescript/version.d.ts +1 -1
  27. package/ios/StreamInCallManager.m +4 -0
  28. package/ios/StreamInCallManager.swift +213 -88
  29. package/package.json +7 -7
  30. package/src/index.ts +2 -0
  31. package/src/modules/call-manager/CallManager.ts +5 -0
  32. package/src/modules/call-manager/native-module.d.ts +11 -0
  33. package/src/modules/call-manager/types.ts +1 -0
  34. package/src/utils/internal/registerSDKGlobals.ts +30 -0
  35. package/src/version.ts +1 -1
  36. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/AudioSetupStoreUtil.kt +0 -41
package/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
4
 
5
+ ## [1.28.0](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-native-sdk-1.27.4...@stream-io/video-react-native-sdk-1.28.0) (2026-01-20)
6
+
7
+ ### Dependency Updates
8
+
9
+ - `@stream-io/noise-cancellation-react-native` updated to version `0.5.0`
10
+ - `@stream-io/video-filters-react-native` updated to version `0.10.0`
11
+ - `@stream-io/video-client` updated to version `1.41.0`
12
+ - `@stream-io/video-react-bindings` updated to version `1.13.0`
13
+
14
+ ### Features
15
+
16
+ - stereo audio output support RN-332 ([#2038](https://github.com/GetStream/stream-video-js/issues/2038)) ([2938037](https://github.com/GetStream/stream-video-js/commit/2938037d18e70ccf112a089eb3ec44cb034aed1d))
17
+
5
18
  ## [1.27.4](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-native-sdk-1.27.3...@stream-io/video-react-native-sdk-1.27.4) (2026-01-16)
6
19
 
7
20
  ### Dependency Updates
@@ -31,7 +31,6 @@ import com.streamvideo.reactnative.audio.utils.AudioDeviceEndpointUtils
31
31
  import com.streamvideo.reactnative.audio.utils.AudioFocusUtil
32
32
  import com.streamvideo.reactnative.audio.utils.AudioManagerUtil
33
33
  import com.streamvideo.reactnative.audio.utils.AudioManagerUtil.Companion.getAvailableAudioDevices
34
- import com.streamvideo.reactnative.audio.utils.AudioSetupStoreUtil
35
34
  import com.streamvideo.reactnative.audio.utils.CallAudioRole
36
35
  import com.streamvideo.reactnative.callmanager.ProximityManager
37
36
  import com.streamvideo.reactnative.callmanager.StreamInCallManagerModule
@@ -90,6 +89,8 @@ class AudioDeviceManager(
90
89
  @EndpointType
91
90
  private var userSelectedAudioDevice: Int? = null
92
91
 
92
+ var enableStereo: Boolean = false
93
+
93
94
  private val mAudioManager =
94
95
  mReactContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager
95
96
 
@@ -99,7 +100,6 @@ class AudioDeviceManager(
99
100
  private var audioFocusLost = false
100
101
 
101
102
  private var audioFocusUtil = AudioFocusUtil(mAudioManager, this)
102
- private var audioSetupStoreUtil = AudioSetupStoreUtil(mReactContext, mAudioManager, this)
103
103
 
104
104
  var callAudioRole: CallAudioRole = CallAudioRole.Communicator
105
105
 
@@ -113,33 +113,38 @@ class AudioDeviceManager(
113
113
  mAudioManager.registerAudioDeviceCallback(this, null)
114
114
  }
115
115
 
116
+ fun setup() {
117
+ if (callAudioRole == CallAudioRole.Communicator) {
118
+ mAudioManager.mode = AudioManager.MODE_IN_COMMUNICATION
119
+ } else {
120
+ // Audio routing is handled automatically by the system in normal media mode
121
+ // and bluetooth microphones may not work on some devices.
122
+ mAudioManager.mode = AudioManager.MODE_NORMAL
123
+ }
124
+ audioFocusUtil.setup(callAudioRole, mReactContext)
125
+ }
126
+
116
127
  fun start(activity: Activity) {
117
128
  runInAudioThread {
129
+ setup()
118
130
  userSelectedAudioDevice = null
119
131
  selectedAudioDeviceEndpoint = null
120
- audioSetupStoreUtil.storeOriginalAudioSetup()
121
132
  if (callAudioRole == CallAudioRole.Communicator) {
122
133
  // Audio routing is manually controlled by the SDK in communication media mode
123
134
  // and local microphone can be published
124
- mAudioManager.mode = AudioManager.MODE_IN_COMMUNICATION
125
135
  activity.volumeControlStream = AudioManager.STREAM_VOICE_CALL
126
136
  bluetoothManager.start()
127
137
  mAudioManager.registerAudioDeviceCallback(this, null)
128
138
  updateAudioDeviceState()
129
139
  proximityManager.start()
130
140
  } else {
131
- // Audio routing is handled automatically by the system in normal media mode
132
- // and bluetooth microphones may not work on some devices.
133
- mAudioManager.mode = AudioManager.MODE_NORMAL
134
141
  activity.volumeControlStream = AudioManager.USE_DEFAULT_STREAM_TYPE
135
142
  }
136
-
137
- audioSetupStoreUtil.storeOriginalAudioSetup()
138
143
  audioFocusUtil.requestFocus(callAudioRole, mReactContext)
139
144
  }
140
145
  }
141
146
 
142
- fun stop() {
147
+ fun stop(activity: Activity) {
143
148
  runInAudioThread {
144
149
  if (callAudioRole == CallAudioRole.Communicator) {
145
150
  if (Build.VERSION.SDK_INT >= 31) {
@@ -147,10 +152,13 @@ class AudioDeviceManager(
147
152
  } else {
148
153
  mAudioManager.setSpeakerphoneOn(false)
149
154
  }
155
+ callAudioRole = CallAudioRole.Communicator
156
+ enableStereo = false
157
+ defaultAudioDevice = AudioDeviceEndpoint.TYPE_SPEAKER
150
158
  bluetoothManager.stop()
151
159
  proximityManager.stop()
152
160
  }
153
- audioSetupStoreUtil.restoreOriginalAudioSetup()
161
+ activity.volumeControlStream = AudioManager.USE_DEFAULT_STREAM_TYPE
154
162
  audioFocusUtil.abandonFocus()
155
163
  }
156
164
  }
@@ -4,6 +4,7 @@ import android.media.AudioAttributes
4
4
  import android.media.AudioFocusRequest
5
5
  import android.media.AudioManager
6
6
  import android.os.Build
7
+ import androidx.annotation.RequiresApi
7
8
  import com.facebook.react.bridge.ReactContext
8
9
  import com.oney.WebRTCModule.WebRTCModule
9
10
  import org.webrtc.audio.JavaAudioDeviceModule
@@ -25,18 +26,31 @@ class AudioFocusUtil(
25
26
  private lateinit var request: AudioFocusRequest
26
27
 
27
28
 
29
+ @RequiresApi(26)
30
+ private fun getAudioAttributes(mode: CallAudioRole): AudioAttributes {
31
+ return AudioAttributes.Builder()
32
+ .setUsage(if (mode == CallAudioRole.Communicator) AudioAttributes.USAGE_VOICE_COMMUNICATION else AudioAttributes.USAGE_MEDIA)
33
+ .setContentType(if (mode == CallAudioRole.Communicator) AudioAttributes.CONTENT_TYPE_SPEECH else AudioAttributes.CONTENT_TYPE_MUSIC)
34
+ .build()
35
+ }
36
+
37
+ private fun setup(audioAttributes: AudioAttributes, reactContext: ReactContext) {
38
+ val webRTCModule = reactContext.getNativeModule(WebRTCModule::class.java)!!
39
+ val adm = webRTCModule.audioDeviceModule as JavaAudioDeviceModule
40
+ WebRtcAudioTrackHelper.setAudioOutputAttributes(adm, audioAttributes)
41
+ }
42
+
43
+ fun setup(mode: CallAudioRole, reactContext: ReactContext) {
44
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
45
+ val audioAttributes = getAudioAttributes(mode)
46
+ setup(audioAttributes, reactContext)
47
+ }
48
+ }
28
49
 
29
50
  fun requestFocus(mode: CallAudioRole, reactContext: ReactContext) {
30
51
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
31
- val audioAttributes = AudioAttributes.Builder()
32
- .setUsage(if (mode == CallAudioRole.Communicator) AudioAttributes.USAGE_VOICE_COMMUNICATION else AudioAttributes.USAGE_MEDIA)
33
- .setContentType(if (mode == CallAudioRole.Communicator) AudioAttributes.CONTENT_TYPE_SPEECH else AudioAttributes.CONTENT_TYPE_MUSIC)
34
- .build()
35
-
36
- // 1. set audio attributes to webrtc
37
- val webRTCModule = reactContext.getNativeModule(WebRTCModule::class.java)!!
38
- val adm = webRTCModule.audioDeviceModule as JavaAudioDeviceModule
39
- WebRtcAudioTrackHelper.setAudioOutputAttributes(adm, audioAttributes)
52
+ val audioAttributes = getAudioAttributes(mode)
53
+ setup(audioAttributes, reactContext)
40
54
 
41
55
  // 2. request the audio focus with the audio attributes
42
56
  request = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
@@ -80,6 +80,24 @@ class StreamInCallManagerModule(reactContext: ReactApplicationContext) :
80
80
  }
81
81
  }
82
82
 
83
+ @ReactMethod
84
+ fun setEnableStereoAudioOutput(enabled: Boolean) {
85
+ AudioDeviceManager.runInAudioThread {
86
+ if (audioManagerActivated) {
87
+ Log.e(TAG, "setEnableStereoAudioOutput(): AudioManager is already activated and so enabling stereo audio output cannot be changed")
88
+ return@runInAudioThread
89
+ }
90
+ mAudioDeviceManager.enableStereo = enabled
91
+ }
92
+ }
93
+
94
+ @ReactMethod
95
+ fun setup() {
96
+ AudioDeviceManager.runInAudioThread {
97
+ mAudioDeviceManager.setup()
98
+ }
99
+ }
100
+
83
101
  @ReactMethod
84
102
  fun start() {
85
103
  AudioDeviceManager.runInAudioThread {
@@ -99,10 +117,12 @@ class StreamInCallManagerModule(reactContext: ReactApplicationContext) :
99
117
  AudioDeviceManager.runInAudioThread {
100
118
  if (audioManagerActivated) {
101
119
  Log.d(TAG, "stop() mAudioDeviceManager")
102
- mAudioDeviceManager.stop()
120
+ reactApplicationContext.currentActivity?.let {
121
+ mAudioDeviceManager.stop(it)
122
+ audioManagerActivated = false
123
+ }
103
124
  setMicrophoneMute(false)
104
125
  setKeepScreenOn(false)
105
- audioManagerActivated = false
106
126
  }
107
127
  }
108
128
  }
@@ -124,11 +144,16 @@ class StreamInCallManagerModule(reactContext: ReactApplicationContext) :
124
144
  @Suppress("unused")
125
145
  @ReactMethod
126
146
  fun setForceSpeakerphoneOn(enable: Boolean) {
127
- if (mAudioDeviceManager.callAudioRole !== CallAudioRole.Communicator) {
128
- Log.e(TAG, "setForceSpeakerphoneOn() is not supported when audio role is not Communicator")
129
- return
147
+ AudioDeviceManager.runInAudioThread {
148
+ if (mAudioDeviceManager.callAudioRole !== CallAudioRole.Communicator) {
149
+ Log.e(
150
+ TAG,
151
+ "setForceSpeakerphoneOn() is not supported when audio role is not Communicator"
152
+ )
153
+ return@runInAudioThread
154
+ }
155
+ mAudioDeviceManager.setSpeakerphoneOn(enable)
130
156
  }
131
- mAudioDeviceManager.setSpeakerphoneOn(enable)
132
157
  }
133
158
 
134
159
  @ReactMethod
@@ -152,23 +177,32 @@ class StreamInCallManagerModule(reactContext: ReactApplicationContext) :
152
177
  @Suppress("unused")
153
178
  @ReactMethod
154
179
  fun chooseAudioDeviceEndpoint(endpointDeviceName: String) {
155
- if (mAudioDeviceManager.callAudioRole !== CallAudioRole.Communicator) {
156
- Log.e(TAG, "chooseAudioDeviceEndpoint() is not supported when audio role is not Communicator")
157
- return
180
+ AudioDeviceManager.runInAudioThread {
181
+ if (mAudioDeviceManager.callAudioRole !== CallAudioRole.Communicator) {
182
+ Log.e(
183
+ TAG,
184
+ "chooseAudioDeviceEndpoint() is not supported when audio role is not Communicator"
185
+ )
186
+ return@runInAudioThread
187
+ }
188
+ mAudioDeviceManager.switchDeviceFromDeviceName(
189
+ endpointDeviceName
190
+ )
158
191
  }
159
- mAudioDeviceManager.switchDeviceFromDeviceName(
160
- endpointDeviceName
161
- )
162
192
  }
163
193
 
164
194
  @ReactMethod
165
195
  fun muteAudioOutput() {
166
- mAudioDeviceManager.muteAudioOutput()
196
+ AudioDeviceManager.runInAudioThread {
197
+ mAudioDeviceManager.muteAudioOutput()
198
+ }
167
199
  }
168
200
 
169
201
  @ReactMethod
170
202
  fun unmuteAudioOutput() {
171
- mAudioDeviceManager.unmuteAudioOutput()
203
+ AudioDeviceManager.runInAudioThread {
204
+ mAudioDeviceManager.unmuteAudioOutput()
205
+ }
172
206
  }
173
207
 
174
208
 
@@ -26,6 +26,7 @@ require("intl-pluralrules");
26
26
  var _reactNativeWebrtc = require("@stream-io/react-native-webrtc");
27
27
  var _Logger = _interopRequireDefault(require("@stream-io/react-native-webrtc/src/Logger"));
28
28
  var _reactNative = require("react-native");
29
+ var _registerSDKGlobals = require("./utils/internal/registerSDKGlobals");
29
30
  var _videoClient = require("@stream-io/video-client");
30
31
  Object.keys(_videoClient).forEach(function (key) {
31
32
  if (key === "default" || key === "__esModule") return;
@@ -160,6 +161,7 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
160
161
  // Reference: https://github.com/react-native-webrtc/react-native-webrtc/blob/16cff1523da457dbcc27bb0744ee2bad3a987c41/Documentation/BasicUsage.md#registering-globals
161
162
  if (_reactNative.Platform.OS !== 'web') {
162
163
  (0, _reactNativeWebrtc.registerGlobals)();
164
+ (0, _registerSDKGlobals.registerSDKGlobals)();
163
165
  }
164
166
 
165
167
  // only enable warning and error logs from webrtc library
@@ -1 +1 @@
1
- {"version":3,"names":["_setClientDetails","require","_reactNativeWebrtc","_Logger","_interopRequireDefault","_reactNative","_videoClient","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get","_videoReactBindings","_components","_contexts","_hooks","_theme","_utils","_translations","_callManager","_StreamVideo","_StreamCall","_NoiseCancellation","e","__esModule","default","Platform","OS","registerGlobals","Logger","enable","ROOT_PREFIX","setClientDetails"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_setClientDetails","require","_reactNativeWebrtc","_Logger","_interopRequireDefault","_reactNative","_registerSDKGlobals","_videoClient","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get","_videoReactBindings","_components","_contexts","_hooks","_theme","_utils","_translations","_callManager","_StreamVideo","_StreamCall","_NoiseCancellation","e","__esModule","default","Platform","OS","registerGlobals","registerSDKGlobals","Logger","enable","ROOT_PREFIX","setClientDetails"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"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","ignoreList":[]}
@@ -86,6 +86,8 @@ class CallManager {
86
86
  * @param config.deviceEndpointType The default audio device endpoint type to set. It can be one of the following:
87
87
  * - `'speaker'`: (Default) For normal video or voice calls.
88
88
  * - `'earpiece'`: For voice-only mobile call type scenarios.
89
+ *
90
+ * @param config.enableStereoAudioOutput Whether to enable stereo audio output. Only supported for listener audio role.
89
91
  */
90
92
  start = config => {
91
93
  NativeManager.setAudioRole(config?.audioRole ?? 'communicator');
@@ -93,6 +95,9 @@ class CallManager {
93
95
  const type = config.deviceEndpointType ?? 'speaker';
94
96
  NativeManager.setDefaultAudioDeviceEndpointType(type);
95
97
  }
98
+ if (config?.audioRole === 'listener' && config.enableStereoAudioOutput) {
99
+ NativeManager.setEnableStereoAudioOutput(true);
100
+ }
96
101
  NativeManager.start();
97
102
  };
98
103
 
@@ -1 +1 @@
1
- {"version":3,"names":["_reactNative","require","NativeManager","NativeModules","StreamInCallManager","invariant","condition","message","Error","AndroidCallManager","getAudioDeviceStatus","Platform","OS","selectAudioDevice","endpointName","chooseAudioDeviceEndpoint","addAudioDeviceChangeListener","onChange","eventEmitter","NativeEventEmitter","s","addListener","remove","IOSCallManager","showDeviceSelector","showAudioRoutePicker","SpeakerManager","setMute","mute","muteAudioOutput","unmuteAudioOutput","setForceSpeakerphoneOn","force","CallManager","android","ios","speaker","start","config","setAudioRole","audioRole","type","deviceEndpointType","setDefaultAudioDeviceEndpointType","stop","logAudioState","exports"],"sourceRoot":"../../../../src","sources":["modules/call-manager/CallManager.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_reactNative","require","NativeManager","NativeModules","StreamInCallManager","invariant","condition","message","Error","AndroidCallManager","getAudioDeviceStatus","Platform","OS","selectAudioDevice","endpointName","chooseAudioDeviceEndpoint","addAudioDeviceChangeListener","onChange","eventEmitter","NativeEventEmitter","s","addListener","remove","IOSCallManager","showDeviceSelector","showAudioRoutePicker","SpeakerManager","setMute","mute","muteAudioOutput","unmuteAudioOutput","setForceSpeakerphoneOn","force","CallManager","android","ios","speaker","start","config","setAudioRole","audioRole","type","deviceEndpointType","setDefaultAudioDeviceEndpointType","enableStereoAudioOutput","setEnableStereoAudioOutput","stop","logAudioState","exports"],"sourceRoot":"../../../../src","sources":["modules/call-manager/CallManager.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.registerSDKGlobals = registerSDKGlobals;
7
+ var _reactNative = require("react-native");
8
+ const StreamInCallManagerNativeModule = _reactNative.NativeModules.StreamInCallManager;
9
+ const streamRNVideoSDKGlobals = {
10
+ callManager: {
11
+ setup: ({
12
+ default_device
13
+ }) => {
14
+ StreamInCallManagerNativeModule.setDefaultAudioDeviceEndpointType(default_device);
15
+ StreamInCallManagerNativeModule.setup();
16
+ },
17
+ start: () => {
18
+ StreamInCallManagerNativeModule.start();
19
+ },
20
+ stop: () => {
21
+ StreamInCallManagerNativeModule.stop();
22
+ }
23
+ }
24
+ };
25
+
26
+ // Note: The global type declaration for `streamRNVideoSDK` is defined in
27
+ // @stream-io/video-client/src/types.ts and is automatically available when
28
+ // importing from the client package.
29
+ function registerSDKGlobals() {
30
+ if (!global.streamRNVideoSDK) {
31
+ global.streamRNVideoSDK = streamRNVideoSDKGlobals;
32
+ }
33
+ }
34
+ //# sourceMappingURL=registerSDKGlobals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNative","require","StreamInCallManagerNativeModule","NativeModules","StreamInCallManager","streamRNVideoSDKGlobals","callManager","setup","default_device","setDefaultAudioDeviceEndpointType","start","stop","registerSDKGlobals","global","streamRNVideoSDK"],"sourceRoot":"../../../../src","sources":["utils/internal/registerSDKGlobals.ts"],"mappings":";;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AAEA,MAAMC,+BAA+B,GAAGC,0BAAa,CAACC,mBAAmB;AAEzE,MAAMC,uBAAgD,GAAG;EACvDC,WAAW,EAAE;IACXC,KAAK,EAAEA,CAAC;MAAEC;IAAe,CAAC,KAAK;MAC7BN,+BAA+B,CAACO,iCAAiC,CAC/DD,cACF,CAAC;MACDN,+BAA+B,CAACK,KAAK,CAAC,CAAC;IACzC,CAAC;IACDG,KAAK,EAAEA,CAAA,KAAM;MACXR,+BAA+B,CAACQ,KAAK,CAAC,CAAC;IACzC,CAAC;IACDC,IAAI,EAAEA,CAAA,KAAM;MACVT,+BAA+B,CAACS,IAAI,CAAC,CAAC;IACxC;EACF;AACF,CAAC;;AAED;AACA;AACA;AACO,SAASC,kBAAkBA,CAAA,EAAG;EACnC,IAAI,CAACC,MAAM,CAACC,gBAAgB,EAAE;IAC5BD,MAAM,CAACC,gBAAgB,GAAGT,uBAAuB;EACnD;AACF","ignoreList":[]}
@@ -4,5 +4,5 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.version = void 0;
7
- const version = exports.version = '1.27.4';
7
+ const version = exports.version = '1.28.0';
8
8
  //# sourceMappingURL=version.js.map
@@ -8,12 +8,14 @@ import 'intl-pluralrules';
8
8
  import { registerGlobals } from '@stream-io/react-native-webrtc';
9
9
  import Logger from '@stream-io/react-native-webrtc/src/Logger';
10
10
  import { Platform } from 'react-native';
11
+ import { registerSDKGlobals } from './utils/internal/registerSDKGlobals';
11
12
 
12
13
  // We're registering globals, because our video JS client is serving SDKs that use browser based webRTC functions.
13
14
  // This will result in creation of 2 global objects: `window` and `navigator`
14
15
  // Reference: https://github.com/react-native-webrtc/react-native-webrtc/blob/16cff1523da457dbcc27bb0744ee2bad3a987c41/Documentation/BasicUsage.md#registering-globals
15
16
  if (Platform.OS !== 'web') {
16
17
  registerGlobals();
18
+ registerSDKGlobals();
17
19
  }
18
20
 
19
21
  // only enable warning and error logs from webrtc library
@@ -1 +1 @@
1
- {"version":3,"names":["setClientDetails","registerGlobals","Logger","Platform","OS","enable","ROOT_PREFIX","StreamVideo","StreamCall"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"AAAA,SAASA,gBAAgB,QAAQ,0BAA0B;AAC3D;AACA,OAAO,wBAAwB;AAC/B;AACA,OAAO,gCAAgC;AACvC;AACA,OAAO,kBAAkB;AACzB,SAASC,eAAe,QAAQ,gCAAgC;AAChE,OAAOC,MAAM,MAAM,2CAA2C;AAC9D,SAASC,QAAQ,QAAQ,cAAc;;AAEvC;AACA;AACA;AACA,IAAIA,QAAQ,CAACC,EAAE,KAAK,KAAK,EAAE;EACzBH,eAAe,CAAC,CAAC;AACnB;;AAEA;AACAC,MAAM,CAACG,MAAM,CAAC,GAAGH,MAAM,CAACI,WAAW,eAAe,CAAC;AAEnD,cAAc,yBAAyB;AACvC,cAAc,iCAAiC;AAC/C,cAAc,cAAc;AAC5B,cAAc,YAAY;AAC1B,cAAc,SAAS;AACvB,cAAc,SAAS;AACvB,cAAc,SAAS;AACvB,cAAc,gBAAgB;AAC9B,cAAc,wBAAwB;;AAEtC;AACA;AACA,SAASC,WAAW,QAAQ,yBAAyB;AACrD,SAASC,UAAU,QAAQ,wBAAwB;AACnD,cAAc,+BAA+B;AAE7CR,gBAAgB,CAAC,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["setClientDetails","registerGlobals","Logger","Platform","registerSDKGlobals","OS","enable","ROOT_PREFIX","StreamVideo","StreamCall"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"AAAA,SAASA,gBAAgB,QAAQ,0BAA0B;AAC3D;AACA,OAAO,wBAAwB;AAC/B;AACA,OAAO,gCAAgC;AACvC;AACA,OAAO,kBAAkB;AACzB,SAASC,eAAe,QAAQ,gCAAgC;AAChE,OAAOC,MAAM,MAAM,2CAA2C;AAC9D,SAASC,QAAQ,QAAQ,cAAc;AACvC,SAASC,kBAAkB,QAAQ,qCAAqC;;AAExE;AACA;AACA;AACA,IAAID,QAAQ,CAACE,EAAE,KAAK,KAAK,EAAE;EACzBJ,eAAe,CAAC,CAAC;EACjBG,kBAAkB,CAAC,CAAC;AACtB;;AAEA;AACAF,MAAM,CAACI,MAAM,CAAC,GAAGJ,MAAM,CAACK,WAAW,eAAe,CAAC;AAEnD,cAAc,yBAAyB;AACvC,cAAc,iCAAiC;AAC/C,cAAc,cAAc;AAC5B,cAAc,YAAY;AAC1B,cAAc,SAAS;AACvB,cAAc,SAAS;AACvB,cAAc,SAAS;AACvB,cAAc,gBAAgB;AAC9B,cAAc,wBAAwB;;AAEtC;AACA;AACA,SAASC,WAAW,QAAQ,yBAAyB;AACrD,SAASC,UAAU,QAAQ,wBAAwB;AACnD,cAAc,+BAA+B;AAE7CT,gBAAgB,CAAC,CAAC","ignoreList":[]}
@@ -80,6 +80,8 @@ export class CallManager {
80
80
  * @param config.deviceEndpointType The default audio device endpoint type to set. It can be one of the following:
81
81
  * - `'speaker'`: (Default) For normal video or voice calls.
82
82
  * - `'earpiece'`: For voice-only mobile call type scenarios.
83
+ *
84
+ * @param config.enableStereoAudioOutput Whether to enable stereo audio output. Only supported for listener audio role.
83
85
  */
84
86
  start = config => {
85
87
  NativeManager.setAudioRole(config?.audioRole ?? 'communicator');
@@ -87,6 +89,9 @@ export class CallManager {
87
89
  const type = config.deviceEndpointType ?? 'speaker';
88
90
  NativeManager.setDefaultAudioDeviceEndpointType(type);
89
91
  }
92
+ if (config?.audioRole === 'listener' && config.enableStereoAudioOutput) {
93
+ NativeManager.setEnableStereoAudioOutput(true);
94
+ }
90
95
  NativeManager.start();
91
96
  };
92
97
 
@@ -1 +1 @@
1
- {"version":3,"names":["NativeEventEmitter","NativeModules","Platform","NativeManager","StreamInCallManager","invariant","condition","message","Error","AndroidCallManager","getAudioDeviceStatus","OS","selectAudioDevice","endpointName","chooseAudioDeviceEndpoint","addAudioDeviceChangeListener","onChange","eventEmitter","s","addListener","remove","IOSCallManager","showDeviceSelector","showAudioRoutePicker","SpeakerManager","setMute","mute","muteAudioOutput","unmuteAudioOutput","setForceSpeakerphoneOn","force","CallManager","android","ios","speaker","start","config","setAudioRole","audioRole","type","deviceEndpointType","setDefaultAudioDeviceEndpointType","stop","logAudioState"],"sourceRoot":"../../../../src","sources":["modules/call-manager/CallManager.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["NativeEventEmitter","NativeModules","Platform","NativeManager","StreamInCallManager","invariant","condition","message","Error","AndroidCallManager","getAudioDeviceStatus","OS","selectAudioDevice","endpointName","chooseAudioDeviceEndpoint","addAudioDeviceChangeListener","onChange","eventEmitter","s","addListener","remove","IOSCallManager","showDeviceSelector","showAudioRoutePicker","SpeakerManager","setMute","mute","muteAudioOutput","unmuteAudioOutput","setForceSpeakerphoneOn","force","CallManager","android","ios","speaker","start","config","setAudioRole","audioRole","type","deviceEndpointType","setDefaultAudioDeviceEndpointType","enableStereoAudioOutput","setEnableStereoAudioOutput","stop","logAudioState"],"sourceRoot":"../../../../src","sources":["modules/call-manager/CallManager.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,28 @@
1
+ import { NativeModules } from 'react-native';
2
+ const StreamInCallManagerNativeModule = NativeModules.StreamInCallManager;
3
+ const streamRNVideoSDKGlobals = {
4
+ callManager: {
5
+ setup: ({
6
+ default_device
7
+ }) => {
8
+ StreamInCallManagerNativeModule.setDefaultAudioDeviceEndpointType(default_device);
9
+ StreamInCallManagerNativeModule.setup();
10
+ },
11
+ start: () => {
12
+ StreamInCallManagerNativeModule.start();
13
+ },
14
+ stop: () => {
15
+ StreamInCallManagerNativeModule.stop();
16
+ }
17
+ }
18
+ };
19
+
20
+ // Note: The global type declaration for `streamRNVideoSDK` is defined in
21
+ // @stream-io/video-client/src/types.ts and is automatically available when
22
+ // importing from the client package.
23
+ export function registerSDKGlobals() {
24
+ if (!global.streamRNVideoSDK) {
25
+ global.streamRNVideoSDK = streamRNVideoSDKGlobals;
26
+ }
27
+ }
28
+ //# sourceMappingURL=registerSDKGlobals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["NativeModules","StreamInCallManagerNativeModule","StreamInCallManager","streamRNVideoSDKGlobals","callManager","setup","default_device","setDefaultAudioDeviceEndpointType","start","stop","registerSDKGlobals","global","streamRNVideoSDK"],"sourceRoot":"../../../../src","sources":["utils/internal/registerSDKGlobals.ts"],"mappings":"AACA,SAASA,aAAa,QAAQ,cAAc;AAE5C,MAAMC,+BAA+B,GAAGD,aAAa,CAACE,mBAAmB;AAEzE,MAAMC,uBAAgD,GAAG;EACvDC,WAAW,EAAE;IACXC,KAAK,EAAEA,CAAC;MAAEC;IAAe,CAAC,KAAK;MAC7BL,+BAA+B,CAACM,iCAAiC,CAC/DD,cACF,CAAC;MACDL,+BAA+B,CAACI,KAAK,CAAC,CAAC;IACzC,CAAC;IACDG,KAAK,EAAEA,CAAA,KAAM;MACXP,+BAA+B,CAACO,KAAK,CAAC,CAAC;IACzC,CAAC;IACDC,IAAI,EAAEA,CAAA,KAAM;MACVR,+BAA+B,CAACQ,IAAI,CAAC,CAAC;IACxC;EACF;AACF,CAAC;;AAED;AACA;AACA;AACA,OAAO,SAASC,kBAAkBA,CAAA,EAAG;EACnC,IAAI,CAACC,MAAM,CAACC,gBAAgB,EAAE;IAC5BD,MAAM,CAACC,gBAAgB,GAAGT,uBAAuB;EACnD;AACF","ignoreList":[]}
@@ -1,2 +1,2 @@
1
- export const version = '1.27.4';
1
+ export const version = '1.28.0';
2
2
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,+CAA+C;AAC/C,OAAO,wBAAwB,CAAC;AAChC,8BAA8B;AAC9B,OAAO,gCAAgC,CAAC;AACxC,6IAA6I;AAC7I,OAAO,kBAAkB,CAAC;AAe1B,cAAc,yBAAyB,CAAC;AACxC,cAAc,iCAAiC,CAAC;AAChD,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,wBAAwB,CAAC;AAIvC,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,cAAc,+BAA+B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,+CAA+C;AAC/C,OAAO,wBAAwB,CAAC;AAChC,8BAA8B;AAC9B,OAAO,gCAAgC,CAAC;AACxC,6IAA6I;AAC7I,OAAO,kBAAkB,CAAC;AAiB1B,cAAc,yBAAyB,CAAC;AACxC,cAAc,iCAAiC,CAAC;AAChD,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,wBAAwB,CAAC;AAIvC,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,cAAc,+BAA+B,CAAC"}
@@ -51,6 +51,8 @@ export declare class CallManager {
51
51
  * @param config.deviceEndpointType The default audio device endpoint type to set. It can be one of the following:
52
52
  * - `'speaker'`: (Default) For normal video or voice calls.
53
53
  * - `'earpiece'`: For voice-only mobile call type scenarios.
54
+ *
55
+ * @param config.enableStereoAudioOutput Whether to enable stereo audio output. Only supported for listener audio role.
54
56
  */
55
57
  start: (config?: StreamInCallManagerConfig) => void;
56
58
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"CallManager.d.ts","sourceRoot":"","sources":["../../../../src/modules/call-manager/CallManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAQvE,cAAM,kBAAkB;IACtB,OAAO,CAAC,YAAY,CAAC,CAAqB;IAE1C;;OAEG;IACH,oBAAoB,QAAa,OAAO,CAAC,iBAAiB,CAAC,CAGzD;IAEF;;;;OAIG;IACH,iBAAiB,GAAI,cAAc,MAAM,KAAG,IAAI,CAG9C;IAEF;;;OAGG;IACH,4BAA4B,GAC1B,UAAU,CAAC,iBAAiB,EAAE,iBAAiB,KAAK,IAAI,KACvD,CAAC,MAAM,IAAI,CAAC,CAKb;CACH;AAED,cAAM,cAAc;IAClB;;OAEG;IACH,kBAAkB,QAAO,IAAI,CAG3B;CACH;AAED,cAAM,cAAc;IAClB;;OAEG;IACH,OAAO,GAAI,MAAM,OAAO,KAAG,IAAI,CAM7B;IAEF;;OAEG;IACH,sBAAsB,GAAI,OAAO,OAAO,KAAG,IAAI,CAE7C;CACH;AAED,qBAAa,WAAW;IACtB,OAAO,qBAA4B;IACnC,GAAG,iBAAwB;IAC3B,OAAO,iBAAwB;IAE/B;;;;;;;;;;;;;;OAcG;IACH,KAAK,GAAI,SAAS,yBAAyB,KAAG,IAAI,CAOhD;IAEF;;OAEG;IACH,IAAI,QAAO,IAAI,CAEb;IAEF;;;OAGG;IACH,aAAa,QAAO,IAAI,CAAkC;CAC3D"}
1
+ {"version":3,"file":"CallManager.d.ts","sourceRoot":"","sources":["../../../../src/modules/call-manager/CallManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAQvE,cAAM,kBAAkB;IACtB,OAAO,CAAC,YAAY,CAAC,CAAqB;IAE1C;;OAEG;IACH,oBAAoB,QAAa,OAAO,CAAC,iBAAiB,CAAC,CAGzD;IAEF;;;;OAIG;IACH,iBAAiB,GAAI,cAAc,MAAM,KAAG,IAAI,CAG9C;IAEF;;;OAGG;IACH,4BAA4B,GAC1B,UAAU,CAAC,iBAAiB,EAAE,iBAAiB,KAAK,IAAI,KACvD,CAAC,MAAM,IAAI,CAAC,CAKb;CACH;AAED,cAAM,cAAc;IAClB;;OAEG;IACH,kBAAkB,QAAO,IAAI,CAG3B;CACH;AAED,cAAM,cAAc;IAClB;;OAEG;IACH,OAAO,GAAI,MAAM,OAAO,KAAG,IAAI,CAM7B;IAEF;;OAEG;IACH,sBAAsB,GAAI,OAAO,OAAO,KAAG,IAAI,CAE7C;CACH;AAED,qBAAa,WAAW;IACtB,OAAO,qBAA4B;IACnC,GAAG,iBAAwB;IAC3B,OAAO,iBAAwB;IAE/B;;;;;;;;;;;;;;;;OAgBG;IACH,KAAK,GAAI,SAAS,yBAAyB,KAAG,IAAI,CAUhD;IAEF;;OAEG;IACH,IAAI,QAAO,IAAI,CAEb;IAEF;;;OAGG;IACH,aAAa,QAAO,IAAI,CAAkC;CAC3D"}
@@ -11,5 +11,6 @@ export type StreamInCallManagerConfig = {
11
11
  deviceEndpointType?: DeviceEndpointType;
12
12
  } | {
13
13
  audioRole: 'listener';
14
+ enableStereoAudioOutput?: boolean;
14
15
  };
15
16
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/modules/call-manager/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,uBAAuB,GAC/B,kBAAkB,GAClB,UAAU,GACV,SAAS,GACT,eAAe,GACf,SAAS,GACT,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mBAAmB,EAAE,uBAAuB,CAAC;IAC7C,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,cAAc,GAAG,UAAU,CAAC;AACpD,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,UAAU,CAAC;AAExD,MAAM,MAAM,yBAAyB,GACjC;IACE,SAAS,EAAE,cAAc,CAAC;IAC1B,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;CACzC,GACD;IACE,SAAS,EAAE,UAAU,CAAC;CACvB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/modules/call-manager/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,uBAAuB,GAC/B,kBAAkB,GAClB,UAAU,GACV,SAAS,GACT,eAAe,GACf,SAAS,GACT,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mBAAmB,EAAE,uBAAuB,CAAC;IAC7C,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,cAAc,GAAG,UAAU,CAAC;AACpD,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,UAAU,CAAC;AAExD,MAAM,MAAM,yBAAyB,GACjC;IACE,SAAS,EAAE,cAAc,CAAC;IAC1B,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;CACzC,GACD;IACE,SAAS,EAAE,UAAU,CAAC;IACtB,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function registerSDKGlobals(): void;
2
+ //# sourceMappingURL=registerSDKGlobals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registerSDKGlobals.d.ts","sourceRoot":"","sources":["../../../../src/utils/internal/registerSDKGlobals.ts"],"names":[],"mappings":"AAyBA,wBAAgB,kBAAkB,SAIjC"}
@@ -1,2 +1,2 @@
1
- export declare const version = "1.27.4";
1
+ export declare const version = "1.28.0";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -7,6 +7,10 @@ RCT_EXTERN_METHOD(setAudioRole:(NSString *)audioRole)
7
7
 
8
8
  RCT_EXTERN_METHOD(setDefaultAudioDeviceEndpointType:(NSString *)endpointType)
9
9
 
10
+ RCT_EXTERN_METHOD(setEnableStereoAudioOutput:(BOOL)enable)
11
+
12
+ RCT_EXTERN_METHOD(setup)
13
+
10
14
  RCT_EXTERN_METHOD(start)
11
15
 
12
16
  RCT_EXTERN_METHOD(stop)
@@ -16,6 +16,19 @@ enum DefaultAudioDevice {
16
16
  case earpiece
17
17
  }
18
18
 
19
+ private enum Constants {
20
+ /// Debounce interval for refreshing stereo playout state after audio route changes.
21
+ ///
22
+ /// When audio routes change rapidly (e.g., connecting/disconnecting Bluetooth devices),
23
+ /// iOS can fire multiple `routeConfigurationChange` notifications in quick succession.
24
+ /// This debounce prevents excessive calls to `refreshStereoPlayoutState()` which can
25
+ /// cause audio glitches or unnecessary reconfiguration overhead.
26
+ ///
27
+ /// 500ms provides a good balance: long enough to coalesce rapid route change events,
28
+ /// but short enough that users won't perceive a delay when switching audio devices.
29
+ static let stereoRefreshDebounceSeconds: TimeInterval = 0.5
30
+ }
31
+
19
32
  @objc(StreamInCallManager)
20
33
  class StreamInCallManager: RCTEventEmitter {
21
34
 
@@ -24,6 +37,7 @@ class StreamInCallManager: RCTEventEmitter {
24
37
  private var audioManagerActivated = false
25
38
  private var callAudioRole: CallAudioRole = .communicator
26
39
  private var defaultAudioDevice: DefaultAudioDevice = .speaker
40
+ private var enableStereo: Bool = false
27
41
  private var previousVolume: Float = 0.75
28
42
 
29
43
  private struct AudioSessionState {
@@ -32,8 +46,8 @@ class StreamInCallManager: RCTEventEmitter {
32
46
  let options: AVAudioSession.CategoryOptions
33
47
  }
34
48
 
35
- private var previousAudioSessionState: AudioSessionState?
36
49
  private var hasRegisteredRouteObserver = false
50
+ private var stereoRefreshWorkItem: DispatchWorkItem?
37
51
 
38
52
  override func invalidate() {
39
53
  stop()
@@ -65,21 +79,87 @@ class StreamInCallManager: RCTEventEmitter {
65
79
  self.defaultAudioDevice = endpointType.lowercased() == "earpiece" ? .earpiece : .speaker
66
80
  }
67
81
  }
82
+
83
+ @objc(setEnableStereoAudioOutput:)
84
+ func setEnableStereoAudioOutput(enabled: Bool) {
85
+ audioSessionQueue.async { [self] in
86
+ if audioManagerActivated {
87
+ log("AudioManager is already activated, enable stereo audio output cannot be changed.")
88
+ return
89
+ }
90
+ self.enableStereo = enabled
91
+ }
92
+ }
93
+
94
+ @objc
95
+ func setup() {
96
+ audioSessionQueue.async { [self] in
97
+ let intendedCategory: AVAudioSession.Category!
98
+ let intendedMode: AVAudioSession.Mode!
99
+ let intendedOptions: AVAudioSession.CategoryOptions!
100
+
101
+ let adm = getAudioDeviceModule()
102
+ let wasRecording = adm.isRecording
103
+ let wasPlaying = adm.isPlaying
104
+ adm.reset()
105
+
106
+ if (callAudioRole == .listener) {
107
+ // enables high quality audio playback but disables microphone
108
+ intendedCategory = .playback
109
+ intendedMode = .default
110
+ intendedOptions = []
111
+ // TODO: for stereo we should disallow BluetoothHFP and allow only allowBluetoothA2DP
112
+ // note: this is the behaviour of iOS native SDK, but fails here with (OSStatus error -50.)
113
+ // intendedOptions = self.enableStereo ? [.allowBluetoothA2DP] : []
114
+ if (self.enableStereo) {
115
+ adm.setStereoPlayoutPreference(true)
116
+ }
117
+ } else {
118
+ intendedCategory = .playAndRecord
119
+ intendedMode = defaultAudioDevice == .speaker ? .videoChat : .voiceChat
120
+
121
+ // XCode 16 and older don't expose .allowBluetoothHFP
122
+ // https://forums.swift.org/t/xcode-26-avaudiosession-categoryoptions-allowbluetooth-deprecated/80956
123
+ #if compiler(>=6.2) // For Xcode 26.0+
124
+ let bluetoothOption: AVAudioSession.CategoryOptions = .allowBluetoothHFP
125
+ #else
126
+ let bluetoothOption: AVAudioSession.CategoryOptions = .allowBluetooth
127
+ #endif
128
+ intendedOptions = defaultAudioDevice == .speaker ? [bluetoothOption, .defaultToSpeaker] : [bluetoothOption]
129
+ }
130
+ log("Setup with category: \(intendedCategory.rawValue), mode: \(intendedMode.rawValue), options: \(String(describing: intendedOptions))")
131
+ let rtcConfig = RTCAudioSessionConfiguration.webRTC()
132
+ rtcConfig.category = intendedCategory.rawValue
133
+ rtcConfig.mode = intendedMode.rawValue
134
+ rtcConfig.categoryOptions = intendedOptions
135
+ RTCAudioSessionConfiguration.setWebRTC(rtcConfig)
136
+
137
+ let session = RTCAudioSession.sharedInstance()
138
+ session.lockForConfiguration()
139
+ defer {
140
+ session.unlockForConfiguration()
141
+ }
142
+ do {
143
+ try session.setCategory(intendedCategory, mode: intendedMode, options: intendedOptions)
144
+ if (wasRecording) {
145
+ try adm.setRecording(wasRecording)
146
+ }
147
+ if (wasPlaying) {
148
+ try adm.setPlayout(wasPlaying)
149
+ }
150
+ } catch {
151
+ log("Error setting audio session: \(error.localizedDescription)")
152
+ }
153
+ }
154
+ }
68
155
 
69
156
  @objc
70
157
  func start() {
158
+ setup()
71
159
  audioSessionQueue.async { [self] in
72
160
  if audioManagerActivated {
73
161
  return
74
162
  }
75
- let session = AVAudioSession.sharedInstance()
76
- previousAudioSessionState = AudioSessionState(
77
- category: session.category,
78
- mode: session.mode,
79
- options: session.categoryOptions
80
- )
81
- configureAudioSession()
82
-
83
163
  DispatchQueue.main.async {
84
164
  // Enable wake lock to prevent the screen from dimming/locking during a call
85
165
  UIApplication.shared.isIdleTimerDisabled = true
@@ -87,7 +167,23 @@ class StreamInCallManager: RCTEventEmitter {
87
167
  self.registerAudioRouteObserver()
88
168
  self.updateProximityMonitoring()
89
169
  self.log("Wake lock enabled (idle timer disabled)")
170
+ self.log("defaultAudioDevice: \(self.defaultAudioDevice)")
171
+ }
172
+ let session = RTCAudioSession.sharedInstance()
173
+ session.lockForConfiguration()
174
+ defer {
175
+ session.unlockForConfiguration()
90
176
  }
177
+ do {
178
+ try session.setActive(true)
179
+ self.log("audio session activated")
180
+ let adm = getAudioDeviceModule()
181
+ try adm.setPlayout(true)
182
+ self.log("adm.setPlayout(true) done")
183
+ } catch {
184
+ log("Error activating audio session: \(error.localizedDescription)")
185
+ }
186
+
91
187
  audioManagerActivated = true
92
188
  }
93
189
  }
@@ -103,21 +199,19 @@ class StreamInCallManager: RCTEventEmitter {
103
199
  defer {
104
200
  session.unlockForConfiguration()
105
201
  }
106
-
107
202
  do {
108
203
  try session.setActive(false)
204
+ let adm = getAudioDeviceModule()
205
+ adm.reset()
109
206
  } catch {
110
207
  log("Error deactivating audio session: \(error.localizedDescription)")
111
208
  }
112
- if let prev = previousAudioSessionState {
113
- let session = AVAudioSession.sharedInstance()
114
- do {
115
- try session.setCategory(prev.category, mode: prev.mode, options: prev.options)
116
- } catch {
117
- log("Error restoring previous audio session: \(error.localizedDescription)")
118
- }
119
- previousAudioSessionState = nil
120
- }
209
+ // Cancel any pending debounced stereo refresh
210
+ stereoRefreshWorkItem?.cancel()
211
+ stereoRefreshWorkItem = nil
212
+ callAudioRole = .communicator
213
+ defaultAudioDevice = .speaker
214
+ enableStereo = false
121
215
  audioManagerActivated = false
122
216
  }
123
217
  // Disable wake lock and proximity when call manager stops so the device can sleep again
@@ -131,68 +225,6 @@ class StreamInCallManager: RCTEventEmitter {
131
225
  }
132
226
  }
133
227
 
134
- private func configureAudioSession() {
135
- let intendedCategory: AVAudioSession.Category!
136
- let intendedMode: AVAudioSession.Mode!
137
- let intendedOptions: AVAudioSession.CategoryOptions!
138
-
139
- if (callAudioRole == .listener) {
140
- // enables high quality audio playback but disables microphone
141
- intendedCategory = .playback
142
- intendedMode = .default
143
- intendedOptions = []
144
- } else {
145
- intendedCategory = .playAndRecord
146
- intendedMode = .voiceChat
147
-
148
- // XCode 16 and older don't expose .allowBluetoothHFP
149
- // https://forums.swift.org/t/xcode-26-avaudiosession-categoryoptions-allowbluetooth-deprecated/80956
150
- #if compiler(>=6.2) // For Xcode 26.0+
151
- let bluetoothOption: AVAudioSession.CategoryOptions = .allowBluetoothHFP
152
- #else
153
- let bluetoothOption: AVAudioSession.CategoryOptions = .allowBluetooth
154
- #endif
155
-
156
- if (defaultAudioDevice == .speaker) {
157
- // defaultToSpeaker will route to speaker if nothing else is connected
158
- intendedOptions = [bluetoothOption, .defaultToSpeaker]
159
- } else {
160
- // having no defaultToSpeaker makes sure audio goes to earpiece if nothing is connected
161
- intendedOptions = [bluetoothOption]
162
- }
163
- }
164
-
165
- // START: set the config that webrtc must use when it takes control
166
- let rtcConfig = RTCAudioSessionConfiguration.webRTC()
167
- rtcConfig.category = intendedCategory.rawValue
168
- rtcConfig.mode = intendedMode.rawValue
169
- rtcConfig.categoryOptions = intendedOptions
170
- RTCAudioSessionConfiguration.setWebRTC(rtcConfig)
171
- // END
172
-
173
- // START: activate the webrtc audio session
174
- let session = RTCAudioSession.sharedInstance()
175
- session.lockForConfiguration()
176
- defer {
177
- session.unlockForConfiguration()
178
- }
179
- do {
180
- try session.setCategory(intendedCategory, mode: intendedMode, options: intendedOptions)
181
- try session.setActive(true)
182
- log("configureAudioSession: setCategory success \(intendedCategory.rawValue) \(intendedMode.rawValue) \(intendedOptions.rawValue)")
183
- } catch {
184
- log("configureAudioSession: setCategory failed due to: \(error.localizedDescription)")
185
- do {
186
- try session.setMode(intendedMode)
187
- try session.setActive(true)
188
- log("configureAudioSession: setMode success \(intendedMode.rawValue)")
189
- } catch {
190
- log("configureAudioSession: Error setting mode: \(error.localizedDescription)")
191
- }
192
- }
193
- // END
194
- }
195
-
196
228
  @objc(showAudioRoutePicker)
197
229
  public func showAudioRoutePicker() {
198
230
  guard #available(iOS 11.0, tvOS 11.0, macOS 10.15, *) else {
@@ -210,15 +242,23 @@ class StreamInCallManager: RCTEventEmitter {
210
242
 
211
243
  @objc(setForceSpeakerphoneOn:)
212
244
  func setForceSpeakerphoneOn(enable: Bool) {
213
- let session = AVAudioSession.sharedInstance()
214
- do {
215
- try session.overrideOutputAudioPort(enable ? .speaker : .none)
216
- try session.setActive(true)
217
- } catch {
218
- log("Error setting speakerphone: \(error)")
245
+ audioSessionQueue.async { [weak self] in
246
+ let session = RTCAudioSession.sharedInstance()
247
+ session.lockForConfiguration()
248
+ defer {
249
+ session.unlockForConfiguration()
250
+ }
251
+ let avAudioSession = AVAudioSession.sharedInstance()
252
+ do {
253
+ try avAudioSession.overrideOutputAudioPort(enable ? .speaker : .none)
254
+ try avAudioSession.setActive(true)
255
+ } catch {
256
+ self?.log("Error setting speakerphone: \(error)")
257
+ }
219
258
  }
220
259
  }
221
260
 
261
+
222
262
  @objc(setMicrophoneMute:)
223
263
  func setMicrophoneMute(enable: Bool) {
224
264
  log("iOS does not support setMicrophoneMute()")
@@ -227,6 +267,16 @@ class StreamInCallManager: RCTEventEmitter {
227
267
  @objc
228
268
  func logAudioState() {
229
269
  let session = AVAudioSession.sharedInstance()
270
+ let adm = getAudioDeviceModule()
271
+
272
+ // WebRTC wraps AVAudioSession with RTCAudioSession; log its state as well.
273
+ let rtcSession = RTCAudioSession.sharedInstance()
274
+ rtcSession.lockForConfiguration()
275
+ defer {
276
+ rtcSession.unlockForConfiguration()
277
+ }
278
+
279
+ let rtcAVSession = rtcSession.session
230
280
  let logString = """
231
281
  Audio State:
232
282
  Category: \(session.category.rawValue)
@@ -236,6 +286,19 @@ class StreamInCallManager: RCTEventEmitter {
236
286
  Category Options: \(session.categoryOptions)
237
287
  InputNumberOfChannels: \(session.inputNumberOfChannels)
238
288
  OutputNumberOfChannels: \(session.outputNumberOfChannels)
289
+ AdmIsPlaying: \(adm.isPlaying)
290
+ AdmIsRecording: \(adm.isRecording)
291
+
292
+ RTC Audio State:
293
+ Wrapped Category: \(rtcAVSession.category.rawValue)
294
+ Wrapped Mode: \(rtcAVSession.mode.rawValue)
295
+ Wrapped Output Port: \(rtcAVSession.currentRoute.outputs.first?.portName ?? "N/A")
296
+ Wrapped Input Port: \(rtcAVSession.currentRoute.inputs.first?.portName ?? "N/A")
297
+ Wrapped Category Options: \(rtcAVSession.categoryOptions)
298
+ UseManualAudio: \(rtcSession.useManualAudio)
299
+ IsAudioEnabled: \(rtcSession.isAudioEnabled)
300
+ IsActive: \(rtcSession.isActive)
301
+ ActivationCount: \(rtcSession.activationCount)
239
302
  """
240
303
  log(logString)
241
304
  }
@@ -316,7 +379,34 @@ class StreamInCallManager: RCTEventEmitter {
316
379
  log("Unregistered AVAudioSession.routeChangeNotification observer")
317
380
  }
318
381
 
319
- @objc private func handleAudioRouteChange(_ notification: Notification) {
382
+ @objc
383
+ private func handleAudioRouteChange(_ notification: Notification) {
384
+ guard let userInfo = notification.userInfo,
385
+ let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
386
+ let reason = AVAudioSession.RouteChangeReason(rawValue: reasonValue) else {
387
+ return
388
+ }
389
+
390
+ log("Audio route change reason: \(routeChangeReasonDescription(reason))")
391
+
392
+ if reason == .routeConfigurationChange {
393
+ audioSessionQueue.async { [weak self] in
394
+ guard let self else { return }
395
+ // Cancel any pending debounced refresh
396
+ stereoRefreshWorkItem?.cancel()
397
+ // Create a new debounced work item
398
+ let workItem = DispatchWorkItem { [weak self] in
399
+ self?.getAudioDeviceModule().refreshStereoPlayoutState()
400
+ self?.log("Executed debounced refreshStereoPlayoutState")
401
+ }
402
+ stereoRefreshWorkItem = workItem
403
+ // Schedule the work item after debounce interval
404
+ audioSessionQueue.asyncAfter(deadline: .now() + Constants.stereoRefreshDebounceSeconds, execute: workItem)
405
+ }
406
+ }
407
+
408
+ logAudioState()
409
+
320
410
  // Route changes can arrive on arbitrary queues; ensure UI-safe work on main
321
411
  DispatchQueue.main.async { [weak self] in
322
412
  self?.updateProximityMonitoring()
@@ -367,6 +457,18 @@ class StreamInCallManager: RCTEventEmitter {
367
457
  }
368
458
 
369
459
  // MARK: - Helper Methods
460
+ private func getAudioDeviceModule() -> AudioDeviceModule {
461
+ guard let bridge = self.bridge else {
462
+ fatalError("StreamInCallManager: RCTBridge is not available yet.")
463
+ }
464
+
465
+ guard let webrtcModule = bridge.module(forName: "WebRTCModule") as? WebRTCModule else {
466
+ fatalError("WebRTCModule is required but not registered with the bridge")
467
+ }
468
+
469
+ return webrtcModule.audioDeviceModule
470
+ }
471
+
370
472
  private func getCurrentWindow() -> UIWindow? {
371
473
  if #available(iOS 13.0, *) {
372
474
  return UIApplication.shared.connectedScenes
@@ -378,6 +480,29 @@ class StreamInCallManager: RCTEventEmitter {
378
480
  }
379
481
  }
380
482
 
483
+ private func routeChangeReasonDescription(_ reason: AVAudioSession.RouteChangeReason) -> String {
484
+ switch reason {
485
+ case .unknown:
486
+ return "unknown"
487
+ case .newDeviceAvailable:
488
+ return "newDeviceAvailable"
489
+ case .oldDeviceUnavailable:
490
+ return "oldDeviceUnavailable"
491
+ case .categoryChange:
492
+ return "categoryChange"
493
+ case .override:
494
+ return "override"
495
+ case .wakeFromSleep:
496
+ return "wakeFromSleep"
497
+ case .noSuitableRouteForCategory:
498
+ return "noSuitableRouteForCategory"
499
+ case .routeConfigurationChange:
500
+ return "routeConfigurationChange"
501
+ @unknown default:
502
+ return "unknown(\(reason.rawValue))"
503
+ }
504
+ }
505
+
381
506
  // MARK: - Logging Helper
382
507
  private func log(_ message: String) {
383
508
  NSLog("InCallManager: %@", message)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-io/video-react-native-sdk",
3
- "version": "1.27.4",
3
+ "version": "1.28.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.40.3",
54
- "@stream-io/video-react-bindings": "1.12.10",
53
+ "@stream-io/video-client": "1.41.0",
54
+ "@stream-io/video-react-bindings": "1.13.0",
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,7 @@
65
65
  "@react-native-firebase/app": ">=17.5.0",
66
66
  "@react-native-firebase/messaging": ">=17.5.0",
67
67
  "@stream-io/noise-cancellation-react-native": ">=0.1.0",
68
- "@stream-io/react-native-webrtc": ">=125.4.4",
68
+ "@stream-io/react-native-webrtc": ">=137.1.0",
69
69
  "@stream-io/video-filters-react-native": ">=0.1.0",
70
70
  "expo": ">=47.0.0",
71
71
  "expo-build-properties": "*",
@@ -130,9 +130,9 @@
130
130
  "@react-native-firebase/app": "^23.4.0",
131
131
  "@react-native-firebase/messaging": "^23.4.0",
132
132
  "@react-native/babel-preset": "^0.81.5",
133
- "@stream-io/noise-cancellation-react-native": "^0.4.4",
134
- "@stream-io/react-native-webrtc": "137.0.2",
135
- "@stream-io/video-filters-react-native": "^0.9.3",
133
+ "@stream-io/noise-cancellation-react-native": "^0.5.0",
134
+ "@stream-io/react-native-webrtc": "137.1.0",
135
+ "@stream-io/video-filters-react-native": "^0.10.0",
136
136
  "@testing-library/jest-native": "^5.4.3",
137
137
  "@testing-library/react-native": "13.3.3",
138
138
  "@tsconfig/node18": "^18.2.4",
package/src/index.ts CHANGED
@@ -8,12 +8,14 @@ import 'intl-pluralrules';
8
8
  import { registerGlobals } from '@stream-io/react-native-webrtc';
9
9
  import Logger from '@stream-io/react-native-webrtc/src/Logger';
10
10
  import { Platform } from 'react-native';
11
+ import { registerSDKGlobals } from './utils/internal/registerSDKGlobals';
11
12
 
12
13
  // We're registering globals, because our video JS client is serving SDKs that use browser based webRTC functions.
13
14
  // This will result in creation of 2 global objects: `window` and `navigator`
14
15
  // Reference: https://github.com/react-native-webrtc/react-native-webrtc/blob/16cff1523da457dbcc27bb0744ee2bad3a987c41/Documentation/BasicUsage.md#registering-globals
15
16
  if (Platform.OS !== 'web') {
16
17
  registerGlobals();
18
+ registerSDKGlobals();
17
19
  }
18
20
 
19
21
  // only enable warning and error logs from webrtc library
@@ -91,6 +91,8 @@ export class CallManager {
91
91
  * @param config.deviceEndpointType The default audio device endpoint type to set. It can be one of the following:
92
92
  * - `'speaker'`: (Default) For normal video or voice calls.
93
93
  * - `'earpiece'`: For voice-only mobile call type scenarios.
94
+ *
95
+ * @param config.enableStereoAudioOutput Whether to enable stereo audio output. Only supported for listener audio role.
94
96
  */
95
97
  start = (config?: StreamInCallManagerConfig): void => {
96
98
  NativeManager.setAudioRole(config?.audioRole ?? 'communicator');
@@ -98,6 +100,9 @@ export class CallManager {
98
100
  const type = config.deviceEndpointType ?? 'speaker';
99
101
  NativeManager.setDefaultAudioDeviceEndpointType(type);
100
102
  }
103
+ if (config?.audioRole === 'listener' && config.enableStereoAudioOutput) {
104
+ NativeManager.setEnableStereoAudioOutput(true);
105
+ }
101
106
  NativeManager.start();
102
107
  };
103
108
 
@@ -51,6 +51,11 @@ export interface CallManager extends NativeModule {
51
51
  */
52
52
  stop: () => void;
53
53
 
54
+ /**
55
+ * Setup the in call manager.
56
+ */
57
+ setup: () => void;
58
+
54
59
  /**
55
60
  * Mutes the speaker
56
61
  */
@@ -66,6 +71,12 @@ export interface CallManager extends NativeModule {
66
71
  */
67
72
  setForceSpeakerphoneOn: (boolean) => void;
68
73
 
74
+ /**
75
+ * Enables or disables stereo audio output.
76
+ * @param enable - Whether to enable stereo audio output.
77
+ */
78
+ setEnableStereoAudioOutput: (enable: boolean) => void;
79
+
69
80
  /**
70
81
  * Log the current audio state natively.
71
82
  * Meant for debugging purposes.
@@ -22,4 +22,5 @@ export type StreamInCallManagerConfig =
22
22
  }
23
23
  | {
24
24
  audioRole: 'listener';
25
+ enableStereoAudioOutput?: boolean;
25
26
  };
@@ -0,0 +1,30 @@
1
+ import { StreamRNVideoSDKGlobals } from '@stream-io/video-client';
2
+ import { NativeModules } from 'react-native';
3
+
4
+ const StreamInCallManagerNativeModule = NativeModules.StreamInCallManager;
5
+
6
+ const streamRNVideoSDKGlobals: StreamRNVideoSDKGlobals = {
7
+ callManager: {
8
+ setup: ({ default_device }) => {
9
+ StreamInCallManagerNativeModule.setDefaultAudioDeviceEndpointType(
10
+ default_device,
11
+ );
12
+ StreamInCallManagerNativeModule.setup();
13
+ },
14
+ start: () => {
15
+ StreamInCallManagerNativeModule.start();
16
+ },
17
+ stop: () => {
18
+ StreamInCallManagerNativeModule.stop();
19
+ },
20
+ },
21
+ };
22
+
23
+ // Note: The global type declaration for `streamRNVideoSDK` is defined in
24
+ // @stream-io/video-client/src/types.ts and is automatically available when
25
+ // importing from the client package.
26
+ export function registerSDKGlobals() {
27
+ if (!global.streamRNVideoSDK) {
28
+ global.streamRNVideoSDK = streamRNVideoSDKGlobals;
29
+ }
30
+ }
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '1.27.4';
1
+ export const version = '1.28.0';
@@ -1,41 +0,0 @@
1
- package com.streamvideo.reactnative.audio.utils
2
-
3
- import android.media.AudioManager
4
- import android.util.Log
5
- import com.facebook.react.bridge.ReactContext
6
- import com.streamvideo.reactnative.audio.AudioDeviceManager
7
- import com.streamvideo.reactnative.callmanager.StreamInCallManagerModule.Companion.TAG
8
-
9
- class AudioSetupStoreUtil(
10
- private val mReactContext: ReactContext,
11
- private val mAudioManager: AudioManager,
12
- private val mAudioDeviceManager: AudioDeviceManager
13
- ) {
14
- private var isOrigAudioSetupStored = false
15
- private var origIsSpeakerPhoneOn = false
16
- private var origIsMicrophoneMute = false
17
- private var origAudioMode = AudioManager.MODE_NORMAL
18
-
19
- fun storeOriginalAudioSetup() {
20
- if (!isOrigAudioSetupStored) {
21
- origAudioMode = mAudioManager.mode
22
- origIsSpeakerPhoneOn = AudioManagerUtil.isSpeakerphoneOn(mAudioManager)
23
- origIsMicrophoneMute = mAudioManager.isMicrophoneMute
24
- isOrigAudioSetupStored = true
25
- }
26
- }
27
-
28
- fun restoreOriginalAudioSetup() {
29
- if (isOrigAudioSetupStored) {
30
- if (origIsSpeakerPhoneOn) {
31
- mAudioDeviceManager.setSpeakerphoneOn(true)
32
- }
33
- mAudioManager.setMicrophoneMute(origIsMicrophoneMute)
34
- mAudioManager.mode = origAudioMode
35
- mReactContext.currentActivity?.apply {
36
- volumeControlStream = AudioManager.USE_DEFAULT_STREAM_TYPE
37
- }
38
- isOrigAudioSetupStored = false
39
- }
40
- }
41
- }