@stream-io/video-client 1.44.3 → 1.44.5
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 +14 -0
- package/dist/index.browser.es.js +134 -45
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +134 -45
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +134 -45
- package/dist/index.es.js.map +1 -1
- package/dist/src/devices/BrowserPermission.d.ts +2 -0
- package/dist/src/devices/CameraManagerState.d.ts +2 -1
- package/dist/src/devices/MicrophoneManagerState.d.ts +2 -1
- package/dist/src/devices/devices.d.ts +2 -2
- package/dist/src/helpers/AudioBindingsWatchdog.d.ts +37 -0
- package/dist/src/helpers/DynascaleManager.d.ts +3 -1
- package/package.json +2 -2
- package/src/devices/BrowserPermission.ts +5 -0
- package/src/devices/CameraManager.ts +6 -1
- package/src/devices/CameraManagerState.ts +3 -2
- package/src/devices/MicrophoneManager.ts +1 -2
- package/src/devices/MicrophoneManagerState.ts +3 -2
- package/src/devices/devices.ts +26 -34
- package/src/helpers/AudioBindingsWatchdog.ts +118 -0
- package/src/helpers/DynascaleManager.ts +22 -24
- package/src/helpers/__tests__/AudioBindingsWatchdog.test.ts +325 -0
- package/src/helpers/__tests__/DynascaleManager.test.ts +64 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
4
|
|
|
5
|
+
## [1.44.5](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.44.4...@stream-io/video-client-1.44.5) (2026-03-27)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- make WebAudio opt-in, add AudioBindingsWatchdog ([#2171](https://github.com/GetStream/stream-video-js/issues/2171)) ([8d00f48](https://github.com/GetStream/stream-video-js/commit/8d00f485a37fec23dca340d32738a3cb1f7f325a))
|
|
10
|
+
|
|
11
|
+
## [1.44.4](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.44.3...@stream-io/video-client-1.44.4) (2026-03-20)
|
|
12
|
+
|
|
13
|
+
- trace device permission state transitions ([#2168](https://github.com/GetStream/stream-video-js/issues/2168)) ([e4203a3](https://github.com/GetStream/stream-video-js/commit/e4203a34cad1c90d1bc5612fc379dd1f0f0ebe5d))
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
- **react:** remove default broken microphone notification from call controls ([#2158](https://github.com/GetStream/stream-video-js/issues/2158)) ([4a95b9c](https://github.com/GetStream/stream-video-js/commit/4a95b9c29e9d2728ae7eea764f07ec8507aa0f5a))
|
|
18
|
+
|
|
5
19
|
## [1.44.3](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.44.2...@stream-io/video-client-1.44.3) (2026-03-06)
|
|
6
20
|
|
|
7
21
|
### Bug Fixes
|
package/dist/index.browser.es.js
CHANGED
|
@@ -6283,7 +6283,7 @@ const getSdkVersion = (sdk) => {
|
|
|
6283
6283
|
return sdk ? `${sdk.major}.${sdk.minor}.${sdk.patch}` : '0.0.0-development';
|
|
6284
6284
|
};
|
|
6285
6285
|
|
|
6286
|
-
const version = "1.44.
|
|
6286
|
+
const version = "1.44.5";
|
|
6287
6287
|
const [major, minor, patch] = version.split('.');
|
|
6288
6288
|
let sdkInfo = {
|
|
6289
6289
|
type: SdkType.PLAIN_JAVASCRIPT,
|
|
@@ -9491,6 +9491,96 @@ class ViewportTracker {
|
|
|
9491
9491
|
}
|
|
9492
9492
|
}
|
|
9493
9493
|
|
|
9494
|
+
const toBindingKey = (sessionId, trackType = 'audioTrack') => `${sessionId}/${trackType}`;
|
|
9495
|
+
/**
|
|
9496
|
+
* Tracks audio element bindings and periodically warns about
|
|
9497
|
+
* remote participants whose audio streams have no bound element.
|
|
9498
|
+
*/
|
|
9499
|
+
class AudioBindingsWatchdog {
|
|
9500
|
+
constructor(state, tracer) {
|
|
9501
|
+
this.state = state;
|
|
9502
|
+
this.tracer = tracer;
|
|
9503
|
+
this.bindings = new Map();
|
|
9504
|
+
this.enabled = true;
|
|
9505
|
+
this.logger = videoLoggerSystem.getLogger('AudioBindingsWatchdog');
|
|
9506
|
+
/**
|
|
9507
|
+
* Registers an audio element binding for the given session and track type.
|
|
9508
|
+
* Warns if a different element is already bound to the same key.
|
|
9509
|
+
*/
|
|
9510
|
+
this.register = (audioElement, sessionId, trackType) => {
|
|
9511
|
+
const key = toBindingKey(sessionId, trackType);
|
|
9512
|
+
const existing = this.bindings.get(key);
|
|
9513
|
+
if (existing && existing !== audioElement) {
|
|
9514
|
+
this.logger.warn(`Audio element already bound to ${sessionId} and ${trackType}`);
|
|
9515
|
+
this.tracer.trace('audioBinding.alreadyBoundWarning', trackType);
|
|
9516
|
+
}
|
|
9517
|
+
this.bindings.set(key, audioElement);
|
|
9518
|
+
};
|
|
9519
|
+
/**
|
|
9520
|
+
* Removes the audio element binding for the given session and track type.
|
|
9521
|
+
*/
|
|
9522
|
+
this.unregister = (sessionId, trackType) => {
|
|
9523
|
+
this.bindings.delete(toBindingKey(sessionId, trackType));
|
|
9524
|
+
};
|
|
9525
|
+
/**
|
|
9526
|
+
* Enables or disables the watchdog.
|
|
9527
|
+
* When disabled, the periodic check stops but bindings are still tracked.
|
|
9528
|
+
*/
|
|
9529
|
+
this.setEnabled = (enabled) => {
|
|
9530
|
+
this.enabled = enabled;
|
|
9531
|
+
if (enabled) {
|
|
9532
|
+
this.start();
|
|
9533
|
+
}
|
|
9534
|
+
else {
|
|
9535
|
+
this.stop();
|
|
9536
|
+
}
|
|
9537
|
+
};
|
|
9538
|
+
/**
|
|
9539
|
+
* Stops the watchdog and unsubscribes from callingState changes.
|
|
9540
|
+
*/
|
|
9541
|
+
this.dispose = () => {
|
|
9542
|
+
this.stop();
|
|
9543
|
+
this.unsubscribeCallingState();
|
|
9544
|
+
};
|
|
9545
|
+
this.start = () => {
|
|
9546
|
+
clearInterval(this.watchdogInterval);
|
|
9547
|
+
this.watchdogInterval = setInterval(() => {
|
|
9548
|
+
const danglingUserIds = [];
|
|
9549
|
+
for (const p of this.state.participants) {
|
|
9550
|
+
if (p.isLocalParticipant)
|
|
9551
|
+
continue;
|
|
9552
|
+
const { audioStream, screenShareAudioStream, sessionId, userId } = p;
|
|
9553
|
+
if (audioStream && !this.bindings.has(toBindingKey(sessionId))) {
|
|
9554
|
+
danglingUserIds.push(userId);
|
|
9555
|
+
}
|
|
9556
|
+
if (screenShareAudioStream &&
|
|
9557
|
+
!this.bindings.has(toBindingKey(sessionId, 'screenShareAudioTrack'))) {
|
|
9558
|
+
danglingUserIds.push(userId);
|
|
9559
|
+
}
|
|
9560
|
+
}
|
|
9561
|
+
if (danglingUserIds.length > 0) {
|
|
9562
|
+
const key = 'audioBinding.danglingWarning';
|
|
9563
|
+
this.tracer.traceOnce(key, key, danglingUserIds);
|
|
9564
|
+
this.logger.warn(`Dangling audio bindings detected. Did you forget to bind the audio element? user_ids: ${danglingUserIds}.`);
|
|
9565
|
+
}
|
|
9566
|
+
}, 3000);
|
|
9567
|
+
};
|
|
9568
|
+
this.stop = () => {
|
|
9569
|
+
clearInterval(this.watchdogInterval);
|
|
9570
|
+
};
|
|
9571
|
+
this.unsubscribeCallingState = createSubscription(state.callingState$, (callingState) => {
|
|
9572
|
+
if (!this.enabled)
|
|
9573
|
+
return;
|
|
9574
|
+
if (callingState !== CallingState.JOINED) {
|
|
9575
|
+
this.stop();
|
|
9576
|
+
}
|
|
9577
|
+
else {
|
|
9578
|
+
this.start();
|
|
9579
|
+
}
|
|
9580
|
+
});
|
|
9581
|
+
}
|
|
9582
|
+
}
|
|
9583
|
+
|
|
9494
9584
|
const DEFAULT_VIEWPORT_VISIBILITY_STATE = {
|
|
9495
9585
|
videoTrack: VisibilityState.UNKNOWN,
|
|
9496
9586
|
screenShareTrack: VisibilityState.UNKNOWN,
|
|
@@ -9516,7 +9606,7 @@ class DynascaleManager {
|
|
|
9516
9606
|
*/
|
|
9517
9607
|
this.viewportTracker = new ViewportTracker();
|
|
9518
9608
|
this.logger = videoLoggerSystem.getLogger('DynascaleManager');
|
|
9519
|
-
this.useWebAudio =
|
|
9609
|
+
this.useWebAudio = false;
|
|
9520
9610
|
this.pendingSubscriptionsUpdate = null;
|
|
9521
9611
|
this.videoTrackSubscriptionOverridesSubject = new BehaviorSubject({});
|
|
9522
9612
|
this.videoTrackSubscriptionOverrides$ = this.videoTrackSubscriptionOverridesSubject.asObservable();
|
|
@@ -9548,7 +9638,8 @@ class DynascaleManager {
|
|
|
9548
9638
|
if (this.pendingSubscriptionsUpdate) {
|
|
9549
9639
|
clearTimeout(this.pendingSubscriptionsUpdate);
|
|
9550
9640
|
}
|
|
9551
|
-
|
|
9641
|
+
this.audioBindingsWatchdog?.dispose();
|
|
9642
|
+
const context = this.audioContext;
|
|
9552
9643
|
if (context && context.state !== 'closed') {
|
|
9553
9644
|
document.removeEventListener('click', this.resumeAudioContext);
|
|
9554
9645
|
await context.close();
|
|
@@ -9747,12 +9838,13 @@ class DynascaleManager {
|
|
|
9747
9838
|
lastDimensions = currentDimensions;
|
|
9748
9839
|
});
|
|
9749
9840
|
resizeObserver?.observe(videoElement);
|
|
9841
|
+
const isVideoTrack = trackType === 'videoTrack';
|
|
9750
9842
|
// element renders and gets bound - track subscription gets
|
|
9751
9843
|
// triggered first other ones get skipped on initial subscriptions
|
|
9752
9844
|
const publishedTracksSubscription = boundParticipant.isLocalParticipant
|
|
9753
9845
|
? null
|
|
9754
9846
|
: participant$
|
|
9755
|
-
.pipe(distinctUntilKeyChanged('publishedTracks'), map((p) =>
|
|
9847
|
+
.pipe(distinctUntilKeyChanged('publishedTracks'), map((p) => (isVideoTrack ? hasVideo(p) : hasScreenShare(p))), distinctUntilChanged())
|
|
9756
9848
|
.subscribe((isPublishing) => {
|
|
9757
9849
|
if (isPublishing) {
|
|
9758
9850
|
// the participant just started to publish a track
|
|
@@ -9772,10 +9864,11 @@ class DynascaleManager {
|
|
|
9772
9864
|
// without prior user interaction:
|
|
9773
9865
|
// https://developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide
|
|
9774
9866
|
videoElement.muted = true;
|
|
9867
|
+
const trackKey = isVideoTrack ? 'videoStream' : 'screenShareStream';
|
|
9775
9868
|
const streamSubscription = participant$
|
|
9776
|
-
.pipe(distinctUntilKeyChanged(
|
|
9869
|
+
.pipe(distinctUntilKeyChanged(trackKey))
|
|
9777
9870
|
.subscribe((p) => {
|
|
9778
|
-
const source =
|
|
9871
|
+
const source = isVideoTrack ? p.videoStream : p.screenShareStream;
|
|
9779
9872
|
if (videoElement.srcObject === source)
|
|
9780
9873
|
return;
|
|
9781
9874
|
videoElement.srcObject = source ?? null;
|
|
@@ -9814,6 +9907,7 @@ class DynascaleManager {
|
|
|
9814
9907
|
const participant = this.callState.findParticipantBySessionId(sessionId);
|
|
9815
9908
|
if (!participant || participant.isLocalParticipant)
|
|
9816
9909
|
return;
|
|
9910
|
+
this.audioBindingsWatchdog?.register(audioElement, sessionId, trackType);
|
|
9817
9911
|
const participant$ = this.callState.participants$.pipe(map((ps) => ps.find((p) => p.sessionId === sessionId)), takeWhile((p) => !!p), distinctUntilChanged(), shareReplay({ bufferSize: 1, refCount: true }));
|
|
9818
9912
|
const updateSinkId = (deviceId, audioContext) => {
|
|
9819
9913
|
if (!deviceId)
|
|
@@ -9832,14 +9926,12 @@ class DynascaleManager {
|
|
|
9832
9926
|
};
|
|
9833
9927
|
let sourceNode = undefined;
|
|
9834
9928
|
let gainNode = undefined;
|
|
9929
|
+
const isAudioTrack = trackType === 'audioTrack';
|
|
9930
|
+
const trackKey = isAudioTrack ? 'audioStream' : 'screenShareAudioStream';
|
|
9835
9931
|
const updateMediaStreamSubscription = participant$
|
|
9836
|
-
.pipe(distinctUntilKeyChanged(
|
|
9837
|
-
? 'screenShareAudioStream'
|
|
9838
|
-
: 'audioStream'))
|
|
9932
|
+
.pipe(distinctUntilKeyChanged(trackKey))
|
|
9839
9933
|
.subscribe((p) => {
|
|
9840
|
-
const source =
|
|
9841
|
-
? p.screenShareAudioStream
|
|
9842
|
-
: p.audioStream;
|
|
9934
|
+
const source = isAudioTrack ? p.audioStream : p.screenShareAudioStream;
|
|
9843
9935
|
if (audioElement.srcObject === source)
|
|
9844
9936
|
return;
|
|
9845
9937
|
setTimeout(() => {
|
|
@@ -9894,6 +9986,7 @@ class DynascaleManager {
|
|
|
9894
9986
|
});
|
|
9895
9987
|
audioElement.autoplay = true;
|
|
9896
9988
|
return () => {
|
|
9989
|
+
this.audioBindingsWatchdog?.unregister(sessionId, trackType);
|
|
9897
9990
|
sinkIdSubscription?.unsubscribe();
|
|
9898
9991
|
volumeSubscription.unsubscribe();
|
|
9899
9992
|
updateMediaStreamSubscription.unsubscribe();
|
|
@@ -9954,6 +10047,9 @@ class DynascaleManager {
|
|
|
9954
10047
|
this.callState = callState;
|
|
9955
10048
|
this.speaker = speaker;
|
|
9956
10049
|
this.tracer = tracer;
|
|
10050
|
+
if (!isReactNative()) {
|
|
10051
|
+
this.audioBindingsWatchdog = new AudioBindingsWatchdog(callState, tracer);
|
|
10052
|
+
}
|
|
9957
10053
|
}
|
|
9958
10054
|
setSfuClient(sfuClient) {
|
|
9959
10055
|
this.sfuClient = sfuClient;
|
|
@@ -10298,6 +10394,9 @@ class BrowserPermission {
|
|
|
10298
10394
|
}
|
|
10299
10395
|
setState(state) {
|
|
10300
10396
|
if (this.state !== state) {
|
|
10397
|
+
const { tracer, queryName } = this.permission;
|
|
10398
|
+
const traceKey = `navigator.mediaDevices.${queryName}.permission`;
|
|
10399
|
+
tracer?.trace(traceKey, { previous: this.state, state });
|
|
10301
10400
|
this.state = state;
|
|
10302
10401
|
this.listeners.forEach((listener) => listener(state));
|
|
10303
10402
|
}
|
|
@@ -10339,9 +10438,6 @@ const getDevices = (permission, kind, tracer) => {
|
|
|
10339
10438
|
const checkIfAudioOutputChangeSupported = () => {
|
|
10340
10439
|
if (typeof document === 'undefined')
|
|
10341
10440
|
return false;
|
|
10342
|
-
// Safari uses WebAudio API for playing audio, so we check the AudioContext prototype
|
|
10343
|
-
if (isSafari())
|
|
10344
|
-
return 'setSinkId' in AudioContext.prototype;
|
|
10345
10441
|
const element = document.createElement('audio');
|
|
10346
10442
|
return 'setSinkId' in element;
|
|
10347
10443
|
};
|
|
@@ -10368,17 +10464,19 @@ const videoDeviceConstraints = {
|
|
|
10368
10464
|
* Keeps track of the browser permission to use microphone. This permission also
|
|
10369
10465
|
* affects an ability to enumerate audio devices.
|
|
10370
10466
|
*/
|
|
10371
|
-
const getAudioBrowserPermission = lazy(() => new BrowserPermission({
|
|
10467
|
+
const getAudioBrowserPermission = lazy((tracer) => new BrowserPermission({
|
|
10372
10468
|
constraints: audioDeviceConstraints,
|
|
10373
10469
|
queryName: 'microphone',
|
|
10470
|
+
tracer,
|
|
10374
10471
|
}));
|
|
10375
10472
|
/**
|
|
10376
10473
|
* Keeps track of the browser permission to use camera. This permission also
|
|
10377
10474
|
* affects an ability to enumerate video devices.
|
|
10378
10475
|
*/
|
|
10379
|
-
const getVideoBrowserPermission = lazy(() => new BrowserPermission({
|
|
10476
|
+
const getVideoBrowserPermission = lazy((tracer) => new BrowserPermission({
|
|
10380
10477
|
constraints: videoDeviceConstraints,
|
|
10381
10478
|
queryName: 'camera',
|
|
10479
|
+
tracer,
|
|
10382
10480
|
}));
|
|
10383
10481
|
const getDeviceChangeObserver = lazy((tracer) => {
|
|
10384
10482
|
// 'addEventListener' is not available in React Native, returning
|
|
@@ -10394,7 +10492,7 @@ const getDeviceChangeObserver = lazy((tracer) => {
|
|
|
10394
10492
|
* the observable errors.
|
|
10395
10493
|
*/
|
|
10396
10494
|
const getAudioDevices = lazy((tracer) => {
|
|
10397
|
-
return merge(getDeviceChangeObserver(tracer), getAudioBrowserPermission().asObservable()).pipe(startWith([]), concatMap(() => getDevices(getAudioBrowserPermission(), 'audioinput', tracer)), shareReplay(1));
|
|
10495
|
+
return merge(getDeviceChangeObserver(tracer), getAudioBrowserPermission(tracer).asObservable()).pipe(startWith([]), concatMap(() => getDevices(getAudioBrowserPermission(tracer), 'audioinput', tracer)), shareReplay(1));
|
|
10398
10496
|
});
|
|
10399
10497
|
/**
|
|
10400
10498
|
* Prompts the user for a permission to use video devices (if not already granted
|
|
@@ -10403,7 +10501,7 @@ const getAudioDevices = lazy((tracer) => {
|
|
|
10403
10501
|
* the observable errors.
|
|
10404
10502
|
*/
|
|
10405
10503
|
const getVideoDevices = lazy((tracer) => {
|
|
10406
|
-
return merge(getDeviceChangeObserver(tracer), getVideoBrowserPermission().asObservable()).pipe(startWith([]), concatMap(() => getDevices(getVideoBrowserPermission(), 'videoinput', tracer)), shareReplay(1));
|
|
10504
|
+
return merge(getDeviceChangeObserver(tracer), getVideoBrowserPermission(tracer).asObservable()).pipe(startWith([]), concatMap(() => getDevices(getVideoBrowserPermission(tracer), 'videoinput', tracer)), shareReplay(1));
|
|
10407
10505
|
});
|
|
10408
10506
|
/**
|
|
10409
10507
|
* Prompts the user for a permission to use video devices (if not already granted
|
|
@@ -10412,7 +10510,7 @@ const getVideoDevices = lazy((tracer) => {
|
|
|
10412
10510
|
* the observable errors.
|
|
10413
10511
|
*/
|
|
10414
10512
|
const getAudioOutputDevices = lazy((tracer) => {
|
|
10415
|
-
return merge(getDeviceChangeObserver(tracer), getAudioBrowserPermission().asObservable()).pipe(startWith([]), concatMap(() => getDevices(getAudioBrowserPermission(), 'audiooutput', tracer)), shareReplay(1));
|
|
10513
|
+
return merge(getDeviceChangeObserver(tracer), getAudioBrowserPermission(tracer).asObservable()).pipe(startWith([]), concatMap(() => getDevices(getAudioBrowserPermission(tracer), 'audiooutput', tracer)), shareReplay(1));
|
|
10416
10514
|
});
|
|
10417
10515
|
let getUserMediaExecId = 0;
|
|
10418
10516
|
const getStream = async (constraints, tracer) => {
|
|
@@ -10478,25 +10576,21 @@ const getAudioStream = async (trackConstraints, tracer) => {
|
|
|
10478
10576
|
},
|
|
10479
10577
|
};
|
|
10480
10578
|
try {
|
|
10481
|
-
await getAudioBrowserPermission().prompt({
|
|
10579
|
+
await getAudioBrowserPermission(tracer).prompt({
|
|
10482
10580
|
throwOnNotAllowed: true,
|
|
10483
10581
|
forcePrompt: true,
|
|
10484
10582
|
});
|
|
10485
10583
|
return await getStream(constraints, tracer);
|
|
10486
10584
|
}
|
|
10487
10585
|
catch (error) {
|
|
10586
|
+
const logger = videoLoggerSystem.getLogger('devices');
|
|
10488
10587
|
if (isNotFoundOrOverconstrainedError(error) && trackConstraints?.deviceId) {
|
|
10489
10588
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
10490
10589
|
const { deviceId, ...relaxedConstraints } = trackConstraints;
|
|
10491
|
-
|
|
10492
|
-
.getLogger('devices')
|
|
10493
|
-
.warn('Failed to get audio stream, will try again with relaxed constraints', { error, constraints, relaxedConstraints });
|
|
10590
|
+
logger.warn('Failed to get audio stream, will try again with relaxed constraints', { error, constraints, relaxedConstraints });
|
|
10494
10591
|
return getAudioStream(relaxedConstraints, tracer);
|
|
10495
10592
|
}
|
|
10496
|
-
|
|
10497
|
-
error,
|
|
10498
|
-
constraints,
|
|
10499
|
-
});
|
|
10593
|
+
logger.error('Failed to get audio stream', { error, constraints });
|
|
10500
10594
|
throw error;
|
|
10501
10595
|
}
|
|
10502
10596
|
};
|
|
@@ -10516,25 +10610,21 @@ const getVideoStream = async (trackConstraints, tracer) => {
|
|
|
10516
10610
|
},
|
|
10517
10611
|
};
|
|
10518
10612
|
try {
|
|
10519
|
-
await getVideoBrowserPermission().prompt({
|
|
10613
|
+
await getVideoBrowserPermission(tracer).prompt({
|
|
10520
10614
|
throwOnNotAllowed: true,
|
|
10521
10615
|
forcePrompt: true,
|
|
10522
10616
|
});
|
|
10523
10617
|
return await getStream(constraints, tracer);
|
|
10524
10618
|
}
|
|
10525
10619
|
catch (error) {
|
|
10620
|
+
const logger = videoLoggerSystem.getLogger('devices');
|
|
10526
10621
|
if (isNotFoundOrOverconstrainedError(error) && trackConstraints?.deviceId) {
|
|
10527
10622
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
10528
10623
|
const { deviceId, ...relaxedConstraints } = trackConstraints;
|
|
10529
|
-
|
|
10530
|
-
|
|
10531
|
-
.warn('Failed to get video stream, will try again with relaxed constraints', { error, constraints, relaxedConstraints });
|
|
10532
|
-
return getVideoStream(relaxedConstraints);
|
|
10624
|
+
logger.warn('Failed to get video stream, will try again with relaxed constraints', { error, constraints, relaxedConstraints });
|
|
10625
|
+
return getVideoStream(relaxedConstraints, tracer);
|
|
10533
10626
|
}
|
|
10534
|
-
|
|
10535
|
-
error,
|
|
10536
|
-
constraints,
|
|
10537
|
-
});
|
|
10627
|
+
logger.error('Failed to get video stream', { error, constraints });
|
|
10538
10628
|
throw error;
|
|
10539
10629
|
}
|
|
10540
10630
|
};
|
|
@@ -11305,8 +11395,8 @@ class DeviceManagerState {
|
|
|
11305
11395
|
}
|
|
11306
11396
|
|
|
11307
11397
|
class CameraManagerState extends DeviceManagerState {
|
|
11308
|
-
constructor() {
|
|
11309
|
-
super('stop-tracks', getVideoBrowserPermission());
|
|
11398
|
+
constructor(tracer) {
|
|
11399
|
+
super('stop-tracks', getVideoBrowserPermission(tracer));
|
|
11310
11400
|
this.directionSubject = new BehaviorSubject(undefined);
|
|
11311
11401
|
/**
|
|
11312
11402
|
* Observable that emits the preferred camera direction
|
|
@@ -11360,7 +11450,7 @@ class CameraManager extends DeviceManager {
|
|
|
11360
11450
|
* @param devicePersistence the device persistence preferences to use.
|
|
11361
11451
|
*/
|
|
11362
11452
|
constructor(call, devicePersistence) {
|
|
11363
|
-
super(call, new CameraManagerState(), TrackType.VIDEO, devicePersistence);
|
|
11453
|
+
super(call, new CameraManagerState(call.tracer), TrackType.VIDEO, devicePersistence);
|
|
11364
11454
|
this.targetResolution = {
|
|
11365
11455
|
width: 1280,
|
|
11366
11456
|
height: 720,
|
|
@@ -11571,8 +11661,8 @@ class AudioDeviceManagerState extends DeviceManagerState {
|
|
|
11571
11661
|
}
|
|
11572
11662
|
|
|
11573
11663
|
class MicrophoneManagerState extends AudioDeviceManagerState {
|
|
11574
|
-
constructor(disableMode) {
|
|
11575
|
-
super(disableMode, getAudioBrowserPermission(), AudioBitrateProfile.VOICE_STANDARD_UNSPECIFIED);
|
|
11664
|
+
constructor(disableMode, tracer) {
|
|
11665
|
+
super(disableMode, getAudioBrowserPermission(tracer), AudioBitrateProfile.VOICE_STANDARD_UNSPECIFIED);
|
|
11576
11666
|
this.speakingWhileMutedSubject = new BehaviorSubject(false);
|
|
11577
11667
|
/**
|
|
11578
11668
|
* An Observable that emits `true` if the user's microphone is muted, but they're speaking.
|
|
@@ -11912,7 +12002,7 @@ class RNSpeechDetector {
|
|
|
11912
12002
|
|
|
11913
12003
|
class MicrophoneManager extends AudioDeviceManager {
|
|
11914
12004
|
constructor(call, devicePersistence, disableMode = 'stop-tracks') {
|
|
11915
|
-
super(call, new MicrophoneManagerState(disableMode), TrackType.AUDIO, devicePersistence);
|
|
12005
|
+
super(call, new MicrophoneManagerState(disableMode, call.tracer), TrackType.AUDIO, devicePersistence);
|
|
11916
12006
|
this.speakingWhileMutedNotificationEnabled = true;
|
|
11917
12007
|
this.soundDetectorConcurrencyTag = Symbol('soundDetectorConcurrencyTag');
|
|
11918
12008
|
this.silenceThresholdMs = 5000;
|
|
@@ -12014,7 +12104,6 @@ class MicrophoneManager extends AudioDeviceManager {
|
|
|
12014
12104
|
deviceId,
|
|
12015
12105
|
label,
|
|
12016
12106
|
};
|
|
12017
|
-
console.log(event);
|
|
12018
12107
|
this.call.tracer.trace('mic.capture_report', event);
|
|
12019
12108
|
this.call.streamClient.dispatchEvent(event);
|
|
12020
12109
|
},
|
|
@@ -15890,7 +15979,7 @@ class StreamClient {
|
|
|
15890
15979
|
this.getUserAgent = () => {
|
|
15891
15980
|
if (!this.cachedUserAgent) {
|
|
15892
15981
|
const { clientAppIdentifier = {} } = this.options;
|
|
15893
|
-
const { sdkName = 'js', sdkVersion = "1.44.
|
|
15982
|
+
const { sdkName = 'js', sdkVersion = "1.44.5", ...extras } = clientAppIdentifier;
|
|
15894
15983
|
this.cachedUserAgent = [
|
|
15895
15984
|
`stream-video-${sdkName}-v${sdkVersion}`,
|
|
15896
15985
|
...Object.entries(extras).map(([key, value]) => `${key}=${value}`),
|