@stream-io/video-client 0.4.1 → 0.4.3

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 CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
4
 
5
+ ### [0.4.3](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-0.4.2...@stream-io/video-client-0.4.3) (2023-11-01)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * **client:** optimized device enumeration ([#1111](https://github.com/GetStream/stream-video-js/issues/1111)) ([435bd33](https://github.com/GetStream/stream-video-js/commit/435bd33afbe8b368413690f8f2d67d0b4918dbaa))
11
+
12
+ ### [0.4.2](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-0.4.1...@stream-io/video-client-0.4.2) (2023-11-01)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * respect server-side settings in the lobby ([#1175](https://github.com/GetStream/stream-video-js/issues/1175)) ([b722a0a](https://github.com/GetStream/stream-video-js/commit/b722a0a4f8fd4e4e56787db3d9a56e45ee195974))
18
+
5
19
  ### [0.4.1](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-0.4.0...@stream-io/video-client-0.4.1) (2023-10-30)
6
20
 
7
21
 
@@ -6564,11 +6564,8 @@ class Publisher {
6564
6564
  ? transceiver.sender.track.stop()
6565
6565
  : (transceiver.sender.track.enabled = false);
6566
6566
  // We don't need to notify SFU if unpublishing in response to remote soft mute
6567
- if (!this.state.localParticipant?.publishedTracks.includes(trackType)) {
6568
- return;
6569
- }
6570
- else {
6571
- return this.notifyTrackMuteStateChanged(undefined, transceiver.sender.track, trackType, true);
6567
+ if (this.state.localParticipant?.publishedTracks.includes(trackType)) {
6568
+ await this.notifyTrackMuteStateChanged(undefined, transceiver.sender.track, trackType, true);
6572
6569
  }
6573
6570
  }
6574
6571
  };
@@ -9956,22 +9953,43 @@ const CallTypes = new CallTypesRegistry([
9956
9953
  }),
9957
9954
  ]);
9958
9955
 
9959
- const getDevices = (constraints) => {
9956
+ /**
9957
+ * Returns an Observable that emits the list of available devices
9958
+ * that meet the given constraints.
9959
+ *
9960
+ * @param constraints the constraints to use when requesting the devices.
9961
+ * @param kind the kind of devices to enumerate.
9962
+ */
9963
+ const getDevices = (constraints, kind) => {
9960
9964
  return new Observable((subscriber) => {
9961
- navigator.mediaDevices
9962
- .getUserMedia(constraints)
9963
- .then((media) => {
9964
- // in Firefox, devices can be enumerated after userMedia is requested
9965
- // and permissions granted. Otherwise, device labels are empty
9966
- navigator.mediaDevices.enumerateDevices().then((devices) => {
9967
- subscriber.next(devices);
9968
- // If we stop the tracks before enumerateDevices -> the labels won't show up in Firefox
9969
- disposeOfMediaStream(media);
9970
- subscriber.complete();
9971
- });
9965
+ const enumerate = async () => {
9966
+ let devices = await navigator.mediaDevices.enumerateDevices();
9967
+ // some browsers report empty device labels (Firefox).
9968
+ // in that case, we need to request permissions (via getUserMedia)
9969
+ // to be able to get the device labels
9970
+ const needsGetUserMedia = devices.some((device) => device.kind === kind && device.label === '');
9971
+ if (needsGetUserMedia) {
9972
+ let mediaStream;
9973
+ try {
9974
+ mediaStream = await navigator.mediaDevices.getUserMedia(constraints);
9975
+ devices = await navigator.mediaDevices.enumerateDevices();
9976
+ }
9977
+ finally {
9978
+ if (mediaStream)
9979
+ disposeOfMediaStream(mediaStream);
9980
+ }
9981
+ }
9982
+ return devices;
9983
+ };
9984
+ enumerate()
9985
+ .then((devices) => {
9986
+ // notify subscribers and complete
9987
+ subscriber.next(devices);
9988
+ subscriber.complete();
9972
9989
  })
9973
9990
  .catch((error) => {
9974
- getLogger(['devices'])('error', 'Failed to get devices', error);
9991
+ const logger = getLogger(['devices']);
9992
+ logger('error', 'Failed to enumerate devices', error);
9975
9993
  subscriber.error(error);
9976
9994
  });
9977
9995
  });
@@ -9985,7 +10003,7 @@ const checkIfAudioOutputChangeSupported = () => {
9985
10003
  if (typeof document === 'undefined')
9986
10004
  return false;
9987
10005
  const element = document.createElement('audio');
9988
- return element.sinkId !== undefined;
10006
+ return 'setSinkId' in element;
9989
10007
  };
9990
10008
  /**
9991
10009
  * The default constraints used to request audio devices.
@@ -10036,10 +10054,13 @@ const getDeviceChangeObserver = memoizedObservable(() => {
10036
10054
  }).pipe(debounceTime(500), concatMap(() => from(navigator.mediaDevices.enumerateDevices())), shareReplay(1));
10037
10055
  });
10038
10056
  const getAudioDevicesObserver = memoizedObservable(() => {
10039
- return merge(getDevices(audioDeviceConstraints), getDeviceChangeObserver()).pipe(shareReplay(1));
10057
+ return merge(getDevices(audioDeviceConstraints, 'audioinput'), getDeviceChangeObserver()).pipe(shareReplay(1));
10058
+ });
10059
+ const getAudioOutputDevicesObserver = memoizedObservable(() => {
10060
+ return merge(getDevices(audioDeviceConstraints, 'audiooutput'), getDeviceChangeObserver()).pipe(shareReplay(1));
10040
10061
  });
10041
10062
  const getVideoDevicesObserver = memoizedObservable(() => {
10042
- return merge(getDevices(videoDeviceConstraints), getDeviceChangeObserver()).pipe(shareReplay(1));
10063
+ return merge(getDevices(videoDeviceConstraints, 'videoinput'), getDeviceChangeObserver()).pipe(shareReplay(1));
10043
10064
  });
10044
10065
  /**
10045
10066
  * Prompts the user for a permission to use audio devices (if not already granted) and lists the available 'audioinput' devices, if devices are added/removed the list is updated.
@@ -10057,7 +10078,7 @@ const getVideoDevices = () => {
10057
10078
  * Prompts the user for a permission to use audio devices (if not already granted) and lists the available 'audiooutput' devices, if devices are added/removed the list is updated. Selecting 'audiooutput' device only makes sense if [the browser has support for changing audio output on 'audio' elements](#checkifaudiooutputchangesupported)
10058
10079
  */
10059
10080
  const getAudioOutputDevices = () => {
10060
- return getAudioDevicesObserver().pipe(map$1((values) => values.filter((d) => d.kind === 'audiooutput')));
10081
+ return getAudioOutputDevicesObserver().pipe(map$1((values) => values.filter((d) => d.kind === 'audiooutput')));
10061
10082
  };
10062
10083
  const getStream = async (constraints) => {
10063
10084
  try {
@@ -10262,9 +10283,8 @@ class InputMediaDeviceManager {
10262
10283
  * Starts stream.
10263
10284
  */
10264
10285
  async enable() {
10265
- if (this.state.status === 'enabled') {
10286
+ if (this.state.status === 'enabled')
10266
10287
  return;
10267
- }
10268
10288
  this.enablePromise = this.unmuteStream();
10269
10289
  try {
10270
10290
  await this.enablePromise;
@@ -10281,10 +10301,10 @@ class InputMediaDeviceManager {
10281
10301
  */
10282
10302
  async disable() {
10283
10303
  this.state.prevStatus = this.state.status;
10284
- if (this.state.status === 'disabled') {
10304
+ if (this.state.status === 'disabled')
10285
10305
  return;
10286
- }
10287
- this.disablePromise = this.muteStream(this.state.disableMode === 'stop-tracks');
10306
+ const stopTracks = this.state.disableMode === 'stop-tracks';
10307
+ this.disablePromise = this.muteStream(stopTracks);
10288
10308
  try {
10289
10309
  await this.disablePromise;
10290
10310
  this.state.setStatus('disabled');
@@ -10321,7 +10341,7 @@ class InputMediaDeviceManager {
10321
10341
  *
10322
10342
  * @param constraints the constraints to set.
10323
10343
  */
10324
- async setDefaultConstraints(constraints) {
10344
+ setDefaultConstraints(constraints) {
10325
10345
  this.state.setDefaultConstraints(constraints);
10326
10346
  }
10327
10347
  /**
@@ -10351,25 +10371,23 @@ class InputMediaDeviceManager {
10351
10371
  return this.state.mediaStream?.getTracks() ?? [];
10352
10372
  }
10353
10373
  async muteStream(stopTracks = true) {
10354
- if (!this.state.mediaStream) {
10374
+ if (!this.state.mediaStream)
10355
10375
  return;
10356
- }
10357
10376
  this.logger('debug', `${stopTracks ? 'Stopping' : 'Disabling'} stream`);
10358
10377
  if (this.call.state.callingState === CallingState.JOINED) {
10359
10378
  await this.stopPublishStream(stopTracks);
10360
10379
  }
10361
10380
  this.muteLocalStream(stopTracks);
10362
- this.getTracks().forEach((track) => {
10363
- if (track.readyState === 'ended') {
10381
+ const allEnded = this.getTracks().every((t) => t.readyState === 'ended');
10382
+ if (allEnded) {
10383
+ if (this.state.mediaStream &&
10364
10384
  // @ts-expect-error release() is present in react-native-webrtc
10365
- // and must be called to dispose the stream
10366
- if (typeof this.state.mediaStream.release === 'function') {
10367
- // @ts-expect-error
10368
- this.state.mediaStream.release();
10369
- }
10370
- this.state.setMediaStream(undefined);
10385
+ typeof this.state.mediaStream.release === 'function') {
10386
+ // @ts-expect-error called to dispose the stream in RN
10387
+ this.state.mediaStream.release();
10371
10388
  }
10372
- });
10389
+ this.state.setMediaStream(undefined);
10390
+ }
10373
10391
  }
10374
10392
  muteTracks() {
10375
10393
  this.getTracks().forEach((track) => {
@@ -13942,7 +13960,7 @@ class StreamClient {
13942
13960
  });
13943
13961
  };
13944
13962
  this.getUserAgent = () => {
13945
- const version = "0.4.1" ;
13963
+ const version = "0.4.3" ;
13946
13964
  return (this.userAgent ||
13947
13965
  `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
13948
13966
  };