@stream-io/video-client 0.3.12 → 0.3.13

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,13 @@
2
2
 
3
3
  This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
4
 
5
+ ### [0.3.13](https://github.com/GetStream/stream-video-js/compare/client0.3.12...client0.3.13) (2023-08-31)
6
+
7
+
8
+ ### Features
9
+
10
+ * speaker management ([#1013](https://github.com/GetStream/stream-video-js/issues/1013)) ([05af437](https://github.com/GetStream/stream-video-js/commit/05af437181175758c3295fbd70ae6d81d6c65595))
11
+
5
12
  ### [0.3.12](https://github.com/GetStream/stream-video-js/compare/client0.3.11...client0.3.12) (2023-08-31)
6
13
 
7
14
 
@@ -4,7 +4,7 @@ import { ServiceType, stackIntercept } from '@protobuf-ts/runtime-rpc';
4
4
  import axios, { AxiosHeaders } from 'axios';
5
5
  export { AxiosError } from 'axios';
6
6
  import { TwirpFetchTransport } from '@protobuf-ts/twirp-transport';
7
- import { ReplaySubject, BehaviorSubject, map as map$2, takeWhile, distinctUntilChanged as distinctUntilChanged$1, distinctUntilKeyChanged, Observable, debounceTime, concatMap, from, shareReplay, merge, combineLatest, filter, pairwise, tap, debounce, timer } from 'rxjs';
7
+ import { ReplaySubject, BehaviorSubject, map as map$2, takeWhile, distinctUntilChanged as distinctUntilChanged$1, distinctUntilKeyChanged, combineLatest, Observable, debounceTime, concatMap, from, shareReplay, merge, filter, pairwise, tap, debounce, timer } from 'rxjs';
8
8
  import * as SDP from 'sdp-transform';
9
9
  import { UAParser } from 'ua-parser-js';
10
10
  import WebSocket from 'isomorphic-ws';
@@ -9510,15 +9510,26 @@ class DynascaleManager {
9510
9510
  }
9511
9511
  });
9512
9512
  });
9513
- const sinkIdSubscription = this.call.state.localParticipant$.subscribe((p) => {
9514
- if (p && p.audioOutputDeviceId && 'setSinkId' in audioElement) {
9513
+ const sinkIdSubscription = combineLatest([
9514
+ this.call.state.localParticipant$,
9515
+ this.call.speaker.state.selectedDevice$,
9516
+ ]).subscribe(([p, selectedDevice]) => {
9517
+ var _a;
9518
+ const deviceId = ((_a = getSdkInfo()) === null || _a === void 0 ? void 0 : _a.type) === SdkType.REACT
9519
+ ? p === null || p === void 0 ? void 0 : p.audioOutputDeviceId
9520
+ : selectedDevice;
9521
+ if ('setSinkId' in audioElement) {
9515
9522
  // @ts-expect-error setSinkId is not yet in the lib
9516
- audioElement.setSinkId(p.audioOutputDeviceId);
9523
+ audioElement.setSinkId(deviceId);
9517
9524
  }
9518
9525
  });
9526
+ const volumeSubscription = this.call.speaker.state.volume$.subscribe((volume) => {
9527
+ audioElement.volume = volume;
9528
+ });
9519
9529
  audioElement.autoplay = true;
9520
9530
  return () => {
9521
9531
  sinkIdSubscription.unsubscribe();
9532
+ volumeSubscription.unsubscribe();
9522
9533
  updateMediaStreamSubscription.unsubscribe();
9523
9534
  };
9524
9535
  };
@@ -9665,6 +9676,127 @@ const CallTypes = new CallTypesRegistry([
9665
9676
  }),
9666
9677
  ]);
9667
9678
 
9679
+ class InputMediaDeviceManagerState {
9680
+ constructor(disableMode = 'stop-tracks') {
9681
+ this.disableMode = disableMode;
9682
+ this.statusSubject = new BehaviorSubject(undefined);
9683
+ this.mediaStreamSubject = new BehaviorSubject(undefined);
9684
+ this.selectedDeviceSubject = new BehaviorSubject(undefined);
9685
+ /**
9686
+ * Gets the current value of an observable, or undefined if the observable has
9687
+ * not emitted a value yet.
9688
+ *
9689
+ * @param observable$ the observable to get the value from.
9690
+ */
9691
+ this.getCurrentValue = getCurrentValue;
9692
+ /**
9693
+ * Updates the value of the provided Subject.
9694
+ * An `update` can either be a new value or a function which takes
9695
+ * the current value and returns a new value.
9696
+ *
9697
+ * @internal
9698
+ *
9699
+ * @param subject the subject to update.
9700
+ * @param update the update to apply to the subject.
9701
+ * @return the updated value.
9702
+ */
9703
+ this.setCurrentValue = setCurrentValue;
9704
+ this.mediaStream$ = this.mediaStreamSubject.asObservable();
9705
+ this.selectedDevice$ = this.selectedDeviceSubject
9706
+ .asObservable()
9707
+ .pipe(distinctUntilChanged$1());
9708
+ this.status$ = this.statusSubject
9709
+ .asObservable()
9710
+ .pipe(distinctUntilChanged$1());
9711
+ }
9712
+ /**
9713
+ * The device status
9714
+ */
9715
+ get status() {
9716
+ return this.getCurrentValue(this.status$);
9717
+ }
9718
+ /**
9719
+ * The currently selected device
9720
+ */
9721
+ get selectedDevice() {
9722
+ return this.getCurrentValue(this.selectedDevice$);
9723
+ }
9724
+ /**
9725
+ * The current media stream, or `undefined` if the device is currently disabled.
9726
+ */
9727
+ get mediaStream() {
9728
+ return this.getCurrentValue(this.mediaStream$);
9729
+ }
9730
+ /**
9731
+ * @internal
9732
+ * @param status
9733
+ */
9734
+ setStatus(status) {
9735
+ this.setCurrentValue(this.statusSubject, status);
9736
+ }
9737
+ /**
9738
+ * @internal
9739
+ * @param stream
9740
+ */
9741
+ setMediaStream(stream) {
9742
+ this.setCurrentValue(this.mediaStreamSubject, stream);
9743
+ if (stream) {
9744
+ this.setDevice(this.getDeviceIdFromStream(stream));
9745
+ }
9746
+ }
9747
+ /**
9748
+ * @internal
9749
+ * @param stream
9750
+ */
9751
+ setDevice(deviceId) {
9752
+ this.setCurrentValue(this.selectedDeviceSubject, deviceId);
9753
+ }
9754
+ }
9755
+
9756
+ class CameraManagerState extends InputMediaDeviceManagerState {
9757
+ constructor() {
9758
+ super('stop-tracks');
9759
+ this.directionSubject = new BehaviorSubject(undefined);
9760
+ this.direction$ = this.directionSubject
9761
+ .asObservable()
9762
+ .pipe(distinctUntilChanged$1());
9763
+ }
9764
+ /**
9765
+ * The preferred camera direction
9766
+ * front - means the camera facing the user
9767
+ * back - means the camera facing the environment
9768
+ */
9769
+ get direction() {
9770
+ return this.getCurrentValue(this.direction$);
9771
+ }
9772
+ /**
9773
+ * @internal
9774
+ */
9775
+ setDirection(direction) {
9776
+ this.setCurrentValue(this.directionSubject, direction);
9777
+ }
9778
+ /**
9779
+ * @internal
9780
+ */
9781
+ setMediaStream(stream) {
9782
+ var _a;
9783
+ super.setMediaStream(stream);
9784
+ if (stream) {
9785
+ // RN getSettings() doesn't return facingMode, so we don't verify camera direction
9786
+ const direction = isReactNative()
9787
+ ? this.direction
9788
+ : ((_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().facingMode) === 'environment'
9789
+ ? 'back'
9790
+ : 'front';
9791
+ this.setDirection(direction);
9792
+ }
9793
+ }
9794
+ getDeviceIdFromStream(stream) {
9795
+ var _a;
9796
+ return (_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
9797
+ }
9798
+ }
9799
+
9668
9800
  const getDevices = (constraints) => {
9669
9801
  return new Observable((subscriber) => {
9670
9802
  navigator.mediaDevices
@@ -10060,127 +10192,6 @@ class InputMediaDeviceManager {
10060
10192
  }
10061
10193
  }
10062
10194
 
10063
- class InputMediaDeviceManagerState {
10064
- constructor(disableMode = 'stop-tracks') {
10065
- this.disableMode = disableMode;
10066
- this.statusSubject = new BehaviorSubject(undefined);
10067
- this.mediaStreamSubject = new BehaviorSubject(undefined);
10068
- this.selectedDeviceSubject = new BehaviorSubject(undefined);
10069
- /**
10070
- * Gets the current value of an observable, or undefined if the observable has
10071
- * not emitted a value yet.
10072
- *
10073
- * @param observable$ the observable to get the value from.
10074
- */
10075
- this.getCurrentValue = getCurrentValue;
10076
- /**
10077
- * Updates the value of the provided Subject.
10078
- * An `update` can either be a new value or a function which takes
10079
- * the current value and returns a new value.
10080
- *
10081
- * @internal
10082
- *
10083
- * @param subject the subject to update.
10084
- * @param update the update to apply to the subject.
10085
- * @return the updated value.
10086
- */
10087
- this.setCurrentValue = setCurrentValue;
10088
- this.mediaStream$ = this.mediaStreamSubject.asObservable();
10089
- this.selectedDevice$ = this.selectedDeviceSubject
10090
- .asObservable()
10091
- .pipe(distinctUntilChanged$1());
10092
- this.status$ = this.statusSubject
10093
- .asObservable()
10094
- .pipe(distinctUntilChanged$1());
10095
- }
10096
- /**
10097
- * The device status
10098
- */
10099
- get status() {
10100
- return this.getCurrentValue(this.status$);
10101
- }
10102
- /**
10103
- * The currently selected device
10104
- */
10105
- get selectedDevice() {
10106
- return this.getCurrentValue(this.selectedDevice$);
10107
- }
10108
- /**
10109
- * The current media stream, or `undefined` if the device is currently disabled.
10110
- */
10111
- get mediaStream() {
10112
- return this.getCurrentValue(this.mediaStream$);
10113
- }
10114
- /**
10115
- * @internal
10116
- * @param status
10117
- */
10118
- setStatus(status) {
10119
- this.setCurrentValue(this.statusSubject, status);
10120
- }
10121
- /**
10122
- * @internal
10123
- * @param stream
10124
- */
10125
- setMediaStream(stream) {
10126
- this.setCurrentValue(this.mediaStreamSubject, stream);
10127
- if (stream) {
10128
- this.setDevice(this.getDeviceIdFromStream(stream));
10129
- }
10130
- }
10131
- /**
10132
- * @internal
10133
- * @param stream
10134
- */
10135
- setDevice(deviceId) {
10136
- this.setCurrentValue(this.selectedDeviceSubject, deviceId);
10137
- }
10138
- }
10139
-
10140
- class CameraManagerState extends InputMediaDeviceManagerState {
10141
- constructor() {
10142
- super('stop-tracks');
10143
- this.directionSubject = new BehaviorSubject(undefined);
10144
- this.direction$ = this.directionSubject
10145
- .asObservable()
10146
- .pipe(distinctUntilChanged$1());
10147
- }
10148
- /**
10149
- * The preferred camera direction
10150
- * front - means the camera facing the user
10151
- * back - means the camera facing the environment
10152
- */
10153
- get direction() {
10154
- return this.getCurrentValue(this.direction$);
10155
- }
10156
- /**
10157
- * @internal
10158
- */
10159
- setDirection(direction) {
10160
- this.setCurrentValue(this.directionSubject, direction);
10161
- }
10162
- /**
10163
- * @internal
10164
- */
10165
- setMediaStream(stream) {
10166
- var _a;
10167
- super.setMediaStream(stream);
10168
- if (stream) {
10169
- // RN getSettings() doesn't return facingMode, so we don't verify camera direction
10170
- const direction = isReactNative()
10171
- ? this.direction
10172
- : ((_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().facingMode) === 'environment'
10173
- ? 'back'
10174
- : 'front';
10175
- this.setDirection(direction);
10176
- }
10177
- }
10178
- getDeviceIdFromStream(stream) {
10179
- var _a;
10180
- return (_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
10181
- }
10182
- }
10183
-
10184
10195
  class CameraManager extends InputMediaDeviceManager {
10185
10196
  constructor(call) {
10186
10197
  super(call, new CameraManagerState());
@@ -10304,6 +10315,116 @@ class MicrophoneManager extends InputMediaDeviceManager {
10304
10315
  }
10305
10316
  }
10306
10317
 
10318
+ class SpeakerState {
10319
+ constructor() {
10320
+ this.selectedDeviceSubject = new BehaviorSubject('');
10321
+ this.volumeSubject = new BehaviorSubject(1);
10322
+ /**
10323
+ * [Tells if the browser supports audio output change on 'audio' elements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId).
10324
+ */
10325
+ this.isDeviceSelectionSupported = checkIfAudioOutputChangeSupported();
10326
+ /**
10327
+ * Gets the current value of an observable, or undefined if the observable has
10328
+ * not emitted a value yet.
10329
+ *
10330
+ * @param observable$ the observable to get the value from.
10331
+ */
10332
+ this.getCurrentValue = getCurrentValue;
10333
+ /**
10334
+ * Updates the value of the provided Subject.
10335
+ * An `update` can either be a new value or a function which takes
10336
+ * the current value and returns a new value.
10337
+ *
10338
+ * @internal
10339
+ *
10340
+ * @param subject the subject to update.
10341
+ * @param update the update to apply to the subject.
10342
+ * @return the updated value.
10343
+ */
10344
+ this.setCurrentValue = setCurrentValue;
10345
+ this.selectedDevice$ = this.selectedDeviceSubject
10346
+ .asObservable()
10347
+ .pipe(distinctUntilChanged$1());
10348
+ this.volume$ = this.volumeSubject
10349
+ .asObservable()
10350
+ .pipe(distinctUntilChanged$1());
10351
+ }
10352
+ /**
10353
+ * The currently selected device
10354
+ *
10355
+ * Note: this feature is not supported in React Native
10356
+ */
10357
+ get selectedDevice() {
10358
+ return this.getCurrentValue(this.selectedDevice$);
10359
+ }
10360
+ /**
10361
+ * The currently selected volume
10362
+ *
10363
+ * Note: this feature is not supported in React Native
10364
+ */
10365
+ get volume() {
10366
+ return this.getCurrentValue(this.volume$);
10367
+ }
10368
+ /**
10369
+ * @internal
10370
+ * @param deviceId
10371
+ */
10372
+ setDevice(deviceId) {
10373
+ this.setCurrentValue(this.selectedDeviceSubject, deviceId);
10374
+ }
10375
+ /**
10376
+ * @internal
10377
+ * @param volume
10378
+ */
10379
+ setVolume(volume) {
10380
+ this.setCurrentValue(this.volumeSubject, volume);
10381
+ }
10382
+ }
10383
+
10384
+ class SpeakerManager {
10385
+ constructor() {
10386
+ this.state = new SpeakerState();
10387
+ }
10388
+ /**
10389
+ * Lists the available audio output devices
10390
+ *
10391
+ * Note: It prompts the user for a permission to use devices (if not already granted)
10392
+ *
10393
+ * @returns an Observable that will be updated if a device is connected or disconnected
10394
+ */
10395
+ listDevices() {
10396
+ return getAudioOutputDevices();
10397
+ }
10398
+ /**
10399
+ * Select device
10400
+ *
10401
+ * Note: this method is not supported in React Native
10402
+ *
10403
+ * @param deviceId empty string means the system default
10404
+ */
10405
+ select(deviceId) {
10406
+ if (isReactNative()) {
10407
+ throw new Error('This feature is not supported in React Native');
10408
+ }
10409
+ this.state.setDevice(deviceId);
10410
+ }
10411
+ /**
10412
+ * Set the volume of the audio elements
10413
+ * @param volume a number between 0 and 1
10414
+ *
10415
+ * Note: this method is not supported in React Native
10416
+ */
10417
+ setVolume(volume) {
10418
+ if (isReactNative()) {
10419
+ throw new Error('This feature is not supported in React Native');
10420
+ }
10421
+ if (volume && (volume < 0 || volume > 1)) {
10422
+ throw new Error('Volume must be between 0 and 1');
10423
+ }
10424
+ this.state.setVolume(volume);
10425
+ }
10426
+ }
10427
+
10307
10428
  /**
10308
10429
  * An object representation of a `Call`.
10309
10430
  */
@@ -10978,6 +11099,8 @@ class Call {
10978
11099
  *
10979
11100
  *
10980
11101
  * @param deviceId the selected device, `undefined` means the user wants to use the system's default audio output
11102
+ *
11103
+ * @deprecated use `call.speaker` instead
10981
11104
  */
10982
11105
  this.setAudioOutputDevice = (deviceId) => {
10983
11106
  if (!this.sfuClient)
@@ -11452,6 +11575,7 @@ class Call {
11452
11575
  this.leaveCallHooks.add(createSubscription(this.trackSubscriptionsSubject.pipe(debounce((v) => timer(v.type)), map$2((v) => v.data)), (subscriptions) => { var _a; return (_a = this.sfuClient) === null || _a === void 0 ? void 0 : _a.updateSubscriptions(subscriptions); }));
11453
11576
  this.camera = new CameraManager(this);
11454
11577
  this.microphone = new MicrophoneManager(this);
11578
+ this.speaker = new SpeakerManager();
11455
11579
  }
11456
11580
  registerEffects() {
11457
11581
  this.leaveCallHooks.add(
@@ -12741,7 +12865,7 @@ class WSConnectionFallback {
12741
12865
  }
12742
12866
  }
12743
12867
 
12744
- const version = '0.3.12';
12868
+ const version = '0.3.13';
12745
12869
 
12746
12870
  const logger = getLogger(['location']);
12747
12871
  const HINT_URL = `https://hint.stream-io-video.com/`;