@stream-io/video-client 0.3.0 → 0.3.2

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 (38) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/index.browser.es.js +863 -455
  3. package/dist/index.browser.es.js.map +1 -1
  4. package/dist/index.cjs.js +867 -453
  5. package/dist/index.cjs.js.map +1 -1
  6. package/dist/index.es.js +863 -455
  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 +6 -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 +6 -0
  36. package/src/rtc/Publisher.ts +11 -19
  37. package/src/rtc/videoLayers.ts +7 -2
  38. package/src/types.ts +4 -0
package/dist/index.es.js CHANGED
@@ -4,11 +4,11 @@ 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
+ import { UAParser } from 'ua-parser-js';
9
10
  import WebSocket from 'isomorphic-ws';
10
11
  import { take, map as map$1, distinctUntilChanged } from 'rxjs/operators';
11
- import { UAParser } from 'ua-parser-js';
12
12
  import https from 'https';
13
13
  import jwt from 'jsonwebtoken';
14
14
  import 'crypto';
@@ -6269,6 +6269,56 @@ function getIceCandidate(candidate) {
6269
6269
  }
6270
6270
  }
6271
6271
 
6272
+ let sdkInfo;
6273
+ let osInfo;
6274
+ let deviceInfo;
6275
+ const setSdkInfo = (info) => {
6276
+ sdkInfo = info;
6277
+ };
6278
+ const getSdkInfo = () => {
6279
+ return sdkInfo;
6280
+ };
6281
+ const setOSInfo = (info) => {
6282
+ osInfo = info;
6283
+ };
6284
+ const getOSInfo = () => {
6285
+ return osInfo;
6286
+ };
6287
+ const setDeviceInfo = (info) => {
6288
+ deviceInfo = info;
6289
+ };
6290
+ const getDeviceInfo = () => {
6291
+ return deviceInfo;
6292
+ };
6293
+ const getClientDetails = () => {
6294
+ if (isReactNative()) {
6295
+ // Since RN doesn't support web, sharing browser info is not required
6296
+ return {
6297
+ sdk: getSdkInfo(),
6298
+ os: getOSInfo(),
6299
+ device: getDeviceInfo(),
6300
+ };
6301
+ }
6302
+ const userAgent = new UAParser(navigator.userAgent);
6303
+ const { browser, os, device, cpu } = userAgent.getResult();
6304
+ return {
6305
+ sdk: getSdkInfo(),
6306
+ browser: {
6307
+ name: browser.name || navigator.userAgent,
6308
+ version: browser.version || '',
6309
+ },
6310
+ os: {
6311
+ name: os.name || '',
6312
+ version: os.version || '',
6313
+ architecture: cpu.architecture || '',
6314
+ },
6315
+ device: {
6316
+ name: `${device.vendor || ''} ${device.model || ''} ${device.type || ''}`,
6317
+ version: '',
6318
+ },
6319
+ };
6320
+ };
6321
+
6272
6322
  const DEFAULT_BITRATE = 1250000;
6273
6323
  const defaultTargetResolution = {
6274
6324
  bitrate: DEFAULT_BITRATE,
@@ -6283,9 +6333,11 @@ const defaultTargetResolution = {
6283
6333
  * @param targetResolution the expected target resolution.
6284
6334
  */
6285
6335
  const findOptimalVideoLayers = (videoTrack, targetResolution = defaultTargetResolution) => {
6336
+ var _a;
6286
6337
  const optimalVideoLayers = [];
6287
6338
  const settings = videoTrack.getSettings();
6288
6339
  const { width: w = 0, height: h = 0 } = settings;
6340
+ const isRNIos = isReactNative() && ((_a = getOSInfo()) === null || _a === void 0 ? void 0 : _a.name.toLowerCase()) === 'ios';
6289
6341
  const maxBitrate = getComputedMaxBitrate(targetResolution, w, h);
6290
6342
  let downscaleFactor = 1;
6291
6343
  ['f', 'h', 'q'].forEach((rid) => {
@@ -6299,10 +6351,11 @@ const findOptimalVideoLayers = (videoTrack, targetResolution = defaultTargetReso
6299
6351
  height: Math.round(h / downscaleFactor),
6300
6352
  maxBitrate: Math.round(maxBitrate / downscaleFactor),
6301
6353
  scaleResolutionDownBy: downscaleFactor,
6354
+ // Simulcast on iOS React-Native requires all encodings to share the same framerate
6302
6355
  maxFramerate: {
6303
6356
  f: 30,
6304
- h: 25,
6305
- q: 20,
6357
+ h: isRNIos ? 30 : 25,
6358
+ q: isRNIos ? 30 : 20,
6306
6359
  }[rid],
6307
6360
  });
6308
6361
  downscaleFactor *= 2;
@@ -6501,6 +6554,7 @@ class Publisher {
6501
6554
  * @param opts
6502
6555
  */
6503
6556
  this.publishStream = (mediaStream, track, trackType, opts = {}) => __awaiter(this, void 0, void 0, function* () {
6557
+ var _a;
6504
6558
  if (track.readyState === 'ended') {
6505
6559
  throw new Error(`Can't publish a track that has ended already.`);
6506
6560
  }
@@ -6528,7 +6582,14 @@ class Publisher {
6528
6582
  const videoEncodings = trackType === TrackType.VIDEO
6529
6583
  ? findOptimalVideoLayers(track, targetResolution)
6530
6584
  : undefined;
6531
- const codecPreferences = this.getCodecPreferences(trackType, opts.preferredCodec);
6585
+ let preferredCodec = opts.preferredCodec;
6586
+ if (!preferredCodec && trackType === TrackType.VIDEO) {
6587
+ const isRNAndroid = isReactNative() && ((_a = getOSInfo()) === null || _a === void 0 ? void 0 : _a.name.toLowerCase()) === 'android';
6588
+ if (isRNAndroid) {
6589
+ preferredCodec = 'VP8';
6590
+ }
6591
+ }
6592
+ const codecPreferences = this.getCodecPreferences(trackType, preferredCodec);
6532
6593
  // listen for 'ended' event on the track as it might be ended abruptly
6533
6594
  // by an external factor as permission revokes, device disconnected, etc.
6534
6595
  // keep in mind that `track.stop()` doesn't trigger this event.
@@ -6622,9 +6683,9 @@ class Publisher {
6622
6683
  });
6623
6684
  };
6624
6685
  this.updateVideoPublishQuality = (enabledRids) => __awaiter(this, void 0, void 0, function* () {
6625
- var _a;
6686
+ var _b;
6626
6687
  logger$3('info', 'Update publish quality, requested rids by SFU:', enabledRids);
6627
- const videoSender = (_a = this.transceiverRegistry[TrackType.VIDEO]) === null || _a === void 0 ? void 0 : _a.sender;
6688
+ const videoSender = (_b = this.transceiverRegistry[TrackType.VIDEO]) === null || _b === void 0 ? void 0 : _b.sender;
6628
6689
  if (!videoSender) {
6629
6690
  logger$3('warn', 'Update publish quality, no video sender found.');
6630
6691
  return;
@@ -6722,8 +6783,8 @@ class Publisher {
6722
6783
  * @param options the optional offer options to use.
6723
6784
  */
6724
6785
  this.negotiate = (options) => __awaiter(this, void 0, void 0, function* () {
6725
- var _b;
6726
- this.isIceRestarting = (_b = options === null || options === void 0 ? void 0 : options.iceRestart) !== null && _b !== void 0 ? _b : false;
6786
+ var _c;
6787
+ this.isIceRestarting = (_c = options === null || options === void 0 ? void 0 : options.iceRestart) !== null && _c !== void 0 ? _c : false;
6727
6788
  const offer = yield this.pc.createOffer(options);
6728
6789
  offer.sdp = this.mungeCodecs(offer.sdp);
6729
6790
  const trackInfos = this.getCurrentTrackInfos(offer.sdp);
@@ -6761,15 +6822,6 @@ class Publisher {
6761
6822
  this.mungeCodecs = (sdp) => {
6762
6823
  if (sdp) {
6763
6824
  sdp = toggleDtx(sdp, this.isDtxEnabled);
6764
- if (isReactNative()) {
6765
- if (this.preferredVideoCodec) {
6766
- sdp = setPreferredCodec(sdp, 'video', this.preferredVideoCodec);
6767
- }
6768
- sdp = setPreferredCodec(sdp, 'audio', this.isRedEnabled ? 'red' : 'opus');
6769
- if (!this.isRedEnabled) {
6770
- sdp = removeCodec(sdp, 'audio', 'red');
6771
- }
6772
- }
6773
6825
  }
6774
6826
  return sdp;
6775
6827
  };
@@ -9467,195 +9519,730 @@ const CallTypes = new CallTypesRegistry([
9467
9519
  }),
9468
9520
  ]);
9469
9521
 
9470
- let sdkInfo;
9471
- let osInfo;
9472
- let deviceInfo;
9473
- const setSdkInfo = (info) => {
9474
- sdkInfo = info;
9475
- };
9476
- const getSdkInfo = () => {
9477
- return sdkInfo;
9478
- };
9479
- const setOSInfo = (info) => {
9480
- osInfo = info;
9481
- };
9482
- const getOSInfo = () => {
9483
- return osInfo;
9484
- };
9485
- const setDeviceInfo = (info) => {
9486
- deviceInfo = info;
9487
- };
9488
- const getDeviceInfo = () => {
9489
- return deviceInfo;
9490
- };
9491
- const getClientDetails = () => {
9492
- if (isReactNative()) {
9493
- // Since RN doesn't support web, sharing browser info is not required
9494
- return {
9495
- sdk: getSdkInfo(),
9496
- os: getOSInfo(),
9497
- device: getDeviceInfo(),
9498
- };
9499
- }
9500
- const userAgent = new UAParser(navigator.userAgent);
9501
- const { browser, os, device, cpu } = userAgent.getResult();
9502
- return {
9503
- sdk: getSdkInfo(),
9504
- browser: {
9505
- name: browser.name || navigator.userAgent,
9506
- version: browser.version || '',
9507
- },
9508
- os: {
9509
- name: os.name || '',
9510
- version: os.version || '',
9511
- architecture: cpu.architecture || '',
9512
- },
9513
- device: {
9514
- name: `${device.vendor || ''} ${device.model || ''} ${device.type || ''}`,
9515
- version: '',
9516
- },
9517
- };
9518
- };
9519
-
9520
- /**
9521
- * An object representation of a `Call`.
9522
- */
9523
- class Call {
9524
- /**
9525
- * Constructs a new `Call` instance.
9526
- *
9527
- * NOTE: Don't call the constructor directly, instead
9528
- * Use the [`StreamVideoClient.call`](./StreamVideoClient.md/#call)
9529
- * method to construct a `Call` instance.
9530
- */
9531
- constructor({ type, id, streamClient, members, ownCapabilities, sortParticipantsBy, clientStore, ringing = false, watching = false, }) {
9532
- /**
9533
- * ViewportTracker instance
9534
- */
9535
- this.viewportTracker = new ViewportTracker();
9536
- /**
9537
- * The state of this call.
9538
- */
9539
- this.state = new CallState();
9540
- /**
9541
- * The permissions context of this call.
9542
- */
9543
- this.permissionsContext = new PermissionsContext();
9544
- /**
9545
- * The event dispatcher instance dedicated to this Call instance.
9546
- * @private
9547
- */
9548
- this.dispatcher = new Dispatcher();
9549
- this.trackSubscriptionsSubject = new BehaviorSubject({ type: DebounceType.MEDIUM, data: [] });
9550
- this.reconnectAttempts = 0;
9551
- this.maxReconnectAttempts = 10;
9552
- /**
9553
- * A list hooks/functions to invoke when the call is left.
9554
- * A typical use case is to clean up some global event handlers.
9555
- * @private
9556
- */
9557
- this.leaveCallHooks = [];
9558
- this.streamClientEventHandlers = new Map();
9559
- /**
9560
- * Leave the call and stop the media streams that were published by the call.
9561
- */
9562
- this.leave = ({ reject = false } = {}) => __awaiter(this, void 0, void 0, function* () {
9563
- var _a, _b, _c, _d;
9564
- const callingState = this.state.callingState;
9565
- if (callingState === CallingState.LEFT) {
9566
- throw new Error('Cannot leave call that has already been left.');
9567
- }
9568
- if (callingState === CallingState.JOINING) {
9569
- yield this.assertCallJoined();
9570
- }
9571
- if (this.ringing) {
9572
- // I'm the one who started the call, so I should cancel it.
9573
- const hasOtherParticipants = this.state.remoteParticipants.length > 0;
9574
- if (this.isCreatedByMe && !hasOtherParticipants) {
9575
- // Signals other users that I have cancelled my call to them
9576
- // before they accepted it.
9577
- yield this.reject();
9578
- }
9579
- else if (reject && callingState === CallingState.RINGING) {
9580
- // Signals other users that I have rejected the incoming call.
9581
- yield this.reject();
9582
- }
9583
- }
9584
- (_a = this.statsReporter) === null || _a === void 0 ? void 0 : _a.stop();
9585
- this.statsReporter = undefined;
9586
- (_b = this.subscriber) === null || _b === void 0 ? void 0 : _b.close();
9587
- this.subscriber = undefined;
9588
- (_c = this.publisher) === null || _c === void 0 ? void 0 : _c.close();
9589
- this.publisher = undefined;
9590
- (_d = this.sfuClient) === null || _d === void 0 ? void 0 : _d.close();
9591
- this.sfuClient = undefined;
9592
- this.dispatcher.offAll();
9593
- // Call all leave call hooks, e.g. to clean up global event handlers
9594
- this.leaveCallHooks.forEach((hook) => hook());
9595
- this.clientStore.unregisterCall(this);
9596
- this.state.setCallingState(CallingState.LEFT);
9597
- });
9522
+ class InputMediaDeviceManagerState {
9523
+ constructor() {
9524
+ this.statusSubject = new BehaviorSubject(undefined);
9525
+ this.mediaStreamSubject = new BehaviorSubject(undefined);
9526
+ this.selectedDeviceSubject = new BehaviorSubject(undefined);
9598
9527
  /**
9599
- * Loads the information about the call.
9528
+ * Gets the current value of an observable, or undefined if the observable has
9529
+ * not emitted a value yet.
9600
9530
  *
9601
- * @param params.ring if set to true, a `call.ring` event will be sent to the call members.
9602
- * @param params.notify if set to true, a `call.notification` event will be sent to the call members.
9603
- * @param params.members_limit the members limit.
9531
+ * @param observable$ the observable to get the value from.
9604
9532
  */
9605
- this.get = (params) => __awaiter(this, void 0, void 0, function* () {
9606
- const response = yield this.streamClient.get(this.streamClientBasePath, params);
9607
- if ((params === null || params === void 0 ? void 0 : params.ring) && !this.ringing) {
9608
- this.ringingSubject.next(true);
9609
- }
9610
- this.state.updateFromCallResponse(response.call);
9611
- this.state.setMembers(response.members);
9612
- this.state.setOwnCapabilities(response.own_capabilities);
9613
- if (this.streamClient._hasConnectionID()) {
9614
- this.watching = true;
9615
- this.clientStore.registerCall(this);
9616
- }
9617
- return response;
9618
- });
9533
+ this.getCurrentValue = getCurrentValue;
9619
9534
  /**
9620
- * Loads the information about the call and creates it if it doesn't exist.
9535
+ * Updates the value of the provided Subject.
9536
+ * An `update` can either be a new value or a function which takes
9537
+ * the current value and returns a new value.
9621
9538
  *
9622
- * @param data the data to create the call with.
9623
- */
9624
- this.getOrCreate = (data) => __awaiter(this, void 0, void 0, function* () {
9625
- const response = yield this.streamClient.post(this.streamClientBasePath, data);
9626
- if ((data === null || data === void 0 ? void 0 : data.ring) && !this.ringing) {
9627
- this.ringingSubject.next(true);
9628
- }
9629
- this.state.updateFromCallResponse(response.call);
9630
- this.state.setMembers(response.members);
9631
- this.state.setOwnCapabilities(response.own_capabilities);
9632
- if (this.streamClient._hasConnectionID()) {
9633
- this.watching = true;
9634
- this.clientStore.registerCall(this);
9635
- }
9636
- return response;
9637
- });
9638
- /**
9639
- * Creates a call
9539
+ * @internal
9640
9540
  *
9641
- * @param data the data to create the call with.
9642
- */
9643
- this.create = (data) => __awaiter(this, void 0, void 0, function* () {
9644
- return this.getOrCreate(data);
9645
- });
9646
- /**
9647
- * A shortcut for {@link Call.get} with `ring` parameter set to `true`.
9648
- * Will send a `call.ring` event to the call members.
9649
- */
9650
- this.ring = () => __awaiter(this, void 0, void 0, function* () {
9651
- return yield this.get({ ring: true });
9652
- });
9653
- /**
9654
- * A shortcut for {@link Call.get} with `notify` parameter set to `true`.
9655
- * Will send a `call.notification` event to the call members.
9541
+ * @param subject the subject to update.
9542
+ * @param update the update to apply to the subject.
9543
+ * @return the updated value.
9656
9544
  */
9657
- this.notify = () => __awaiter(this, void 0, void 0, function* () {
9658
- return yield this.get({ notify: true });
9545
+ this.setCurrentValue = setCurrentValue;
9546
+ this.mediaStream$ = this.mediaStreamSubject.asObservable();
9547
+ this.selectedDevice$ = this.selectedDeviceSubject
9548
+ .asObservable()
9549
+ .pipe(distinctUntilChanged$1());
9550
+ this.status$ = this.statusSubject.asObservable();
9551
+ }
9552
+ /**
9553
+ * The device status
9554
+ */
9555
+ get status() {
9556
+ return this.getCurrentValue(this.status$);
9557
+ }
9558
+ /**
9559
+ * The currently selected device
9560
+ */
9561
+ get selectedDevice() {
9562
+ return this.getCurrentValue(this.selectedDevice$);
9563
+ }
9564
+ /**
9565
+ * The current media stream, or `undefined` if the device is currently disabled.
9566
+ */
9567
+ get mediaStream() {
9568
+ return this.getCurrentValue(this.mediaStream$);
9569
+ }
9570
+ /**
9571
+ * @internal
9572
+ * @param status
9573
+ */
9574
+ setStatus(status) {
9575
+ this.setCurrentValue(this.statusSubject, status);
9576
+ }
9577
+ /**
9578
+ * @internal
9579
+ * @param stream
9580
+ */
9581
+ setMediaStream(stream) {
9582
+ this.setCurrentValue(this.mediaStreamSubject, stream);
9583
+ if (stream) {
9584
+ this.setDevice(this.getDeviceIdFromStream(stream));
9585
+ }
9586
+ }
9587
+ /**
9588
+ * @internal
9589
+ * @param stream
9590
+ */
9591
+ setDevice(deviceId) {
9592
+ this.setCurrentValue(this.selectedDeviceSubject, deviceId);
9593
+ }
9594
+ }
9595
+
9596
+ class CameraManagerState extends InputMediaDeviceManagerState {
9597
+ constructor() {
9598
+ super();
9599
+ this.directionSubject = new BehaviorSubject(undefined);
9600
+ this.direction$ = this.directionSubject
9601
+ .asObservable()
9602
+ .pipe(distinctUntilChanged$1());
9603
+ }
9604
+ /**
9605
+ * The preferred camera direction
9606
+ * front - means the camera facing the user
9607
+ * back - means the camera facing the environment
9608
+ */
9609
+ get direction() {
9610
+ return this.getCurrentValue(this.direction$);
9611
+ }
9612
+ /**
9613
+ * @internal
9614
+ */
9615
+ setDirection(direction) {
9616
+ this.setCurrentValue(this.directionSubject, direction);
9617
+ }
9618
+ /**
9619
+ * @internal
9620
+ */
9621
+ setMediaStream(stream) {
9622
+ var _a;
9623
+ super.setMediaStream(stream);
9624
+ if (stream) {
9625
+ // RN getSettings() doesn't return facingMode, so we don't verify camera direction
9626
+ const direction = isReactNative()
9627
+ ? this.direction
9628
+ : ((_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().facingMode) === 'environment'
9629
+ ? 'back'
9630
+ : 'front';
9631
+ this.setDirection(direction);
9632
+ }
9633
+ }
9634
+ getDeviceIdFromStream(stream) {
9635
+ var _a;
9636
+ return (_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
9637
+ }
9638
+ }
9639
+
9640
+ const getDevices = (constraints) => {
9641
+ return new Observable((subscriber) => {
9642
+ navigator.mediaDevices
9643
+ .getUserMedia(constraints)
9644
+ .then((media) => {
9645
+ // in Firefox, devices can be enumerated after userMedia is requested
9646
+ // and permissions granted. Otherwise, device labels are empty
9647
+ navigator.mediaDevices.enumerateDevices().then((devices) => {
9648
+ subscriber.next(devices);
9649
+ // If we stop the tracks before enumerateDevices -> the labels won't show up in Firefox
9650
+ disposeOfMediaStream(media);
9651
+ subscriber.complete();
9652
+ });
9653
+ })
9654
+ .catch((error) => {
9655
+ getLogger(['devices'])('error', 'Failed to get devices', error);
9656
+ subscriber.error(error);
9657
+ });
9658
+ });
9659
+ };
9660
+ /**
9661
+ * [Tells if the browser supports audio output change on 'audio' elements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId).
9662
+ *
9663
+ * @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.
9664
+ */
9665
+ const checkIfAudioOutputChangeSupported = () => {
9666
+ if (typeof document === 'undefined')
9667
+ return false;
9668
+ const element = document.createElement('audio');
9669
+ return element.sinkId !== undefined;
9670
+ };
9671
+ /**
9672
+ * The default constraints used to request audio devices.
9673
+ */
9674
+ const audioDeviceConstraints = {
9675
+ audio: {
9676
+ autoGainControl: true,
9677
+ noiseSuppression: true,
9678
+ echoCancellation: true,
9679
+ },
9680
+ };
9681
+ /**
9682
+ * The default constraints used to request video devices.
9683
+ */
9684
+ const videoDeviceConstraints = {
9685
+ video: {
9686
+ width: 1280,
9687
+ height: 720,
9688
+ },
9689
+ };
9690
+ // 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
9691
+ const deviceChange$ = new Observable((subscriber) => {
9692
+ var _a, _b;
9693
+ const deviceChangeHandler = () => subscriber.next();
9694
+ (_b = (_a = navigator.mediaDevices).addEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
9695
+ return () => {
9696
+ var _a, _b;
9697
+ return (_b = (_a = navigator.mediaDevices).removeEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
9698
+ };
9699
+ }).pipe(debounceTime(500), concatMap(() => from(navigator.mediaDevices.enumerateDevices())), shareReplay(1));
9700
+ const audioDevices$ = merge(getDevices(audioDeviceConstraints), deviceChange$).pipe(shareReplay(1));
9701
+ const videoDevices$ = merge(getDevices(videoDeviceConstraints), deviceChange$).pipe(shareReplay(1));
9702
+ /**
9703
+ * 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.
9704
+ *
9705
+ * @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.
9706
+ * @returns
9707
+ */
9708
+ const getAudioDevices = () => audioDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'audioinput')));
9709
+ /**
9710
+ * 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.
9711
+ *
9712
+ * @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.
9713
+ * @returns
9714
+ */
9715
+ const getVideoDevices = () => videoDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'videoinput' && d.deviceId.length)));
9716
+ /**
9717
+ * 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)
9718
+ *
9719
+ * @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.
9720
+ * @returns
9721
+ */
9722
+ const getAudioOutputDevices = () => {
9723
+ return audioDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'audiooutput')));
9724
+ };
9725
+ const getStream = (constraints) => __awaiter(void 0, void 0, void 0, function* () {
9726
+ try {
9727
+ return yield navigator.mediaDevices.getUserMedia(constraints);
9728
+ }
9729
+ catch (e) {
9730
+ getLogger(['devices'])('error', `Failed get user media`, {
9731
+ error: e,
9732
+ constraints: constraints,
9733
+ });
9734
+ throw e;
9735
+ }
9736
+ });
9737
+ /**
9738
+ * Returns an audio media stream that fulfills the given constraints.
9739
+ * If no constraints are provided, it uses the browser's default ones.
9740
+ *
9741
+ * @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.
9742
+ * @param trackConstraints the constraints to use when requesting the stream.
9743
+ * @returns the new `MediaStream` fulfilling the given constraints.
9744
+ */
9745
+ const getAudioStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
9746
+ const constraints = {
9747
+ audio: Object.assign(Object.assign({}, audioDeviceConstraints.audio), trackConstraints),
9748
+ };
9749
+ return getStream(constraints);
9750
+ });
9751
+ /**
9752
+ * Returns a video media stream that fulfills the given constraints.
9753
+ * If no constraints are provided, it uses the browser's default ones.
9754
+ *
9755
+ * @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.
9756
+ * @param trackConstraints the constraints to use when requesting the stream.
9757
+ * @returns a new `MediaStream` fulfilling the given constraints.
9758
+ */
9759
+ const getVideoStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
9760
+ const constraints = {
9761
+ video: Object.assign(Object.assign({}, videoDeviceConstraints.video), trackConstraints),
9762
+ };
9763
+ return getStream(constraints);
9764
+ });
9765
+ /**
9766
+ * Prompts the user for a permission to share a screen.
9767
+ * If the user grants the permission, a screen sharing stream is returned. Throws otherwise.
9768
+ *
9769
+ * The callers of this API are responsible to handle the possible errors.
9770
+ *
9771
+ * @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.
9772
+ *
9773
+ * @param options any additional options to pass to the [`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) API.
9774
+ */
9775
+ const getScreenShareStream = (options) => __awaiter(void 0, void 0, void 0, function* () {
9776
+ try {
9777
+ return yield navigator.mediaDevices.getDisplayMedia(Object.assign({ video: true, audio: false }, options));
9778
+ }
9779
+ catch (e) {
9780
+ getLogger(['devices'])('error', 'Failed to get screen share stream', e);
9781
+ throw e;
9782
+ }
9783
+ });
9784
+ const watchForDisconnectedDevice = (kind, deviceId$) => {
9785
+ let devices$;
9786
+ switch (kind) {
9787
+ case 'audioinput':
9788
+ devices$ = getAudioDevices();
9789
+ break;
9790
+ case 'videoinput':
9791
+ devices$ = getVideoDevices();
9792
+ break;
9793
+ case 'audiooutput':
9794
+ devices$ = getAudioOutputDevices();
9795
+ break;
9796
+ }
9797
+ return combineLatest([devices$, deviceId$]).pipe(filter(([devices, deviceId]) => !!deviceId && !devices.find((d) => d.deviceId === deviceId)), map$2(() => true));
9798
+ };
9799
+ /**
9800
+ * Notifies the subscriber if a given 'audioinput' device is disconnected
9801
+ *
9802
+ * @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.
9803
+ * @param deviceId$ an Observable that specifies which device to watch for
9804
+ * @returns
9805
+ */
9806
+ const watchForDisconnectedAudioDevice = (deviceId$) => {
9807
+ return watchForDisconnectedDevice('audioinput', deviceId$);
9808
+ };
9809
+ /**
9810
+ * Notifies the subscriber if a given 'videoinput' device is disconnected
9811
+ *
9812
+ * @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.
9813
+ * @param deviceId$ an Observable that specifies which device to watch for
9814
+ * @returns
9815
+ */
9816
+ const watchForDisconnectedVideoDevice = (deviceId$) => {
9817
+ return watchForDisconnectedDevice('videoinput', deviceId$);
9818
+ };
9819
+ /**
9820
+ * Notifies the subscriber if a given 'audiooutput' device is disconnected
9821
+ *
9822
+ * @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.
9823
+ * @param deviceId$ an Observable that specifies which device to watch for
9824
+ * @returns
9825
+ */
9826
+ const watchForDisconnectedAudioOutputDevice = (deviceId$) => {
9827
+ return watchForDisconnectedDevice('audiooutput', deviceId$);
9828
+ };
9829
+ const watchForAddedDefaultDevice = (kind) => {
9830
+ let devices$;
9831
+ switch (kind) {
9832
+ case 'audioinput':
9833
+ devices$ = getAudioDevices();
9834
+ break;
9835
+ case 'videoinput':
9836
+ devices$ = getVideoDevices();
9837
+ break;
9838
+ case 'audiooutput':
9839
+ devices$ = getAudioOutputDevices();
9840
+ break;
9841
+ default:
9842
+ throw new Error('Unknown MediaDeviceKind', kind);
9843
+ }
9844
+ return devices$.pipe(pairwise(), filter(([prev, current]) => {
9845
+ const prevDefault = prev.find((device) => device.deviceId === 'default');
9846
+ const currentDefault = current.find((device) => device.deviceId === 'default');
9847
+ return !!(current.length > prev.length &&
9848
+ prevDefault &&
9849
+ currentDefault &&
9850
+ prevDefault.groupId !== currentDefault.groupId);
9851
+ }), map$2(() => true));
9852
+ };
9853
+ /**
9854
+ * Notifies the subscriber about newly added default audio input device.
9855
+ * @returns Observable<boolean>
9856
+ */
9857
+ const watchForAddedDefaultAudioDevice = () => watchForAddedDefaultDevice('audioinput');
9858
+ /**
9859
+ * Notifies the subscriber about newly added default audio output device.
9860
+ * @returns Observable<boolean>
9861
+ */
9862
+ const watchForAddedDefaultAudioOutputDevice = () => watchForAddedDefaultDevice('audiooutput');
9863
+ /**
9864
+ * Notifies the subscriber about newly added default video input device.
9865
+ * @returns Observable<boolean>
9866
+ */
9867
+ const watchForAddedDefaultVideoDevice = () => watchForAddedDefaultDevice('videoinput');
9868
+ /**
9869
+ * Deactivates MediaStream (stops and removes tracks) to be later garbage collected
9870
+ *
9871
+ * @param stream MediaStream
9872
+ * @returns void
9873
+ */
9874
+ const disposeOfMediaStream = (stream) => {
9875
+ if (!stream.active)
9876
+ return;
9877
+ stream.getTracks().forEach((track) => {
9878
+ track.stop();
9879
+ stream.removeTrack(track);
9880
+ });
9881
+ // @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the stream
9882
+ if (typeof stream.release === 'function') {
9883
+ // @ts-expect-error
9884
+ stream.release();
9885
+ }
9886
+ };
9887
+
9888
+ class InputMediaDeviceManager {
9889
+ constructor(call, state) {
9890
+ this.call = call;
9891
+ this.state = state;
9892
+ }
9893
+ /**
9894
+ * Lists the available audio/video devices
9895
+ *
9896
+ * Note: It prompts the user for a permission to use devices (if not already granted)
9897
+ *
9898
+ * @returns an Observable that will be updated if a device is connected or disconnected
9899
+ */
9900
+ listDevices() {
9901
+ return this.getDevices();
9902
+ }
9903
+ /**
9904
+ * Starts camera/microphone
9905
+ */
9906
+ enable() {
9907
+ return __awaiter(this, void 0, void 0, function* () {
9908
+ if (this.state.status === 'enabled') {
9909
+ return;
9910
+ }
9911
+ yield this.startStream();
9912
+ this.state.setStatus('enabled');
9913
+ });
9914
+ }
9915
+ /**
9916
+ * Stops camera/microphone
9917
+ * @returns
9918
+ */
9919
+ disable() {
9920
+ return __awaiter(this, void 0, void 0, function* () {
9921
+ if (this.state.status === 'disabled') {
9922
+ return;
9923
+ }
9924
+ yield this.stopStream();
9925
+ this.state.setStatus('disabled');
9926
+ });
9927
+ }
9928
+ /**
9929
+ * If current device statis is disabled, it will enable the device, else it will disable it.
9930
+ * @returns
9931
+ */
9932
+ toggle() {
9933
+ return __awaiter(this, void 0, void 0, function* () {
9934
+ if (this.state.status === 'enabled') {
9935
+ return this.disable();
9936
+ }
9937
+ else {
9938
+ return this.enable();
9939
+ }
9940
+ });
9941
+ }
9942
+ /**
9943
+ * Select device
9944
+ *
9945
+ * Note: this method is not supported in React Native
9946
+ *
9947
+ * @param deviceId
9948
+ */
9949
+ select(deviceId) {
9950
+ return __awaiter(this, void 0, void 0, function* () {
9951
+ if (isReactNative()) {
9952
+ throw new Error('This method is not supported in React Native');
9953
+ }
9954
+ if (deviceId === this.state.selectedDevice) {
9955
+ return;
9956
+ }
9957
+ this.state.setDevice(deviceId);
9958
+ yield this.applySettingsToStream();
9959
+ });
9960
+ }
9961
+ applySettingsToStream() {
9962
+ return __awaiter(this, void 0, void 0, function* () {
9963
+ if (this.state.status === 'enabled') {
9964
+ yield this.stopStream();
9965
+ yield this.startStream();
9966
+ }
9967
+ });
9968
+ }
9969
+ stopStream() {
9970
+ return __awaiter(this, void 0, void 0, function* () {
9971
+ if (!this.state.mediaStream) {
9972
+ return;
9973
+ }
9974
+ if (this.call.state.callingState === CallingState.JOINED) {
9975
+ yield this.stopPublishStream();
9976
+ }
9977
+ else if (this.state.mediaStream) {
9978
+ disposeOfMediaStream(this.state.mediaStream);
9979
+ }
9980
+ this.state.setMediaStream(undefined);
9981
+ });
9982
+ }
9983
+ startStream() {
9984
+ return __awaiter(this, void 0, void 0, function* () {
9985
+ if (this.state.mediaStream) {
9986
+ return;
9987
+ }
9988
+ const constraints = { deviceId: this.state.selectedDevice };
9989
+ const stream = yield this.getStream(constraints);
9990
+ if (this.call.state.callingState === CallingState.JOINED) {
9991
+ yield this.publishStream(stream);
9992
+ }
9993
+ this.state.setMediaStream(stream);
9994
+ });
9995
+ }
9996
+ }
9997
+
9998
+ class CameraManager extends InputMediaDeviceManager {
9999
+ constructor(call) {
10000
+ super(call, new CameraManagerState());
10001
+ }
10002
+ /**
10003
+ * Select the camera direaction
10004
+ * @param direction
10005
+ */
10006
+ selectDirection(direction) {
10007
+ return __awaiter(this, void 0, void 0, function* () {
10008
+ this.state.setDirection(direction);
10009
+ // Providing both device id and direction doesn't work, so we deselect the device
10010
+ this.state.setDevice(undefined);
10011
+ yield this.applySettingsToStream();
10012
+ });
10013
+ }
10014
+ /**
10015
+ * Flips the camera direction: if it's front it will change to back, if it's back, it will change to front.
10016
+ *
10017
+ * Note: if there is no available camera with the desired direction, this method will do nothing.
10018
+ * @returns
10019
+ */
10020
+ flip() {
10021
+ return __awaiter(this, void 0, void 0, function* () {
10022
+ const newDirection = this.state.direction === 'front' ? 'back' : 'front';
10023
+ this.selectDirection(newDirection);
10024
+ });
10025
+ }
10026
+ getDevices() {
10027
+ return getVideoDevices();
10028
+ }
10029
+ getStream(constraints) {
10030
+ // We can't set both device id and facing mode
10031
+ // Device id has higher priority
10032
+ if (!constraints.deviceId && this.state.direction) {
10033
+ constraints.facingMode =
10034
+ this.state.direction === 'front' ? 'user' : 'environment';
10035
+ }
10036
+ return getVideoStream(constraints);
10037
+ }
10038
+ publishStream(stream) {
10039
+ return this.call.publishVideoStream(stream);
10040
+ }
10041
+ stopPublishStream() {
10042
+ return this.call.stopPublish(TrackType.VIDEO);
10043
+ }
10044
+ /**
10045
+ * Disables the video tracks of the camera
10046
+ */
10047
+ pause() {
10048
+ var _a;
10049
+ (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks().forEach((track) => {
10050
+ track.enabled = false;
10051
+ });
10052
+ }
10053
+ /**
10054
+ * (Re)enables the video tracks of the camera
10055
+ */
10056
+ resume() {
10057
+ var _a;
10058
+ (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks().forEach((track) => {
10059
+ track.enabled = true;
10060
+ });
10061
+ }
10062
+ }
10063
+
10064
+ class MicrophoneManagerState extends InputMediaDeviceManagerState {
10065
+ getDeviceIdFromStream(stream) {
10066
+ var _a;
10067
+ return (_a = stream.getAudioTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
10068
+ }
10069
+ }
10070
+
10071
+ class MicrophoneManager extends InputMediaDeviceManager {
10072
+ constructor(call) {
10073
+ super(call, new MicrophoneManagerState());
10074
+ }
10075
+ getDevices() {
10076
+ return getAudioDevices();
10077
+ }
10078
+ getStream(constraints) {
10079
+ return getAudioStream(constraints);
10080
+ }
10081
+ publishStream(stream) {
10082
+ return this.call.publishAudioStream(stream);
10083
+ }
10084
+ stopPublishStream() {
10085
+ return this.call.stopPublish(TrackType.AUDIO);
10086
+ }
10087
+ /**
10088
+ * Disables the audio tracks of the microphone
10089
+ */
10090
+ pause() {
10091
+ var _a;
10092
+ (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().forEach((track) => {
10093
+ track.enabled = false;
10094
+ });
10095
+ }
10096
+ /**
10097
+ * (Re)enables the audio tracks of the microphone
10098
+ */
10099
+ resume() {
10100
+ var _a;
10101
+ (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().forEach((track) => {
10102
+ track.enabled = true;
10103
+ });
10104
+ }
10105
+ }
10106
+
10107
+ /**
10108
+ * An object representation of a `Call`.
10109
+ */
10110
+ class Call {
10111
+ /**
10112
+ * Constructs a new `Call` instance.
10113
+ *
10114
+ * NOTE: Don't call the constructor directly, instead
10115
+ * Use the [`StreamVideoClient.call`](./StreamVideoClient.md/#call)
10116
+ * method to construct a `Call` instance.
10117
+ */
10118
+ constructor({ type, id, streamClient, members, ownCapabilities, sortParticipantsBy, clientStore, ringing = false, watching = false, }) {
10119
+ /**
10120
+ * ViewportTracker instance
10121
+ */
10122
+ this.viewportTracker = new ViewportTracker();
10123
+ /**
10124
+ * The state of this call.
10125
+ */
10126
+ this.state = new CallState();
10127
+ /**
10128
+ * The permissions context of this call.
10129
+ */
10130
+ this.permissionsContext = new PermissionsContext();
10131
+ /**
10132
+ * The event dispatcher instance dedicated to this Call instance.
10133
+ * @private
10134
+ */
10135
+ this.dispatcher = new Dispatcher();
10136
+ this.trackSubscriptionsSubject = new BehaviorSubject({ type: DebounceType.MEDIUM, data: [] });
10137
+ this.reconnectAttempts = 0;
10138
+ this.maxReconnectAttempts = 10;
10139
+ /**
10140
+ * A list hooks/functions to invoke when the call is left.
10141
+ * A typical use case is to clean up some global event handlers.
10142
+ * @private
10143
+ */
10144
+ this.leaveCallHooks = [];
10145
+ this.streamClientEventHandlers = new Map();
10146
+ /**
10147
+ * Leave the call and stop the media streams that were published by the call.
10148
+ */
10149
+ this.leave = ({ reject = false } = {}) => __awaiter(this, void 0, void 0, function* () {
10150
+ var _a, _b, _c, _d;
10151
+ const callingState = this.state.callingState;
10152
+ if (callingState === CallingState.LEFT) {
10153
+ throw new Error('Cannot leave call that has already been left.');
10154
+ }
10155
+ if (callingState === CallingState.JOINING) {
10156
+ yield this.assertCallJoined();
10157
+ }
10158
+ if (this.ringing) {
10159
+ // I'm the one who started the call, so I should cancel it.
10160
+ const hasOtherParticipants = this.state.remoteParticipants.length > 0;
10161
+ if (this.isCreatedByMe && !hasOtherParticipants) {
10162
+ // Signals other users that I have cancelled my call to them
10163
+ // before they accepted it.
10164
+ yield this.reject();
10165
+ }
10166
+ else if (reject && callingState === CallingState.RINGING) {
10167
+ // Signals other users that I have rejected the incoming call.
10168
+ yield this.reject();
10169
+ }
10170
+ }
10171
+ (_a = this.statsReporter) === null || _a === void 0 ? void 0 : _a.stop();
10172
+ this.statsReporter = undefined;
10173
+ (_b = this.subscriber) === null || _b === void 0 ? void 0 : _b.close();
10174
+ this.subscriber = undefined;
10175
+ (_c = this.publisher) === null || _c === void 0 ? void 0 : _c.close();
10176
+ this.publisher = undefined;
10177
+ (_d = this.sfuClient) === null || _d === void 0 ? void 0 : _d.close();
10178
+ this.sfuClient = undefined;
10179
+ this.dispatcher.offAll();
10180
+ // Call all leave call hooks, e.g. to clean up global event handlers
10181
+ this.leaveCallHooks.forEach((hook) => hook());
10182
+ this.clientStore.unregisterCall(this);
10183
+ this.state.setCallingState(CallingState.LEFT);
10184
+ });
10185
+ /**
10186
+ * Loads the information about the call.
10187
+ *
10188
+ * @param params.ring if set to true, a `call.ring` event will be sent to the call members.
10189
+ * @param params.notify if set to true, a `call.notification` event will be sent to the call members.
10190
+ * @param params.members_limit the members limit.
10191
+ */
10192
+ this.get = (params) => __awaiter(this, void 0, void 0, function* () {
10193
+ const response = yield this.streamClient.get(this.streamClientBasePath, params);
10194
+ if ((params === null || params === void 0 ? void 0 : params.ring) && !this.ringing) {
10195
+ this.ringingSubject.next(true);
10196
+ }
10197
+ this.state.updateFromCallResponse(response.call);
10198
+ this.state.setMembers(response.members);
10199
+ this.state.setOwnCapabilities(response.own_capabilities);
10200
+ if (this.streamClient._hasConnectionID()) {
10201
+ this.watching = true;
10202
+ this.clientStore.registerCall(this);
10203
+ }
10204
+ return response;
10205
+ });
10206
+ /**
10207
+ * Loads the information about the call and creates it if it doesn't exist.
10208
+ *
10209
+ * @param data the data to create the call with.
10210
+ */
10211
+ this.getOrCreate = (data) => __awaiter(this, void 0, void 0, function* () {
10212
+ const response = yield this.streamClient.post(this.streamClientBasePath, data);
10213
+ if ((data === null || data === void 0 ? void 0 : data.ring) && !this.ringing) {
10214
+ this.ringingSubject.next(true);
10215
+ }
10216
+ this.state.updateFromCallResponse(response.call);
10217
+ this.state.setMembers(response.members);
10218
+ this.state.setOwnCapabilities(response.own_capabilities);
10219
+ if (this.streamClient._hasConnectionID()) {
10220
+ this.watching = true;
10221
+ this.clientStore.registerCall(this);
10222
+ }
10223
+ return response;
10224
+ });
10225
+ /**
10226
+ * Creates a call
10227
+ *
10228
+ * @param data the data to create the call with.
10229
+ */
10230
+ this.create = (data) => __awaiter(this, void 0, void 0, function* () {
10231
+ return this.getOrCreate(data);
10232
+ });
10233
+ /**
10234
+ * A shortcut for {@link Call.get} with `ring` parameter set to `true`.
10235
+ * Will send a `call.ring` event to the call members.
10236
+ */
10237
+ this.ring = () => __awaiter(this, void 0, void 0, function* () {
10238
+ return yield this.get({ ring: true });
10239
+ });
10240
+ /**
10241
+ * A shortcut for {@link Call.get} with `notify` parameter set to `true`.
10242
+ * Will send a `call.notification` event to the call members.
10243
+ */
10244
+ this.notify = () => __awaiter(this, void 0, void 0, function* () {
10245
+ return yield this.get({ notify: true });
9659
10246
  });
9660
10247
  /**
9661
10248
  * Marks the incoming call as accepted.
@@ -9683,7 +10270,7 @@ class Call {
9683
10270
  * @returns a promise which resolves once the call join-flow has finished.
9684
10271
  */
9685
10272
  this.join = (data) => __awaiter(this, void 0, void 0, function* () {
9686
- var _e, _f, _g;
10273
+ var _e, _f, _g, _h;
9687
10274
  const callingState = this.state.callingState;
9688
10275
  if ([CallingState.JOINED, CallingState.JOINING].includes(callingState)) {
9689
10276
  this.logger('warn', 'Join method called twice, you should only call this once');
@@ -9952,6 +10539,11 @@ class Call {
9952
10539
  this.state.setServerSidePins(pins);
9953
10540
  this.reconnectAttempts = 0; // reset the reconnect attempts counter
9954
10541
  this.state.setCallingState(CallingState.JOINED);
10542
+ // React uses a different device management for now
10543
+ if (((_h = getSdkInfo()) === null || _h === void 0 ? void 0 : _h.type) !== SdkType.REACT) {
10544
+ this.initCamera();
10545
+ this.initMic();
10546
+ }
9955
10547
  // 3. once we have the "joinResponse", and possibly reconciled the local state
9956
10548
  // we schedule a fast subscription update for all remote participants
9957
10549
  // that were visible before we reconnected or migrated to a new SFU.
@@ -10074,9 +10666,9 @@ class Call {
10074
10666
  * @param trackType the track type to stop publishing.
10075
10667
  */
10076
10668
  this.stopPublish = (trackType) => __awaiter(this, void 0, void 0, function* () {
10077
- var _h;
10669
+ var _j;
10078
10670
  this.logger('info', `stopPublish ${TrackType[trackType]}`);
10079
- yield ((_h = this.publisher) === null || _h === void 0 ? void 0 : _h.unpublishStream(trackType));
10671
+ yield ((_j = this.publisher) === null || _j === void 0 ? void 0 : _j.unpublishStream(trackType));
10080
10672
  });
10081
10673
  /**
10082
10674
  * Update track subscription configuration for one or more participants.
@@ -10177,6 +10769,8 @@ class Call {
10177
10769
  *
10178
10770
  *
10179
10771
  * @param deviceId the selected device, pass `undefined` to clear the device selection
10772
+ *
10773
+ * @deprecated use call.microphone.select
10180
10774
  */
10181
10775
  this.setAudioDevice = (deviceId) => {
10182
10776
  if (!this.sfuClient)
@@ -10191,6 +10785,8 @@ class Call {
10191
10785
  * 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
10786
  *
10193
10787
  * @param deviceId the selected device, pass `undefined` to clear the device selection
10788
+ *
10789
+ * @deprecated use call.camera.select
10194
10790
  */
10195
10791
  this.setVideoDevice = (deviceId) => {
10196
10792
  if (!this.sfuClient)
@@ -10223,8 +10819,8 @@ class Call {
10223
10819
  * @returns
10224
10820
  */
10225
10821
  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);
10822
+ var _k;
10823
+ return (_k = this.publisher) === null || _k === void 0 ? void 0 : _k.updateVideoPublishQuality(enabledRids);
10228
10824
  });
10229
10825
  this.assertCallJoined = () => {
10230
10826
  return new Promise((resolve) => {
@@ -10567,6 +11163,8 @@ class Call {
10567
11163
  this.leaveCallHooks.push(registerEventHandlers(this, this.state, this.dispatcher));
10568
11164
  this.registerEffects();
10569
11165
  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); }));
11166
+ this.camera = new CameraManager(this);
11167
+ this.microphone = new MicrophoneManager(this);
10570
11168
  }
10571
11169
  registerEffects() {
10572
11170
  this.leaveCallHooks.push(
@@ -10674,6 +11272,64 @@ class Call {
10674
11272
  var _a;
10675
11273
  return ((_a = this.state.createdBy) === null || _a === void 0 ? void 0 : _a.id) === this.currentUserId;
10676
11274
  }
11275
+ initCamera() {
11276
+ var _a, _b, _c;
11277
+ if (((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.videoStream) ||
11278
+ !this.permissionsContext.hasPermission('send-video')) {
11279
+ return;
11280
+ }
11281
+ // Set camera direction if it's not yet set
11282
+ // This will also start publishing if camera is enabled
11283
+ if (!this.camera.state.direction && !this.camera.state.selectedDevice) {
11284
+ let defaultDirection = 'front';
11285
+ const backendSetting = (_b = this.state.settings) === null || _b === void 0 ? void 0 : _b.video.camera_facing;
11286
+ if (backendSetting) {
11287
+ defaultDirection = backendSetting === 'front' ? 'front' : 'back';
11288
+ }
11289
+ this.camera.selectDirection(defaultDirection);
11290
+ }
11291
+ else if (this.camera.state.status === 'enabled') {
11292
+ // Publish already started media streams (this is the case if there is a lobby screen before join)
11293
+ // Wait for media stream
11294
+ this.camera.state.mediaStream$
11295
+ .pipe(takeWhile((s) => s === undefined, true))
11296
+ .subscribe((stream) => {
11297
+ var _a;
11298
+ if (!((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.videoStream)) {
11299
+ this.publishVideoStream(stream);
11300
+ }
11301
+ });
11302
+ }
11303
+ // Apply backend config (this is the case if there is no lobby screen before join)
11304
+ if (this.camera.state.status === undefined &&
11305
+ ((_c = this.state.settings) === null || _c === void 0 ? void 0 : _c.video.camera_default_on)) {
11306
+ void this.camera.enable();
11307
+ }
11308
+ }
11309
+ initMic() {
11310
+ var _a, _b;
11311
+ if (((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.audioStream) ||
11312
+ !this.permissionsContext.hasPermission('send-audio')) {
11313
+ return;
11314
+ }
11315
+ // Publish already started media streams (this is the case if there is a lobby screen before join)
11316
+ if (this.microphone.state.status === 'enabled') {
11317
+ // Wait for media stream
11318
+ this.microphone.state.mediaStream$
11319
+ .pipe(takeWhile((s) => s === undefined, true))
11320
+ .subscribe((stream) => {
11321
+ var _a;
11322
+ if (!((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.audioStream)) {
11323
+ this.publishAudioStream(stream);
11324
+ }
11325
+ });
11326
+ }
11327
+ // Apply backend config (this is the case if there is no lobby screen before join)
11328
+ if (this.microphone.state.status === undefined &&
11329
+ ((_b = this.state.settings) === null || _b === void 0 ? void 0 : _b.audio.mic_default_on)) {
11330
+ void this.microphone.enable();
11331
+ }
11332
+ }
10677
11333
  }
10678
11334
 
10679
11335
  class InsightMetrics {
@@ -11785,7 +12441,7 @@ class WSConnectionFallback {
11785
12441
  }
11786
12442
  }
11787
12443
 
11788
- const version = '0.3.0';
12444
+ const version = '0.3.2';
11789
12445
 
11790
12446
  const logger = getLogger(['location']);
11791
12447
  const HINT_URL = `https://hint.stream-io-video.com/`;
@@ -12759,254 +13415,6 @@ class StreamVideoServerClient extends StreamVideoClient {
12759
13415
  }
12760
13416
  }
12761
13417
 
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
13418
  const DETECTION_FREQUENCY_IN_MS = 500;
13011
13419
  const AUDIO_LEVEL_THRESHOLD = 150;
13012
13420
  const FFT_SIZE = 128;
@@ -13087,5 +13495,5 @@ var browsers = /*#__PURE__*/Object.freeze({
13087
13495
  isSafari: isSafari
13088
13496
  });
13089
13497
 
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 };
13498
+ export { AudioSettingsDefaultDeviceEnum, AudioSettingsRequestDefaultDeviceEnum, browsers as Browsers, Call, CallState, CallType, CallTypes, CallingState, CameraManager, CameraManagerState, CreateDeviceRequestPushProviderEnum, DebounceType, ErrorFromResponse, InputMediaDeviceManager, InputMediaDeviceManagerState, MicrophoneManager, MicrophoneManagerState, 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
13499
  //# sourceMappingURL=index.es.js.map