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