@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.cjs.js CHANGED
@@ -9537,6 +9537,591 @@ const getClientDetails = () => {
9537
9537
  };
9538
9538
  };
9539
9539
 
9540
+ class InputMediaDeviceManagerState {
9541
+ constructor() {
9542
+ this.statusSubject = new rxjs.BehaviorSubject(undefined);
9543
+ this.mediaStreamSubject = new rxjs.BehaviorSubject(undefined);
9544
+ this.selectedDeviceSubject = new rxjs.BehaviorSubject(undefined);
9545
+ /**
9546
+ * Gets the current value of an observable, or undefined if the observable has
9547
+ * not emitted a value yet.
9548
+ *
9549
+ * @param observable$ the observable to get the value from.
9550
+ */
9551
+ this.getCurrentValue = getCurrentValue;
9552
+ /**
9553
+ * Updates the value of the provided Subject.
9554
+ * An `update` can either be a new value or a function which takes
9555
+ * the current value and returns a new value.
9556
+ *
9557
+ * @internal
9558
+ *
9559
+ * @param subject the subject to update.
9560
+ * @param update the update to apply to the subject.
9561
+ * @return the updated value.
9562
+ */
9563
+ this.setCurrentValue = setCurrentValue;
9564
+ this.mediaStream$ = this.mediaStreamSubject.asObservable();
9565
+ this.selectedDevice$ = this.selectedDeviceSubject
9566
+ .asObservable()
9567
+ .pipe(rxjs.distinctUntilChanged());
9568
+ this.status$ = this.statusSubject.asObservable();
9569
+ }
9570
+ /**
9571
+ * The device status
9572
+ */
9573
+ get status() {
9574
+ return this.getCurrentValue(this.status$);
9575
+ }
9576
+ /**
9577
+ * The currently selected device
9578
+ */
9579
+ get selectedDevice() {
9580
+ return this.getCurrentValue(this.selectedDevice$);
9581
+ }
9582
+ /**
9583
+ * The current media stream, or `undefined` if the device is currently disabled.
9584
+ */
9585
+ get mediaStream() {
9586
+ return this.getCurrentValue(this.mediaStream$);
9587
+ }
9588
+ /**
9589
+ * @internal
9590
+ * @param status
9591
+ */
9592
+ setStatus(status) {
9593
+ this.setCurrentValue(this.statusSubject, status);
9594
+ }
9595
+ /**
9596
+ * @internal
9597
+ * @param stream
9598
+ */
9599
+ setMediaStream(stream) {
9600
+ this.setCurrentValue(this.mediaStreamSubject, stream);
9601
+ if (stream) {
9602
+ this.setDevice(this.getDeviceIdFromStream(stream));
9603
+ }
9604
+ }
9605
+ /**
9606
+ * @internal
9607
+ * @param stream
9608
+ */
9609
+ setDevice(deviceId) {
9610
+ this.setCurrentValue(this.selectedDeviceSubject, deviceId);
9611
+ }
9612
+ }
9613
+
9614
+ class CameraManagerState extends InputMediaDeviceManagerState {
9615
+ constructor() {
9616
+ super();
9617
+ this.directionSubject = new rxjs.BehaviorSubject(undefined);
9618
+ this.direction$ = this.directionSubject
9619
+ .asObservable()
9620
+ .pipe(rxjs.distinctUntilChanged());
9621
+ }
9622
+ /**
9623
+ * The preferred camera direction
9624
+ * front - means the camera facing the user
9625
+ * back - means the camera facing the environment
9626
+ */
9627
+ get direction() {
9628
+ return this.getCurrentValue(this.direction$);
9629
+ }
9630
+ /**
9631
+ * @internal
9632
+ */
9633
+ setDirection(direction) {
9634
+ this.setCurrentValue(this.directionSubject, direction);
9635
+ }
9636
+ /**
9637
+ * @internal
9638
+ */
9639
+ setMediaStream(stream) {
9640
+ var _a;
9641
+ super.setMediaStream(stream);
9642
+ if (stream) {
9643
+ // RN getSettings() doesn't return facingMode, so we don't verify camera direction
9644
+ const direction = isReactNative()
9645
+ ? this.direction
9646
+ : ((_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().facingMode) === 'environment'
9647
+ ? 'back'
9648
+ : 'front';
9649
+ this.setDirection(direction);
9650
+ }
9651
+ }
9652
+ getDeviceIdFromStream(stream) {
9653
+ var _a;
9654
+ return (_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
9655
+ }
9656
+ }
9657
+
9658
+ const getDevices = (constraints) => {
9659
+ return new rxjs.Observable((subscriber) => {
9660
+ navigator.mediaDevices
9661
+ .getUserMedia(constraints)
9662
+ .then((media) => {
9663
+ // in Firefox, devices can be enumerated after userMedia is requested
9664
+ // and permissions granted. Otherwise, device labels are empty
9665
+ navigator.mediaDevices.enumerateDevices().then((devices) => {
9666
+ subscriber.next(devices);
9667
+ // If we stop the tracks before enumerateDevices -> the labels won't show up in Firefox
9668
+ disposeOfMediaStream(media);
9669
+ subscriber.complete();
9670
+ });
9671
+ })
9672
+ .catch((error) => {
9673
+ getLogger(['devices'])('error', 'Failed to get devices', error);
9674
+ subscriber.error(error);
9675
+ });
9676
+ });
9677
+ };
9678
+ /**
9679
+ * [Tells if the browser supports audio output change on 'audio' elements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId).
9680
+ *
9681
+ * @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.
9682
+ */
9683
+ const checkIfAudioOutputChangeSupported = () => {
9684
+ if (typeof document === 'undefined')
9685
+ return false;
9686
+ const element = document.createElement('audio');
9687
+ return element.sinkId !== undefined;
9688
+ };
9689
+ /**
9690
+ * The default constraints used to request audio devices.
9691
+ */
9692
+ const audioDeviceConstraints = {
9693
+ audio: {
9694
+ autoGainControl: true,
9695
+ noiseSuppression: true,
9696
+ echoCancellation: true,
9697
+ },
9698
+ };
9699
+ /**
9700
+ * The default constraints used to request video devices.
9701
+ */
9702
+ const videoDeviceConstraints = {
9703
+ video: {
9704
+ width: 1280,
9705
+ height: 720,
9706
+ },
9707
+ };
9708
+ // 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
9709
+ const deviceChange$ = new rxjs.Observable((subscriber) => {
9710
+ var _a, _b;
9711
+ const deviceChangeHandler = () => subscriber.next();
9712
+ (_b = (_a = navigator.mediaDevices).addEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
9713
+ return () => {
9714
+ var _a, _b;
9715
+ return (_b = (_a = navigator.mediaDevices).removeEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
9716
+ };
9717
+ }).pipe(rxjs.debounceTime(500), rxjs.concatMap(() => rxjs.from(navigator.mediaDevices.enumerateDevices())), rxjs.shareReplay(1));
9718
+ const audioDevices$ = rxjs.merge(getDevices(audioDeviceConstraints), deviceChange$).pipe(rxjs.shareReplay(1));
9719
+ const videoDevices$ = rxjs.merge(getDevices(videoDeviceConstraints), deviceChange$).pipe(rxjs.shareReplay(1));
9720
+ /**
9721
+ * 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.
9722
+ *
9723
+ * @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.
9724
+ * @returns
9725
+ */
9726
+ const getAudioDevices = () => audioDevices$.pipe(rxjs.map((values) => values.filter((d) => d.kind === 'audioinput')));
9727
+ /**
9728
+ * 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.
9729
+ *
9730
+ * @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.
9731
+ * @returns
9732
+ */
9733
+ const getVideoDevices = () => videoDevices$.pipe(rxjs.map((values) => values.filter((d) => d.kind === 'videoinput' && d.deviceId.length)));
9734
+ /**
9735
+ * 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)
9736
+ *
9737
+ * @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.
9738
+ * @returns
9739
+ */
9740
+ const getAudioOutputDevices = () => {
9741
+ return audioDevices$.pipe(rxjs.map((values) => values.filter((d) => d.kind === 'audiooutput')));
9742
+ };
9743
+ const getStream = (constraints) => __awaiter(void 0, void 0, void 0, function* () {
9744
+ try {
9745
+ return yield navigator.mediaDevices.getUserMedia(constraints);
9746
+ }
9747
+ catch (e) {
9748
+ getLogger(['devices'])('error', `Failed get user media`, {
9749
+ error: e,
9750
+ constraints: constraints,
9751
+ });
9752
+ throw e;
9753
+ }
9754
+ });
9755
+ /**
9756
+ * Returns an audio media stream that fulfills the given constraints.
9757
+ * If no constraints are provided, it uses the browser's default ones.
9758
+ *
9759
+ * @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.
9760
+ * @param trackConstraints the constraints to use when requesting the stream.
9761
+ * @returns the new `MediaStream` fulfilling the given constraints.
9762
+ */
9763
+ const getAudioStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
9764
+ const constraints = {
9765
+ audio: Object.assign(Object.assign({}, audioDeviceConstraints.audio), trackConstraints),
9766
+ };
9767
+ return getStream(constraints);
9768
+ });
9769
+ /**
9770
+ * Returns a video media stream that fulfills the given constraints.
9771
+ * If no constraints are provided, it uses the browser's default ones.
9772
+ *
9773
+ * @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.
9774
+ * @param trackConstraints the constraints to use when requesting the stream.
9775
+ * @returns a new `MediaStream` fulfilling the given constraints.
9776
+ */
9777
+ const getVideoStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
9778
+ const constraints = {
9779
+ video: Object.assign(Object.assign({}, videoDeviceConstraints.video), trackConstraints),
9780
+ };
9781
+ return getStream(constraints);
9782
+ });
9783
+ /**
9784
+ * Prompts the user for a permission to share a screen.
9785
+ * If the user grants the permission, a screen sharing stream is returned. Throws otherwise.
9786
+ *
9787
+ * The callers of this API are responsible to handle the possible errors.
9788
+ *
9789
+ * @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.
9790
+ *
9791
+ * @param options any additional options to pass to the [`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) API.
9792
+ */
9793
+ const getScreenShareStream = (options) => __awaiter(void 0, void 0, void 0, function* () {
9794
+ try {
9795
+ return yield navigator.mediaDevices.getDisplayMedia(Object.assign({ video: true, audio: false }, options));
9796
+ }
9797
+ catch (e) {
9798
+ getLogger(['devices'])('error', 'Failed to get screen share stream', e);
9799
+ throw e;
9800
+ }
9801
+ });
9802
+ const watchForDisconnectedDevice = (kind, deviceId$) => {
9803
+ let devices$;
9804
+ switch (kind) {
9805
+ case 'audioinput':
9806
+ devices$ = getAudioDevices();
9807
+ break;
9808
+ case 'videoinput':
9809
+ devices$ = getVideoDevices();
9810
+ break;
9811
+ case 'audiooutput':
9812
+ devices$ = getAudioOutputDevices();
9813
+ break;
9814
+ }
9815
+ return rxjs.combineLatest([devices$, deviceId$]).pipe(rxjs.filter(([devices, deviceId]) => !!deviceId && !devices.find((d) => d.deviceId === deviceId)), rxjs.map(() => true));
9816
+ };
9817
+ /**
9818
+ * Notifies the subscriber if a given 'audioinput' 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 watchForDisconnectedAudioDevice = (deviceId$) => {
9825
+ return watchForDisconnectedDevice('audioinput', deviceId$);
9826
+ };
9827
+ /**
9828
+ * Notifies the subscriber if a given 'videoinput' device is disconnected
9829
+ *
9830
+ * @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.
9831
+ * @param deviceId$ an Observable that specifies which device to watch for
9832
+ * @returns
9833
+ */
9834
+ const watchForDisconnectedVideoDevice = (deviceId$) => {
9835
+ return watchForDisconnectedDevice('videoinput', deviceId$);
9836
+ };
9837
+ /**
9838
+ * Notifies the subscriber if a given 'audiooutput' device is disconnected
9839
+ *
9840
+ * @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.
9841
+ * @param deviceId$ an Observable that specifies which device to watch for
9842
+ * @returns
9843
+ */
9844
+ const watchForDisconnectedAudioOutputDevice = (deviceId$) => {
9845
+ return watchForDisconnectedDevice('audiooutput', deviceId$);
9846
+ };
9847
+ const watchForAddedDefaultDevice = (kind) => {
9848
+ let devices$;
9849
+ switch (kind) {
9850
+ case 'audioinput':
9851
+ devices$ = getAudioDevices();
9852
+ break;
9853
+ case 'videoinput':
9854
+ devices$ = getVideoDevices();
9855
+ break;
9856
+ case 'audiooutput':
9857
+ devices$ = getAudioOutputDevices();
9858
+ break;
9859
+ default:
9860
+ throw new Error('Unknown MediaDeviceKind', kind);
9861
+ }
9862
+ return devices$.pipe(rxjs.pairwise(), rxjs.filter(([prev, current]) => {
9863
+ const prevDefault = prev.find((device) => device.deviceId === 'default');
9864
+ const currentDefault = current.find((device) => device.deviceId === 'default');
9865
+ return !!(current.length > prev.length &&
9866
+ prevDefault &&
9867
+ currentDefault &&
9868
+ prevDefault.groupId !== currentDefault.groupId);
9869
+ }), rxjs.map(() => true));
9870
+ };
9871
+ /**
9872
+ * Notifies the subscriber about newly added default audio input device.
9873
+ * @returns Observable<boolean>
9874
+ */
9875
+ const watchForAddedDefaultAudioDevice = () => watchForAddedDefaultDevice('audioinput');
9876
+ /**
9877
+ * Notifies the subscriber about newly added default audio output device.
9878
+ * @returns Observable<boolean>
9879
+ */
9880
+ const watchForAddedDefaultAudioOutputDevice = () => watchForAddedDefaultDevice('audiooutput');
9881
+ /**
9882
+ * Notifies the subscriber about newly added default video input device.
9883
+ * @returns Observable<boolean>
9884
+ */
9885
+ const watchForAddedDefaultVideoDevice = () => watchForAddedDefaultDevice('videoinput');
9886
+ /**
9887
+ * Deactivates MediaStream (stops and removes tracks) to be later garbage collected
9888
+ *
9889
+ * @param stream MediaStream
9890
+ * @returns void
9891
+ */
9892
+ const disposeOfMediaStream = (stream) => {
9893
+ if (!stream.active)
9894
+ return;
9895
+ stream.getTracks().forEach((track) => {
9896
+ track.stop();
9897
+ stream.removeTrack(track);
9898
+ });
9899
+ // @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the stream
9900
+ if (typeof stream.release === 'function') {
9901
+ // @ts-expect-error
9902
+ stream.release();
9903
+ }
9904
+ };
9905
+
9906
+ class InputMediaDeviceManager {
9907
+ constructor(call, state) {
9908
+ this.call = call;
9909
+ this.state = state;
9910
+ }
9911
+ /**
9912
+ * Lists the available audio/video devices
9913
+ *
9914
+ * Note: It prompts the user for a permission to use devices (if not already granted)
9915
+ *
9916
+ * @returns an Observable that will be updated if a device is connected or disconnected
9917
+ */
9918
+ listDevices() {
9919
+ return this.getDevices();
9920
+ }
9921
+ /**
9922
+ * Starts camera/microphone
9923
+ */
9924
+ enable() {
9925
+ return __awaiter(this, void 0, void 0, function* () {
9926
+ if (this.state.status === 'enabled') {
9927
+ return;
9928
+ }
9929
+ yield this.startStream();
9930
+ this.state.setStatus('enabled');
9931
+ });
9932
+ }
9933
+ /**
9934
+ * Stops camera/microphone
9935
+ * @returns
9936
+ */
9937
+ disable() {
9938
+ return __awaiter(this, void 0, void 0, function* () {
9939
+ if (this.state.status === 'disabled') {
9940
+ return;
9941
+ }
9942
+ yield this.stopStream();
9943
+ this.state.setStatus('disabled');
9944
+ });
9945
+ }
9946
+ /**
9947
+ * If current device statis is disabled, it will enable the device, else it will disable it.
9948
+ * @returns
9949
+ */
9950
+ toggle() {
9951
+ return __awaiter(this, void 0, void 0, function* () {
9952
+ if (this.state.status === 'enabled') {
9953
+ return this.disable();
9954
+ }
9955
+ else {
9956
+ return this.enable();
9957
+ }
9958
+ });
9959
+ }
9960
+ /**
9961
+ * Select device
9962
+ *
9963
+ * Note: this method is not supported in React Native
9964
+ *
9965
+ * @param deviceId
9966
+ */
9967
+ select(deviceId) {
9968
+ return __awaiter(this, void 0, void 0, function* () {
9969
+ if (isReactNative()) {
9970
+ throw new Error('This method is not supported in React Native');
9971
+ }
9972
+ if (deviceId === this.state.selectedDevice) {
9973
+ return;
9974
+ }
9975
+ this.state.setDevice(deviceId);
9976
+ yield this.applySettingsToStream();
9977
+ });
9978
+ }
9979
+ applySettingsToStream() {
9980
+ return __awaiter(this, void 0, void 0, function* () {
9981
+ if (this.state.status === 'enabled') {
9982
+ yield this.stopStream();
9983
+ yield this.startStream();
9984
+ }
9985
+ });
9986
+ }
9987
+ stopStream() {
9988
+ return __awaiter(this, void 0, void 0, function* () {
9989
+ if (!this.state.mediaStream) {
9990
+ return;
9991
+ }
9992
+ if (this.call.state.callingState === exports.CallingState.JOINED) {
9993
+ yield this.stopPublishStream();
9994
+ }
9995
+ else if (this.state.mediaStream) {
9996
+ disposeOfMediaStream(this.state.mediaStream);
9997
+ }
9998
+ this.state.setMediaStream(undefined);
9999
+ });
10000
+ }
10001
+ startStream() {
10002
+ return __awaiter(this, void 0, void 0, function* () {
10003
+ if (this.state.mediaStream) {
10004
+ return;
10005
+ }
10006
+ const constraints = { deviceId: this.state.selectedDevice };
10007
+ const stream = yield this.getStream(constraints);
10008
+ if (this.call.state.callingState === exports.CallingState.JOINED) {
10009
+ yield this.publishStream(stream);
10010
+ }
10011
+ this.state.setMediaStream(stream);
10012
+ });
10013
+ }
10014
+ }
10015
+
10016
+ class CameraManager extends InputMediaDeviceManager {
10017
+ constructor(call) {
10018
+ super(call, new CameraManagerState());
10019
+ }
10020
+ /**
10021
+ * Select the camera direaction
10022
+ * @param direction
10023
+ */
10024
+ selectDirection(direction) {
10025
+ return __awaiter(this, void 0, void 0, function* () {
10026
+ this.state.setDirection(direction);
10027
+ // Providing both device id and direction doesn't work, so we deselect the device
10028
+ this.state.setDevice(undefined);
10029
+ yield this.applySettingsToStream();
10030
+ });
10031
+ }
10032
+ /**
10033
+ * Flips the camera direction: if it's front it will change to back, if it's back, it will change to front.
10034
+ *
10035
+ * Note: if there is no available camera with the desired direction, this method will do nothing.
10036
+ * @returns
10037
+ */
10038
+ flip() {
10039
+ return __awaiter(this, void 0, void 0, function* () {
10040
+ const newDirection = this.state.direction === 'front' ? 'back' : 'front';
10041
+ this.selectDirection(newDirection);
10042
+ });
10043
+ }
10044
+ getDevices() {
10045
+ return getVideoDevices();
10046
+ }
10047
+ getStream(constraints) {
10048
+ // We can't set both device id and facing mode
10049
+ // Device id has higher priority
10050
+ if (!constraints.deviceId && this.state.direction) {
10051
+ constraints.facingMode =
10052
+ this.state.direction === 'front' ? 'user' : 'environment';
10053
+ }
10054
+ return getVideoStream(constraints);
10055
+ }
10056
+ publishStream(stream) {
10057
+ return this.call.publishVideoStream(stream);
10058
+ }
10059
+ stopPublishStream() {
10060
+ return this.call.stopPublish(TrackType.VIDEO);
10061
+ }
10062
+ /**
10063
+ * Disables the video tracks of the camera
10064
+ */
10065
+ pause() {
10066
+ var _a;
10067
+ (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks().forEach((track) => {
10068
+ track.enabled = false;
10069
+ });
10070
+ }
10071
+ /**
10072
+ * (Re)enables the video tracks of the camera
10073
+ */
10074
+ resume() {
10075
+ var _a;
10076
+ (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks().forEach((track) => {
10077
+ track.enabled = true;
10078
+ });
10079
+ }
10080
+ }
10081
+
10082
+ class MicrophoneManagerState extends InputMediaDeviceManagerState {
10083
+ getDeviceIdFromStream(stream) {
10084
+ var _a;
10085
+ return (_a = stream.getAudioTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
10086
+ }
10087
+ }
10088
+
10089
+ class MicrophoneManager extends InputMediaDeviceManager {
10090
+ constructor(call) {
10091
+ super(call, new MicrophoneManagerState());
10092
+ }
10093
+ getDevices() {
10094
+ return getAudioDevices();
10095
+ }
10096
+ getStream(constraints) {
10097
+ return getAudioStream(constraints);
10098
+ }
10099
+ publishStream(stream) {
10100
+ return this.call.publishAudioStream(stream);
10101
+ }
10102
+ stopPublishStream() {
10103
+ return this.call.stopPublish(TrackType.AUDIO);
10104
+ }
10105
+ /**
10106
+ * Disables the audio tracks of the microphone
10107
+ */
10108
+ pause() {
10109
+ var _a;
10110
+ (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().forEach((track) => {
10111
+ track.enabled = false;
10112
+ });
10113
+ }
10114
+ /**
10115
+ * (Re)enables the audio tracks of the microphone
10116
+ */
10117
+ resume() {
10118
+ var _a;
10119
+ (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().forEach((track) => {
10120
+ track.enabled = true;
10121
+ });
10122
+ }
10123
+ }
10124
+
9540
10125
  /**
9541
10126
  * An object representation of a `Call`.
9542
10127
  */
@@ -9703,7 +10288,7 @@ class Call {
9703
10288
  * @returns a promise which resolves once the call join-flow has finished.
9704
10289
  */
9705
10290
  this.join = (data) => __awaiter(this, void 0, void 0, function* () {
9706
- var _e, _f, _g;
10291
+ var _e, _f, _g, _h;
9707
10292
  const callingState = this.state.callingState;
9708
10293
  if ([exports.CallingState.JOINED, exports.CallingState.JOINING].includes(callingState)) {
9709
10294
  this.logger('warn', 'Join method called twice, you should only call this once');
@@ -9972,6 +10557,11 @@ class Call {
9972
10557
  this.state.setServerSidePins(pins);
9973
10558
  this.reconnectAttempts = 0; // reset the reconnect attempts counter
9974
10559
  this.state.setCallingState(exports.CallingState.JOINED);
10560
+ // React uses a different device management for now
10561
+ if (((_h = getSdkInfo()) === null || _h === void 0 ? void 0 : _h.type) !== SdkType.REACT) {
10562
+ this.initCamera();
10563
+ this.initMic();
10564
+ }
9975
10565
  // 3. once we have the "joinResponse", and possibly reconciled the local state
9976
10566
  // we schedule a fast subscription update for all remote participants
9977
10567
  // that were visible before we reconnected or migrated to a new SFU.
@@ -10094,9 +10684,9 @@ class Call {
10094
10684
  * @param trackType the track type to stop publishing.
10095
10685
  */
10096
10686
  this.stopPublish = (trackType) => __awaiter(this, void 0, void 0, function* () {
10097
- var _h;
10687
+ var _j;
10098
10688
  this.logger('info', `stopPublish ${TrackType[trackType]}`);
10099
- yield ((_h = this.publisher) === null || _h === void 0 ? void 0 : _h.unpublishStream(trackType));
10689
+ yield ((_j = this.publisher) === null || _j === void 0 ? void 0 : _j.unpublishStream(trackType));
10100
10690
  });
10101
10691
  /**
10102
10692
  * Update track subscription configuration for one or more participants.
@@ -10197,6 +10787,8 @@ class Call {
10197
10787
  *
10198
10788
  *
10199
10789
  * @param deviceId the selected device, pass `undefined` to clear the device selection
10790
+ *
10791
+ * @deprecated use call.microphone.select
10200
10792
  */
10201
10793
  this.setAudioDevice = (deviceId) => {
10202
10794
  if (!this.sfuClient)
@@ -10211,6 +10803,8 @@ class Call {
10211
10803
  * 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.
10212
10804
  *
10213
10805
  * @param deviceId the selected device, pass `undefined` to clear the device selection
10806
+ *
10807
+ * @deprecated use call.camera.select
10214
10808
  */
10215
10809
  this.setVideoDevice = (deviceId) => {
10216
10810
  if (!this.sfuClient)
@@ -10243,8 +10837,8 @@ class Call {
10243
10837
  * @returns
10244
10838
  */
10245
10839
  this.updatePublishQuality = (enabledRids) => __awaiter(this, void 0, void 0, function* () {
10246
- var _j;
10247
- return (_j = this.publisher) === null || _j === void 0 ? void 0 : _j.updateVideoPublishQuality(enabledRids);
10840
+ var _k;
10841
+ return (_k = this.publisher) === null || _k === void 0 ? void 0 : _k.updateVideoPublishQuality(enabledRids);
10248
10842
  });
10249
10843
  this.assertCallJoined = () => {
10250
10844
  return new Promise((resolve) => {
@@ -10587,6 +11181,8 @@ class Call {
10587
11181
  this.leaveCallHooks.push(registerEventHandlers(this, this.state, this.dispatcher));
10588
11182
  this.registerEffects();
10589
11183
  this.leaveCallHooks.push(createSubscription(this.trackSubscriptionsSubject.pipe(rxjs.debounce((v) => rxjs.timer(v.type)), rxjs.map((v) => v.data)), (subscriptions) => { var _a; return (_a = this.sfuClient) === null || _a === void 0 ? void 0 : _a.updateSubscriptions(subscriptions); }));
11184
+ this.camera = new CameraManager(this);
11185
+ this.microphone = new MicrophoneManager(this);
10590
11186
  }
10591
11187
  registerEffects() {
10592
11188
  this.leaveCallHooks.push(
@@ -10694,6 +11290,64 @@ class Call {
10694
11290
  var _a;
10695
11291
  return ((_a = this.state.createdBy) === null || _a === void 0 ? void 0 : _a.id) === this.currentUserId;
10696
11292
  }
11293
+ initCamera() {
11294
+ var _a, _b, _c;
11295
+ if (((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.videoStream) ||
11296
+ !this.permissionsContext.hasPermission('send-video')) {
11297
+ return;
11298
+ }
11299
+ // Set camera direction if it's not yet set
11300
+ // This will also start publishing if camera is enabled
11301
+ if (!this.camera.state.direction && !this.camera.state.selectedDevice) {
11302
+ let defaultDirection = 'front';
11303
+ const backendSetting = (_b = this.state.settings) === null || _b === void 0 ? void 0 : _b.video.camera_facing;
11304
+ if (backendSetting) {
11305
+ defaultDirection = backendSetting === 'front' ? 'front' : 'back';
11306
+ }
11307
+ this.camera.selectDirection(defaultDirection);
11308
+ }
11309
+ else if (this.camera.state.status === 'enabled') {
11310
+ // Publish already started media streams (this is the case if there is a lobby screen before join)
11311
+ // Wait for media stream
11312
+ this.camera.state.mediaStream$
11313
+ .pipe(rxjs.takeWhile((s) => s === undefined, true))
11314
+ .subscribe((stream) => {
11315
+ var _a;
11316
+ if (!((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.videoStream)) {
11317
+ this.publishVideoStream(stream);
11318
+ }
11319
+ });
11320
+ }
11321
+ // Apply backend config (this is the case if there is no lobby screen before join)
11322
+ if (this.camera.state.status === undefined &&
11323
+ ((_c = this.state.settings) === null || _c === void 0 ? void 0 : _c.video.camera_default_on)) {
11324
+ void this.camera.enable();
11325
+ }
11326
+ }
11327
+ initMic() {
11328
+ var _a, _b;
11329
+ if (((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.audioStream) ||
11330
+ !this.permissionsContext.hasPermission('send-audio')) {
11331
+ return;
11332
+ }
11333
+ // Publish already started media streams (this is the case if there is a lobby screen before join)
11334
+ if (this.microphone.state.status === 'enabled') {
11335
+ // Wait for media stream
11336
+ this.microphone.state.mediaStream$
11337
+ .pipe(rxjs.takeWhile((s) => s === undefined, true))
11338
+ .subscribe((stream) => {
11339
+ var _a;
11340
+ if (!((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.audioStream)) {
11341
+ this.publishAudioStream(stream);
11342
+ }
11343
+ });
11344
+ }
11345
+ // Apply backend config (this is the case if there is no lobby screen before join)
11346
+ if (this.microphone.state.status === undefined &&
11347
+ ((_b = this.state.settings) === null || _b === void 0 ? void 0 : _b.audio.mic_default_on)) {
11348
+ void this.microphone.enable();
11349
+ }
11350
+ }
10697
11351
  }
10698
11352
 
10699
11353
  class InsightMetrics {
@@ -11805,7 +12459,7 @@ class WSConnectionFallback {
11805
12459
  }
11806
12460
  }
11807
12461
 
11808
- const version = '0.3.0';
12462
+ const version = '0.3.1';
11809
12463
 
11810
12464
  const logger = getLogger(['location']);
11811
12465
  const HINT_URL = `https://hint.stream-io-video.com/`;
@@ -12779,254 +13433,6 @@ class StreamVideoServerClient extends StreamVideoClient {
12779
13433
  }
12780
13434
  }
12781
13435
 
12782
- const getDevices = (constraints) => {
12783
- return new rxjs.Observable((subscriber) => {
12784
- navigator.mediaDevices
12785
- .getUserMedia(constraints)
12786
- .then((media) => {
12787
- // in Firefox, devices can be enumerated after userMedia is requested
12788
- // and permissions granted. Otherwise, device labels are empty
12789
- navigator.mediaDevices.enumerateDevices().then((devices) => {
12790
- subscriber.next(devices);
12791
- // If we stop the tracks before enumerateDevices -> the labels won't show up in Firefox
12792
- disposeOfMediaStream(media);
12793
- subscriber.complete();
12794
- });
12795
- })
12796
- .catch((error) => {
12797
- getLogger(['devices'])('error', 'Failed to get devices', error);
12798
- subscriber.error(error);
12799
- });
12800
- });
12801
- };
12802
- /**
12803
- * [Tells if the browser supports audio output change on 'audio' elements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId).
12804
- *
12805
- * @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.
12806
- */
12807
- const checkIfAudioOutputChangeSupported = () => {
12808
- if (typeof document === 'undefined')
12809
- return false;
12810
- const element = document.createElement('audio');
12811
- return element.sinkId !== undefined;
12812
- };
12813
- /**
12814
- * The default constraints used to request audio devices.
12815
- */
12816
- const audioDeviceConstraints = {
12817
- audio: {
12818
- autoGainControl: true,
12819
- noiseSuppression: true,
12820
- echoCancellation: true,
12821
- },
12822
- };
12823
- /**
12824
- * The default constraints used to request video devices.
12825
- */
12826
- const videoDeviceConstraints = {
12827
- video: {
12828
- width: 1280,
12829
- height: 720,
12830
- },
12831
- };
12832
- // 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
12833
- const deviceChange$ = new rxjs.Observable((subscriber) => {
12834
- var _a, _b;
12835
- const deviceChangeHandler = () => subscriber.next();
12836
- (_b = (_a = navigator.mediaDevices).addEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
12837
- return () => {
12838
- var _a, _b;
12839
- return (_b = (_a = navigator.mediaDevices).removeEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
12840
- };
12841
- }).pipe(rxjs.debounceTime(500), rxjs.concatMap(() => rxjs.from(navigator.mediaDevices.enumerateDevices())), rxjs.shareReplay(1));
12842
- const audioDevices$ = rxjs.merge(getDevices(audioDeviceConstraints), deviceChange$).pipe(rxjs.shareReplay(1));
12843
- const videoDevices$ = rxjs.merge(getDevices(videoDeviceConstraints), deviceChange$).pipe(rxjs.shareReplay(1));
12844
- /**
12845
- * 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.
12846
- *
12847
- * @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.
12848
- * @returns
12849
- */
12850
- const getAudioDevices = () => audioDevices$.pipe(rxjs.map((values) => values.filter((d) => d.kind === 'audioinput')));
12851
- /**
12852
- * 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.
12853
- *
12854
- * @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.
12855
- * @returns
12856
- */
12857
- const getVideoDevices = () => videoDevices$.pipe(rxjs.map((values) => values.filter((d) => d.kind === 'videoinput' && d.deviceId.length)));
12858
- /**
12859
- * 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)
12860
- *
12861
- * @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.
12862
- * @returns
12863
- */
12864
- const getAudioOutputDevices = () => {
12865
- return audioDevices$.pipe(rxjs.map((values) => values.filter((d) => d.kind === 'audiooutput')));
12866
- };
12867
- const getStream = (constraints) => __awaiter(void 0, void 0, void 0, function* () {
12868
- try {
12869
- return yield navigator.mediaDevices.getUserMedia(constraints);
12870
- }
12871
- catch (e) {
12872
- getLogger(['devices'])('error', `Failed get user media`, {
12873
- error: e,
12874
- constraints: constraints,
12875
- });
12876
- throw e;
12877
- }
12878
- });
12879
- /**
12880
- * Returns an audio media stream that fulfills the given constraints.
12881
- * If no constraints are provided, it uses the browser's default ones.
12882
- *
12883
- * @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.
12884
- * @param trackConstraints the constraints to use when requesting the stream.
12885
- * @returns the new `MediaStream` fulfilling the given constraints.
12886
- */
12887
- const getAudioStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
12888
- const constraints = {
12889
- audio: Object.assign(Object.assign({}, audioDeviceConstraints.audio), trackConstraints),
12890
- };
12891
- return getStream(constraints);
12892
- });
12893
- /**
12894
- * Returns a video media stream that fulfills the given constraints.
12895
- * If no constraints are provided, it uses the browser's default ones.
12896
- *
12897
- * @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.
12898
- * @param trackConstraints the constraints to use when requesting the stream.
12899
- * @returns a new `MediaStream` fulfilling the given constraints.
12900
- */
12901
- const getVideoStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
12902
- const constraints = {
12903
- video: Object.assign(Object.assign({}, videoDeviceConstraints.video), trackConstraints),
12904
- };
12905
- return getStream(constraints);
12906
- });
12907
- /**
12908
- * Prompts the user for a permission to share a screen.
12909
- * If the user grants the permission, a screen sharing stream is returned. Throws otherwise.
12910
- *
12911
- * The callers of this API are responsible to handle the possible errors.
12912
- *
12913
- * @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.
12914
- *
12915
- * @param options any additional options to pass to the [`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) API.
12916
- */
12917
- const getScreenShareStream = (options) => __awaiter(void 0, void 0, void 0, function* () {
12918
- try {
12919
- return yield navigator.mediaDevices.getDisplayMedia(Object.assign({ video: true, audio: false }, options));
12920
- }
12921
- catch (e) {
12922
- getLogger(['devices'])('error', 'Failed to get screen share stream', e);
12923
- throw e;
12924
- }
12925
- });
12926
- const watchForDisconnectedDevice = (kind, deviceId$) => {
12927
- let devices$;
12928
- switch (kind) {
12929
- case 'audioinput':
12930
- devices$ = getAudioDevices();
12931
- break;
12932
- case 'videoinput':
12933
- devices$ = getVideoDevices();
12934
- break;
12935
- case 'audiooutput':
12936
- devices$ = getAudioOutputDevices();
12937
- break;
12938
- }
12939
- return rxjs.combineLatest([devices$, deviceId$]).pipe(rxjs.filter(([devices, deviceId]) => !!deviceId && !devices.find((d) => d.deviceId === deviceId)), rxjs.map(() => true));
12940
- };
12941
- /**
12942
- * Notifies the subscriber if a given 'audioinput' 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 watchForDisconnectedAudioDevice = (deviceId$) => {
12949
- return watchForDisconnectedDevice('audioinput', deviceId$);
12950
- };
12951
- /**
12952
- * Notifies the subscriber if a given 'videoinput' device is disconnected
12953
- *
12954
- * @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.
12955
- * @param deviceId$ an Observable that specifies which device to watch for
12956
- * @returns
12957
- */
12958
- const watchForDisconnectedVideoDevice = (deviceId$) => {
12959
- return watchForDisconnectedDevice('videoinput', deviceId$);
12960
- };
12961
- /**
12962
- * Notifies the subscriber if a given 'audiooutput' device is disconnected
12963
- *
12964
- * @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.
12965
- * @param deviceId$ an Observable that specifies which device to watch for
12966
- * @returns
12967
- */
12968
- const watchForDisconnectedAudioOutputDevice = (deviceId$) => {
12969
- return watchForDisconnectedDevice('audiooutput', deviceId$);
12970
- };
12971
- const watchForAddedDefaultDevice = (kind) => {
12972
- let devices$;
12973
- switch (kind) {
12974
- case 'audioinput':
12975
- devices$ = getAudioDevices();
12976
- break;
12977
- case 'videoinput':
12978
- devices$ = getVideoDevices();
12979
- break;
12980
- case 'audiooutput':
12981
- devices$ = getAudioOutputDevices();
12982
- break;
12983
- default:
12984
- throw new Error('Unknown MediaDeviceKind', kind);
12985
- }
12986
- return devices$.pipe(rxjs.pairwise(), rxjs.filter(([prev, current]) => {
12987
- const prevDefault = prev.find((device) => device.deviceId === 'default');
12988
- const currentDefault = current.find((device) => device.deviceId === 'default');
12989
- return !!(current.length > prev.length &&
12990
- prevDefault &&
12991
- currentDefault &&
12992
- prevDefault.groupId !== currentDefault.groupId);
12993
- }), rxjs.map(() => true));
12994
- };
12995
- /**
12996
- * Notifies the subscriber about newly added default audio input device.
12997
- * @returns Observable<boolean>
12998
- */
12999
- const watchForAddedDefaultAudioDevice = () => watchForAddedDefaultDevice('audioinput');
13000
- /**
13001
- * Notifies the subscriber about newly added default audio output device.
13002
- * @returns Observable<boolean>
13003
- */
13004
- const watchForAddedDefaultAudioOutputDevice = () => watchForAddedDefaultDevice('audiooutput');
13005
- /**
13006
- * Notifies the subscriber about newly added default video input device.
13007
- * @returns Observable<boolean>
13008
- */
13009
- const watchForAddedDefaultVideoDevice = () => watchForAddedDefaultDevice('videoinput');
13010
- /**
13011
- * Deactivates MediaStream (stops and removes tracks) to be later garbage collected
13012
- *
13013
- * @param stream MediaStream
13014
- * @returns void
13015
- */
13016
- const disposeOfMediaStream = (stream) => {
13017
- if (!stream.active)
13018
- return;
13019
- stream.getTracks().forEach((track) => {
13020
- track.stop();
13021
- stream.removeTrack(track);
13022
- });
13023
- // @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the stream
13024
- if (typeof stream.release === 'function') {
13025
- // @ts-expect-error
13026
- stream.release();
13027
- }
13028
- };
13029
-
13030
13436
  const DETECTION_FREQUENCY_IN_MS = 500;
13031
13437
  const AUDIO_LEVEL_THRESHOLD = 150;
13032
13438
  const FFT_SIZE = 128;
@@ -13118,8 +13524,12 @@ exports.Call = Call;
13118
13524
  exports.CallState = CallState;
13119
13525
  exports.CallType = CallType;
13120
13526
  exports.CallTypes = CallTypes;
13527
+ exports.CameraManager = CameraManager;
13121
13528
  exports.CreateDeviceRequestPushProviderEnum = CreateDeviceRequestPushProviderEnum;
13122
13529
  exports.ErrorFromResponse = ErrorFromResponse;
13530
+ exports.InputMediaDeviceManager = InputMediaDeviceManager;
13531
+ exports.InputMediaDeviceManagerState = InputMediaDeviceManagerState;
13532
+ exports.MicrophoneManager = MicrophoneManager;
13123
13533
  exports.OwnCapability = OwnCapability;
13124
13534
  exports.RecordSettingsModeEnum = RecordSettingsModeEnum;
13125
13535
  exports.RecordSettingsQualityEnum = RecordSettingsQualityEnum;