@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/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.removeSubscriptions = () => {
10313
- this.subscriptions.forEach((s) => s.unsubscribe());
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
- stream = await this.getStream(constraints);
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
- ]).subscribe(async ([[prevDevices, currentDevices], deviceId]) => {
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
- this.removeSubscriptions = () => {
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.removeSubscriptions();
11484
- this.microphone.removeSubscriptions();
11485
- this.screenShare.removeSubscriptions();
11486
- this.speaker.removeSubscriptions();
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.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
  */