@stream-io/video-client 0.6.6 → 0.6.8
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 -17
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +134 -17
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +134 -17
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +17 -1
- package/dist/src/StreamVideoClient.d.ts +8 -1
- package/dist/src/coordinator/connection/client.d.ts +6 -6
- package/dist/src/devices/InputMediaDeviceManager.d.ts +18 -1
- package/dist/src/devices/SpeakerManager.d.ts +6 -1
- package/dist/src/gen/coordinator/index.d.ts +374 -2
- package/dist/src/rtc/signal.d.ts +1 -0
- package/package.json +4 -4
- package/src/Call.ts +42 -4
- package/src/StreamVideoClient.ts +15 -0
- package/src/devices/InputMediaDeviceManager.ts +140 -48
- package/src/devices/SpeakerManager.ts +6 -1
- package/src/devices/__tests__/InputMediaDeviceManagerFilters.test.ts +115 -0
- package/src/gen/coordinator/index.ts +367 -2
- package/src/helpers/DynascaleManager.ts +0 -2
- package/src/store/CallState.ts +5 -0
package/dist/index.es.js
CHANGED
|
@@ -5805,7 +5805,7 @@ class SignalServerClient {
|
|
|
5805
5805
|
const defaultOptions = {
|
|
5806
5806
|
baseUrl: '',
|
|
5807
5807
|
sendJson: true,
|
|
5808
|
-
timeout: 5 * 1000,
|
|
5808
|
+
timeout: 5 * 1000, // ms.
|
|
5809
5809
|
jsonOptions: {
|
|
5810
5810
|
ignoreUnknownFields: true,
|
|
5811
5811
|
},
|
|
@@ -6211,7 +6211,7 @@ const findOptimalScreenSharingLayers = (videoTrack, preferences) => {
|
|
|
6211
6211
|
return [
|
|
6212
6212
|
{
|
|
6213
6213
|
active: true,
|
|
6214
|
-
rid: 'q',
|
|
6214
|
+
rid: 'q', // single track, start from 'q'
|
|
6215
6215
|
width: settings.width || 0,
|
|
6216
6216
|
height: settings.height || 0,
|
|
6217
6217
|
scaleResolutionDownBy: 1,
|
|
@@ -7064,9 +7064,14 @@ class CallState {
|
|
|
7064
7064
|
this.thumbnails$ = this.thumbnailsSubject.asObservable();
|
|
7065
7065
|
this.eventHandlers = {
|
|
7066
7066
|
// these events are not updating the call state:
|
|
7067
|
+
'call.closed_caption': undefined,
|
|
7067
7068
|
'call.permission_request': undefined,
|
|
7068
7069
|
'call.recording_failed': undefined,
|
|
7069
7070
|
'call.recording_ready': undefined,
|
|
7071
|
+
'call.transcription_started': undefined,
|
|
7072
|
+
'call.transcription_stopped': undefined,
|
|
7073
|
+
'call.transcription_ready': undefined,
|
|
7074
|
+
'call.transcription_failed': undefined,
|
|
7070
7075
|
'call.user_muted': undefined,
|
|
7071
7076
|
'connection.error': undefined,
|
|
7072
7077
|
'connection.ok': undefined,
|
|
@@ -9899,7 +9904,6 @@ class DynascaleManager {
|
|
|
9899
9904
|
// play audio through the system's default device
|
|
9900
9905
|
const { selectedDevice } = this.call.speaker.state;
|
|
9901
9906
|
if (selectedDevice && 'setSinkId' in audioElement) {
|
|
9902
|
-
// @ts-expect-error setSinkId is not yet in the lib
|
|
9903
9907
|
audioElement.setSinkId(selectedDevice);
|
|
9904
9908
|
}
|
|
9905
9909
|
}
|
|
@@ -9909,7 +9913,6 @@ class DynascaleManager {
|
|
|
9909
9913
|
? null
|
|
9910
9914
|
: this.call.speaker.state.selectedDevice$.subscribe((deviceId) => {
|
|
9911
9915
|
if (deviceId) {
|
|
9912
|
-
// @ts-expect-error setSinkId is not yet in the lib
|
|
9913
9916
|
audioElement.setSinkId(deviceId);
|
|
9914
9917
|
}
|
|
9915
9918
|
});
|
|
@@ -10309,8 +10312,14 @@ class InputMediaDeviceManager {
|
|
|
10309
10312
|
this.stopOnLeave = true;
|
|
10310
10313
|
this.subscriptions = [];
|
|
10311
10314
|
this.isTrackStoppedDueToTrackEnd = false;
|
|
10312
|
-
this.
|
|
10313
|
-
|
|
10315
|
+
this.filters = [];
|
|
10316
|
+
/**
|
|
10317
|
+
* Disposes the manager.
|
|
10318
|
+
*
|
|
10319
|
+
* @internal
|
|
10320
|
+
*/
|
|
10321
|
+
this.dispose = () => {
|
|
10322
|
+
this.subscriptions.forEach((s) => s());
|
|
10314
10323
|
};
|
|
10315
10324
|
this.logger = getLogger([`${TrackType[trackType].toLowerCase()} manager`]);
|
|
10316
10325
|
if (deviceIds$ &&
|
|
@@ -10387,6 +10396,23 @@ class InputMediaDeviceManager {
|
|
|
10387
10396
|
return this.enable();
|
|
10388
10397
|
}
|
|
10389
10398
|
}
|
|
10399
|
+
/**
|
|
10400
|
+
* Registers a filter that will be applied to the stream.
|
|
10401
|
+
*
|
|
10402
|
+
* The registered filter will get the existing stream, and it should return
|
|
10403
|
+
* a new stream with the applied filter.
|
|
10404
|
+
*
|
|
10405
|
+
* @param filter the filter to register.
|
|
10406
|
+
* @returns a function that will unregister the filter.
|
|
10407
|
+
*/
|
|
10408
|
+
async registerFilter(filter) {
|
|
10409
|
+
this.filters.push(filter);
|
|
10410
|
+
await this.applySettingsToStream();
|
|
10411
|
+
return async () => {
|
|
10412
|
+
this.filters = this.filters.filter((f) => f !== filter);
|
|
10413
|
+
await this.applySettingsToStream();
|
|
10414
|
+
};
|
|
10415
|
+
}
|
|
10390
10416
|
/**
|
|
10391
10417
|
* Will set the default constraints for the device.
|
|
10392
10418
|
*
|
|
@@ -10482,7 +10508,62 @@ class InputMediaDeviceManager {
|
|
|
10482
10508
|
...defaultConstraints,
|
|
10483
10509
|
deviceId: this.state.selectedDevice,
|
|
10484
10510
|
};
|
|
10485
|
-
|
|
10511
|
+
/**
|
|
10512
|
+
* Chains two media streams together.
|
|
10513
|
+
*
|
|
10514
|
+
* In our case, filters MediaStreams are derived from their parent MediaStream.
|
|
10515
|
+
* However, once a child filter's track is stopped,
|
|
10516
|
+
* the tracks of the parent MediaStream aren't automatically stopped.
|
|
10517
|
+
* This leads to a situation where the camera indicator light is still on
|
|
10518
|
+
* even though the user stopped publishing video.
|
|
10519
|
+
*
|
|
10520
|
+
* This function works around this issue by stopping the parent MediaStream's tracks
|
|
10521
|
+
* as well once the child filter's tracks are stopped.
|
|
10522
|
+
*
|
|
10523
|
+
* It works by patching the stop() method of the child filter's tracks to also stop
|
|
10524
|
+
* the parent MediaStream's tracks of the same type. Here we assume that
|
|
10525
|
+
* the parent MediaStream has only one track of each type.
|
|
10526
|
+
*
|
|
10527
|
+
* @param parentStream the parent MediaStream. Omit for the root stream.
|
|
10528
|
+
*/
|
|
10529
|
+
const chainWith = (parentStream) => async (filterStream) => {
|
|
10530
|
+
if (!parentStream)
|
|
10531
|
+
return filterStream;
|
|
10532
|
+
// TODO OL: take care of track.enabled property as well
|
|
10533
|
+
const parent = await parentStream;
|
|
10534
|
+
filterStream.getTracks().forEach((track) => {
|
|
10535
|
+
const originalStop = track.stop;
|
|
10536
|
+
track.stop = function stop() {
|
|
10537
|
+
originalStop.call(track);
|
|
10538
|
+
parent.getTracks().forEach((parentTrack) => {
|
|
10539
|
+
if (parentTrack.kind === track.kind) {
|
|
10540
|
+
parentTrack.stop();
|
|
10541
|
+
}
|
|
10542
|
+
});
|
|
10543
|
+
};
|
|
10544
|
+
});
|
|
10545
|
+
parent.getTracks().forEach((parentTrack) => {
|
|
10546
|
+
// When the parent stream abruptly ends, we propagate the event
|
|
10547
|
+
// to the filter stream.
|
|
10548
|
+
// This usually happens when the camera/microphone permissions
|
|
10549
|
+
// are revoked or when the device is disconnected.
|
|
10550
|
+
const handleParentTrackEnded = () => {
|
|
10551
|
+
filterStream.getTracks().forEach((track) => {
|
|
10552
|
+
if (parentTrack.kind !== track.kind)
|
|
10553
|
+
return;
|
|
10554
|
+
track.stop();
|
|
10555
|
+
track.dispatchEvent(new Event('ended')); // propagate the event
|
|
10556
|
+
});
|
|
10557
|
+
};
|
|
10558
|
+
parentTrack.addEventListener('ended', handleParentTrackEnded);
|
|
10559
|
+
this.subscriptions.push(() => {
|
|
10560
|
+
parentTrack.removeEventListener('ended', handleParentTrackEnded);
|
|
10561
|
+
});
|
|
10562
|
+
});
|
|
10563
|
+
return filterStream;
|
|
10564
|
+
};
|
|
10565
|
+
// we publish the last MediaStream of the chain
|
|
10566
|
+
stream = await this.filters.reduce((parent, filter) => parent.then(filter).then(chainWith(parent)), this.getStream(constraints));
|
|
10486
10567
|
}
|
|
10487
10568
|
if (this.call.state.callingState === CallingState.JOINED) {
|
|
10488
10569
|
await this.publishStream(stream);
|
|
@@ -10518,10 +10599,10 @@ class InputMediaDeviceManager {
|
|
|
10518
10599
|
return '';
|
|
10519
10600
|
}
|
|
10520
10601
|
handleDisconnectedOrReplacedDevices() {
|
|
10521
|
-
this.subscriptions.push(combineLatest([
|
|
10602
|
+
this.subscriptions.push(createSubscription(combineLatest([
|
|
10522
10603
|
deviceIds$.pipe(pairwise()),
|
|
10523
10604
|
this.state.selectedDevice$,
|
|
10524
|
-
])
|
|
10605
|
+
]), async ([[prevDevices, currentDevices], deviceId]) => {
|
|
10525
10606
|
if (!deviceId) {
|
|
10526
10607
|
return;
|
|
10527
10608
|
}
|
|
@@ -11285,7 +11366,12 @@ class SpeakerManager {
|
|
|
11285
11366
|
constructor(call) {
|
|
11286
11367
|
this.state = new SpeakerState();
|
|
11287
11368
|
this.subscriptions = [];
|
|
11288
|
-
|
|
11369
|
+
/**
|
|
11370
|
+
* Disposes the manager.
|
|
11371
|
+
*
|
|
11372
|
+
* @internal
|
|
11373
|
+
*/
|
|
11374
|
+
this.dispose = () => {
|
|
11289
11375
|
this.subscriptions.forEach((s) => s.unsubscribe());
|
|
11290
11376
|
};
|
|
11291
11377
|
this.call = call;
|
|
@@ -11480,10 +11566,10 @@ class Call {
|
|
|
11480
11566
|
// Call all leave call hooks, e.g. to clean up global event handlers
|
|
11481
11567
|
this.leaveCallHooks.forEach((hook) => hook());
|
|
11482
11568
|
this.clientStore.unregisterCall(this);
|
|
11483
|
-
this.camera.
|
|
11484
|
-
this.microphone.
|
|
11485
|
-
this.screenShare.
|
|
11486
|
-
this.speaker.
|
|
11569
|
+
this.camera.dispose();
|
|
11570
|
+
this.microphone.dispose();
|
|
11571
|
+
this.screenShare.dispose();
|
|
11572
|
+
this.speaker.dispose();
|
|
11487
11573
|
const stopOnLeavePromises = [];
|
|
11488
11574
|
if (this.camera.stopOnLeave) {
|
|
11489
11575
|
stopOnLeavePromises.push(this.camera.disable(true));
|
|
@@ -12285,6 +12371,20 @@ class Call {
|
|
|
12285
12371
|
this.stopRecording = async () => {
|
|
12286
12372
|
return this.streamClient.post(`${this.streamClientBasePath}/stop_recording`, {});
|
|
12287
12373
|
};
|
|
12374
|
+
/**
|
|
12375
|
+
* Starts the transcription of the call.
|
|
12376
|
+
*
|
|
12377
|
+
* @param request the request data.
|
|
12378
|
+
*/
|
|
12379
|
+
this.startTranscription = async (request) => {
|
|
12380
|
+
return this.streamClient.post(`${this.streamClientBasePath}/start_transcription`, request);
|
|
12381
|
+
};
|
|
12382
|
+
/**
|
|
12383
|
+
* Stops the transcription of the call.
|
|
12384
|
+
*/
|
|
12385
|
+
this.stopTranscription = async () => {
|
|
12386
|
+
return this.streamClient.post(`${this.streamClientBasePath}/stop_transcription`);
|
|
12387
|
+
};
|
|
12288
12388
|
/**
|
|
12289
12389
|
* Sends a `call.permission_request` event to all users connected to the call. The call settings object contains infomration about which permissions can be requested during a call (for example a user might be allowed to request permission to publish audio, but not video).
|
|
12290
12390
|
*/
|
|
@@ -12493,6 +12593,14 @@ class Call {
|
|
|
12493
12593
|
}
|
|
12494
12594
|
return this.streamClient.get(`${endpoint}/recordings`);
|
|
12495
12595
|
};
|
|
12596
|
+
/**
|
|
12597
|
+
* Retrieves the list of transcriptions for the current call.
|
|
12598
|
+
*
|
|
12599
|
+
* @returns the list of transcriptions.
|
|
12600
|
+
*/
|
|
12601
|
+
this.queryTranscriptions = async () => {
|
|
12602
|
+
return this.streamClient.get(`${this.streamClientBasePath}/transcriptions`);
|
|
12603
|
+
};
|
|
12496
12604
|
/**
|
|
12497
12605
|
* Retrieve call statistics for a particular call session (historical).
|
|
12498
12606
|
* Here `callSessionID` is mandatory.
|
|
@@ -13561,7 +13669,7 @@ function UserFromToken(token) {
|
|
|
13561
13669
|
*/
|
|
13562
13670
|
function DevToken(userId) {
|
|
13563
13671
|
return [
|
|
13564
|
-
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
|
|
13672
|
+
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', //{"alg": "HS256", "typ": "JWT"}
|
|
13565
13673
|
encodeBase64(JSON.stringify({ user_id: userId })),
|
|
13566
13674
|
'devtoken', // hardcoded signature
|
|
13567
13675
|
].join('.');
|
|
@@ -14373,7 +14481,7 @@ class StreamClient {
|
|
|
14373
14481
|
});
|
|
14374
14482
|
};
|
|
14375
14483
|
this.getUserAgent = () => {
|
|
14376
|
-
const version = "0.6.
|
|
14484
|
+
const version = "0.6.8" ;
|
|
14377
14485
|
return (this.userAgent ||
|
|
14378
14486
|
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
|
|
14379
14487
|
};
|
|
@@ -14488,7 +14596,7 @@ class StreamClient {
|
|
|
14488
14596
|
}
|
|
14489
14597
|
this.options = {
|
|
14490
14598
|
timeout: 5000,
|
|
14491
|
-
withCredentials: false,
|
|
14599
|
+
withCredentials: false, // making sure cookies are not sent
|
|
14492
14600
|
warmUp: false,
|
|
14493
14601
|
...inputOptions,
|
|
14494
14602
|
};
|
|
@@ -14631,6 +14739,15 @@ class StreamVideoClient {
|
|
|
14631
14739
|
calls: calls,
|
|
14632
14740
|
};
|
|
14633
14741
|
};
|
|
14742
|
+
/**
|
|
14743
|
+
* Retrieve the list of available call statistics reports matching a particular condition.
|
|
14744
|
+
*
|
|
14745
|
+
* @param data Filter and sort conditions for retrieving available call report summaries.
|
|
14746
|
+
* @returns List with summary of available call reports matching the condition.
|
|
14747
|
+
*/
|
|
14748
|
+
this.queryCallStats = async (data = {}) => {
|
|
14749
|
+
return this.streamClient.post(`/call/stats`, data);
|
|
14750
|
+
};
|
|
14634
14751
|
/**
|
|
14635
14752
|
* Returns a list of available data centers available for hosting calls.
|
|
14636
14753
|
*/
|