@stream-io/video-client 1.41.0 → 1.41.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/index.browser.es.js +86 -14
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +86 -14
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +86 -14
- package/dist/index.es.js.map +1 -1
- package/dist/src/devices/SpeakerManager.d.ts +3 -0
- package/dist/src/helpers/DynascaleManager.d.ts +13 -1
- package/dist/src/helpers/types.d.ts +16 -0
- package/dist/src/types.d.ts +2 -2
- package/package.json +2 -2
- package/src/Call.ts +6 -4
- package/src/devices/SpeakerManager.ts +40 -0
- package/src/helpers/DynascaleManager.ts +57 -9
- package/src/helpers/__tests__/DynascaleManager.test.ts +8 -1
- package/src/helpers/types.ts +26 -0
- package/src/rtc/__tests__/mocks/webrtc.mocks.ts +1 -0
- package/src/types.ts +2 -2
package/dist/index.es.js
CHANGED
|
@@ -6189,7 +6189,7 @@ const getSdkVersion = (sdk) => {
|
|
|
6189
6189
|
return sdk ? `${sdk.major}.${sdk.minor}.${sdk.patch}` : '0.0.0-development';
|
|
6190
6190
|
};
|
|
6191
6191
|
|
|
6192
|
-
const version = "1.41.
|
|
6192
|
+
const version = "1.41.1";
|
|
6193
6193
|
const [major, minor, patch] = version.split('.');
|
|
6194
6194
|
let sdkInfo = {
|
|
6195
6195
|
type: SdkType.PLAIN_JAVASCRIPT,
|
|
@@ -9373,12 +9373,13 @@ class DynascaleManager {
|
|
|
9373
9373
|
/**
|
|
9374
9374
|
* Creates a new DynascaleManager instance.
|
|
9375
9375
|
*/
|
|
9376
|
-
constructor(callState, speaker) {
|
|
9376
|
+
constructor(callState, speaker, tracer) {
|
|
9377
9377
|
/**
|
|
9378
9378
|
* The viewport tracker instance.
|
|
9379
9379
|
*/
|
|
9380
9380
|
this.viewportTracker = new ViewportTracker();
|
|
9381
9381
|
this.logger = videoLoggerSystem.getLogger('DynascaleManager');
|
|
9382
|
+
this.useWebAudio = isSafari();
|
|
9382
9383
|
this.pendingSubscriptionsUpdate = null;
|
|
9383
9384
|
this.videoTrackSubscriptionOverridesSubject = new BehaviorSubject({});
|
|
9384
9385
|
this.videoTrackSubscriptionOverrides$ = this.videoTrackSubscriptionOverridesSubject.asObservable();
|
|
@@ -9418,6 +9419,10 @@ class DynascaleManager {
|
|
|
9418
9419
|
}
|
|
9419
9420
|
};
|
|
9420
9421
|
this.setVideoTrackSubscriptionOverrides = (override, sessionIds) => {
|
|
9422
|
+
this.tracer.trace('setVideoTrackSubscriptionOverrides', [
|
|
9423
|
+
override,
|
|
9424
|
+
sessionIds,
|
|
9425
|
+
]);
|
|
9421
9426
|
if (!sessionIds) {
|
|
9422
9427
|
return setCurrentValue(this.videoTrackSubscriptionOverridesSubject, override ? { [globalOverrideKey]: override } : {});
|
|
9423
9428
|
}
|
|
@@ -9499,6 +9504,18 @@ class DynascaleManager {
|
|
|
9499
9504
|
this.setViewport = (element) => {
|
|
9500
9505
|
return this.viewportTracker.setViewport(element);
|
|
9501
9506
|
};
|
|
9507
|
+
/**
|
|
9508
|
+
* Sets whether to use WebAudio API for audio playback.
|
|
9509
|
+
* Must be set before joining the call.
|
|
9510
|
+
*
|
|
9511
|
+
* @internal
|
|
9512
|
+
*
|
|
9513
|
+
* @param useWebAudio whether to use WebAudio API.
|
|
9514
|
+
*/
|
|
9515
|
+
this.setUseWebAudio = (useWebAudio) => {
|
|
9516
|
+
this.tracer.trace('setUseWebAudio', useWebAudio);
|
|
9517
|
+
this.useWebAudio = useWebAudio;
|
|
9518
|
+
};
|
|
9502
9519
|
/**
|
|
9503
9520
|
* Binds a DOM <video> element to the given session id.
|
|
9504
9521
|
* This method will make sure that the video element will play
|
|
@@ -9714,6 +9731,7 @@ class DynascaleManager {
|
|
|
9714
9731
|
// we will play audio directly through the audio element in other browsers
|
|
9715
9732
|
audioElement.muted = false;
|
|
9716
9733
|
audioElement.play().catch((e) => {
|
|
9734
|
+
this.tracer.trace('audioPlaybackError', e.message);
|
|
9717
9735
|
this.logger.warn(`Failed to play audio stream`, e);
|
|
9718
9736
|
});
|
|
9719
9737
|
}
|
|
@@ -9748,32 +9766,57 @@ class DynascaleManager {
|
|
|
9748
9766
|
};
|
|
9749
9767
|
};
|
|
9750
9768
|
this.getOrCreateAudioContext = () => {
|
|
9751
|
-
if (this.
|
|
9769
|
+
if (!this.useWebAudio)
|
|
9770
|
+
return;
|
|
9771
|
+
if (this.audioContext)
|
|
9752
9772
|
return this.audioContext;
|
|
9753
9773
|
const context = new AudioContext();
|
|
9774
|
+
this.tracer.trace('audioContext.create', context.state);
|
|
9754
9775
|
if (context.state === 'suspended') {
|
|
9755
9776
|
document.addEventListener('click', this.resumeAudioContext);
|
|
9756
9777
|
}
|
|
9757
|
-
|
|
9778
|
+
context.addEventListener('statechange', () => {
|
|
9779
|
+
this.tracer.trace('audioContext.state', context.state);
|
|
9780
|
+
if (context.state === 'interrupted') {
|
|
9781
|
+
this.resumeAudioContext();
|
|
9782
|
+
}
|
|
9783
|
+
});
|
|
9758
9784
|
const audioSession = navigator.audioSession;
|
|
9759
9785
|
if (audioSession) {
|
|
9760
9786
|
// https://github.com/w3c/audio-session/blob/main/explainer.md
|
|
9761
9787
|
audioSession.type = 'play-and-record';
|
|
9788
|
+
let isSessionInterrupted = false;
|
|
9789
|
+
audioSession.addEventListener('statechange', () => {
|
|
9790
|
+
this.tracer.trace('audioSession.state', audioSession.state);
|
|
9791
|
+
if (audioSession.state === 'interrupted') {
|
|
9792
|
+
isSessionInterrupted = true;
|
|
9793
|
+
}
|
|
9794
|
+
else if (isSessionInterrupted) {
|
|
9795
|
+
this.resumeAudioContext();
|
|
9796
|
+
isSessionInterrupted = false;
|
|
9797
|
+
}
|
|
9798
|
+
});
|
|
9762
9799
|
}
|
|
9763
9800
|
return (this.audioContext = context);
|
|
9764
9801
|
};
|
|
9765
9802
|
this.resumeAudioContext = () => {
|
|
9766
|
-
if (this.audioContext
|
|
9767
|
-
|
|
9768
|
-
|
|
9769
|
-
|
|
9770
|
-
|
|
9803
|
+
if (!this.audioContext)
|
|
9804
|
+
return;
|
|
9805
|
+
const { state } = this.audioContext;
|
|
9806
|
+
if (state === 'suspended' || state === 'interrupted') {
|
|
9807
|
+
const tag = 'audioContext.resume';
|
|
9808
|
+
this.audioContext.resume().then(() => {
|
|
9809
|
+
this.tracer.trace(tag, this.audioContext?.state);
|
|
9771
9810
|
document.removeEventListener('click', this.resumeAudioContext);
|
|
9811
|
+
}, (err) => {
|
|
9812
|
+
this.tracer.trace(`${tag}Error`, this.audioContext?.state);
|
|
9813
|
+
this.logger.warn(`Can't resume audio context`, err);
|
|
9772
9814
|
});
|
|
9773
9815
|
}
|
|
9774
9816
|
};
|
|
9775
9817
|
this.callState = callState;
|
|
9776
9818
|
this.speaker = speaker;
|
|
9819
|
+
this.tracer = tracer;
|
|
9777
9820
|
}
|
|
9778
9821
|
setSfuClient(sfuClient) {
|
|
9779
9822
|
this.sfuClient = sfuClient;
|
|
@@ -11993,6 +12036,37 @@ class SpeakerManager {
|
|
|
11993
12036
|
this.state = new SpeakerState(call.tracer);
|
|
11994
12037
|
this.setup();
|
|
11995
12038
|
}
|
|
12039
|
+
apply(settings) {
|
|
12040
|
+
if (!isReactNative()) {
|
|
12041
|
+
return;
|
|
12042
|
+
}
|
|
12043
|
+
/// Determines if the speaker should be enabled based on a priority hierarchy of
|
|
12044
|
+
/// settings.
|
|
12045
|
+
///
|
|
12046
|
+
/// The priority order is as follows:
|
|
12047
|
+
/// 1. If video camera is set to be on by default, speaker is enabled
|
|
12048
|
+
/// 2. If audio speaker is set to be on by default, speaker is enabled
|
|
12049
|
+
/// 3. If the default audio device is set to speaker, speaker is enabled
|
|
12050
|
+
///
|
|
12051
|
+
/// This ensures that the speaker state aligns with the most important user
|
|
12052
|
+
/// preference or system requirement.
|
|
12053
|
+
const speakerOnWithSettingsPriority = settings.video.camera_default_on ||
|
|
12054
|
+
settings.audio.speaker_default_on ||
|
|
12055
|
+
settings.audio.default_device ===
|
|
12056
|
+
AudioSettingsRequestDefaultDeviceEnum.SPEAKER;
|
|
12057
|
+
const defaultDevice = speakerOnWithSettingsPriority
|
|
12058
|
+
? AudioSettingsRequestDefaultDeviceEnum.SPEAKER
|
|
12059
|
+
: AudioSettingsRequestDefaultDeviceEnum.EARPIECE;
|
|
12060
|
+
if (this.defaultDevice !== defaultDevice) {
|
|
12061
|
+
this.call.logger.debug('SpeakerManager: setting default device', {
|
|
12062
|
+
defaultDevice,
|
|
12063
|
+
});
|
|
12064
|
+
this.defaultDevice = defaultDevice;
|
|
12065
|
+
globalThis.streamRNVideoSDK?.callManager.setup({
|
|
12066
|
+
defaultDevice,
|
|
12067
|
+
});
|
|
12068
|
+
}
|
|
12069
|
+
}
|
|
11996
12070
|
setup() {
|
|
11997
12071
|
if (this.areSubscriptionsSetUp) {
|
|
11998
12072
|
return;
|
|
@@ -13934,9 +14008,7 @@ class Call {
|
|
|
13934
14008
|
* @internal
|
|
13935
14009
|
*/
|
|
13936
14010
|
this.applyDeviceConfig = async (settings, publish) => {
|
|
13937
|
-
|
|
13938
|
-
default_device: settings.audio.default_device,
|
|
13939
|
-
});
|
|
14011
|
+
this.speaker.apply(settings);
|
|
13940
14012
|
await this.camera.apply(settings.video, publish).catch((err) => {
|
|
13941
14013
|
this.logger.warn('Camera init failed', err);
|
|
13942
14014
|
});
|
|
@@ -14106,7 +14178,7 @@ class Call {
|
|
|
14106
14178
|
this.microphone = new MicrophoneManager(this);
|
|
14107
14179
|
this.speaker = new SpeakerManager(this);
|
|
14108
14180
|
this.screenShare = new ScreenShareManager(this);
|
|
14109
|
-
this.dynascaleManager = new DynascaleManager(this.state, this.speaker);
|
|
14181
|
+
this.dynascaleManager = new DynascaleManager(this.state, this.speaker, this.tracer);
|
|
14110
14182
|
}
|
|
14111
14183
|
/**
|
|
14112
14184
|
* A flag indicating whether the call is "ringing" type of call.
|
|
@@ -15248,7 +15320,7 @@ class StreamClient {
|
|
|
15248
15320
|
this.getUserAgent = () => {
|
|
15249
15321
|
if (!this.cachedUserAgent) {
|
|
15250
15322
|
const { clientAppIdentifier = {} } = this.options;
|
|
15251
|
-
const { sdkName = 'js', sdkVersion = "1.41.
|
|
15323
|
+
const { sdkName = 'js', sdkVersion = "1.41.1", ...extras } = clientAppIdentifier;
|
|
15252
15324
|
this.cachedUserAgent = [
|
|
15253
15325
|
`stream-video-${sdkName}-v${sdkVersion}`,
|
|
15254
15326
|
...Object.entries(extras).map(([key, value]) => `${key}=${value}`),
|