@stream-io/video-client 1.58.0 → 1.59.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.
- package/CHANGELOG.md +15 -0
- package/dist/index.browser.es.js +319 -71
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +329 -69
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.es.js +319 -71
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +15 -4
- package/dist/src/StreamVideoClient.d.ts +9 -1
- package/dist/src/devices/CameraManager.d.ts +2 -1
- package/dist/src/devices/DeviceManager.d.ts +1 -1
- package/dist/src/devices/MicrophoneManager.d.ts +2 -1
- package/dist/src/gen/coordinator/index.d.ts +26 -0
- package/dist/src/helpers/MediaStreamRecorder.d.ts +26 -0
- package/dist/src/helpers/concurrency.d.ts +8 -0
- package/dist/src/helpers/loopback.d.ts +55 -0
- package/dist/src/reporting/ClientEventReporter.d.ts +0 -2
- package/dist/src/rtc/Subscriber.d.ts +5 -0
- package/index.ts +2 -0
- package/package.json +1 -1
- package/src/Call.ts +156 -134
- package/src/StreamVideoClient.ts +35 -8
- package/src/__tests__/Call.lifecycle.test.ts +33 -2
- package/src/__tests__/Call.publishing.test.ts +42 -1
- package/src/__tests__/StreamVideoClient.api.test.ts +33 -0
- package/src/__tests__/StreamVideoClient.rewatch.test.ts +213 -0
- package/src/__tests__/StreamVideoClient.ringing.test.ts +11 -4
- package/src/__tests__/StreamVideoClient.test.ts +14 -12
- package/src/devices/CameraManager.ts +16 -4
- package/src/devices/DeviceManager.ts +7 -4
- package/src/devices/MicrophoneManager.ts +11 -3
- package/src/devices/__tests__/CameraManager.test.ts +27 -1
- package/src/devices/__tests__/DeviceManager.test.ts +49 -1
- package/src/devices/__tests__/MicrophoneManager.test.ts +23 -1
- package/src/events/call.ts +6 -3
- package/src/gen/coordinator/index.ts +26 -0
- package/src/helpers/MediaStreamRecorder.ts +104 -0
- package/src/helpers/__tests__/MediaStreamRecorder.test.ts +324 -0
- package/src/helpers/__tests__/concurrency.test.ts +74 -0
- package/src/helpers/__tests__/loopback.test.ts +367 -0
- package/src/helpers/concurrency.ts +24 -0
- package/src/helpers/loopback.ts +200 -0
- package/src/reporting/ClientEventReporter.ts +15 -28
- package/src/reporting/__tests__/ClientEventReporter.test.ts +3 -7
- package/src/rtc/Subscriber.ts +8 -0
- package/src/rtc/__tests__/Subscriber.test.ts +101 -0
package/dist/index.es.js
CHANGED
|
@@ -7,7 +7,7 @@ import { TwirpFetchTransport, TwirpErrorCode } from '@protobuf-ts/twirp-transpor
|
|
|
7
7
|
import * as scopedLogger from '@stream-io/logger';
|
|
8
8
|
export { LogLevelEnum } from '@stream-io/logger';
|
|
9
9
|
import { parse, write } from 'sdp-transform';
|
|
10
|
-
import { Subject, Observable, combineLatest, BehaviorSubject, ReplaySubject, shareReplay, map, distinctUntilChanged, startWith, takeWhile, distinctUntilKeyChanged, fromEventPattern, concatMap, merge, from, fromEvent, tap, debounceTime, pairwise, firstValueFrom, of } from 'rxjs';
|
|
10
|
+
import { Subject, Observable, combineLatest, BehaviorSubject, ReplaySubject, shareReplay, map, distinctUntilChanged, startWith, takeWhile, distinctUntilKeyChanged, fromEventPattern, concatMap, merge, from, fromEvent, tap, debounceTime, pairwise, firstValueFrom, of, Subscription } from 'rxjs';
|
|
11
11
|
import { UAParser } from 'ua-parser-js';
|
|
12
12
|
import { WorkerTimer } from '@stream-io/worker-timer';
|
|
13
13
|
import https from 'https';
|
|
@@ -5060,7 +5060,7 @@ const toIceCandidate = (iceTrickle) => {
|
|
|
5060
5060
|
}
|
|
5061
5061
|
};
|
|
5062
5062
|
|
|
5063
|
-
const version = "1.
|
|
5063
|
+
const version = "1.59.0";
|
|
5064
5064
|
const [major, minor, patch] = version.split('.');
|
|
5065
5065
|
let sdkInfo = {
|
|
5066
5066
|
type: SdkType.PLAIN_JAVASCRIPT,
|
|
@@ -5317,6 +5317,27 @@ const withoutConcurrency = createRunner(wrapWithContinuationTracking);
|
|
|
5317
5317
|
*/
|
|
5318
5318
|
const withCancellation = createRunner(wrapWithCancellation);
|
|
5319
5319
|
const pendingPromises = new Map();
|
|
5320
|
+
/**
|
|
5321
|
+
* Wraps an async function so concurrent calls share the in-flight promise
|
|
5322
|
+
* instead of queueing another execution.
|
|
5323
|
+
*
|
|
5324
|
+
* @param cb Async function to wrap.
|
|
5325
|
+
* @returns Wrapped async function.
|
|
5326
|
+
*/
|
|
5327
|
+
function singleFlight(cb) {
|
|
5328
|
+
let pending;
|
|
5329
|
+
return (...args) => {
|
|
5330
|
+
if (pending)
|
|
5331
|
+
return pending;
|
|
5332
|
+
const promise = cb(...args).finally(() => {
|
|
5333
|
+
if (pending === promise) {
|
|
5334
|
+
pending = undefined;
|
|
5335
|
+
}
|
|
5336
|
+
});
|
|
5337
|
+
pending = promise;
|
|
5338
|
+
return promise;
|
|
5339
|
+
};
|
|
5340
|
+
}
|
|
5320
5341
|
function hasPending(tag) {
|
|
5321
5342
|
return pendingPromises.has(tag);
|
|
5322
5343
|
}
|
|
@@ -9805,6 +9826,11 @@ class Subscriber extends BasePeerConnection {
|
|
|
9805
9826
|
throw e;
|
|
9806
9827
|
}
|
|
9807
9828
|
};
|
|
9829
|
+
/**
|
|
9830
|
+
* Whether the given stream is one the SFU echoed back to us
|
|
9831
|
+
* (`allowOwnTracksLoopback`) rather than a local capture stream.
|
|
9832
|
+
*/
|
|
9833
|
+
isSelfSubscribedStream = (stream) => !!stream && !!this.trackedStreams?.has(stream);
|
|
9808
9834
|
handleOnTrack = (e) => {
|
|
9809
9835
|
const { streams, track } = e;
|
|
9810
9836
|
const [primaryStream] = streams;
|
|
@@ -9894,6 +9920,8 @@ class Subscriber extends BasePeerConnection {
|
|
|
9894
9920
|
const target = this.state.participants.find((p) => p.trackLookupPrefix === trackId);
|
|
9895
9921
|
if (!target)
|
|
9896
9922
|
return;
|
|
9923
|
+
if (target.isLocalParticipant)
|
|
9924
|
+
return;
|
|
9897
9925
|
this.state.updateParticipant(target.sessionId, (p) => {
|
|
9898
9926
|
const current = p.interruptedTracks ?? [];
|
|
9899
9927
|
const has = current.includes(trackType);
|
|
@@ -10636,7 +10664,6 @@ const watchCallRejected = (call) => {
|
|
|
10636
10664
|
*/
|
|
10637
10665
|
const watchCallEnded = (call) => {
|
|
10638
10666
|
return function onCallEnded() {
|
|
10639
|
-
globalThis.streamRNVideoSDK?.callingX?.endCall(call, 'remote');
|
|
10640
10667
|
const { callingState } = call.state;
|
|
10641
10668
|
if (callingState !== CallingState.IDLE &&
|
|
10642
10669
|
callingState !== CallingState.LEFT) {
|
|
@@ -10645,9 +10672,13 @@ const watchCallEnded = (call) => {
|
|
|
10645
10672
|
reason: 'call.ended event received',
|
|
10646
10673
|
});
|
|
10647
10674
|
call
|
|
10648
|
-
.leave({
|
|
10675
|
+
.leave({
|
|
10676
|
+
message: 'call.ended event received',
|
|
10677
|
+
reject: false,
|
|
10678
|
+
reason: 'ended',
|
|
10679
|
+
})
|
|
10649
10680
|
.catch((err) => {
|
|
10650
|
-
call.logger.error('Failed to leave call after call.ended
|
|
10681
|
+
call.logger.error('Failed to leave call after call.ended', err);
|
|
10651
10682
|
});
|
|
10652
10683
|
}
|
|
10653
10684
|
};
|
|
@@ -13453,7 +13484,7 @@ class DeviceManager {
|
|
|
13453
13484
|
createSyntheticDevice(selectedDevice, deviceKind);
|
|
13454
13485
|
writePreferences(currentDevice, deviceKey, muted, storageKey);
|
|
13455
13486
|
}
|
|
13456
|
-
async applyPersistedPreferences(enabledInCallType) {
|
|
13487
|
+
async applyPersistedPreferences(enabledInCallType, forceDisabled = false) {
|
|
13457
13488
|
const deviceKey = this.trackType === TrackType.AUDIO ? 'microphone' : 'camera';
|
|
13458
13489
|
const preferences = readPreferences(this.devicePersistence.storageKey);
|
|
13459
13490
|
const preferenceList = toPreferenceList(preferences[deviceKey]);
|
|
@@ -13480,13 +13511,13 @@ class DeviceManager {
|
|
|
13480
13511
|
}
|
|
13481
13512
|
const canPublish = this.call.permissionsContext.canPublish(this.trackType);
|
|
13482
13513
|
if (typeof muted === 'boolean' && enabledInCallType && canPublish) {
|
|
13483
|
-
await this.applyMutedState(muted);
|
|
13514
|
+
await this.applyMutedState(muted, forceDisabled);
|
|
13484
13515
|
appliedMute = true;
|
|
13485
13516
|
}
|
|
13486
13517
|
return appliedDevice || appliedMute;
|
|
13487
13518
|
}
|
|
13488
|
-
async applyMutedState(muted) {
|
|
13489
|
-
if (this.state.status !== undefined)
|
|
13519
|
+
async applyMutedState(muted, forceDisabled) {
|
|
13520
|
+
if (forceDisabled || this.state.status !== undefined)
|
|
13490
13521
|
return;
|
|
13491
13522
|
if (muted) {
|
|
13492
13523
|
await this.disable();
|
|
@@ -13838,8 +13869,9 @@ class CameraManager extends DeviceManager {
|
|
|
13838
13869
|
*
|
|
13839
13870
|
* @param settings the video settings to apply.
|
|
13840
13871
|
* @param publish whether to publish the stream after applying the settings.
|
|
13872
|
+
* @param forceDisabled whether to keep the camera disabled, regardless of server-side or local preferences.
|
|
13841
13873
|
*/
|
|
13842
|
-
async apply(settings, publish) {
|
|
13874
|
+
async apply(settings, publish, forceDisabled = false) {
|
|
13843
13875
|
// Wait for any in progress camera operation
|
|
13844
13876
|
await this.statusChangeSettled();
|
|
13845
13877
|
await this.selectTargetResolution(settings.target_resolution);
|
|
@@ -13851,8 +13883,7 @@ class CameraManager extends DeviceManager {
|
|
|
13851
13883
|
if (shouldApplyDefaults &&
|
|
13852
13884
|
this.devicePersistence.enabled &&
|
|
13853
13885
|
permissionState === 'granted') {
|
|
13854
|
-
persistedPreferencesApplied =
|
|
13855
|
-
await this.applyPersistedPreferences(enabledInCallType);
|
|
13886
|
+
persistedPreferencesApplied = await this.applyPersistedPreferences(enabledInCallType, forceDisabled);
|
|
13856
13887
|
}
|
|
13857
13888
|
// apply a direction and enable the camera only if in "pristine" state,
|
|
13858
13889
|
// and there are no persisted preferences
|
|
@@ -13862,7 +13893,10 @@ class CameraManager extends DeviceManager {
|
|
|
13862
13893
|
const direction = settings.camera_facing === 'front' ? 'front' : 'back';
|
|
13863
13894
|
await this.selectDirection(direction, { enableCamera: false });
|
|
13864
13895
|
}
|
|
13865
|
-
if (
|
|
13896
|
+
if (!forceDisabled &&
|
|
13897
|
+
canPublish &&
|
|
13898
|
+
settings.camera_default_on &&
|
|
13899
|
+
enabledInCallType) {
|
|
13866
13900
|
await this.enable();
|
|
13867
13901
|
}
|
|
13868
13902
|
}
|
|
@@ -14457,8 +14491,9 @@ class MicrophoneManager extends AudioDeviceManager {
|
|
|
14457
14491
|
* Applies the audio settings to the microphone.
|
|
14458
14492
|
* @param settings the audio settings to apply.
|
|
14459
14493
|
* @param publish whether to publish the stream after applying the settings.
|
|
14494
|
+
* @param forceDisabled whether to keep the mic disabled, regardless of server-side or local preferences.
|
|
14460
14495
|
*/
|
|
14461
|
-
async apply(settings, publish) {
|
|
14496
|
+
async apply(settings, publish, forceDisabled = false) {
|
|
14462
14497
|
// Wait for any in progress mic operation
|
|
14463
14498
|
await this.statusChangeSettled();
|
|
14464
14499
|
// apply server-side settings only when the device state is pristine
|
|
@@ -14470,11 +14505,11 @@ class MicrophoneManager extends AudioDeviceManager {
|
|
|
14470
14505
|
if (shouldApplyDefaults &&
|
|
14471
14506
|
this.devicePersistence.enabled &&
|
|
14472
14507
|
permissionState === 'granted') {
|
|
14473
|
-
persistedPreferencesApplied = await this.applyPersistedPreferences(true);
|
|
14508
|
+
persistedPreferencesApplied = await this.applyPersistedPreferences(true, forceDisabled);
|
|
14474
14509
|
}
|
|
14475
14510
|
const canPublish = this.call.permissionsContext.canPublish(this.trackType);
|
|
14476
14511
|
if (shouldApplyDefaults && !persistedPreferencesApplied) {
|
|
14477
|
-
if (canPublish && settings.mic_default_on) {
|
|
14512
|
+
if (!forceDisabled && canPublish && settings.mic_default_on) {
|
|
14478
14513
|
await this.enable();
|
|
14479
14514
|
}
|
|
14480
14515
|
}
|
|
@@ -15443,7 +15478,7 @@ class Call {
|
|
|
15443
15478
|
}
|
|
15444
15479
|
}
|
|
15445
15480
|
}
|
|
15446
|
-
globalThis.streamRNVideoSDK?.callingX?.endCall(this);
|
|
15481
|
+
globalThis.streamRNVideoSDK?.callingX?.endCall(this, reason === 'ended' ? 'remote' : undefined);
|
|
15447
15482
|
this.statsReporter?.stop();
|
|
15448
15483
|
this.statsReporter = undefined;
|
|
15449
15484
|
const leaveReason = message ?? reason ?? 'user is leaving the call';
|
|
@@ -15606,8 +15641,18 @@ class Call {
|
|
|
15606
15641
|
// const calls = useCalls().filter((c) => c.ringing);
|
|
15607
15642
|
const calls = this.clientStore.calls.filter((c) => c.cid !== this.cid);
|
|
15608
15643
|
this.clientStore.setCalls([this, ...calls]);
|
|
15609
|
-
|
|
15610
|
-
|
|
15644
|
+
await this.applyDeviceConfig(settings, { publish: false });
|
|
15645
|
+
};
|
|
15646
|
+
/**
|
|
15647
|
+
* Applies a backend-provided call state snapshot
|
|
15648
|
+
* (call, members, own capabilities) to this instance.
|
|
15649
|
+
*
|
|
15650
|
+
* @internal an internal method and should not be used outside the SDK.
|
|
15651
|
+
*/
|
|
15652
|
+
updateFromCallStateResponse = (response) => {
|
|
15653
|
+
this.state.updateFromCallResponse(response.call);
|
|
15654
|
+
this.state.setMembers(response.members);
|
|
15655
|
+
this.state.setOwnCapabilities(response.own_capabilities);
|
|
15611
15656
|
};
|
|
15612
15657
|
/**
|
|
15613
15658
|
* Loads the information about the call.
|
|
@@ -15620,9 +15665,7 @@ class Call {
|
|
|
15620
15665
|
get = async (params) => {
|
|
15621
15666
|
await this.setup();
|
|
15622
15667
|
const response = await this.streamClient.get(this.streamClientBasePath, params);
|
|
15623
|
-
this.
|
|
15624
|
-
this.state.setMembers(response.members);
|
|
15625
|
-
this.state.setOwnCapabilities(response.own_capabilities);
|
|
15668
|
+
this.updateFromCallStateResponse(response);
|
|
15626
15669
|
if (params?.ring) {
|
|
15627
15670
|
this.ringingSubject.next(true);
|
|
15628
15671
|
}
|
|
@@ -15630,9 +15673,7 @@ class Call {
|
|
|
15630
15673
|
this.watching = true;
|
|
15631
15674
|
this.clientStore.registerOrUpdateCall(this);
|
|
15632
15675
|
}
|
|
15633
|
-
|
|
15634
|
-
const skipSpeakerApply = isReactNative();
|
|
15635
|
-
await this.applyDeviceConfig(response.call.settings, false, skipSpeakerApply);
|
|
15676
|
+
await this.applyDeviceConfig(response.call.settings, { publish: false });
|
|
15636
15677
|
return response;
|
|
15637
15678
|
};
|
|
15638
15679
|
/**
|
|
@@ -15643,9 +15684,7 @@ class Call {
|
|
|
15643
15684
|
getOrCreate = async (data) => {
|
|
15644
15685
|
await this.setup();
|
|
15645
15686
|
const response = await this.streamClient.post(this.streamClientBasePath, data);
|
|
15646
|
-
this.
|
|
15647
|
-
this.state.setMembers(response.members);
|
|
15648
|
-
this.state.setOwnCapabilities(response.own_capabilities);
|
|
15687
|
+
this.updateFromCallStateResponse(response);
|
|
15649
15688
|
if (data?.ring) {
|
|
15650
15689
|
this.ringingSubject.next(true);
|
|
15651
15690
|
}
|
|
@@ -15653,9 +15692,7 @@ class Call {
|
|
|
15653
15692
|
this.watching = true;
|
|
15654
15693
|
this.clientStore.registerOrUpdateCall(this);
|
|
15655
15694
|
}
|
|
15656
|
-
|
|
15657
|
-
const skipSpeakerApply = isReactNative();
|
|
15658
|
-
await this.applyDeviceConfig(response.call.settings, false, skipSpeakerApply);
|
|
15695
|
+
await this.applyDeviceConfig(response.call.settings, { publish: false });
|
|
15659
15696
|
return response;
|
|
15660
15697
|
};
|
|
15661
15698
|
/**
|
|
@@ -15719,7 +15756,7 @@ class Call {
|
|
|
15719
15756
|
*
|
|
15720
15757
|
* @returns a promise which resolves once the call join-flow has finished.
|
|
15721
15758
|
*/
|
|
15722
|
-
join = async ({ maxJoinRetries = 3, joinResponseTimeout, rpcRequestTimeout, allowOwnTracksLoopback = false, ...data } = {}) => {
|
|
15759
|
+
join = singleFlight(async ({ maxJoinRetries = 3, joinResponseTimeout, rpcRequestTimeout, allowOwnTracksLoopback = false, ...data } = {}) => {
|
|
15723
15760
|
const callingState = this.state.callingState;
|
|
15724
15761
|
if ([CallingState.JOINED, CallingState.JOINING].includes(callingState)) {
|
|
15725
15762
|
throw new Error(`Illegal State: call.join() shall be called only once`);
|
|
@@ -15741,7 +15778,6 @@ class Call {
|
|
|
15741
15778
|
callId: this.id,
|
|
15742
15779
|
getCallSessionId: () => this.state.session?.id ?? '',
|
|
15743
15780
|
getSfuId: () => this.credentials?.server.edge_name ?? '',
|
|
15744
|
-
getUserSessionId: () => this.sfuClient?.sessionId ?? '',
|
|
15745
15781
|
});
|
|
15746
15782
|
this.joinResponseTimeout = joinResponseTimeout;
|
|
15747
15783
|
this.rpcRequestTimeout = rpcRequestTimeout;
|
|
@@ -15793,7 +15829,7 @@ class Call {
|
|
|
15793
15829
|
callingX?.endCall(this, 'error');
|
|
15794
15830
|
throw error;
|
|
15795
15831
|
}
|
|
15796
|
-
};
|
|
15832
|
+
});
|
|
15797
15833
|
/**
|
|
15798
15834
|
* Will make a single attempt to watch for call related WebSocket events
|
|
15799
15835
|
* and initiate a call session with the server.
|
|
@@ -15965,7 +16001,10 @@ class Call {
|
|
|
15965
16001
|
if (!this.deviceSettingsAppliedOnce &&
|
|
15966
16002
|
this.state.settings &&
|
|
15967
16003
|
!supersededByLeave()) {
|
|
15968
|
-
await this.applyDeviceConfig(this.state.settings,
|
|
16004
|
+
await this.applyDeviceConfig(this.state.settings, {
|
|
16005
|
+
publish: true,
|
|
16006
|
+
skipSpeakerApply: false,
|
|
16007
|
+
});
|
|
15969
16008
|
this.deviceSettingsAppliedOnce = true;
|
|
15970
16009
|
}
|
|
15971
16010
|
if (!this.callManagerStarted && !supersededByLeave()) {
|
|
@@ -16755,12 +16794,16 @@ class Call {
|
|
|
16755
16794
|
const streamStateProp = trackTypeToParticipantStreamKey(trackType);
|
|
16756
16795
|
if (!streamStateProp)
|
|
16757
16796
|
continue;
|
|
16758
|
-
this.state.updateParticipant(sessionId, (p) =>
|
|
16759
|
-
|
|
16760
|
-
|
|
16761
|
-
|
|
16762
|
-
|
|
16763
|
-
|
|
16797
|
+
this.state.updateParticipant(sessionId, (p) => {
|
|
16798
|
+
const currentStream = p[streamStateProp];
|
|
16799
|
+
const isEchoedStream = this.subscriber?.isSelfSubscribedStream(currentStream);
|
|
16800
|
+
return {
|
|
16801
|
+
publishedTracks: mediaStream
|
|
16802
|
+
? pushToIfMissing([...p.publishedTracks], trackType)
|
|
16803
|
+
: p.publishedTracks.filter((t) => t !== trackType),
|
|
16804
|
+
[streamStateProp]: isEchoedStream ? currentStream : mediaStream,
|
|
16805
|
+
};
|
|
16806
|
+
});
|
|
16764
16807
|
}
|
|
16765
16808
|
};
|
|
16766
16809
|
/**
|
|
@@ -17450,18 +17493,21 @@ class Call {
|
|
|
17450
17493
|
*
|
|
17451
17494
|
* @internal
|
|
17452
17495
|
*/
|
|
17453
|
-
applyDeviceConfig = async (settings,
|
|
17496
|
+
applyDeviceConfig = async (settings, opts) => {
|
|
17497
|
+
const { publish,
|
|
17498
|
+
// Skip speaker setup on RN until joining (explicitly passed as false during join())
|
|
17499
|
+
skipSpeakerApply = isReactNative(), withDisabledDevices, } = opts;
|
|
17454
17500
|
if (!skipSpeakerApply) {
|
|
17455
|
-
await this.speaker
|
|
17456
|
-
|
|
17457
|
-
|
|
17501
|
+
await this.speaker
|
|
17502
|
+
.apply(settings)
|
|
17503
|
+
.catch((err) => this.logger.warn('Speaker init failed', err));
|
|
17458
17504
|
}
|
|
17459
|
-
await this.camera
|
|
17460
|
-
|
|
17461
|
-
|
|
17462
|
-
await this.microphone
|
|
17463
|
-
|
|
17464
|
-
|
|
17505
|
+
await this.camera
|
|
17506
|
+
.apply(settings.video, publish, withDisabledDevices)
|
|
17507
|
+
.catch((err) => this.logger.warn('Camera init failed', err));
|
|
17508
|
+
await this.microphone
|
|
17509
|
+
.apply(settings.audio, publish, withDisabledDevices)
|
|
17510
|
+
.catch((err) => this.logger.warn('Mic init failed', err));
|
|
17465
17511
|
};
|
|
17466
17512
|
/**
|
|
17467
17513
|
* Will begin tracking the given element for visibility changes within the
|
|
@@ -18969,11 +19015,11 @@ class StreamClient {
|
|
|
18969
19015
|
return await this.wsConnection.connect(this.defaultWSTimeout);
|
|
18970
19016
|
};
|
|
18971
19017
|
getSdkVersion = () => this.options.clientAppIdentifier?.sdkVersion ||
|
|
18972
|
-
"1.
|
|
19018
|
+
"1.59.0";
|
|
18973
19019
|
getUserAgent = () => {
|
|
18974
19020
|
if (!this.cachedUserAgent) {
|
|
18975
19021
|
const { clientAppIdentifier = {} } = this.options;
|
|
18976
|
-
const { sdkName = 'js', sdkVersion = "1.
|
|
19022
|
+
const { sdkName = 'js', sdkVersion = "1.59.0", ...extras } = clientAppIdentifier;
|
|
18977
19023
|
this.cachedUserAgent = [
|
|
18978
19024
|
`stream-video-${sdkName}-v${sdkVersion}`,
|
|
18979
19025
|
...Object.entries(extras).map(([key, value]) => `${key}=${value}`),
|
|
@@ -19336,7 +19382,6 @@ class ClientEventReporter {
|
|
|
19336
19382
|
user_id: this.streamClient.userID || this.coordinatorConnectUserId,
|
|
19337
19383
|
type: ctx?.callType,
|
|
19338
19384
|
id: ctx?.callId,
|
|
19339
|
-
call_cid: cid,
|
|
19340
19385
|
stage: 'JoinInitiated',
|
|
19341
19386
|
join_attempt_id: joinAttemptId,
|
|
19342
19387
|
...(coordinatorConnectId && {
|
|
@@ -19518,7 +19563,6 @@ class ClientEventReporter {
|
|
|
19518
19563
|
startedAt: Date.now(),
|
|
19519
19564
|
joinAttemptIdSnapshot: this.joinAttemptIds.get(cid),
|
|
19520
19565
|
sfuId: this.getSfuId(cid),
|
|
19521
|
-
userSessionId: this.getUserSessionId(cid),
|
|
19522
19566
|
wasPreviouslyConnected: this.pcEverConnected.get(key) === true,
|
|
19523
19567
|
lastIceState: iceConnectionState,
|
|
19524
19568
|
};
|
|
@@ -19529,9 +19573,6 @@ class ClientEventReporter {
|
|
|
19529
19573
|
peer_connection: role,
|
|
19530
19574
|
was_previously_connected: pair.wasPreviouslyConnected,
|
|
19531
19575
|
...(pair.sfuId && { sfu_id: pair.sfuId }),
|
|
19532
|
-
...(pair.userSessionId && {
|
|
19533
|
-
user_session_id: pair.userSessionId,
|
|
19534
|
-
}),
|
|
19535
19576
|
event_type: 'initiated',
|
|
19536
19577
|
});
|
|
19537
19578
|
};
|
|
@@ -19546,9 +19587,6 @@ class ClientEventReporter {
|
|
|
19546
19587
|
peer_connection: role,
|
|
19547
19588
|
was_previously_connected: pair.wasPreviouslyConnected,
|
|
19548
19589
|
...(pair.sfuId && { sfu_id: pair.sfuId }),
|
|
19549
|
-
...(pair.userSessionId && {
|
|
19550
|
-
user_session_id: pair.userSessionId,
|
|
19551
|
-
}),
|
|
19552
19590
|
event_type: 'completed',
|
|
19553
19591
|
outcome: 'success',
|
|
19554
19592
|
retry_count_attempt: 0,
|
|
@@ -19566,9 +19604,6 @@ class ClientEventReporter {
|
|
|
19566
19604
|
...this.sessionIdField(cid),
|
|
19567
19605
|
peer_connection: role,
|
|
19568
19606
|
was_previously_connected: pair.wasPreviouslyConnected,
|
|
19569
|
-
...(pair.userSessionId && {
|
|
19570
|
-
user_session_id: pair.userSessionId,
|
|
19571
|
-
}),
|
|
19572
19607
|
...(pair.sfuId && { sfu_id: pair.sfuId }),
|
|
19573
19608
|
event_type: 'completed',
|
|
19574
19609
|
outcome: 'failure',
|
|
@@ -19581,7 +19616,6 @@ class ClientEventReporter {
|
|
|
19581
19616
|
this.peerConnectionPairs.delete(key);
|
|
19582
19617
|
};
|
|
19583
19618
|
getSfuId = (cid) => this.callContexts.get(cid)?.getSfuId() ?? '';
|
|
19584
|
-
getUserSessionId = (cid) => this.callContexts.get(cid)?.getUserSessionId() ?? '';
|
|
19585
19619
|
sessionIdField = (cid) => {
|
|
19586
19620
|
const callSessionId = this.callContexts.get(cid)?.getCallSessionId() ?? '';
|
|
19587
19621
|
return callSessionId ? { call_session_id: callSessionId } : {};
|
|
@@ -19593,7 +19627,6 @@ class ClientEventReporter {
|
|
|
19593
19627
|
user_id: this.streamClient.userID || this.coordinatorConnectUserId,
|
|
19594
19628
|
type: ctx?.callType ?? '',
|
|
19595
19629
|
id: ctx?.callId ?? '',
|
|
19596
|
-
call_cid: cid,
|
|
19597
19630
|
stage,
|
|
19598
19631
|
stage_id: pair.sid,
|
|
19599
19632
|
...(pair.joinAttemptIdSnapshot && {
|
|
@@ -19844,6 +19877,7 @@ class StreamVideoClient {
|
|
|
19844
19877
|
}
|
|
19845
19878
|
else {
|
|
19846
19879
|
await call.updateFromRingingEvent(e);
|
|
19880
|
+
await call.get();
|
|
19847
19881
|
}
|
|
19848
19882
|
}
|
|
19849
19883
|
else {
|
|
@@ -19882,6 +19916,13 @@ class StreamVideoClient {
|
|
|
19882
19916
|
this.logger.error(`Failed to init call from event ${e.type}`, err);
|
|
19883
19917
|
}
|
|
19884
19918
|
};
|
|
19919
|
+
/**
|
|
19920
|
+
* Queries the API for calls matching the given filters.
|
|
19921
|
+
* @param data the query data.
|
|
19922
|
+
*/
|
|
19923
|
+
doQueryCalls = (data) => {
|
|
19924
|
+
return this.streamClient.post('/calls', data);
|
|
19925
|
+
};
|
|
19885
19926
|
/**
|
|
19886
19927
|
* Rewatches the given calls with retry logic.
|
|
19887
19928
|
* @param callsToReWatch array of call IDs to rewatch
|
|
@@ -19892,10 +19933,16 @@ class StreamVideoClient {
|
|
|
19892
19933
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
19893
19934
|
try {
|
|
19894
19935
|
this.logger.info(`Rewatching calls ${callsToReWatch.join(', ')} attempt ${attempt + 1}`);
|
|
19895
|
-
await this.
|
|
19936
|
+
const response = await this.doQueryCalls({
|
|
19896
19937
|
watch: true,
|
|
19897
19938
|
filter_conditions: { cid: { $in: callsToReWatch } },
|
|
19898
19939
|
});
|
|
19940
|
+
for (const c of response.calls) {
|
|
19941
|
+
const call = this.writeableStateStore.findCall(c.call.type, c.call.id);
|
|
19942
|
+
if (call) {
|
|
19943
|
+
call.updateFromCallStateResponse(c);
|
|
19944
|
+
}
|
|
19945
|
+
}
|
|
19899
19946
|
return;
|
|
19900
19947
|
}
|
|
19901
19948
|
catch (err) {
|
|
@@ -20038,9 +20085,11 @@ class StreamVideoClient {
|
|
|
20038
20085
|
* Will query the API for calls matching the given filters.
|
|
20039
20086
|
*
|
|
20040
20087
|
* @param data the query data.
|
|
20088
|
+
* @param opts additional options, for tweaking the API behavior.
|
|
20041
20089
|
*/
|
|
20042
|
-
queryCalls = async (data = {}) => {
|
|
20043
|
-
const
|
|
20090
|
+
queryCalls = async (data = {}, opts = {}) => {
|
|
20091
|
+
const { withDisabledDevices = true } = opts;
|
|
20092
|
+
const response = await this.doQueryCalls(data);
|
|
20044
20093
|
const calls = [];
|
|
20045
20094
|
for (const c of response.calls) {
|
|
20046
20095
|
const call = new Call({
|
|
@@ -20054,7 +20103,10 @@ class StreamVideoClient {
|
|
|
20054
20103
|
clientStore: this.writeableStateStore,
|
|
20055
20104
|
});
|
|
20056
20105
|
call.state.updateFromCallResponse(c.call);
|
|
20057
|
-
await call.applyDeviceConfig(c.call.settings,
|
|
20106
|
+
await call.applyDeviceConfig(c.call.settings, {
|
|
20107
|
+
publish: false,
|
|
20108
|
+
withDisabledDevices,
|
|
20109
|
+
});
|
|
20058
20110
|
if (data.watch) {
|
|
20059
20111
|
await call.setup();
|
|
20060
20112
|
this.writeableStateStore.registerCall(call);
|
|
@@ -20206,6 +20258,202 @@ const humanize = (n) => {
|
|
|
20206
20258
|
return String(n);
|
|
20207
20259
|
};
|
|
20208
20260
|
|
|
20261
|
+
/** Default loopback stream wait timeout. */
|
|
20262
|
+
const LOOPBACK_STREAMS_WAIT_TIMEOUT_MS = 10 * 1000;
|
|
20263
|
+
/** Default loopback recording duration. */
|
|
20264
|
+
const DEFAULT_LOOPBACK_RECORDING_DURATION_MS = 10 * 1000;
|
|
20265
|
+
/** Shortest permitted loopback recording duration. */
|
|
20266
|
+
const MIN_LOOPBACK_RECORDING_DURATION_MS = 5 * 1000;
|
|
20267
|
+
/** Longest permitted loopback recording duration. */
|
|
20268
|
+
const MAX_LOOPBACK_RECORDING_DURATION_MS = 2 * 60 * 1000;
|
|
20269
|
+
/** Thrown when loopback tracks do not arrive in time. */
|
|
20270
|
+
class LoopbackStreamsTimeoutError extends Error {
|
|
20271
|
+
constructor() {
|
|
20272
|
+
super('Timed out waiting for loopback streams. Ensure the call was joined ' +
|
|
20273
|
+
'with `allowOwnTracksLoopback: true` and that the SFU is configured ' +
|
|
20274
|
+
'to echo self-sub tracks.');
|
|
20275
|
+
this.name = 'LoopbackStreamsTimeoutError';
|
|
20276
|
+
}
|
|
20277
|
+
}
|
|
20278
|
+
/**
|
|
20279
|
+
* Returns the streams on the given participant that the SFU echoed back to us,
|
|
20280
|
+
* ignoring the local capture streams the publishing path writes to the same
|
|
20281
|
+
* fields.
|
|
20282
|
+
*/
|
|
20283
|
+
const getLoopbackStreams = (call, participant) => {
|
|
20284
|
+
const { subscriber } = call ?? {};
|
|
20285
|
+
const { audioStream, videoStream } = participant ?? {};
|
|
20286
|
+
return {
|
|
20287
|
+
loopbackVideoStream: subscriber?.isSelfSubscribedStream(videoStream)
|
|
20288
|
+
? videoStream
|
|
20289
|
+
: undefined,
|
|
20290
|
+
loopbackAudioStream: subscriber?.isSelfSubscribedStream(audioStream)
|
|
20291
|
+
? audioStream
|
|
20292
|
+
: undefined,
|
|
20293
|
+
};
|
|
20294
|
+
};
|
|
20295
|
+
/**
|
|
20296
|
+
* Returns loopback tracks when all required tracks are present.
|
|
20297
|
+
*
|
|
20298
|
+
* Prefer {@link waitForLoopbackStreams}, which observes call state until the
|
|
20299
|
+
* tracks arrive. This is the synchronous snapshot it is built from.
|
|
20300
|
+
*
|
|
20301
|
+
* @internal
|
|
20302
|
+
*/
|
|
20303
|
+
const getLoopbackTracks = (call, participant, includeVideo) => {
|
|
20304
|
+
if (!participant)
|
|
20305
|
+
return undefined;
|
|
20306
|
+
const { loopbackAudioStream, loopbackVideoStream } = getLoopbackStreams(call, participant);
|
|
20307
|
+
const audioTrack = loopbackAudioStream?.getAudioTracks()[0];
|
|
20308
|
+
const videoTrack = includeVideo
|
|
20309
|
+
? loopbackVideoStream?.getVideoTracks()[0]
|
|
20310
|
+
: undefined;
|
|
20311
|
+
if (!audioTrack || (includeVideo && !videoTrack)) {
|
|
20312
|
+
return undefined;
|
|
20313
|
+
}
|
|
20314
|
+
return { audioTrack, videoTrack };
|
|
20315
|
+
};
|
|
20316
|
+
/** Waits for the requested loopback tracks. */
|
|
20317
|
+
const waitForLoopbackStreams = (call, opts) => {
|
|
20318
|
+
const callState = call.state;
|
|
20319
|
+
const { includeVideo, signal, timeoutMs = LOOPBACK_STREAMS_WAIT_TIMEOUT_MS, } = opts;
|
|
20320
|
+
return new Promise((resolve, reject) => {
|
|
20321
|
+
const initial = getLoopbackTracks(call, callState.localParticipant, includeVideo);
|
|
20322
|
+
if (initial) {
|
|
20323
|
+
resolve(initial);
|
|
20324
|
+
return;
|
|
20325
|
+
}
|
|
20326
|
+
if (signal.aborted) {
|
|
20327
|
+
resolve(null);
|
|
20328
|
+
return;
|
|
20329
|
+
}
|
|
20330
|
+
let settled = false;
|
|
20331
|
+
const subscriptions = new Subscription();
|
|
20332
|
+
const cleanup = () => {
|
|
20333
|
+
if (settled)
|
|
20334
|
+
return;
|
|
20335
|
+
settled = true;
|
|
20336
|
+
clearTimeout(timeoutId);
|
|
20337
|
+
signal.removeEventListener('abort', onAbort);
|
|
20338
|
+
subscriptions.unsubscribe();
|
|
20339
|
+
};
|
|
20340
|
+
const onAbort = () => {
|
|
20341
|
+
cleanup();
|
|
20342
|
+
resolve(null);
|
|
20343
|
+
};
|
|
20344
|
+
const timeoutId = setTimeout(() => {
|
|
20345
|
+
cleanup();
|
|
20346
|
+
reject(new LoopbackStreamsTimeoutError());
|
|
20347
|
+
}, timeoutMs);
|
|
20348
|
+
signal.addEventListener('abort', onAbort);
|
|
20349
|
+
subscriptions.add(callState.localParticipant$.subscribe((participant) => {
|
|
20350
|
+
const ready = getLoopbackTracks(call, participant, includeVideo);
|
|
20351
|
+
if (ready) {
|
|
20352
|
+
cleanup();
|
|
20353
|
+
resolve(ready);
|
|
20354
|
+
}
|
|
20355
|
+
}));
|
|
20356
|
+
});
|
|
20357
|
+
};
|
|
20358
|
+
/** Enables loopback audio while `fn` runs, then restores it. */
|
|
20359
|
+
const withLoopbackAudioEnabled = async (tracks, fn) => {
|
|
20360
|
+
const restore = enableLoopbackAudio(tracks);
|
|
20361
|
+
try {
|
|
20362
|
+
return await fn();
|
|
20363
|
+
}
|
|
20364
|
+
finally {
|
|
20365
|
+
restore();
|
|
20366
|
+
}
|
|
20367
|
+
};
|
|
20368
|
+
/** Enables loopback audio and returns a restore function. */
|
|
20369
|
+
const enableLoopbackAudio = (tracks) => {
|
|
20370
|
+
const { audioTrack } = tracks;
|
|
20371
|
+
const previous = audioTrack?.enabled ?? false;
|
|
20372
|
+
if (audioTrack) {
|
|
20373
|
+
audioTrack.enabled = true;
|
|
20374
|
+
}
|
|
20375
|
+
return () => {
|
|
20376
|
+
if (audioTrack) {
|
|
20377
|
+
audioTrack.enabled = previous;
|
|
20378
|
+
}
|
|
20379
|
+
};
|
|
20380
|
+
};
|
|
20381
|
+
/** Clamps and rounds a loopback recording duration. */
|
|
20382
|
+
const clampLoopbackRecordingDuration = (durationMs) => Math.round(Math.min(MAX_LOOPBACK_RECORDING_DURATION_MS, Math.max(MIN_LOOPBACK_RECORDING_DURATION_MS, durationMs)));
|
|
20383
|
+
|
|
20384
|
+
/** Single-use `MediaRecorder` wrapper that returns an in-memory blob. */
|
|
20385
|
+
class MediaStreamRecorder {
|
|
20386
|
+
recording = promiseWithResolvers();
|
|
20387
|
+
logger = videoLoggerSystem.getLogger('MediaStreamRecorder');
|
|
20388
|
+
chunks = [];
|
|
20389
|
+
timeoutId;
|
|
20390
|
+
recorder;
|
|
20391
|
+
tracks;
|
|
20392
|
+
maxDurationMs;
|
|
20393
|
+
constructor(stream, options = {}) {
|
|
20394
|
+
if (typeof MediaRecorder === 'undefined') {
|
|
20395
|
+
throw new Error('MediaRecorder is not available in this environment');
|
|
20396
|
+
}
|
|
20397
|
+
this.tracks = stream.getTracks();
|
|
20398
|
+
if (this.tracks.length === 0) {
|
|
20399
|
+
throw new Error('cannot record a MediaStream that has no tracks');
|
|
20400
|
+
}
|
|
20401
|
+
this.maxDurationMs = options.maxDurationMs;
|
|
20402
|
+
this.recorder = new MediaRecorder(new MediaStream(this.tracks));
|
|
20403
|
+
this.recorder.ondataavailable = (event) => {
|
|
20404
|
+
if (event.data?.size)
|
|
20405
|
+
this.chunks.push(event.data);
|
|
20406
|
+
};
|
|
20407
|
+
this.recorder.onstop = this.handleStop;
|
|
20408
|
+
this.recorder.onerror = this.handleError;
|
|
20409
|
+
}
|
|
20410
|
+
/** Starts recording and resolves when recording stops. */
|
|
20411
|
+
start = () => {
|
|
20412
|
+
if (this.isSettled()) {
|
|
20413
|
+
throw new Error('MediaStreamRecorder is single-use: this instance has already ' +
|
|
20414
|
+
'recorded. Construct a new one.');
|
|
20415
|
+
}
|
|
20416
|
+
if (this.recorder.state === 'inactive') {
|
|
20417
|
+
this.tracks.forEach((track) => track.addEventListener('ended', this.stop));
|
|
20418
|
+
if (this.maxDurationMs !== undefined) {
|
|
20419
|
+
this.timeoutId = setTimeout(this.stop, this.maxDurationMs);
|
|
20420
|
+
}
|
|
20421
|
+
this.recorder.start();
|
|
20422
|
+
}
|
|
20423
|
+
return this.recording.promise;
|
|
20424
|
+
};
|
|
20425
|
+
/** Stops recording early. */
|
|
20426
|
+
stop = () => {
|
|
20427
|
+
if (this.recorder.state !== 'inactive')
|
|
20428
|
+
this.recorder.stop();
|
|
20429
|
+
};
|
|
20430
|
+
isSettled = () => this.recording.isResolved() || this.recording.isRejected();
|
|
20431
|
+
detach = () => {
|
|
20432
|
+
clearTimeout(this.timeoutId);
|
|
20433
|
+
this.tracks.forEach((track) => track.removeEventListener('ended', this.stop));
|
|
20434
|
+
};
|
|
20435
|
+
handleStop = () => {
|
|
20436
|
+
this.detach();
|
|
20437
|
+
if (this.chunks.length === 0) {
|
|
20438
|
+
this.logger.warn('MediaRecorder recording produced no data');
|
|
20439
|
+
this.recording.resolve(null);
|
|
20440
|
+
return;
|
|
20441
|
+
}
|
|
20442
|
+
const mimeType = this.chunks[0].type || this.recorder.mimeType;
|
|
20443
|
+
this.recording.resolve({
|
|
20444
|
+
blob: new Blob(this.chunks, { type: mimeType }),
|
|
20445
|
+
});
|
|
20446
|
+
};
|
|
20447
|
+
handleError = (event) => {
|
|
20448
|
+
if (this.isSettled())
|
|
20449
|
+
return;
|
|
20450
|
+
this.detach();
|
|
20451
|
+
const error = event.error;
|
|
20452
|
+
this.logger.error('MediaRecorder error', error);
|
|
20453
|
+
this.recording.reject(error ?? new Error('MediaRecorder failed'));
|
|
20454
|
+
};
|
|
20455
|
+
}
|
|
20456
|
+
|
|
20209
20457
|
/**
|
|
20210
20458
|
* Tiny, type-safe event emitter.
|
|
20211
20459
|
*
|
|
@@ -20557,5 +20805,5 @@ var e2eeWorker$1 = /*#__PURE__*/Object.freeze({
|
|
|
20557
20805
|
e2eeWorker: e2eeWorker
|
|
20558
20806
|
});
|
|
20559
20807
|
|
|
20560
|
-
export { AudioSettingsRequestDefaultDeviceEnum, AudioSettingsResponseDefaultDeviceEnum, browsers as Browsers, Call, CallRecordingFailedEventRecordingTypeEnum, CallRecordingReadyEventRecordingTypeEnum, CallRecordingStartedEventRecordingTypeEnum, CallRecordingStoppedEventRecordingTypeEnum, CallState, CallType, CallTypes, CallingState, CameraManager, CameraManagerState, CreateDeviceRequestPushProviderEnum, DebounceType, DeviceManager, DeviceManagerState, DynascaleManager, EncryptionManager, EncryptionSettingsRequestModeEnum, EncryptionSettingsResponseModeEnum, ErrorFromResponse, FrameRecordingSettingsRequestModeEnum, FrameRecordingSettingsRequestQualityEnum, FrameRecordingSettingsResponseModeEnum, HLSSettingsRequestQualityTracksEnum, IndividualRecordingSettingsRequestModeEnum, IndividualRecordingSettingsRequestOutputTypesEnum, IndividualRecordingSettingsResponseModeEnum, IngressAudioEncodingOptionsRequestChannelsEnum, IngressSourceRequestFpsEnum, IngressVideoLayerRequestCodecEnum, LayoutSettingsRequestNameEnum, MicrophoneManager, MicrophoneManagerState, NoiseCancellationSettingsModeEnum, OwnCapability, RTMPBroadcastRequestQualityEnum, RTMPSettingsRequestQualityEnum, RawRecordingSettingsRequestModeEnum, RawRecordingSettingsResponseModeEnum, RecordSettingsRequestModeEnum, RecordSettingsRequestQualityEnum, RequestPermissionRequestPermissionsEnum, rxUtils as RxUtils, ScreenShareManager, ScreenShareState, events as SfuEvents, SfuJoinError, models as SfuModels, SfuTimeoutError, SpeakerManager, SpeakerState, StartClosedCaptionsRequestLanguageEnum, StartTranscriptionRequestLanguageEnum, StreamSfuClient, StreamVideoClient, StreamVideoReadOnlyStateStore, StreamVideoWriteableStateStore, TranscriptionSettingsRequestClosedCaptionModeEnum, TranscriptionSettingsRequestLanguageEnum, TranscriptionSettingsRequestModeEnum, TranscriptionSettingsResponseClosedCaptionModeEnum, TranscriptionSettingsResponseLanguageEnum, TranscriptionSettingsResponseModeEnum, TranslationSettingsLanguagesEnum, UpdateUserPermissionsRequestGrantPermissionsEnum, UpdateUserPermissionsRequestRevokePermissionsEnum, VideoSettingsRequestCameraFacingEnum, VideoSettingsResponseCameraFacingEnum, ViewportTracker, VisibilityState, WSAuthMessageProductsEnum, checkIfAudioOutputChangeSupported, combineComparators, conditional, createSoundDetector, defaultSortPreset, descending, deviceIds$, disposeOfMediaStream, dominantSpeaker, getAudioBrowserPermission, getAudioDevices, getAudioOutputDevices, getAudioStream, getCallMediaEngineProvider, getClientDetails, getDeviceState, getScreenShareStream, getSdkInfo, getVideoBrowserPermission, getVideoDevices, getVideoStream, getWebRTCInfo, hasAudio$1 as hasAudio, hasInterruptedTrack, hasPausedTrack, hasScreenShare, hasScreenShareAudio, hasVideo, humanize, isPinned, livestreamOrAudioRoomSortPreset, logToConsole, name, noopComparator, paginatedLayoutSortPreset, pinned, publishingAudio, publishingVideo, reactionType, resolveDeviceId, role, screenSharing, setCallMediaEngineProvider, setDeviceInfo, setOSInfo, setPowerState, setSdkInfo, setThermalState, setWebRTCInfo, speakerLayoutSortPreset, speaking, videoLoggerSystem, withParticipantSource };
|
|
20808
|
+
export { AudioSettingsRequestDefaultDeviceEnum, AudioSettingsResponseDefaultDeviceEnum, browsers as Browsers, Call, CallRecordingFailedEventRecordingTypeEnum, CallRecordingReadyEventRecordingTypeEnum, CallRecordingStartedEventRecordingTypeEnum, CallRecordingStoppedEventRecordingTypeEnum, CallState, CallType, CallTypes, CallingState, CameraManager, CameraManagerState, CreateDeviceRequestPushProviderEnum, DEFAULT_LOOPBACK_RECORDING_DURATION_MS, DebounceType, DeviceManager, DeviceManagerState, DynascaleManager, EncryptionManager, EncryptionSettingsRequestModeEnum, EncryptionSettingsResponseModeEnum, ErrorFromResponse, FrameRecordingSettingsRequestModeEnum, FrameRecordingSettingsRequestQualityEnum, FrameRecordingSettingsResponseModeEnum, HLSSettingsRequestQualityTracksEnum, IndividualRecordingSettingsRequestModeEnum, IndividualRecordingSettingsRequestOutputTypesEnum, IndividualRecordingSettingsResponseModeEnum, IngressAudioEncodingOptionsRequestChannelsEnum, IngressSourceRequestFpsEnum, IngressVideoLayerRequestCodecEnum, LOOPBACK_STREAMS_WAIT_TIMEOUT_MS, LayoutSettingsRequestNameEnum, LoopbackStreamsTimeoutError, MAX_LOOPBACK_RECORDING_DURATION_MS, MIN_LOOPBACK_RECORDING_DURATION_MS, MediaStreamRecorder, MicrophoneManager, MicrophoneManagerState, NoiseCancellationSettingsModeEnum, OwnCapability, RTMPBroadcastRequestQualityEnum, RTMPSettingsRequestQualityEnum, RawRecordingSettingsRequestModeEnum, RawRecordingSettingsResponseModeEnum, RecordSettingsRequestModeEnum, RecordSettingsRequestQualityEnum, RequestPermissionRequestPermissionsEnum, rxUtils as RxUtils, ScreenShareManager, ScreenShareState, events as SfuEvents, SfuJoinError, models as SfuModels, SfuTimeoutError, SpeakerManager, SpeakerState, StartClosedCaptionsRequestLanguageEnum, StartTranscriptionRequestLanguageEnum, StreamSfuClient, StreamVideoClient, StreamVideoReadOnlyStateStore, StreamVideoWriteableStateStore, TranscriptionSettingsRequestClosedCaptionModeEnum, TranscriptionSettingsRequestLanguageEnum, TranscriptionSettingsRequestModeEnum, TranscriptionSettingsResponseClosedCaptionModeEnum, TranscriptionSettingsResponseLanguageEnum, TranscriptionSettingsResponseModeEnum, TranslationSettingsLanguagesEnum, UpdateUserPermissionsRequestGrantPermissionsEnum, UpdateUserPermissionsRequestRevokePermissionsEnum, VideoSettingsRequestCameraFacingEnum, VideoSettingsResponseCameraFacingEnum, ViewportTracker, VisibilityState, WSAuthMessageProductsEnum, checkIfAudioOutputChangeSupported, clampLoopbackRecordingDuration, combineComparators, conditional, createSoundDetector, defaultSortPreset, descending, deviceIds$, disposeOfMediaStream, dominantSpeaker, enableLoopbackAudio, getAudioBrowserPermission, getAudioDevices, getAudioOutputDevices, getAudioStream, getCallMediaEngineProvider, getClientDetails, getDeviceState, getLoopbackStreams, getLoopbackTracks, getScreenShareStream, getSdkInfo, getVideoBrowserPermission, getVideoDevices, getVideoStream, getWebRTCInfo, hasAudio$1 as hasAudio, hasInterruptedTrack, hasPausedTrack, hasScreenShare, hasScreenShareAudio, hasVideo, humanize, isPinned, livestreamOrAudioRoomSortPreset, logToConsole, name, noopComparator, paginatedLayoutSortPreset, pinned, publishingAudio, publishingVideo, reactionType, resolveDeviceId, role, screenSharing, setCallMediaEngineProvider, setDeviceInfo, setOSInfo, setPowerState, setSdkInfo, setThermalState, setWebRTCInfo, speakerLayoutSortPreset, speaking, videoLoggerSystem, waitForLoopbackStreams, withLoopbackAudioEnabled, withParticipantSource };
|
|
20561
20809
|
//# sourceMappingURL=index.es.js.map
|