@stream-io/video-client 0.3.8 → 0.3.10
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 +481 -152
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +480 -150
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +481 -152
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +50 -10
- package/dist/src/helpers/DynascaleManager.d.ts +70 -0
- package/dist/src/helpers/__tests__/DynascaleManager.test.d.ts +4 -0
- package/dist/src/types.d.ts +4 -5
- package/dist/version.d.ts +1 -1
- package/index.ts +2 -1
- package/package.json +8 -7
- package/src/Call.ts +140 -24
- package/src/events/__tests__/participant.test.ts +4 -1
- package/src/events/participant.ts +4 -1
- package/src/helpers/DynascaleManager.ts +345 -0
- package/src/helpers/__tests__/DynascaleManager.test.ts +391 -0
- package/src/sorting/__tests__/participant-data.ts +24 -6
- package/src/sorting/presets.ts +2 -2
- package/src/store/__tests__/CallState.test.ts +3 -3
- package/src/store/rxUtils.ts +10 -1
- package/src/types.ts +5 -5
package/dist/index.cjs.js
CHANGED
|
@@ -5734,7 +5734,7 @@ exports.VisibilityState = void 0;
|
|
|
5734
5734
|
})(exports.VisibilityState || (exports.VisibilityState = {}));
|
|
5735
5735
|
exports.DebounceType = void 0;
|
|
5736
5736
|
(function (DebounceType) {
|
|
5737
|
-
DebounceType[DebounceType["IMMEDIATE"] =
|
|
5737
|
+
DebounceType[DebounceType["IMMEDIATE"] = 20] = "IMMEDIATE";
|
|
5738
5738
|
DebounceType[DebounceType["FAST"] = 100] = "FAST";
|
|
5739
5739
|
DebounceType[DebounceType["MEDIUM"] = 600] = "MEDIUM";
|
|
5740
5740
|
DebounceType[DebounceType["SLOW"] = 1200] = "SLOW";
|
|
@@ -7609,10 +7609,20 @@ const retryable = (rpc, logger) => __awaiter(void 0, void 0, void 0, function* (
|
|
|
7609
7609
|
*/
|
|
7610
7610
|
const getCurrentValue = (observable$) => {
|
|
7611
7611
|
let value;
|
|
7612
|
+
let err = undefined;
|
|
7612
7613
|
observable$
|
|
7613
7614
|
.pipe(operators.take(1))
|
|
7614
|
-
.subscribe(
|
|
7615
|
+
.subscribe({
|
|
7616
|
+
next: (v) => {
|
|
7617
|
+
value = v;
|
|
7618
|
+
},
|
|
7619
|
+
error: (e) => {
|
|
7620
|
+
err = e;
|
|
7621
|
+
},
|
|
7622
|
+
})
|
|
7615
7623
|
.unsubscribe();
|
|
7624
|
+
if (err)
|
|
7625
|
+
throw err;
|
|
7616
7626
|
return value;
|
|
7617
7627
|
};
|
|
7618
7628
|
/**
|
|
@@ -7971,8 +7981,11 @@ const hasAudio = (p) => p.publishedTracks.includes(TrackType.AUDIO);
|
|
|
7971
7981
|
// a comparator decorator which applies the decorated comparator only if the
|
|
7972
7982
|
// participant is invisible.
|
|
7973
7983
|
// This ensures stable sorting when all participants are visible.
|
|
7974
|
-
const ifInvisibleBy = conditional((a, b) =>
|
|
7975
|
-
|
|
7984
|
+
const ifInvisibleBy = conditional((a, b) => {
|
|
7985
|
+
var _a, _b;
|
|
7986
|
+
return ((_a = a.viewportVisibilityState) === null || _a === void 0 ? void 0 : _a.videoTrack) === exports.VisibilityState.INVISIBLE ||
|
|
7987
|
+
((_b = b.viewportVisibilityState) === null || _b === void 0 ? void 0 : _b.videoTrack) === exports.VisibilityState.INVISIBLE;
|
|
7988
|
+
});
|
|
7976
7989
|
/**
|
|
7977
7990
|
* The default sorting preset.
|
|
7978
7991
|
*/
|
|
@@ -8849,7 +8862,10 @@ const watchParticipantJoined = (state) => {
|
|
|
8849
8862
|
// response and then follow up with a `participantJoined` event for
|
|
8850
8863
|
// already announced participants.
|
|
8851
8864
|
state.updateOrAddParticipant(participant.sessionId, Object.assign(participant, {
|
|
8852
|
-
viewportVisibilityState:
|
|
8865
|
+
viewportVisibilityState: {
|
|
8866
|
+
videoTrack: exports.VisibilityState.UNKNOWN,
|
|
8867
|
+
screenShareTrack: exports.VisibilityState.UNKNOWN,
|
|
8868
|
+
},
|
|
8853
8869
|
}));
|
|
8854
8870
|
};
|
|
8855
8871
|
};
|
|
@@ -9406,6 +9422,234 @@ class ViewportTracker {
|
|
|
9406
9422
|
}
|
|
9407
9423
|
}
|
|
9408
9424
|
|
|
9425
|
+
const DEFAULT_VIEWPORT_VISIBILITY_STATE = {
|
|
9426
|
+
videoTrack: exports.VisibilityState.UNKNOWN,
|
|
9427
|
+
screenShareTrack: exports.VisibilityState.UNKNOWN,
|
|
9428
|
+
};
|
|
9429
|
+
/**
|
|
9430
|
+
* A manager class that handles dynascale related tasks like:
|
|
9431
|
+
*
|
|
9432
|
+
* - binding video elements to session ids
|
|
9433
|
+
* - binding audio elements to session ids
|
|
9434
|
+
* - tracking element visibility
|
|
9435
|
+
* - updating subscriptions based on viewport visibility
|
|
9436
|
+
* - updating subscriptions based on video element dimensions
|
|
9437
|
+
* - updating subscriptions based on published tracks
|
|
9438
|
+
*/
|
|
9439
|
+
class DynascaleManager {
|
|
9440
|
+
/**
|
|
9441
|
+
* Creates a new DynascaleManager instance.
|
|
9442
|
+
*
|
|
9443
|
+
* @param call the call to manage.
|
|
9444
|
+
*/
|
|
9445
|
+
constructor(call) {
|
|
9446
|
+
/**
|
|
9447
|
+
* The viewport tracker instance.
|
|
9448
|
+
*/
|
|
9449
|
+
this.viewportTracker = new ViewportTracker();
|
|
9450
|
+
this.logger = getLogger(['DynascaleManager']);
|
|
9451
|
+
/**
|
|
9452
|
+
* Will begin tracking the given element for visibility changes within the
|
|
9453
|
+
* configured viewport element (`call.setViewport`).
|
|
9454
|
+
*
|
|
9455
|
+
* @param element the element to track.
|
|
9456
|
+
* @param sessionId the session id.
|
|
9457
|
+
* @param trackType the kind of video.
|
|
9458
|
+
* @returns Untrack.
|
|
9459
|
+
*/
|
|
9460
|
+
this.trackElementVisibility = (element, sessionId, trackType) => {
|
|
9461
|
+
const cleanup = this.viewportTracker.observe(element, (entry) => {
|
|
9462
|
+
this.call.state.updateParticipant(sessionId, (participant) => {
|
|
9463
|
+
var _a;
|
|
9464
|
+
const previousVisibilityState = (_a = participant.viewportVisibilityState) !== null && _a !== void 0 ? _a : DEFAULT_VIEWPORT_VISIBILITY_STATE;
|
|
9465
|
+
// observer triggers when the element is "moved" to be a fullscreen element
|
|
9466
|
+
// keep it VISIBLE if that happens to prevent fullscreen with placeholder
|
|
9467
|
+
const isVisible = entry.isIntersecting || document.fullscreenElement === element
|
|
9468
|
+
? exports.VisibilityState.VISIBLE
|
|
9469
|
+
: exports.VisibilityState.INVISIBLE;
|
|
9470
|
+
return Object.assign(Object.assign({}, participant), { viewportVisibilityState: Object.assign(Object.assign({}, previousVisibilityState), { [trackType]: isVisible }) });
|
|
9471
|
+
});
|
|
9472
|
+
});
|
|
9473
|
+
return () => {
|
|
9474
|
+
cleanup();
|
|
9475
|
+
// reset visibility state to UNKNOWN upon cleanup
|
|
9476
|
+
// so that the layouts that are not actively observed
|
|
9477
|
+
// can still function normally (runtime layout switching)
|
|
9478
|
+
this.call.state.updateParticipant(sessionId, (participant) => {
|
|
9479
|
+
var _a;
|
|
9480
|
+
const previousVisibilityState = (_a = participant.viewportVisibilityState) !== null && _a !== void 0 ? _a : DEFAULT_VIEWPORT_VISIBILITY_STATE;
|
|
9481
|
+
return Object.assign(Object.assign({}, participant), { viewportVisibilityState: Object.assign(Object.assign({}, previousVisibilityState), { [trackType]: exports.VisibilityState.UNKNOWN }) });
|
|
9482
|
+
});
|
|
9483
|
+
};
|
|
9484
|
+
};
|
|
9485
|
+
/**
|
|
9486
|
+
* Sets the viewport element to track bound video elements for visibility.
|
|
9487
|
+
*
|
|
9488
|
+
* @param element the viewport element.
|
|
9489
|
+
*/
|
|
9490
|
+
this.setViewport = (element) => {
|
|
9491
|
+
return this.viewportTracker.setViewport(element);
|
|
9492
|
+
};
|
|
9493
|
+
/**
|
|
9494
|
+
* Binds a DOM <video> element to the given session id.
|
|
9495
|
+
* This method will make sure that the video element will play
|
|
9496
|
+
* the correct video stream for the given session id.
|
|
9497
|
+
*
|
|
9498
|
+
* Under the hood, it would also keep track of the video element dimensions
|
|
9499
|
+
* and update the subscription accordingly in order to optimize the bandwidth.
|
|
9500
|
+
*
|
|
9501
|
+
* If a "viewport" is configured, the video element will be automatically
|
|
9502
|
+
* tracked for visibility and the subscription will be updated accordingly.
|
|
9503
|
+
*
|
|
9504
|
+
* @param videoElement the video element to bind to.
|
|
9505
|
+
* @param sessionId the session id.
|
|
9506
|
+
* @param trackType the kind of video.
|
|
9507
|
+
*/
|
|
9508
|
+
this.bindVideoElement = (videoElement, sessionId, trackType) => {
|
|
9509
|
+
const boundParticipant = this.call.state.findParticipantBySessionId(sessionId);
|
|
9510
|
+
if (!boundParticipant)
|
|
9511
|
+
return;
|
|
9512
|
+
const requestTrackWithDimensions = (debounceType, dimension) => {
|
|
9513
|
+
this.call.updateSubscriptionsPartial(trackType, { [sessionId]: { dimension } }, debounceType);
|
|
9514
|
+
};
|
|
9515
|
+
const participant$ = this.call.state.participants$.pipe(rxjs.map((participants) => participants.find((participant) => participant.sessionId === sessionId)), rxjs.takeWhile((participant) => !!participant), rxjs.distinctUntilChanged());
|
|
9516
|
+
// keep copy for resize observer handler
|
|
9517
|
+
let viewportVisibilityState;
|
|
9518
|
+
const viewportVisibilityStateSubscription = boundParticipant.isLocalParticipant
|
|
9519
|
+
? null
|
|
9520
|
+
: participant$
|
|
9521
|
+
.pipe(rxjs.map((p) => { var _a; return (_a = p.viewportVisibilityState) === null || _a === void 0 ? void 0 : _a[trackType]; }), rxjs.distinctUntilChanged())
|
|
9522
|
+
.subscribe((nextViewportVisibilityState) => {
|
|
9523
|
+
// skip initial trigger
|
|
9524
|
+
if (!viewportVisibilityState) {
|
|
9525
|
+
viewportVisibilityState =
|
|
9526
|
+
nextViewportVisibilityState !== null && nextViewportVisibilityState !== void 0 ? nextViewportVisibilityState : exports.VisibilityState.UNKNOWN;
|
|
9527
|
+
return;
|
|
9528
|
+
}
|
|
9529
|
+
viewportVisibilityState =
|
|
9530
|
+
nextViewportVisibilityState !== null && nextViewportVisibilityState !== void 0 ? nextViewportVisibilityState : exports.VisibilityState.UNKNOWN;
|
|
9531
|
+
if (nextViewportVisibilityState === exports.VisibilityState.INVISIBLE) {
|
|
9532
|
+
return requestTrackWithDimensions(exports.DebounceType.MEDIUM, undefined);
|
|
9533
|
+
}
|
|
9534
|
+
requestTrackWithDimensions(exports.DebounceType.MEDIUM, {
|
|
9535
|
+
width: videoElement.clientWidth,
|
|
9536
|
+
height: videoElement.clientHeight,
|
|
9537
|
+
});
|
|
9538
|
+
});
|
|
9539
|
+
let lastDimensions;
|
|
9540
|
+
const resizeObserver = boundParticipant.isLocalParticipant
|
|
9541
|
+
? null
|
|
9542
|
+
: new ResizeObserver(() => {
|
|
9543
|
+
const currentDimensions = `${videoElement.clientWidth},${videoElement.clientHeight}`;
|
|
9544
|
+
// skip initial trigger
|
|
9545
|
+
if (!lastDimensions) {
|
|
9546
|
+
lastDimensions = currentDimensions;
|
|
9547
|
+
return;
|
|
9548
|
+
}
|
|
9549
|
+
if (lastDimensions === currentDimensions ||
|
|
9550
|
+
viewportVisibilityState === exports.VisibilityState.INVISIBLE) {
|
|
9551
|
+
return;
|
|
9552
|
+
}
|
|
9553
|
+
requestTrackWithDimensions(exports.DebounceType.SLOW, {
|
|
9554
|
+
width: videoElement.clientWidth,
|
|
9555
|
+
height: videoElement.clientHeight,
|
|
9556
|
+
});
|
|
9557
|
+
lastDimensions = currentDimensions;
|
|
9558
|
+
});
|
|
9559
|
+
resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.observe(videoElement);
|
|
9560
|
+
const publishedTracksSubscription = boundParticipant.isLocalParticipant
|
|
9561
|
+
? null
|
|
9562
|
+
: participant$
|
|
9563
|
+
.pipe(rxjs.distinctUntilKeyChanged('publishedTracks'), rxjs.map((p) => p.publishedTracks.includes(trackType === 'videoTrack'
|
|
9564
|
+
? TrackType.VIDEO
|
|
9565
|
+
: TrackType.SCREEN_SHARE)), rxjs.distinctUntilChanged())
|
|
9566
|
+
.subscribe((isPublishing) => {
|
|
9567
|
+
if (isPublishing) {
|
|
9568
|
+
// the participant just started to publish a track
|
|
9569
|
+
requestTrackWithDimensions(exports.DebounceType.IMMEDIATE, {
|
|
9570
|
+
width: videoElement.clientWidth,
|
|
9571
|
+
height: videoElement.clientHeight,
|
|
9572
|
+
});
|
|
9573
|
+
}
|
|
9574
|
+
else {
|
|
9575
|
+
// the participant just stopped publishing a track
|
|
9576
|
+
requestTrackWithDimensions(exports.DebounceType.IMMEDIATE, undefined);
|
|
9577
|
+
}
|
|
9578
|
+
});
|
|
9579
|
+
const streamSubscription = participant$
|
|
9580
|
+
.pipe(rxjs.distinctUntilKeyChanged(trackType === 'videoTrack' ? 'videoStream' : 'screenShareStream'))
|
|
9581
|
+
.subscribe((p) => {
|
|
9582
|
+
const source = trackType === 'videoTrack' ? p.videoStream : p.screenShareStream;
|
|
9583
|
+
if (videoElement.srcObject === source)
|
|
9584
|
+
return;
|
|
9585
|
+
setTimeout(() => {
|
|
9586
|
+
videoElement.srcObject = source !== null && source !== void 0 ? source : null;
|
|
9587
|
+
if (videoElement.srcObject) {
|
|
9588
|
+
videoElement.play().catch((e) => {
|
|
9589
|
+
this.logger('warn', `Failed to play stream`, e);
|
|
9590
|
+
});
|
|
9591
|
+
}
|
|
9592
|
+
}, 0);
|
|
9593
|
+
});
|
|
9594
|
+
videoElement.playsInline = true;
|
|
9595
|
+
videoElement.autoplay = true;
|
|
9596
|
+
// explicitly marking the element as muted will allow autoplay to work
|
|
9597
|
+
// without prior user interaction:
|
|
9598
|
+
// https://developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide
|
|
9599
|
+
videoElement.muted = true;
|
|
9600
|
+
return () => {
|
|
9601
|
+
viewportVisibilityStateSubscription === null || viewportVisibilityStateSubscription === void 0 ? void 0 : viewportVisibilityStateSubscription.unsubscribe();
|
|
9602
|
+
publishedTracksSubscription === null || publishedTracksSubscription === void 0 ? void 0 : publishedTracksSubscription.unsubscribe();
|
|
9603
|
+
streamSubscription.unsubscribe();
|
|
9604
|
+
resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.disconnect();
|
|
9605
|
+
};
|
|
9606
|
+
};
|
|
9607
|
+
/**
|
|
9608
|
+
* Binds a DOM <audio> element to the given session id.
|
|
9609
|
+
*
|
|
9610
|
+
* This method will make sure that the audio element will
|
|
9611
|
+
* play the correct audio stream for the given session id.
|
|
9612
|
+
*
|
|
9613
|
+
* @param audioElement the audio element to bind to.
|
|
9614
|
+
* @param sessionId the session id.
|
|
9615
|
+
* @returns a cleanup function that will unbind the audio element.
|
|
9616
|
+
*/
|
|
9617
|
+
this.bindAudioElement = (audioElement, sessionId) => {
|
|
9618
|
+
const participant = this.call.state.findParticipantBySessionId(sessionId);
|
|
9619
|
+
if (!participant || participant.isLocalParticipant)
|
|
9620
|
+
return;
|
|
9621
|
+
const participant$ = this.call.state.participants$.pipe(rxjs.map((participants) => participants.find((p) => p.sessionId === sessionId)), rxjs.takeWhile((p) => !!p), rxjs.distinctUntilChanged());
|
|
9622
|
+
const updateMediaStreamSubscription = participant$
|
|
9623
|
+
.pipe(rxjs.distinctUntilKeyChanged('audioStream'))
|
|
9624
|
+
.subscribe((p) => {
|
|
9625
|
+
const source = p.audioStream;
|
|
9626
|
+
if (audioElement.srcObject === source)
|
|
9627
|
+
return;
|
|
9628
|
+
setTimeout(() => {
|
|
9629
|
+
audioElement.srcObject = source !== null && source !== void 0 ? source : null;
|
|
9630
|
+
if (audioElement.srcObject) {
|
|
9631
|
+
audioElement.play().catch((e) => {
|
|
9632
|
+
this.logger('warn', `Failed to play stream`, e);
|
|
9633
|
+
});
|
|
9634
|
+
}
|
|
9635
|
+
});
|
|
9636
|
+
});
|
|
9637
|
+
const sinkIdSubscription = this.call.state.localParticipant$.subscribe((p) => {
|
|
9638
|
+
if (p && p.audioOutputDeviceId && 'setSinkId' in audioElement) {
|
|
9639
|
+
// @ts-expect-error setSinkId is not yet in the lib
|
|
9640
|
+
audioElement.setSinkId(p.audioOutputDeviceId);
|
|
9641
|
+
}
|
|
9642
|
+
});
|
|
9643
|
+
audioElement.autoplay = true;
|
|
9644
|
+
return () => {
|
|
9645
|
+
sinkIdSubscription.unsubscribe();
|
|
9646
|
+
updateMediaStreamSubscription.unsubscribe();
|
|
9647
|
+
};
|
|
9648
|
+
};
|
|
9649
|
+
this.call = call;
|
|
9650
|
+
}
|
|
9651
|
+
}
|
|
9652
|
+
|
|
9409
9653
|
/**
|
|
9410
9654
|
* Stores the permissions for the current user and exposes
|
|
9411
9655
|
* a few helper methods which make it easier to work with permissions.
|
|
@@ -9545,127 +9789,6 @@ const CallTypes = new CallTypesRegistry([
|
|
|
9545
9789
|
}),
|
|
9546
9790
|
]);
|
|
9547
9791
|
|
|
9548
|
-
class InputMediaDeviceManagerState {
|
|
9549
|
-
constructor(disableMode = 'stop-tracks') {
|
|
9550
|
-
this.disableMode = disableMode;
|
|
9551
|
-
this.statusSubject = new rxjs.BehaviorSubject(undefined);
|
|
9552
|
-
this.mediaStreamSubject = new rxjs.BehaviorSubject(undefined);
|
|
9553
|
-
this.selectedDeviceSubject = new rxjs.BehaviorSubject(undefined);
|
|
9554
|
-
/**
|
|
9555
|
-
* Gets the current value of an observable, or undefined if the observable has
|
|
9556
|
-
* not emitted a value yet.
|
|
9557
|
-
*
|
|
9558
|
-
* @param observable$ the observable to get the value from.
|
|
9559
|
-
*/
|
|
9560
|
-
this.getCurrentValue = getCurrentValue;
|
|
9561
|
-
/**
|
|
9562
|
-
* Updates the value of the provided Subject.
|
|
9563
|
-
* An `update` can either be a new value or a function which takes
|
|
9564
|
-
* the current value and returns a new value.
|
|
9565
|
-
*
|
|
9566
|
-
* @internal
|
|
9567
|
-
*
|
|
9568
|
-
* @param subject the subject to update.
|
|
9569
|
-
* @param update the update to apply to the subject.
|
|
9570
|
-
* @return the updated value.
|
|
9571
|
-
*/
|
|
9572
|
-
this.setCurrentValue = setCurrentValue;
|
|
9573
|
-
this.mediaStream$ = this.mediaStreamSubject.asObservable();
|
|
9574
|
-
this.selectedDevice$ = this.selectedDeviceSubject
|
|
9575
|
-
.asObservable()
|
|
9576
|
-
.pipe(rxjs.distinctUntilChanged());
|
|
9577
|
-
this.status$ = this.statusSubject
|
|
9578
|
-
.asObservable()
|
|
9579
|
-
.pipe(rxjs.distinctUntilChanged());
|
|
9580
|
-
}
|
|
9581
|
-
/**
|
|
9582
|
-
* The device status
|
|
9583
|
-
*/
|
|
9584
|
-
get status() {
|
|
9585
|
-
return this.getCurrentValue(this.status$);
|
|
9586
|
-
}
|
|
9587
|
-
/**
|
|
9588
|
-
* The currently selected device
|
|
9589
|
-
*/
|
|
9590
|
-
get selectedDevice() {
|
|
9591
|
-
return this.getCurrentValue(this.selectedDevice$);
|
|
9592
|
-
}
|
|
9593
|
-
/**
|
|
9594
|
-
* The current media stream, or `undefined` if the device is currently disabled.
|
|
9595
|
-
*/
|
|
9596
|
-
get mediaStream() {
|
|
9597
|
-
return this.getCurrentValue(this.mediaStream$);
|
|
9598
|
-
}
|
|
9599
|
-
/**
|
|
9600
|
-
* @internal
|
|
9601
|
-
* @param status
|
|
9602
|
-
*/
|
|
9603
|
-
setStatus(status) {
|
|
9604
|
-
this.setCurrentValue(this.statusSubject, status);
|
|
9605
|
-
}
|
|
9606
|
-
/**
|
|
9607
|
-
* @internal
|
|
9608
|
-
* @param stream
|
|
9609
|
-
*/
|
|
9610
|
-
setMediaStream(stream) {
|
|
9611
|
-
this.setCurrentValue(this.mediaStreamSubject, stream);
|
|
9612
|
-
if (stream) {
|
|
9613
|
-
this.setDevice(this.getDeviceIdFromStream(stream));
|
|
9614
|
-
}
|
|
9615
|
-
}
|
|
9616
|
-
/**
|
|
9617
|
-
* @internal
|
|
9618
|
-
* @param stream
|
|
9619
|
-
*/
|
|
9620
|
-
setDevice(deviceId) {
|
|
9621
|
-
this.setCurrentValue(this.selectedDeviceSubject, deviceId);
|
|
9622
|
-
}
|
|
9623
|
-
}
|
|
9624
|
-
|
|
9625
|
-
class CameraManagerState extends InputMediaDeviceManagerState {
|
|
9626
|
-
constructor() {
|
|
9627
|
-
super('stop-tracks');
|
|
9628
|
-
this.directionSubject = new rxjs.BehaviorSubject(undefined);
|
|
9629
|
-
this.direction$ = this.directionSubject
|
|
9630
|
-
.asObservable()
|
|
9631
|
-
.pipe(rxjs.distinctUntilChanged());
|
|
9632
|
-
}
|
|
9633
|
-
/**
|
|
9634
|
-
* The preferred camera direction
|
|
9635
|
-
* front - means the camera facing the user
|
|
9636
|
-
* back - means the camera facing the environment
|
|
9637
|
-
*/
|
|
9638
|
-
get direction() {
|
|
9639
|
-
return this.getCurrentValue(this.direction$);
|
|
9640
|
-
}
|
|
9641
|
-
/**
|
|
9642
|
-
* @internal
|
|
9643
|
-
*/
|
|
9644
|
-
setDirection(direction) {
|
|
9645
|
-
this.setCurrentValue(this.directionSubject, direction);
|
|
9646
|
-
}
|
|
9647
|
-
/**
|
|
9648
|
-
* @internal
|
|
9649
|
-
*/
|
|
9650
|
-
setMediaStream(stream) {
|
|
9651
|
-
var _a;
|
|
9652
|
-
super.setMediaStream(stream);
|
|
9653
|
-
if (stream) {
|
|
9654
|
-
// RN getSettings() doesn't return facingMode, so we don't verify camera direction
|
|
9655
|
-
const direction = isReactNative()
|
|
9656
|
-
? this.direction
|
|
9657
|
-
: ((_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().facingMode) === 'environment'
|
|
9658
|
-
? 'back'
|
|
9659
|
-
: 'front';
|
|
9660
|
-
this.setDirection(direction);
|
|
9661
|
-
}
|
|
9662
|
-
}
|
|
9663
|
-
getDeviceIdFromStream(stream) {
|
|
9664
|
-
var _a;
|
|
9665
|
-
return (_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
|
|
9666
|
-
}
|
|
9667
|
-
}
|
|
9668
|
-
|
|
9669
9792
|
const getDevices = (constraints) => {
|
|
9670
9793
|
return new rxjs.Observable((subscriber) => {
|
|
9671
9794
|
navigator.mediaDevices
|
|
@@ -10061,6 +10184,127 @@ class InputMediaDeviceManager {
|
|
|
10061
10184
|
}
|
|
10062
10185
|
}
|
|
10063
10186
|
|
|
10187
|
+
class InputMediaDeviceManagerState {
|
|
10188
|
+
constructor(disableMode = 'stop-tracks') {
|
|
10189
|
+
this.disableMode = disableMode;
|
|
10190
|
+
this.statusSubject = new rxjs.BehaviorSubject(undefined);
|
|
10191
|
+
this.mediaStreamSubject = new rxjs.BehaviorSubject(undefined);
|
|
10192
|
+
this.selectedDeviceSubject = new rxjs.BehaviorSubject(undefined);
|
|
10193
|
+
/**
|
|
10194
|
+
* Gets the current value of an observable, or undefined if the observable has
|
|
10195
|
+
* not emitted a value yet.
|
|
10196
|
+
*
|
|
10197
|
+
* @param observable$ the observable to get the value from.
|
|
10198
|
+
*/
|
|
10199
|
+
this.getCurrentValue = getCurrentValue;
|
|
10200
|
+
/**
|
|
10201
|
+
* Updates the value of the provided Subject.
|
|
10202
|
+
* An `update` can either be a new value or a function which takes
|
|
10203
|
+
* the current value and returns a new value.
|
|
10204
|
+
*
|
|
10205
|
+
* @internal
|
|
10206
|
+
*
|
|
10207
|
+
* @param subject the subject to update.
|
|
10208
|
+
* @param update the update to apply to the subject.
|
|
10209
|
+
* @return the updated value.
|
|
10210
|
+
*/
|
|
10211
|
+
this.setCurrentValue = setCurrentValue;
|
|
10212
|
+
this.mediaStream$ = this.mediaStreamSubject.asObservable();
|
|
10213
|
+
this.selectedDevice$ = this.selectedDeviceSubject
|
|
10214
|
+
.asObservable()
|
|
10215
|
+
.pipe(rxjs.distinctUntilChanged());
|
|
10216
|
+
this.status$ = this.statusSubject
|
|
10217
|
+
.asObservable()
|
|
10218
|
+
.pipe(rxjs.distinctUntilChanged());
|
|
10219
|
+
}
|
|
10220
|
+
/**
|
|
10221
|
+
* The device status
|
|
10222
|
+
*/
|
|
10223
|
+
get status() {
|
|
10224
|
+
return this.getCurrentValue(this.status$);
|
|
10225
|
+
}
|
|
10226
|
+
/**
|
|
10227
|
+
* The currently selected device
|
|
10228
|
+
*/
|
|
10229
|
+
get selectedDevice() {
|
|
10230
|
+
return this.getCurrentValue(this.selectedDevice$);
|
|
10231
|
+
}
|
|
10232
|
+
/**
|
|
10233
|
+
* The current media stream, or `undefined` if the device is currently disabled.
|
|
10234
|
+
*/
|
|
10235
|
+
get mediaStream() {
|
|
10236
|
+
return this.getCurrentValue(this.mediaStream$);
|
|
10237
|
+
}
|
|
10238
|
+
/**
|
|
10239
|
+
* @internal
|
|
10240
|
+
* @param status
|
|
10241
|
+
*/
|
|
10242
|
+
setStatus(status) {
|
|
10243
|
+
this.setCurrentValue(this.statusSubject, status);
|
|
10244
|
+
}
|
|
10245
|
+
/**
|
|
10246
|
+
* @internal
|
|
10247
|
+
* @param stream
|
|
10248
|
+
*/
|
|
10249
|
+
setMediaStream(stream) {
|
|
10250
|
+
this.setCurrentValue(this.mediaStreamSubject, stream);
|
|
10251
|
+
if (stream) {
|
|
10252
|
+
this.setDevice(this.getDeviceIdFromStream(stream));
|
|
10253
|
+
}
|
|
10254
|
+
}
|
|
10255
|
+
/**
|
|
10256
|
+
* @internal
|
|
10257
|
+
* @param stream
|
|
10258
|
+
*/
|
|
10259
|
+
setDevice(deviceId) {
|
|
10260
|
+
this.setCurrentValue(this.selectedDeviceSubject, deviceId);
|
|
10261
|
+
}
|
|
10262
|
+
}
|
|
10263
|
+
|
|
10264
|
+
class CameraManagerState extends InputMediaDeviceManagerState {
|
|
10265
|
+
constructor() {
|
|
10266
|
+
super('stop-tracks');
|
|
10267
|
+
this.directionSubject = new rxjs.BehaviorSubject(undefined);
|
|
10268
|
+
this.direction$ = this.directionSubject
|
|
10269
|
+
.asObservable()
|
|
10270
|
+
.pipe(rxjs.distinctUntilChanged());
|
|
10271
|
+
}
|
|
10272
|
+
/**
|
|
10273
|
+
* The preferred camera direction
|
|
10274
|
+
* front - means the camera facing the user
|
|
10275
|
+
* back - means the camera facing the environment
|
|
10276
|
+
*/
|
|
10277
|
+
get direction() {
|
|
10278
|
+
return this.getCurrentValue(this.direction$);
|
|
10279
|
+
}
|
|
10280
|
+
/**
|
|
10281
|
+
* @internal
|
|
10282
|
+
*/
|
|
10283
|
+
setDirection(direction) {
|
|
10284
|
+
this.setCurrentValue(this.directionSubject, direction);
|
|
10285
|
+
}
|
|
10286
|
+
/**
|
|
10287
|
+
* @internal
|
|
10288
|
+
*/
|
|
10289
|
+
setMediaStream(stream) {
|
|
10290
|
+
var _a;
|
|
10291
|
+
super.setMediaStream(stream);
|
|
10292
|
+
if (stream) {
|
|
10293
|
+
// RN getSettings() doesn't return facingMode, so we don't verify camera direction
|
|
10294
|
+
const direction = isReactNative()
|
|
10295
|
+
? this.direction
|
|
10296
|
+
: ((_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().facingMode) === 'environment'
|
|
10297
|
+
? 'back'
|
|
10298
|
+
: 'front';
|
|
10299
|
+
this.setDirection(direction);
|
|
10300
|
+
}
|
|
10301
|
+
}
|
|
10302
|
+
getDeviceIdFromStream(stream) {
|
|
10303
|
+
var _a;
|
|
10304
|
+
return (_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
|
|
10305
|
+
}
|
|
10306
|
+
}
|
|
10307
|
+
|
|
10064
10308
|
class CameraManager extends InputMediaDeviceManager {
|
|
10065
10309
|
constructor(call) {
|
|
10066
10310
|
super(call, new CameraManagerState());
|
|
@@ -10196,14 +10440,14 @@ class Call {
|
|
|
10196
10440
|
* method to construct a `Call` instance.
|
|
10197
10441
|
*/
|
|
10198
10442
|
constructor({ type, id, streamClient, members, ownCapabilities, sortParticipantsBy, clientStore, ringing = false, watching = false, }) {
|
|
10199
|
-
/**
|
|
10200
|
-
* ViewportTracker instance
|
|
10201
|
-
*/
|
|
10202
|
-
this.viewportTracker = new ViewportTracker();
|
|
10203
10443
|
/**
|
|
10204
10444
|
* The state of this call.
|
|
10205
10445
|
*/
|
|
10206
10446
|
this.state = new CallState();
|
|
10447
|
+
/**
|
|
10448
|
+
* The DynascaleManager instance.
|
|
10449
|
+
*/
|
|
10450
|
+
this.dynascaleManager = new DynascaleManager(this);
|
|
10207
10451
|
/**
|
|
10208
10452
|
* The permissions context of this call.
|
|
10209
10453
|
*/
|
|
@@ -10221,7 +10465,7 @@ class Call {
|
|
|
10221
10465
|
* A typical use case is to clean up some global event handlers.
|
|
10222
10466
|
* @private
|
|
10223
10467
|
*/
|
|
10224
|
-
this.leaveCallHooks =
|
|
10468
|
+
this.leaveCallHooks = new Set();
|
|
10225
10469
|
this.streamClientEventHandlers = new Map();
|
|
10226
10470
|
/**
|
|
10227
10471
|
* Leave the call and stop the media streams that were published by the call.
|
|
@@ -10527,7 +10771,7 @@ class Call {
|
|
|
10527
10771
|
unsubscribeOfflineEvent();
|
|
10528
10772
|
this.state.setCallingState(exports.CallingState.OFFLINE);
|
|
10529
10773
|
});
|
|
10530
|
-
this.leaveCallHooks.
|
|
10774
|
+
this.leaveCallHooks.add(() => {
|
|
10531
10775
|
unsubscribeOnlineEvent();
|
|
10532
10776
|
unsubscribeOfflineEvent();
|
|
10533
10777
|
});
|
|
@@ -10604,7 +10848,10 @@ class Call {
|
|
|
10604
10848
|
return currentParticipants.map((p) => {
|
|
10605
10849
|
const participant = Object.assign(p, {
|
|
10606
10850
|
isLocalParticipant: p.sessionId === sfuClient.sessionId,
|
|
10607
|
-
viewportVisibilityState:
|
|
10851
|
+
viewportVisibilityState: {
|
|
10852
|
+
videoTrack: exports.VisibilityState.UNKNOWN,
|
|
10853
|
+
screenShareTrack: exports.VisibilityState.UNKNOWN,
|
|
10854
|
+
},
|
|
10608
10855
|
});
|
|
10609
10856
|
// We need to preserve the local state of the participant
|
|
10610
10857
|
// (e.g. videoDimension, visibilityState, pinnedAt, etc.)
|
|
@@ -10761,15 +11008,30 @@ class Call {
|
|
|
10761
11008
|
* You have to create a subscription for each participant for all the different kinds of tracks you want to receive.
|
|
10762
11009
|
* You can only subscribe for tracks after the participant started publishing the given kind of track.
|
|
10763
11010
|
*
|
|
10764
|
-
* @param
|
|
11011
|
+
* @param trackType the kind of subscription to update.
|
|
10765
11012
|
* @param changes the list of subscription changes to do.
|
|
10766
11013
|
* @param type the debounce type to use for the update.
|
|
10767
11014
|
*/
|
|
10768
|
-
this.updateSubscriptionsPartial = (
|
|
11015
|
+
this.updateSubscriptionsPartial = (trackType, changes, type = exports.DebounceType.SLOW) => {
|
|
11016
|
+
if (trackType === 'video') {
|
|
11017
|
+
this.logger('warn', `updateSubscriptionsPartial: ${trackType} is deprecated. Please switch to 'videoTrack'`);
|
|
11018
|
+
trackType = 'videoTrack';
|
|
11019
|
+
}
|
|
11020
|
+
else if (trackType === 'screen') {
|
|
11021
|
+
this.logger('warn', `updateSubscriptionsPartial: ${trackType} is deprecated. Please switch to 'screenShareTrack'`);
|
|
11022
|
+
trackType = 'screenShareTrack';
|
|
11023
|
+
}
|
|
10769
11024
|
const participants = this.state.updateParticipants(Object.entries(changes).reduce((acc, [sessionId, change]) => {
|
|
10770
|
-
|
|
11025
|
+
var _a, _b;
|
|
11026
|
+
if ((_a = change.dimension) === null || _a === void 0 ? void 0 : _a.height) {
|
|
11027
|
+
change.dimension.height = Math.ceil(change.dimension.height);
|
|
11028
|
+
}
|
|
11029
|
+
if ((_b = change.dimension) === null || _b === void 0 ? void 0 : _b.width) {
|
|
11030
|
+
change.dimension.width = Math.ceil(change.dimension.width);
|
|
11031
|
+
}
|
|
11032
|
+
const prop = trackType === 'videoTrack'
|
|
10771
11033
|
? 'videoDimension'
|
|
10772
|
-
:
|
|
11034
|
+
: trackType === 'screenShareTrack'
|
|
10773
11035
|
? 'screenShareDimension'
|
|
10774
11036
|
: undefined;
|
|
10775
11037
|
if (prop) {
|
|
@@ -10785,10 +11047,10 @@ class Call {
|
|
|
10785
11047
|
};
|
|
10786
11048
|
this.updateSubscriptions = (participants, type = exports.DebounceType.SLOW) => {
|
|
10787
11049
|
const subscriptions = [];
|
|
10788
|
-
|
|
11050
|
+
for (const p of participants) {
|
|
10789
11051
|
// we don't want to subscribe to our own tracks
|
|
10790
11052
|
if (p.isLocalParticipant)
|
|
10791
|
-
|
|
11053
|
+
continue;
|
|
10792
11054
|
// NOTE: audio tracks don't have to be requested explicitly
|
|
10793
11055
|
// as the SFU will implicitly subscribe us to all of them,
|
|
10794
11056
|
// once they become available.
|
|
@@ -10809,7 +11071,7 @@ class Call {
|
|
|
10809
11071
|
dimension: p.screenShareDimension,
|
|
10810
11072
|
});
|
|
10811
11073
|
}
|
|
10812
|
-
}
|
|
11074
|
+
}
|
|
10813
11075
|
// schedule update
|
|
10814
11076
|
this.trackSubscriptionsSubject.next({ type, data: subscriptions });
|
|
10815
11077
|
};
|
|
@@ -11198,7 +11460,7 @@ class Call {
|
|
|
11198
11460
|
this.dropTimeout = setTimeout(() => this.leave(), timeoutMs);
|
|
11199
11461
|
}), rxjs.takeWhile(() => !!this.clientStore.calls.find((call) => call.cid === this.cid)))
|
|
11200
11462
|
.subscribe();
|
|
11201
|
-
this.leaveCallHooks.
|
|
11463
|
+
this.leaveCallHooks.add(() => {
|
|
11202
11464
|
!subscription.closed && subscription.unsubscribe();
|
|
11203
11465
|
});
|
|
11204
11466
|
};
|
|
@@ -11225,6 +11487,69 @@ class Call {
|
|
|
11225
11487
|
this.sendCustomEvent = (payload) => __awaiter(this, void 0, void 0, function* () {
|
|
11226
11488
|
return this.streamClient.post(`${this.streamClientBasePath}/event`, { custom: payload });
|
|
11227
11489
|
});
|
|
11490
|
+
/**
|
|
11491
|
+
* Will begin tracking the given element for visibility changes within the
|
|
11492
|
+
* configured viewport element (`call.setViewport`).
|
|
11493
|
+
*
|
|
11494
|
+
* @param element the element to track.
|
|
11495
|
+
* @param sessionId the session id.
|
|
11496
|
+
* @param trackType the video mode.
|
|
11497
|
+
*/
|
|
11498
|
+
this.trackElementVisibility = (element, sessionId, trackType) => {
|
|
11499
|
+
return this.dynascaleManager.trackElementVisibility(element, sessionId, trackType);
|
|
11500
|
+
};
|
|
11501
|
+
/**
|
|
11502
|
+
* Sets the viewport element to track bound video elements for visibility.
|
|
11503
|
+
*
|
|
11504
|
+
* @param element the viewport element.
|
|
11505
|
+
*/
|
|
11506
|
+
this.setViewport = (element) => {
|
|
11507
|
+
return this.dynascaleManager.setViewport(element);
|
|
11508
|
+
};
|
|
11509
|
+
/**
|
|
11510
|
+
* Binds a DOM <video> element to the given session id.
|
|
11511
|
+
* This method will make sure that the video element will play
|
|
11512
|
+
* the correct video stream for the given session id.
|
|
11513
|
+
*
|
|
11514
|
+
* Under the hood, it would also keep track of the video element dimensions
|
|
11515
|
+
* and update the subscription accordingly in order to optimize the bandwidth.
|
|
11516
|
+
*
|
|
11517
|
+
* If a "viewport" is configured, the video element will be automatically
|
|
11518
|
+
* tracked for visibility and the subscription will be updated accordingly.
|
|
11519
|
+
*
|
|
11520
|
+
* @param videoElement the video element to bind to.
|
|
11521
|
+
* @param sessionId the session id.
|
|
11522
|
+
* @param trackType the kind of video.
|
|
11523
|
+
*/
|
|
11524
|
+
this.bindVideoElement = (videoElement, sessionId, trackType) => {
|
|
11525
|
+
const unbind = this.dynascaleManager.bindVideoElement(videoElement, sessionId, trackType);
|
|
11526
|
+
if (!unbind)
|
|
11527
|
+
return;
|
|
11528
|
+
this.leaveCallHooks.add(unbind);
|
|
11529
|
+
return () => {
|
|
11530
|
+
this.leaveCallHooks.delete(unbind);
|
|
11531
|
+
unbind();
|
|
11532
|
+
};
|
|
11533
|
+
};
|
|
11534
|
+
/**
|
|
11535
|
+
* Binds a DOM <audio> element to the given session id.
|
|
11536
|
+
*
|
|
11537
|
+
* This method will make sure that the audio element will
|
|
11538
|
+
* play the correct audio stream for the given session id.
|
|
11539
|
+
*
|
|
11540
|
+
* @param audioElement the audio element to bind to.
|
|
11541
|
+
* @param sessionId the session id.
|
|
11542
|
+
*/
|
|
11543
|
+
this.bindAudioElement = (audioElement, sessionId) => {
|
|
11544
|
+
const unbind = this.dynascaleManager.bindAudioElement(audioElement, sessionId);
|
|
11545
|
+
if (!unbind)
|
|
11546
|
+
return;
|
|
11547
|
+
this.leaveCallHooks.add(unbind);
|
|
11548
|
+
return () => {
|
|
11549
|
+
this.leaveCallHooks.delete(unbind);
|
|
11550
|
+
unbind();
|
|
11551
|
+
};
|
|
11552
|
+
};
|
|
11228
11553
|
this.type = type;
|
|
11229
11554
|
this.id = id;
|
|
11230
11555
|
this.cid = `${type}:${id}`;
|
|
@@ -11246,20 +11571,21 @@ class Call {
|
|
|
11246
11571
|
// update state with the latest event data
|
|
11247
11572
|
this.state.updateFromEvent(event);
|
|
11248
11573
|
});
|
|
11249
|
-
this.leaveCallHooks.
|
|
11574
|
+
this.leaveCallHooks.add(registerEventHandlers(this, this.state, this.dispatcher));
|
|
11250
11575
|
this.registerEffects();
|
|
11251
|
-
this.leaveCallHooks.
|
|
11576
|
+
this.leaveCallHooks.add(createSubscription(this.trackSubscriptionsSubject.pipe(rxjs.debounce((v) => rxjs.timer(v.type)), rxjs.map((v) => v.data)), (subscriptions) => { var _a; return (_a = this.sfuClient) === null || _a === void 0 ? void 0 : _a.updateSubscriptions(subscriptions); }));
|
|
11252
11577
|
this.camera = new CameraManager(this);
|
|
11253
11578
|
this.microphone = new MicrophoneManager(this);
|
|
11254
11579
|
}
|
|
11255
11580
|
registerEffects() {
|
|
11256
|
-
this.leaveCallHooks.
|
|
11581
|
+
this.leaveCallHooks.add(
|
|
11257
11582
|
// handles updating the permissions context when the settings change.
|
|
11258
11583
|
createSubscription(this.state.settings$, (settings) => {
|
|
11259
11584
|
if (!settings)
|
|
11260
11585
|
return;
|
|
11261
11586
|
this.permissionsContext.setCallSettings(settings);
|
|
11262
|
-
})
|
|
11587
|
+
}));
|
|
11588
|
+
this.leaveCallHooks.add(
|
|
11263
11589
|
// handle the case when the user permissions are modified.
|
|
11264
11590
|
createSubscription(this.state.ownCapabilities$, (ownCapabilities) => {
|
|
11265
11591
|
// update the permission context.
|
|
@@ -11280,7 +11606,8 @@ class Call {
|
|
|
11280
11606
|
});
|
|
11281
11607
|
}
|
|
11282
11608
|
}
|
|
11283
|
-
})
|
|
11609
|
+
}));
|
|
11610
|
+
this.leaveCallHooks.add(
|
|
11284
11611
|
// handles the case when the user is blocked by the call owner.
|
|
11285
11612
|
createSubscription(this.state.blockedUserIds$, (blockedUserIds) => __awaiter(this, void 0, void 0, function* () {
|
|
11286
11613
|
if (!blockedUserIds)
|
|
@@ -11290,7 +11617,8 @@ class Call {
|
|
|
11290
11617
|
this.logger('info', 'Leaving call because of being blocked');
|
|
11291
11618
|
yield this.leave();
|
|
11292
11619
|
}
|
|
11293
|
-
}))
|
|
11620
|
+
})));
|
|
11621
|
+
this.leaveCallHooks.add(
|
|
11294
11622
|
// watch for auto drop cancellation
|
|
11295
11623
|
createSubscription(this.state.callingState$, (callingState) => {
|
|
11296
11624
|
if (!this.ringing)
|
|
@@ -11301,7 +11629,8 @@ class Call {
|
|
|
11301
11629
|
clearTimeout(this.dropTimeout);
|
|
11302
11630
|
this.dropTimeout = undefined;
|
|
11303
11631
|
}
|
|
11304
|
-
})
|
|
11632
|
+
}));
|
|
11633
|
+
this.leaveCallHooks.add(
|
|
11305
11634
|
// "ringing" mode effects and event handlers
|
|
11306
11635
|
createSubscription(this.ringingSubject, (isRinging) => {
|
|
11307
11636
|
if (!isRinging)
|
|
@@ -11310,7 +11639,7 @@ class Call {
|
|
|
11310
11639
|
if (this.state.callingState === exports.CallingState.IDLE) {
|
|
11311
11640
|
this.state.setCallingState(exports.CallingState.RINGING);
|
|
11312
11641
|
}
|
|
11313
|
-
this.leaveCallHooks.
|
|
11642
|
+
this.leaveCallHooks.add(registerRingingCallEventHandlers(this));
|
|
11314
11643
|
}));
|
|
11315
11644
|
}
|
|
11316
11645
|
on(eventName, fn) {
|
|
@@ -12537,7 +12866,7 @@ class WSConnectionFallback {
|
|
|
12537
12866
|
}
|
|
12538
12867
|
}
|
|
12539
12868
|
|
|
12540
|
-
const version = '0.3.
|
|
12869
|
+
const version = '0.3.10';
|
|
12541
12870
|
|
|
12542
12871
|
const logger = getLogger(['location']);
|
|
12543
12872
|
const HINT_URL = `https://hint.stream-io-video.com/`;
|
|
@@ -13611,6 +13940,7 @@ exports.CallTypes = CallTypes;
|
|
|
13611
13940
|
exports.CameraManager = CameraManager;
|
|
13612
13941
|
exports.CameraManagerState = CameraManagerState;
|
|
13613
13942
|
exports.CreateDeviceRequestPushProviderEnum = CreateDeviceRequestPushProviderEnum;
|
|
13943
|
+
exports.DynascaleManager = DynascaleManager;
|
|
13614
13944
|
exports.ErrorFromResponse = ErrorFromResponse;
|
|
13615
13945
|
exports.InputMediaDeviceManager = InputMediaDeviceManager;
|
|
13616
13946
|
exports.InputMediaDeviceManagerState = InputMediaDeviceManagerState;
|