@stream-io/video-client 0.3.0 → 0.3.1

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/index.browser.es.js +662 -256
  3. package/dist/index.browser.es.js.map +1 -1
  4. package/dist/index.cjs.js +664 -254
  5. package/dist/index.cjs.js.map +1 -1
  6. package/dist/index.es.js +662 -256
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/src/Call.d.ts +18 -1
  9. package/dist/src/devices/CameraManager.d.ts +31 -0
  10. package/dist/src/devices/CameraManagerState.d.ts +28 -0
  11. package/dist/src/devices/InputMediaDeviceManager.d.ts +47 -0
  12. package/dist/src/devices/InputMediaDeviceManagerState.d.ts +69 -0
  13. package/dist/src/devices/MicrophoneManager.d.ts +19 -0
  14. package/dist/src/devices/MicrophoneManagerState.d.ts +4 -0
  15. package/dist/src/devices/__tests__/CameraManager.test.d.ts +1 -0
  16. package/dist/src/devices/__tests__/InputMediaDeviceManager.test.d.ts +1 -0
  17. package/dist/src/devices/__tests__/MicrophoneManager.test.d.ts +1 -0
  18. package/dist/src/devices/__tests__/mocks.d.ts +13 -0
  19. package/dist/src/devices/index.d.ts +4 -0
  20. package/dist/src/types.d.ts +4 -0
  21. package/dist/version.d.ts +1 -1
  22. package/package.json +1 -1
  23. package/src/Call.ts +100 -3
  24. package/src/__tests__/StreamVideoClient.test.ts +3 -0
  25. package/src/devices/CameraManager.ts +73 -0
  26. package/src/devices/CameraManagerState.ts +61 -0
  27. package/src/devices/InputMediaDeviceManager.ts +121 -0
  28. package/src/devices/InputMediaDeviceManagerState.ts +111 -0
  29. package/src/devices/MicrophoneManager.ts +45 -0
  30. package/src/devices/MicrophoneManagerState.ts +9 -0
  31. package/src/devices/__tests__/CameraManager.test.ts +150 -0
  32. package/src/devices/__tests__/InputMediaDeviceManager.test.ts +159 -0
  33. package/src/devices/__tests__/MicrophoneManager.test.ts +103 -0
  34. package/src/devices/__tests__/mocks.ts +98 -0
  35. package/src/devices/index.ts +4 -0
  36. package/src/types.ts +4 -0
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, takeWhile, filter, pairwise, tap, debounce, timer, map as map$2, Observable, debounceTime, concatMap, from, shareReplay, merge, combineLatest } from 'rxjs';
7
+ import { ReplaySubject, BehaviorSubject, distinctUntilChanged as distinctUntilChanged$1, Observable, debounceTime, concatMap, from, shareReplay, merge, map as map$2, combineLatest, filter, pairwise, takeWhile, tap, debounce, timer } from 'rxjs';
8
8
  import * as SDP from 'sdp-transform';
9
9
  import WebSocket from 'isomorphic-ws';
10
10
  import { take, map as map$1, distinctUntilChanged } from 'rxjs/operators';
@@ -9517,6 +9517,591 @@ const getClientDetails = () => {
9517
9517
  };
9518
9518
  };
9519
9519
 
9520
+ class InputMediaDeviceManagerState {
9521
+ constructor() {
9522
+ this.statusSubject = new BehaviorSubject(undefined);
9523
+ this.mediaStreamSubject = new BehaviorSubject(undefined);
9524
+ this.selectedDeviceSubject = new BehaviorSubject(undefined);
9525
+ /**
9526
+ * Gets the current value of an observable, or undefined if the observable has
9527
+ * not emitted a value yet.
9528
+ *
9529
+ * @param observable$ the observable to get the value from.
9530
+ */
9531
+ this.getCurrentValue = getCurrentValue;
9532
+ /**
9533
+ * Updates the value of the provided Subject.
9534
+ * An `update` can either be a new value or a function which takes
9535
+ * the current value and returns a new value.
9536
+ *
9537
+ * @internal
9538
+ *
9539
+ * @param subject the subject to update.
9540
+ * @param update the update to apply to the subject.
9541
+ * @return the updated value.
9542
+ */
9543
+ this.setCurrentValue = setCurrentValue;
9544
+ this.mediaStream$ = this.mediaStreamSubject.asObservable();
9545
+ this.selectedDevice$ = this.selectedDeviceSubject
9546
+ .asObservable()
9547
+ .pipe(distinctUntilChanged$1());
9548
+ this.status$ = this.statusSubject.asObservable();
9549
+ }
9550
+ /**
9551
+ * The device status
9552
+ */
9553
+ get status() {
9554
+ return this.getCurrentValue(this.status$);
9555
+ }
9556
+ /**
9557
+ * The currently selected device
9558
+ */
9559
+ get selectedDevice() {
9560
+ return this.getCurrentValue(this.selectedDevice$);
9561
+ }
9562
+ /**
9563
+ * The current media stream, or `undefined` if the device is currently disabled.
9564
+ */
9565
+ get mediaStream() {
9566
+ return this.getCurrentValue(this.mediaStream$);
9567
+ }
9568
+ /**
9569
+ * @internal
9570
+ * @param status
9571
+ */
9572
+ setStatus(status) {
9573
+ this.setCurrentValue(this.statusSubject, status);
9574
+ }
9575
+ /**
9576
+ * @internal
9577
+ * @param stream
9578
+ */
9579
+ setMediaStream(stream) {
9580
+ this.setCurrentValue(this.mediaStreamSubject, stream);
9581
+ if (stream) {
9582
+ this.setDevice(this.getDeviceIdFromStream(stream));
9583
+ }
9584
+ }
9585
+ /**
9586
+ * @internal
9587
+ * @param stream
9588
+ */
9589
+ setDevice(deviceId) {
9590
+ this.setCurrentValue(this.selectedDeviceSubject, deviceId);
9591
+ }
9592
+ }
9593
+
9594
+ class CameraManagerState extends InputMediaDeviceManagerState {
9595
+ constructor() {
9596
+ super();
9597
+ this.directionSubject = new BehaviorSubject(undefined);
9598
+ this.direction$ = this.directionSubject
9599
+ .asObservable()
9600
+ .pipe(distinctUntilChanged$1());
9601
+ }
9602
+ /**
9603
+ * The preferred camera direction
9604
+ * front - means the camera facing the user
9605
+ * back - means the camera facing the environment
9606
+ */
9607
+ get direction() {
9608
+ return this.getCurrentValue(this.direction$);
9609
+ }
9610
+ /**
9611
+ * @internal
9612
+ */
9613
+ setDirection(direction) {
9614
+ this.setCurrentValue(this.directionSubject, direction);
9615
+ }
9616
+ /**
9617
+ * @internal
9618
+ */
9619
+ setMediaStream(stream) {
9620
+ var _a;
9621
+ super.setMediaStream(stream);
9622
+ if (stream) {
9623
+ // RN getSettings() doesn't return facingMode, so we don't verify camera direction
9624
+ const direction = isReactNative()
9625
+ ? this.direction
9626
+ : ((_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().facingMode) === 'environment'
9627
+ ? 'back'
9628
+ : 'front';
9629
+ this.setDirection(direction);
9630
+ }
9631
+ }
9632
+ getDeviceIdFromStream(stream) {
9633
+ var _a;
9634
+ return (_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
9635
+ }
9636
+ }
9637
+
9638
+ const getDevices = (constraints) => {
9639
+ return new Observable((subscriber) => {
9640
+ navigator.mediaDevices
9641
+ .getUserMedia(constraints)
9642
+ .then((media) => {
9643
+ // in Firefox, devices can be enumerated after userMedia is requested
9644
+ // and permissions granted. Otherwise, device labels are empty
9645
+ navigator.mediaDevices.enumerateDevices().then((devices) => {
9646
+ subscriber.next(devices);
9647
+ // If we stop the tracks before enumerateDevices -> the labels won't show up in Firefox
9648
+ disposeOfMediaStream(media);
9649
+ subscriber.complete();
9650
+ });
9651
+ })
9652
+ .catch((error) => {
9653
+ getLogger(['devices'])('error', 'Failed to get devices', error);
9654
+ subscriber.error(error);
9655
+ });
9656
+ });
9657
+ };
9658
+ /**
9659
+ * [Tells if the browser supports audio output change on 'audio' elements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId).
9660
+ *
9661
+ * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
9662
+ */
9663
+ const checkIfAudioOutputChangeSupported = () => {
9664
+ if (typeof document === 'undefined')
9665
+ return false;
9666
+ const element = document.createElement('audio');
9667
+ return element.sinkId !== undefined;
9668
+ };
9669
+ /**
9670
+ * The default constraints used to request audio devices.
9671
+ */
9672
+ const audioDeviceConstraints = {
9673
+ audio: {
9674
+ autoGainControl: true,
9675
+ noiseSuppression: true,
9676
+ echoCancellation: true,
9677
+ },
9678
+ };
9679
+ /**
9680
+ * The default constraints used to request video devices.
9681
+ */
9682
+ const videoDeviceConstraints = {
9683
+ video: {
9684
+ width: 1280,
9685
+ height: 720,
9686
+ },
9687
+ };
9688
+ // Audio and video devices are requested in two separate requests: that way users will be presented with two separate prompts -> they can give access to just camera, or just microphone
9689
+ const deviceChange$ = new Observable((subscriber) => {
9690
+ var _a, _b;
9691
+ const deviceChangeHandler = () => subscriber.next();
9692
+ (_b = (_a = navigator.mediaDevices).addEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
9693
+ return () => {
9694
+ var _a, _b;
9695
+ return (_b = (_a = navigator.mediaDevices).removeEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
9696
+ };
9697
+ }).pipe(debounceTime(500), concatMap(() => from(navigator.mediaDevices.enumerateDevices())), shareReplay(1));
9698
+ const audioDevices$ = merge(getDevices(audioDeviceConstraints), deviceChange$).pipe(shareReplay(1));
9699
+ const videoDevices$ = merge(getDevices(videoDeviceConstraints), deviceChange$).pipe(shareReplay(1));
9700
+ /**
9701
+ * 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.
9702
+ *
9703
+ * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
9704
+ * @returns
9705
+ */
9706
+ const getAudioDevices = () => audioDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'audioinput')));
9707
+ /**
9708
+ * Prompts the user for a permission to use video devices (if not already granted) and lists the available 'videoinput' devices, if devices are added/removed the list is updated.
9709
+ *
9710
+ * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
9711
+ * @returns
9712
+ */
9713
+ const getVideoDevices = () => videoDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'videoinput' && d.deviceId.length)));
9714
+ /**
9715
+ * 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)
9716
+ *
9717
+ * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
9718
+ * @returns
9719
+ */
9720
+ const getAudioOutputDevices = () => {
9721
+ return audioDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'audiooutput')));
9722
+ };
9723
+ const getStream = (constraints) => __awaiter(void 0, void 0, void 0, function* () {
9724
+ try {
9725
+ return yield navigator.mediaDevices.getUserMedia(constraints);
9726
+ }
9727
+ catch (e) {
9728
+ getLogger(['devices'])('error', `Failed get user media`, {
9729
+ error: e,
9730
+ constraints: constraints,
9731
+ });
9732
+ throw e;
9733
+ }
9734
+ });
9735
+ /**
9736
+ * Returns an audio media stream that fulfills the given constraints.
9737
+ * If no constraints are provided, it uses the browser's default ones.
9738
+ *
9739
+ * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
9740
+ * @param trackConstraints the constraints to use when requesting the stream.
9741
+ * @returns the new `MediaStream` fulfilling the given constraints.
9742
+ */
9743
+ const getAudioStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
9744
+ const constraints = {
9745
+ audio: Object.assign(Object.assign({}, audioDeviceConstraints.audio), trackConstraints),
9746
+ };
9747
+ return getStream(constraints);
9748
+ });
9749
+ /**
9750
+ * Returns a video media stream that fulfills the given constraints.
9751
+ * If no constraints are provided, it uses the browser's default ones.
9752
+ *
9753
+ * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
9754
+ * @param trackConstraints the constraints to use when requesting the stream.
9755
+ * @returns a new `MediaStream` fulfilling the given constraints.
9756
+ */
9757
+ const getVideoStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
9758
+ const constraints = {
9759
+ video: Object.assign(Object.assign({}, videoDeviceConstraints.video), trackConstraints),
9760
+ };
9761
+ return getStream(constraints);
9762
+ });
9763
+ /**
9764
+ * Prompts the user for a permission to share a screen.
9765
+ * If the user grants the permission, a screen sharing stream is returned. Throws otherwise.
9766
+ *
9767
+ * The callers of this API are responsible to handle the possible errors.
9768
+ *
9769
+ * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
9770
+ *
9771
+ * @param options any additional options to pass to the [`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) API.
9772
+ */
9773
+ const getScreenShareStream = (options) => __awaiter(void 0, void 0, void 0, function* () {
9774
+ try {
9775
+ return yield navigator.mediaDevices.getDisplayMedia(Object.assign({ video: true, audio: false }, options));
9776
+ }
9777
+ catch (e) {
9778
+ getLogger(['devices'])('error', 'Failed to get screen share stream', e);
9779
+ throw e;
9780
+ }
9781
+ });
9782
+ const watchForDisconnectedDevice = (kind, deviceId$) => {
9783
+ let devices$;
9784
+ switch (kind) {
9785
+ case 'audioinput':
9786
+ devices$ = getAudioDevices();
9787
+ break;
9788
+ case 'videoinput':
9789
+ devices$ = getVideoDevices();
9790
+ break;
9791
+ case 'audiooutput':
9792
+ devices$ = getAudioOutputDevices();
9793
+ break;
9794
+ }
9795
+ return combineLatest([devices$, deviceId$]).pipe(filter(([devices, deviceId]) => !!deviceId && !devices.find((d) => d.deviceId === deviceId)), map$2(() => true));
9796
+ };
9797
+ /**
9798
+ * Notifies the subscriber if a given 'audioinput' device is disconnected
9799
+ *
9800
+ * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
9801
+ * @param deviceId$ an Observable that specifies which device to watch for
9802
+ * @returns
9803
+ */
9804
+ const watchForDisconnectedAudioDevice = (deviceId$) => {
9805
+ return watchForDisconnectedDevice('audioinput', deviceId$);
9806
+ };
9807
+ /**
9808
+ * Notifies the subscriber if a given 'videoinput' device is disconnected
9809
+ *
9810
+ * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
9811
+ * @param deviceId$ an Observable that specifies which device to watch for
9812
+ * @returns
9813
+ */
9814
+ const watchForDisconnectedVideoDevice = (deviceId$) => {
9815
+ return watchForDisconnectedDevice('videoinput', deviceId$);
9816
+ };
9817
+ /**
9818
+ * Notifies the subscriber if a given 'audiooutput' device is disconnected
9819
+ *
9820
+ * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
9821
+ * @param deviceId$ an Observable that specifies which device to watch for
9822
+ * @returns
9823
+ */
9824
+ const watchForDisconnectedAudioOutputDevice = (deviceId$) => {
9825
+ return watchForDisconnectedDevice('audiooutput', deviceId$);
9826
+ };
9827
+ const watchForAddedDefaultDevice = (kind) => {
9828
+ let devices$;
9829
+ switch (kind) {
9830
+ case 'audioinput':
9831
+ devices$ = getAudioDevices();
9832
+ break;
9833
+ case 'videoinput':
9834
+ devices$ = getVideoDevices();
9835
+ break;
9836
+ case 'audiooutput':
9837
+ devices$ = getAudioOutputDevices();
9838
+ break;
9839
+ default:
9840
+ throw new Error('Unknown MediaDeviceKind', kind);
9841
+ }
9842
+ return devices$.pipe(pairwise(), filter(([prev, current]) => {
9843
+ const prevDefault = prev.find((device) => device.deviceId === 'default');
9844
+ const currentDefault = current.find((device) => device.deviceId === 'default');
9845
+ return !!(current.length > prev.length &&
9846
+ prevDefault &&
9847
+ currentDefault &&
9848
+ prevDefault.groupId !== currentDefault.groupId);
9849
+ }), map$2(() => true));
9850
+ };
9851
+ /**
9852
+ * Notifies the subscriber about newly added default audio input device.
9853
+ * @returns Observable<boolean>
9854
+ */
9855
+ const watchForAddedDefaultAudioDevice = () => watchForAddedDefaultDevice('audioinput');
9856
+ /**
9857
+ * Notifies the subscriber about newly added default audio output device.
9858
+ * @returns Observable<boolean>
9859
+ */
9860
+ const watchForAddedDefaultAudioOutputDevice = () => watchForAddedDefaultDevice('audiooutput');
9861
+ /**
9862
+ * Notifies the subscriber about newly added default video input device.
9863
+ * @returns Observable<boolean>
9864
+ */
9865
+ const watchForAddedDefaultVideoDevice = () => watchForAddedDefaultDevice('videoinput');
9866
+ /**
9867
+ * Deactivates MediaStream (stops and removes tracks) to be later garbage collected
9868
+ *
9869
+ * @param stream MediaStream
9870
+ * @returns void
9871
+ */
9872
+ const disposeOfMediaStream = (stream) => {
9873
+ if (!stream.active)
9874
+ return;
9875
+ stream.getTracks().forEach((track) => {
9876
+ track.stop();
9877
+ stream.removeTrack(track);
9878
+ });
9879
+ // @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the stream
9880
+ if (typeof stream.release === 'function') {
9881
+ // @ts-expect-error
9882
+ stream.release();
9883
+ }
9884
+ };
9885
+
9886
+ class InputMediaDeviceManager {
9887
+ constructor(call, state) {
9888
+ this.call = call;
9889
+ this.state = state;
9890
+ }
9891
+ /**
9892
+ * Lists the available audio/video devices
9893
+ *
9894
+ * Note: It prompts the user for a permission to use devices (if not already granted)
9895
+ *
9896
+ * @returns an Observable that will be updated if a device is connected or disconnected
9897
+ */
9898
+ listDevices() {
9899
+ return this.getDevices();
9900
+ }
9901
+ /**
9902
+ * Starts camera/microphone
9903
+ */
9904
+ enable() {
9905
+ return __awaiter(this, void 0, void 0, function* () {
9906
+ if (this.state.status === 'enabled') {
9907
+ return;
9908
+ }
9909
+ yield this.startStream();
9910
+ this.state.setStatus('enabled');
9911
+ });
9912
+ }
9913
+ /**
9914
+ * Stops camera/microphone
9915
+ * @returns
9916
+ */
9917
+ disable() {
9918
+ return __awaiter(this, void 0, void 0, function* () {
9919
+ if (this.state.status === 'disabled') {
9920
+ return;
9921
+ }
9922
+ yield this.stopStream();
9923
+ this.state.setStatus('disabled');
9924
+ });
9925
+ }
9926
+ /**
9927
+ * If current device statis is disabled, it will enable the device, else it will disable it.
9928
+ * @returns
9929
+ */
9930
+ toggle() {
9931
+ return __awaiter(this, void 0, void 0, function* () {
9932
+ if (this.state.status === 'enabled') {
9933
+ return this.disable();
9934
+ }
9935
+ else {
9936
+ return this.enable();
9937
+ }
9938
+ });
9939
+ }
9940
+ /**
9941
+ * Select device
9942
+ *
9943
+ * Note: this method is not supported in React Native
9944
+ *
9945
+ * @param deviceId
9946
+ */
9947
+ select(deviceId) {
9948
+ return __awaiter(this, void 0, void 0, function* () {
9949
+ if (isReactNative()) {
9950
+ throw new Error('This method is not supported in React Native');
9951
+ }
9952
+ if (deviceId === this.state.selectedDevice) {
9953
+ return;
9954
+ }
9955
+ this.state.setDevice(deviceId);
9956
+ yield this.applySettingsToStream();
9957
+ });
9958
+ }
9959
+ applySettingsToStream() {
9960
+ return __awaiter(this, void 0, void 0, function* () {
9961
+ if (this.state.status === 'enabled') {
9962
+ yield this.stopStream();
9963
+ yield this.startStream();
9964
+ }
9965
+ });
9966
+ }
9967
+ stopStream() {
9968
+ return __awaiter(this, void 0, void 0, function* () {
9969
+ if (!this.state.mediaStream) {
9970
+ return;
9971
+ }
9972
+ if (this.call.state.callingState === CallingState.JOINED) {
9973
+ yield this.stopPublishStream();
9974
+ }
9975
+ else if (this.state.mediaStream) {
9976
+ disposeOfMediaStream(this.state.mediaStream);
9977
+ }
9978
+ this.state.setMediaStream(undefined);
9979
+ });
9980
+ }
9981
+ startStream() {
9982
+ return __awaiter(this, void 0, void 0, function* () {
9983
+ if (this.state.mediaStream) {
9984
+ return;
9985
+ }
9986
+ const constraints = { deviceId: this.state.selectedDevice };
9987
+ const stream = yield this.getStream(constraints);
9988
+ if (this.call.state.callingState === CallingState.JOINED) {
9989
+ yield this.publishStream(stream);
9990
+ }
9991
+ this.state.setMediaStream(stream);
9992
+ });
9993
+ }
9994
+ }
9995
+
9996
+ class CameraManager extends InputMediaDeviceManager {
9997
+ constructor(call) {
9998
+ super(call, new CameraManagerState());
9999
+ }
10000
+ /**
10001
+ * Select the camera direaction
10002
+ * @param direction
10003
+ */
10004
+ selectDirection(direction) {
10005
+ return __awaiter(this, void 0, void 0, function* () {
10006
+ this.state.setDirection(direction);
10007
+ // Providing both device id and direction doesn't work, so we deselect the device
10008
+ this.state.setDevice(undefined);
10009
+ yield this.applySettingsToStream();
10010
+ });
10011
+ }
10012
+ /**
10013
+ * Flips the camera direction: if it's front it will change to back, if it's back, it will change to front.
10014
+ *
10015
+ * Note: if there is no available camera with the desired direction, this method will do nothing.
10016
+ * @returns
10017
+ */
10018
+ flip() {
10019
+ return __awaiter(this, void 0, void 0, function* () {
10020
+ const newDirection = this.state.direction === 'front' ? 'back' : 'front';
10021
+ this.selectDirection(newDirection);
10022
+ });
10023
+ }
10024
+ getDevices() {
10025
+ return getVideoDevices();
10026
+ }
10027
+ getStream(constraints) {
10028
+ // We can't set both device id and facing mode
10029
+ // Device id has higher priority
10030
+ if (!constraints.deviceId && this.state.direction) {
10031
+ constraints.facingMode =
10032
+ this.state.direction === 'front' ? 'user' : 'environment';
10033
+ }
10034
+ return getVideoStream(constraints);
10035
+ }
10036
+ publishStream(stream) {
10037
+ return this.call.publishVideoStream(stream);
10038
+ }
10039
+ stopPublishStream() {
10040
+ return this.call.stopPublish(TrackType.VIDEO);
10041
+ }
10042
+ /**
10043
+ * Disables the video tracks of the camera
10044
+ */
10045
+ pause() {
10046
+ var _a;
10047
+ (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks().forEach((track) => {
10048
+ track.enabled = false;
10049
+ });
10050
+ }
10051
+ /**
10052
+ * (Re)enables the video tracks of the camera
10053
+ */
10054
+ resume() {
10055
+ var _a;
10056
+ (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks().forEach((track) => {
10057
+ track.enabled = true;
10058
+ });
10059
+ }
10060
+ }
10061
+
10062
+ class MicrophoneManagerState extends InputMediaDeviceManagerState {
10063
+ getDeviceIdFromStream(stream) {
10064
+ var _a;
10065
+ return (_a = stream.getAudioTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
10066
+ }
10067
+ }
10068
+
10069
+ class MicrophoneManager extends InputMediaDeviceManager {
10070
+ constructor(call) {
10071
+ super(call, new MicrophoneManagerState());
10072
+ }
10073
+ getDevices() {
10074
+ return getAudioDevices();
10075
+ }
10076
+ getStream(constraints) {
10077
+ return getAudioStream(constraints);
10078
+ }
10079
+ publishStream(stream) {
10080
+ return this.call.publishAudioStream(stream);
10081
+ }
10082
+ stopPublishStream() {
10083
+ return this.call.stopPublish(TrackType.AUDIO);
10084
+ }
10085
+ /**
10086
+ * Disables the audio tracks of the microphone
10087
+ */
10088
+ pause() {
10089
+ var _a;
10090
+ (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().forEach((track) => {
10091
+ track.enabled = false;
10092
+ });
10093
+ }
10094
+ /**
10095
+ * (Re)enables the audio tracks of the microphone
10096
+ */
10097
+ resume() {
10098
+ var _a;
10099
+ (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().forEach((track) => {
10100
+ track.enabled = true;
10101
+ });
10102
+ }
10103
+ }
10104
+
9520
10105
  /**
9521
10106
  * An object representation of a `Call`.
9522
10107
  */
@@ -9683,7 +10268,7 @@ class Call {
9683
10268
  * @returns a promise which resolves once the call join-flow has finished.
9684
10269
  */
9685
10270
  this.join = (data) => __awaiter(this, void 0, void 0, function* () {
9686
- var _e, _f, _g;
10271
+ var _e, _f, _g, _h;
9687
10272
  const callingState = this.state.callingState;
9688
10273
  if ([CallingState.JOINED, CallingState.JOINING].includes(callingState)) {
9689
10274
  this.logger('warn', 'Join method called twice, you should only call this once');
@@ -9952,6 +10537,11 @@ class Call {
9952
10537
  this.state.setServerSidePins(pins);
9953
10538
  this.reconnectAttempts = 0; // reset the reconnect attempts counter
9954
10539
  this.state.setCallingState(CallingState.JOINED);
10540
+ // React uses a different device management for now
10541
+ if (((_h = getSdkInfo()) === null || _h === void 0 ? void 0 : _h.type) !== SdkType.REACT) {
10542
+ this.initCamera();
10543
+ this.initMic();
10544
+ }
9955
10545
  // 3. once we have the "joinResponse", and possibly reconciled the local state
9956
10546
  // we schedule a fast subscription update for all remote participants
9957
10547
  // that were visible before we reconnected or migrated to a new SFU.
@@ -10074,9 +10664,9 @@ class Call {
10074
10664
  * @param trackType the track type to stop publishing.
10075
10665
  */
10076
10666
  this.stopPublish = (trackType) => __awaiter(this, void 0, void 0, function* () {
10077
- var _h;
10667
+ var _j;
10078
10668
  this.logger('info', `stopPublish ${TrackType[trackType]}`);
10079
- yield ((_h = this.publisher) === null || _h === void 0 ? void 0 : _h.unpublishStream(trackType));
10669
+ yield ((_j = this.publisher) === null || _j === void 0 ? void 0 : _j.unpublishStream(trackType));
10080
10670
  });
10081
10671
  /**
10082
10672
  * Update track subscription configuration for one or more participants.
@@ -10177,6 +10767,8 @@ class Call {
10177
10767
  *
10178
10768
  *
10179
10769
  * @param deviceId the selected device, pass `undefined` to clear the device selection
10770
+ *
10771
+ * @deprecated use call.microphone.select
10180
10772
  */
10181
10773
  this.setAudioDevice = (deviceId) => {
10182
10774
  if (!this.sfuClient)
@@ -10191,6 +10783,8 @@ class Call {
10191
10783
  * This method only stores the selection, if you want to start publishing a media stream call the [`publishVideoStream` method](#publishvideostream) that will set `videoDeviceId` as well.
10192
10784
  *
10193
10785
  * @param deviceId the selected device, pass `undefined` to clear the device selection
10786
+ *
10787
+ * @deprecated use call.camera.select
10194
10788
  */
10195
10789
  this.setVideoDevice = (deviceId) => {
10196
10790
  if (!this.sfuClient)
@@ -10223,8 +10817,8 @@ class Call {
10223
10817
  * @returns
10224
10818
  */
10225
10819
  this.updatePublishQuality = (enabledRids) => __awaiter(this, void 0, void 0, function* () {
10226
- var _j;
10227
- return (_j = this.publisher) === null || _j === void 0 ? void 0 : _j.updateVideoPublishQuality(enabledRids);
10820
+ var _k;
10821
+ return (_k = this.publisher) === null || _k === void 0 ? void 0 : _k.updateVideoPublishQuality(enabledRids);
10228
10822
  });
10229
10823
  this.assertCallJoined = () => {
10230
10824
  return new Promise((resolve) => {
@@ -10567,6 +11161,8 @@ class Call {
10567
11161
  this.leaveCallHooks.push(registerEventHandlers(this, this.state, this.dispatcher));
10568
11162
  this.registerEffects();
10569
11163
  this.leaveCallHooks.push(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); }));
11164
+ this.camera = new CameraManager(this);
11165
+ this.microphone = new MicrophoneManager(this);
10570
11166
  }
10571
11167
  registerEffects() {
10572
11168
  this.leaveCallHooks.push(
@@ -10674,6 +11270,64 @@ class Call {
10674
11270
  var _a;
10675
11271
  return ((_a = this.state.createdBy) === null || _a === void 0 ? void 0 : _a.id) === this.currentUserId;
10676
11272
  }
11273
+ initCamera() {
11274
+ var _a, _b, _c;
11275
+ if (((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.videoStream) ||
11276
+ !this.permissionsContext.hasPermission('send-video')) {
11277
+ return;
11278
+ }
11279
+ // Set camera direction if it's not yet set
11280
+ // This will also start publishing if camera is enabled
11281
+ if (!this.camera.state.direction && !this.camera.state.selectedDevice) {
11282
+ let defaultDirection = 'front';
11283
+ const backendSetting = (_b = this.state.settings) === null || _b === void 0 ? void 0 : _b.video.camera_facing;
11284
+ if (backendSetting) {
11285
+ defaultDirection = backendSetting === 'front' ? 'front' : 'back';
11286
+ }
11287
+ this.camera.selectDirection(defaultDirection);
11288
+ }
11289
+ else if (this.camera.state.status === 'enabled') {
11290
+ // Publish already started media streams (this is the case if there is a lobby screen before join)
11291
+ // Wait for media stream
11292
+ this.camera.state.mediaStream$
11293
+ .pipe(takeWhile((s) => s === undefined, true))
11294
+ .subscribe((stream) => {
11295
+ var _a;
11296
+ if (!((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.videoStream)) {
11297
+ this.publishVideoStream(stream);
11298
+ }
11299
+ });
11300
+ }
11301
+ // Apply backend config (this is the case if there is no lobby screen before join)
11302
+ if (this.camera.state.status === undefined &&
11303
+ ((_c = this.state.settings) === null || _c === void 0 ? void 0 : _c.video.camera_default_on)) {
11304
+ void this.camera.enable();
11305
+ }
11306
+ }
11307
+ initMic() {
11308
+ var _a, _b;
11309
+ if (((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.audioStream) ||
11310
+ !this.permissionsContext.hasPermission('send-audio')) {
11311
+ return;
11312
+ }
11313
+ // Publish already started media streams (this is the case if there is a lobby screen before join)
11314
+ if (this.microphone.state.status === 'enabled') {
11315
+ // Wait for media stream
11316
+ this.microphone.state.mediaStream$
11317
+ .pipe(takeWhile((s) => s === undefined, true))
11318
+ .subscribe((stream) => {
11319
+ var _a;
11320
+ if (!((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.audioStream)) {
11321
+ this.publishAudioStream(stream);
11322
+ }
11323
+ });
11324
+ }
11325
+ // Apply backend config (this is the case if there is no lobby screen before join)
11326
+ if (this.microphone.state.status === undefined &&
11327
+ ((_b = this.state.settings) === null || _b === void 0 ? void 0 : _b.audio.mic_default_on)) {
11328
+ void this.microphone.enable();
11329
+ }
11330
+ }
10677
11331
  }
10678
11332
 
10679
11333
  class InsightMetrics {
@@ -11785,7 +12439,7 @@ class WSConnectionFallback {
11785
12439
  }
11786
12440
  }
11787
12441
 
11788
- const version = '0.3.0';
12442
+ const version = '0.3.1';
11789
12443
 
11790
12444
  const logger = getLogger(['location']);
11791
12445
  const HINT_URL = `https://hint.stream-io-video.com/`;
@@ -12759,254 +13413,6 @@ class StreamVideoServerClient extends StreamVideoClient {
12759
13413
  }
12760
13414
  }
12761
13415
 
12762
- const getDevices = (constraints) => {
12763
- return new Observable((subscriber) => {
12764
- navigator.mediaDevices
12765
- .getUserMedia(constraints)
12766
- .then((media) => {
12767
- // in Firefox, devices can be enumerated after userMedia is requested
12768
- // and permissions granted. Otherwise, device labels are empty
12769
- navigator.mediaDevices.enumerateDevices().then((devices) => {
12770
- subscriber.next(devices);
12771
- // If we stop the tracks before enumerateDevices -> the labels won't show up in Firefox
12772
- disposeOfMediaStream(media);
12773
- subscriber.complete();
12774
- });
12775
- })
12776
- .catch((error) => {
12777
- getLogger(['devices'])('error', 'Failed to get devices', error);
12778
- subscriber.error(error);
12779
- });
12780
- });
12781
- };
12782
- /**
12783
- * [Tells if the browser supports audio output change on 'audio' elements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId).
12784
- *
12785
- * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
12786
- */
12787
- const checkIfAudioOutputChangeSupported = () => {
12788
- if (typeof document === 'undefined')
12789
- return false;
12790
- const element = document.createElement('audio');
12791
- return element.sinkId !== undefined;
12792
- };
12793
- /**
12794
- * The default constraints used to request audio devices.
12795
- */
12796
- const audioDeviceConstraints = {
12797
- audio: {
12798
- autoGainControl: true,
12799
- noiseSuppression: true,
12800
- echoCancellation: true,
12801
- },
12802
- };
12803
- /**
12804
- * The default constraints used to request video devices.
12805
- */
12806
- const videoDeviceConstraints = {
12807
- video: {
12808
- width: 1280,
12809
- height: 720,
12810
- },
12811
- };
12812
- // Audio and video devices are requested in two separate requests: that way users will be presented with two separate prompts -> they can give access to just camera, or just microphone
12813
- const deviceChange$ = new Observable((subscriber) => {
12814
- var _a, _b;
12815
- const deviceChangeHandler = () => subscriber.next();
12816
- (_b = (_a = navigator.mediaDevices).addEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
12817
- return () => {
12818
- var _a, _b;
12819
- return (_b = (_a = navigator.mediaDevices).removeEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
12820
- };
12821
- }).pipe(debounceTime(500), concatMap(() => from(navigator.mediaDevices.enumerateDevices())), shareReplay(1));
12822
- const audioDevices$ = merge(getDevices(audioDeviceConstraints), deviceChange$).pipe(shareReplay(1));
12823
- const videoDevices$ = merge(getDevices(videoDeviceConstraints), deviceChange$).pipe(shareReplay(1));
12824
- /**
12825
- * 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.
12826
- *
12827
- * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
12828
- * @returns
12829
- */
12830
- const getAudioDevices = () => audioDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'audioinput')));
12831
- /**
12832
- * Prompts the user for a permission to use video devices (if not already granted) and lists the available 'videoinput' devices, if devices are added/removed the list is updated.
12833
- *
12834
- * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
12835
- * @returns
12836
- */
12837
- const getVideoDevices = () => videoDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'videoinput' && d.deviceId.length)));
12838
- /**
12839
- * 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)
12840
- *
12841
- * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
12842
- * @returns
12843
- */
12844
- const getAudioOutputDevices = () => {
12845
- return audioDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'audiooutput')));
12846
- };
12847
- const getStream = (constraints) => __awaiter(void 0, void 0, void 0, function* () {
12848
- try {
12849
- return yield navigator.mediaDevices.getUserMedia(constraints);
12850
- }
12851
- catch (e) {
12852
- getLogger(['devices'])('error', `Failed get user media`, {
12853
- error: e,
12854
- constraints: constraints,
12855
- });
12856
- throw e;
12857
- }
12858
- });
12859
- /**
12860
- * Returns an audio media stream that fulfills the given constraints.
12861
- * If no constraints are provided, it uses the browser's default ones.
12862
- *
12863
- * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
12864
- * @param trackConstraints the constraints to use when requesting the stream.
12865
- * @returns the new `MediaStream` fulfilling the given constraints.
12866
- */
12867
- const getAudioStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
12868
- const constraints = {
12869
- audio: Object.assign(Object.assign({}, audioDeviceConstraints.audio), trackConstraints),
12870
- };
12871
- return getStream(constraints);
12872
- });
12873
- /**
12874
- * Returns a video media stream that fulfills the given constraints.
12875
- * If no constraints are provided, it uses the browser's default ones.
12876
- *
12877
- * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
12878
- * @param trackConstraints the constraints to use when requesting the stream.
12879
- * @returns a new `MediaStream` fulfilling the given constraints.
12880
- */
12881
- const getVideoStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
12882
- const constraints = {
12883
- video: Object.assign(Object.assign({}, videoDeviceConstraints.video), trackConstraints),
12884
- };
12885
- return getStream(constraints);
12886
- });
12887
- /**
12888
- * Prompts the user for a permission to share a screen.
12889
- * If the user grants the permission, a screen sharing stream is returned. Throws otherwise.
12890
- *
12891
- * The callers of this API are responsible to handle the possible errors.
12892
- *
12893
- * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
12894
- *
12895
- * @param options any additional options to pass to the [`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) API.
12896
- */
12897
- const getScreenShareStream = (options) => __awaiter(void 0, void 0, void 0, function* () {
12898
- try {
12899
- return yield navigator.mediaDevices.getDisplayMedia(Object.assign({ video: true, audio: false }, options));
12900
- }
12901
- catch (e) {
12902
- getLogger(['devices'])('error', 'Failed to get screen share stream', e);
12903
- throw e;
12904
- }
12905
- });
12906
- const watchForDisconnectedDevice = (kind, deviceId$) => {
12907
- let devices$;
12908
- switch (kind) {
12909
- case 'audioinput':
12910
- devices$ = getAudioDevices();
12911
- break;
12912
- case 'videoinput':
12913
- devices$ = getVideoDevices();
12914
- break;
12915
- case 'audiooutput':
12916
- devices$ = getAudioOutputDevices();
12917
- break;
12918
- }
12919
- return combineLatest([devices$, deviceId$]).pipe(filter(([devices, deviceId]) => !!deviceId && !devices.find((d) => d.deviceId === deviceId)), map$2(() => true));
12920
- };
12921
- /**
12922
- * Notifies the subscriber if a given 'audioinput' device is disconnected
12923
- *
12924
- * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
12925
- * @param deviceId$ an Observable that specifies which device to watch for
12926
- * @returns
12927
- */
12928
- const watchForDisconnectedAudioDevice = (deviceId$) => {
12929
- return watchForDisconnectedDevice('audioinput', deviceId$);
12930
- };
12931
- /**
12932
- * Notifies the subscriber if a given 'videoinput' device is disconnected
12933
- *
12934
- * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
12935
- * @param deviceId$ an Observable that specifies which device to watch for
12936
- * @returns
12937
- */
12938
- const watchForDisconnectedVideoDevice = (deviceId$) => {
12939
- return watchForDisconnectedDevice('videoinput', deviceId$);
12940
- };
12941
- /**
12942
- * Notifies the subscriber if a given 'audiooutput' device is disconnected
12943
- *
12944
- * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
12945
- * @param deviceId$ an Observable that specifies which device to watch for
12946
- * @returns
12947
- */
12948
- const watchForDisconnectedAudioOutputDevice = (deviceId$) => {
12949
- return watchForDisconnectedDevice('audiooutput', deviceId$);
12950
- };
12951
- const watchForAddedDefaultDevice = (kind) => {
12952
- let devices$;
12953
- switch (kind) {
12954
- case 'audioinput':
12955
- devices$ = getAudioDevices();
12956
- break;
12957
- case 'videoinput':
12958
- devices$ = getVideoDevices();
12959
- break;
12960
- case 'audiooutput':
12961
- devices$ = getAudioOutputDevices();
12962
- break;
12963
- default:
12964
- throw new Error('Unknown MediaDeviceKind', kind);
12965
- }
12966
- return devices$.pipe(pairwise(), filter(([prev, current]) => {
12967
- const prevDefault = prev.find((device) => device.deviceId === 'default');
12968
- const currentDefault = current.find((device) => device.deviceId === 'default');
12969
- return !!(current.length > prev.length &&
12970
- prevDefault &&
12971
- currentDefault &&
12972
- prevDefault.groupId !== currentDefault.groupId);
12973
- }), map$2(() => true));
12974
- };
12975
- /**
12976
- * Notifies the subscriber about newly added default audio input device.
12977
- * @returns Observable<boolean>
12978
- */
12979
- const watchForAddedDefaultAudioDevice = () => watchForAddedDefaultDevice('audioinput');
12980
- /**
12981
- * Notifies the subscriber about newly added default audio output device.
12982
- * @returns Observable<boolean>
12983
- */
12984
- const watchForAddedDefaultAudioOutputDevice = () => watchForAddedDefaultDevice('audiooutput');
12985
- /**
12986
- * Notifies the subscriber about newly added default video input device.
12987
- * @returns Observable<boolean>
12988
- */
12989
- const watchForAddedDefaultVideoDevice = () => watchForAddedDefaultDevice('videoinput');
12990
- /**
12991
- * Deactivates MediaStream (stops and removes tracks) to be later garbage collected
12992
- *
12993
- * @param stream MediaStream
12994
- * @returns void
12995
- */
12996
- const disposeOfMediaStream = (stream) => {
12997
- if (!stream.active)
12998
- return;
12999
- stream.getTracks().forEach((track) => {
13000
- track.stop();
13001
- stream.removeTrack(track);
13002
- });
13003
- // @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the stream
13004
- if (typeof stream.release === 'function') {
13005
- // @ts-expect-error
13006
- stream.release();
13007
- }
13008
- };
13009
-
13010
13416
  const DETECTION_FREQUENCY_IN_MS = 500;
13011
13417
  const AUDIO_LEVEL_THRESHOLD = 150;
13012
13418
  const FFT_SIZE = 128;
@@ -13087,5 +13493,5 @@ var browsers = /*#__PURE__*/Object.freeze({
13087
13493
  isSafari: isSafari
13088
13494
  });
13089
13495
 
13090
- export { AudioSettingsDefaultDeviceEnum, AudioSettingsRequestDefaultDeviceEnum, browsers as Browsers, Call, CallState, CallType, CallTypes, CallingState, CreateDeviceRequestPushProviderEnum, DebounceType, ErrorFromResponse, OwnCapability, RecordSettingsModeEnum, RecordSettingsQualityEnum, RecordSettingsRequestModeEnum, RecordSettingsRequestQualityEnum, rxUtils as RxUtils, events as SfuEvents, models as SfuModels, StreamSfuClient, StreamVideoClient, StreamVideoReadOnlyStateStore, StreamVideoServerClient, StreamVideoWriteableStateStore, TranscriptionSettingsModeEnum, TranscriptionSettingsRequestModeEnum, VideoSettingsCameraFacingEnum, VideoSettingsRequestCameraFacingEnum, ViewportTracker, VisibilityState, checkIfAudioOutputChangeSupported, combineComparators, conditional, createSoundDetector, defaultSortPreset, descending, disposeOfMediaStream, dominantSpeaker, getAudioDevices, getAudioOutputDevices, getAudioStream, getClientDetails, getDeviceInfo, getLogger, getOSInfo, getScreenShareStream, getSdkInfo, getVideoDevices, getVideoStream, isStreamVideoLocalParticipant, livestreamOrAudioRoomSortPreset, logLevels, logToConsole, name, noopComparator, pinned, publishingAudio, publishingVideo, reactionType, role, screenSharing, setDeviceInfo, setLogLevel, setLogger, setOSInfo, setSdkInfo, speakerLayoutSortPreset, speaking, watchForAddedDefaultAudioDevice, watchForAddedDefaultAudioOutputDevice, watchForAddedDefaultVideoDevice, watchForDisconnectedAudioDevice, watchForDisconnectedAudioOutputDevice, watchForDisconnectedVideoDevice };
13496
+ export { AudioSettingsDefaultDeviceEnum, AudioSettingsRequestDefaultDeviceEnum, browsers as Browsers, Call, CallState, CallType, CallTypes, CallingState, CameraManager, CreateDeviceRequestPushProviderEnum, DebounceType, ErrorFromResponse, InputMediaDeviceManager, InputMediaDeviceManagerState, MicrophoneManager, OwnCapability, RecordSettingsModeEnum, RecordSettingsQualityEnum, RecordSettingsRequestModeEnum, RecordSettingsRequestQualityEnum, rxUtils as RxUtils, events as SfuEvents, models as SfuModels, StreamSfuClient, StreamVideoClient, StreamVideoReadOnlyStateStore, StreamVideoServerClient, StreamVideoWriteableStateStore, TranscriptionSettingsModeEnum, TranscriptionSettingsRequestModeEnum, VideoSettingsCameraFacingEnum, VideoSettingsRequestCameraFacingEnum, ViewportTracker, VisibilityState, checkIfAudioOutputChangeSupported, combineComparators, conditional, createSoundDetector, defaultSortPreset, descending, disposeOfMediaStream, dominantSpeaker, getAudioDevices, getAudioOutputDevices, getAudioStream, getClientDetails, getDeviceInfo, getLogger, getOSInfo, getScreenShareStream, getSdkInfo, getVideoDevices, getVideoStream, isStreamVideoLocalParticipant, livestreamOrAudioRoomSortPreset, logLevels, logToConsole, name, noopComparator, pinned, publishingAudio, publishingVideo, reactionType, role, screenSharing, setDeviceInfo, setLogLevel, setLogger, setOSInfo, setSdkInfo, speakerLayoutSortPreset, speaking, watchForAddedDefaultAudioDevice, watchForAddedDefaultAudioOutputDevice, watchForAddedDefaultVideoDevice, watchForDisconnectedAudioDevice, watchForDisconnectedAudioOutputDevice, watchForDisconnectedVideoDevice };
13091
13497
  //# sourceMappingURL=index.es.js.map