@stream-io/video-client 0.2.3 → 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 (71) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/index.browser.es.js +982 -675
  3. package/dist/index.browser.es.js.map +1 -1
  4. package/dist/index.cjs.js +984 -673
  5. package/dist/index.cjs.js.map +1 -1
  6. package/dist/index.es.js +982 -675
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/src/Call.d.ts +21 -9
  9. package/dist/src/StreamVideoClient.d.ts +3 -1
  10. package/dist/src/devices/CameraManager.d.ts +31 -0
  11. package/dist/src/devices/CameraManagerState.d.ts +28 -0
  12. package/dist/src/devices/InputMediaDeviceManager.d.ts +47 -0
  13. package/dist/src/devices/InputMediaDeviceManagerState.d.ts +69 -0
  14. package/dist/src/devices/MicrophoneManager.d.ts +19 -0
  15. package/dist/src/devices/MicrophoneManagerState.d.ts +4 -0
  16. package/dist/src/devices/__tests__/mocks.d.ts +13 -0
  17. package/dist/src/devices/index.d.ts +4 -0
  18. package/dist/src/events/call-permissions.d.ts +0 -5
  19. package/dist/src/events/call.d.ts +0 -6
  20. package/dist/src/events/index.d.ts +0 -6
  21. package/dist/src/rtc/Dispatcher.d.ts +2 -2
  22. package/dist/src/rtc/Publisher.d.ts +0 -1
  23. package/dist/src/store/CallState.d.ts +164 -89
  24. package/dist/src/types.d.ts +5 -7
  25. package/dist/version.d.ts +1 -1
  26. package/package.json +1 -1
  27. package/src/Call.ts +130 -44
  28. package/src/StreamVideoClient.ts +14 -17
  29. package/src/__tests__/StreamVideoClient.test.ts +3 -0
  30. package/src/devices/CameraManager.ts +73 -0
  31. package/src/devices/CameraManagerState.ts +61 -0
  32. package/src/devices/InputMediaDeviceManager.ts +121 -0
  33. package/src/devices/InputMediaDeviceManagerState.ts +111 -0
  34. package/src/devices/MicrophoneManager.ts +45 -0
  35. package/src/devices/MicrophoneManagerState.ts +9 -0
  36. package/src/devices/__tests__/CameraManager.test.ts +150 -0
  37. package/src/devices/__tests__/InputMediaDeviceManager.test.ts +159 -0
  38. package/src/devices/__tests__/MicrophoneManager.test.ts +103 -0
  39. package/src/devices/__tests__/mocks.ts +98 -0
  40. package/src/devices/index.ts +4 -0
  41. package/src/events/__tests__/call-permissions.test.ts +1 -61
  42. package/src/events/__tests__/call.test.ts +5 -50
  43. package/src/events/call-permissions.ts +0 -14
  44. package/src/events/call.ts +5 -16
  45. package/src/events/callEventHandlers.ts +2 -57
  46. package/src/events/index.ts +0 -6
  47. package/src/rtc/Dispatcher.ts +2 -2
  48. package/src/rtc/Publisher.ts +4 -6
  49. package/src/store/CallState.ts +475 -119
  50. package/src/store/__tests__/CallState.test.ts +447 -1
  51. package/src/types.ts +4 -8
  52. package/dist/src/events/__tests__/sessions.test.d.ts +0 -1
  53. package/dist/src/events/backstage.d.ts +0 -6
  54. package/dist/src/events/members.d.ts +0 -18
  55. package/dist/src/events/moderation.d.ts +0 -14
  56. package/dist/src/events/reactions.d.ts +0 -8
  57. package/dist/src/events/recording.d.ts +0 -18
  58. package/dist/src/events/sessions.d.ts +0 -26
  59. package/src/events/__tests__/backstage.test.ts +0 -15
  60. package/src/events/__tests__/members.test.ts +0 -135
  61. package/src/events/__tests__/recording.test.ts +0 -65
  62. package/src/events/__tests__/sessions.test.ts +0 -135
  63. package/src/events/backstage.ts +0 -15
  64. package/src/events/members.ts +0 -62
  65. package/src/events/moderation.ts +0 -35
  66. package/src/events/reactions.ts +0 -30
  67. package/src/events/recording.ts +0 -64
  68. package/src/events/sessions.ts +0 -102
  69. /package/dist/src/{events/__tests__/backstage.test.d.ts → devices/__tests__/CameraManager.test.d.ts} +0 -0
  70. /package/dist/src/{events/__tests__/members.test.d.ts → devices/__tests__/InputMediaDeviceManager.test.d.ts} +0 -0
  71. /package/dist/src/{events/__tests__/recording.test.d.ts → devices/__tests__/MicrophoneManager.test.d.ts} +0 -0
@@ -4,7 +4,7 @@ import { ServiceType, stackIntercept } from '@protobuf-ts/runtime-rpc';
4
4
  import axios, { AxiosHeaders } from 'axios';
5
5
  export { AxiosError } from 'axios';
6
6
  import { TwirpFetchTransport } from '@protobuf-ts/twirp-transport';
7
- import { ReplaySubject, BehaviorSubject, takeWhile, filter, pairwise, tap, debounce, timer, map as map$2, Observable, debounceTime, concatMap, from, shareReplay, merge, combineLatest } from 'rxjs';
7
+ import { ReplaySubject, BehaviorSubject, distinctUntilChanged as distinctUntilChanged$1, Observable, debounceTime, concatMap, from, shareReplay, merge, map as map$2, combineLatest, filter, pairwise, takeWhile, tap, debounce, timer } from 'rxjs';
8
8
  import * as SDP from 'sdp-transform';
9
9
  import WebSocket from 'isomorphic-ws';
10
10
  import { take, map as map$1, distinctUntilChanged } from 'rxjs/operators';
@@ -6520,8 +6520,8 @@ class Publisher {
6520
6520
  track.removeEventListener('ended', handleTrackEnded);
6521
6521
  });
6522
6522
  if (!transceiver) {
6523
- const metadata = this.state.metadata;
6524
- const targetResolution = metadata === null || metadata === void 0 ? void 0 : metadata.settings.video.target_resolution;
6523
+ const { settings } = this.state;
6524
+ const targetResolution = settings === null || settings === void 0 ? void 0 : settings.video.target_resolution;
6525
6525
  const videoEncodings = trackType === TrackType.VIDEO
6526
6526
  ? findOptimalVideoLayers(track, targetResolution)
6527
6527
  : undefined;
@@ -6799,8 +6799,8 @@ class Publisher {
6799
6799
  }
6800
6800
  return String(media.mid);
6801
6801
  };
6802
- const metadata = this.state.metadata;
6803
- const targetResolution = metadata === null || metadata === void 0 ? void 0 : metadata.settings.video.target_resolution;
6802
+ const { settings } = this.state;
6803
+ const targetResolution = settings === null || settings === void 0 ? void 0 : settings.video.target_resolution;
6804
6804
  return this.pc
6805
6805
  .getTransceivers()
6806
6806
  .filter((t) => t.direction === 'sendonly' && t.sender.track)
@@ -6893,7 +6893,6 @@ class Publisher {
6893
6893
  this.pc = this.createPeerConnection(connectionConfig);
6894
6894
  this.sfuClient = sfuClient;
6895
6895
  this.state = state;
6896
- this.dispatcher = dispatcher;
6897
6896
  this.isDtxEnabled = isDtxEnabled;
6898
6897
  this.isRedEnabled = isRedEnabled;
6899
6898
  this.preferredVideoCodec = preferredVideoCodec;
@@ -7521,17 +7520,6 @@ const retryable = (rpc, logger) => __awaiter(void 0, void 0, void 0, function* (
7521
7520
  return rpcCallResult;
7522
7521
  });
7523
7522
 
7524
- /**
7525
- * Watches for `call.live_started` events.
7526
- */
7527
- const watchCallLiveStarted = (state) => {
7528
- return function onCallLiveStarted(event) {
7529
- if (event.type !== 'call.live_started')
7530
- return;
7531
- state.setMetadata((metadata) => (Object.assign(Object.assign({}, metadata), { backstage: false })));
7532
- };
7533
- };
7534
-
7535
7523
  /**
7536
7524
  * Gets the current value of an observable, or undefined if the observable has
7537
7525
  * not emitted a value yet.
@@ -7974,71 +7962,29 @@ class CallState {
7974
7962
  *
7975
7963
  */
7976
7964
  constructor() {
7977
- /**
7978
- * The raw call metadata object, as defined on the backend.
7979
- *
7980
- * @internal
7981
- */
7982
- this.metadataSubject = new BehaviorSubject(undefined);
7983
- /**
7984
- * The list of members of the current call.
7985
- *
7986
- * @internal
7987
- */
7965
+ this.backstageSubject = new BehaviorSubject(false);
7966
+ this.blockedUserIdsSubject = new BehaviorSubject([]);
7967
+ this.createdAtSubject = new BehaviorSubject(new Date());
7968
+ this.endedAtSubject = new BehaviorSubject(undefined);
7969
+ this.startsAtSubject = new BehaviorSubject(undefined);
7970
+ this.updatedAtSubject = new BehaviorSubject(new Date());
7971
+ this.createdBySubject = new BehaviorSubject(undefined);
7972
+ this.customSubject = new BehaviorSubject({});
7973
+ this.egressSubject = new BehaviorSubject(undefined);
7974
+ this.ingressSubject = new BehaviorSubject(undefined);
7975
+ this.recordingSubject = new BehaviorSubject(false);
7976
+ this.sessionSubject = new BehaviorSubject(undefined);
7977
+ this.settingsSubject = new BehaviorSubject(undefined);
7978
+ this.transcribingSubject = new BehaviorSubject(false);
7979
+ this.endedBySubject = new BehaviorSubject(undefined);
7988
7980
  this.membersSubject = new BehaviorSubject([]);
7989
- /**
7990
- * The list of capabilities of the current user.
7991
- *
7992
- * @private
7993
- */
7994
7981
  this.ownCapabilitiesSubject = new BehaviorSubject([]);
7995
- /**
7996
- * The calling state.
7997
- *
7998
- * @internal
7999
- */
8000
7982
  this.callingStateSubject = new BehaviorSubject(CallingState.UNKNOWN);
8001
- /**
8002
- * The time the call session actually started.
8003
- *
8004
- * @internal
8005
- */
8006
7983
  this.startedAtSubject = new BehaviorSubject(undefined);
8007
- /**
8008
- * The server-side counted number of participants connected to the current call.
8009
- * This number includes the anonymous participants as well.
8010
- *
8011
- * @internal
8012
- */
8013
7984
  this.participantCountSubject = new BehaviorSubject(0);
8014
- /**
8015
- * The server-side counted number of anonymous participants connected to the current call.
8016
- * This number excludes the regular participants.
8017
- *
8018
- * @internal
8019
- */
8020
7985
  this.anonymousParticipantCountSubject = new BehaviorSubject(0);
8021
- /**
8022
- * All participants of the current call (including the logged-in user).
8023
- *
8024
- * @internal
8025
- */
8026
7986
  this.participantsSubject = new BehaviorSubject([]);
8027
- /**
8028
- * The latest stats report of the current call.
8029
- * When stats gathering is enabled, this observable will emit a new value
8030
- * at a regular (configurable) interval.
8031
- *
8032
- * Consumers of this observable can implement their own batching logic
8033
- * in case they want to show historical stat data.
8034
- *
8035
- * @internal
8036
- */
8037
7987
  this.callStatsReportSubject = new BehaviorSubject(undefined);
8038
- /**
8039
- * Emits a list of details about recordings performed for the current call.
8040
- */
8041
- this.callRecordingListSubject = new BehaviorSubject([]);
8042
7988
  /**
8043
7989
  * A list of comparators that are used to sort the participants.
8044
7990
  *
@@ -8121,15 +8067,6 @@ class CallState {
8121
8067
  this.setCallingState = (state) => {
8122
8068
  return this.setCurrentValue(this.callingStateSubject, state);
8123
8069
  };
8124
- /**
8125
- * Sets the list of call recordings.
8126
- *
8127
- * @internal
8128
- * @param recordings the list of call recordings.
8129
- */
8130
- this.setCallRecordingsList = (recordings) => {
8131
- return this.setCurrentValue(this.callRecordingListSubject, recordings);
8132
- };
8133
8070
  /**
8134
8071
  * Sets the call stats report.
8135
8072
  *
@@ -8139,16 +8076,6 @@ class CallState {
8139
8076
  this.setCallStatsReport = (report) => {
8140
8077
  return this.setCurrentValue(this.callStatsReportSubject, report);
8141
8078
  };
8142
- /**
8143
- * Sets the metadata of the current call.
8144
- *
8145
- * @internal
8146
- *
8147
- * @param metadata the metadata to set.
8148
- */
8149
- this.setMetadata = (metadata) => {
8150
- return this.setCurrentValue(this.metadataSubject, metadata);
8151
- };
8152
8079
  /**
8153
8080
  * Sets the members of the current call.
8154
8081
  *
@@ -8247,6 +8174,19 @@ class CallState {
8247
8174
  return p;
8248
8175
  }));
8249
8176
  };
8177
+ /**
8178
+ * Updates the call state with the data received from the server.
8179
+ *
8180
+ * @internal
8181
+ *
8182
+ * @param event the video event that our backend sent us.
8183
+ */
8184
+ this.updateFromEvent = (event) => {
8185
+ const update = this.eventHandlers[event.type];
8186
+ if (update) {
8187
+ update(event);
8188
+ }
8189
+ };
8250
8190
  /**
8251
8191
  * Updates the participant pinned state with server side pinning data.
8252
8192
  *
@@ -8275,25 +8215,174 @@ class CallState {
8275
8215
  return participant;
8276
8216
  }));
8277
8217
  };
8278
- this.logger = getLogger(['call-state']);
8218
+ /**
8219
+ * Updates the call state with the data received from the server.
8220
+ *
8221
+ * @internal
8222
+ *
8223
+ * @param call the call response from the server.
8224
+ */
8225
+ this.updateFromCallResponse = (call) => {
8226
+ this.setCurrentValue(this.backstageSubject, call.backstage);
8227
+ this.setCurrentValue(this.blockedUserIdsSubject, call.blocked_user_ids);
8228
+ this.setCurrentValue(this.createdAtSubject, new Date(call.created_at));
8229
+ this.setCurrentValue(this.updatedAtSubject, new Date(call.updated_at));
8230
+ this.setCurrentValue(this.startsAtSubject, call.starts_at ? new Date(call.starts_at) : undefined);
8231
+ this.setCurrentValue(this.endedAtSubject, call.ended_at ? new Date(call.ended_at) : undefined);
8232
+ this.setCurrentValue(this.createdBySubject, call.created_by);
8233
+ this.setCurrentValue(this.customSubject, call.custom);
8234
+ this.setCurrentValue(this.egressSubject, call.egress);
8235
+ this.setCurrentValue(this.ingressSubject, call.ingress);
8236
+ this.setCurrentValue(this.recordingSubject, call.recording);
8237
+ this.setCurrentValue(this.sessionSubject, call.session);
8238
+ this.setCurrentValue(this.settingsSubject, call.settings);
8239
+ this.setCurrentValue(this.transcribingSubject, call.transcribing);
8240
+ };
8241
+ this.updateFromMemberRemoved = (event) => {
8242
+ this.setCurrentValue(this.membersSubject, (members) => members.filter((m) => event.members.indexOf(m.user_id) === -1));
8243
+ };
8244
+ this.updateFromMemberAdded = (event) => {
8245
+ this.setCurrentValue(this.membersSubject, (members) => [
8246
+ ...members,
8247
+ ...event.members,
8248
+ ]);
8249
+ };
8250
+ this.updateFromBroadcastStopped = () => {
8251
+ this.setCurrentValue(this.egressSubject, (egress) => (Object.assign(Object.assign({}, egress), { broadcasting: false })));
8252
+ };
8253
+ this.updateFromBroadcastStarted = (event) => {
8254
+ this.setCurrentValue(this.egressSubject, (egress) => (Object.assign(Object.assign({}, egress), { broadcasting: true, hls: Object.assign(Object.assign({}, egress.hls), { playlist_url: event.hls_playlist_url }) })));
8255
+ };
8256
+ this.updateFromSessionParticipantLeft = (event) => {
8257
+ this.setCurrentValue(this.sessionSubject, (session) => {
8258
+ if (!session) {
8259
+ this.logger('warn', `Received call.session_participant_left event but no session is available.`, event);
8260
+ return session;
8261
+ }
8262
+ const { participants, participants_count_by_role } = session;
8263
+ const { user, user_session_id } = event.participant;
8264
+ return Object.assign(Object.assign({}, session), { participants: participants.filter((p) => p.user_session_id !== user_session_id), participants_count_by_role: Object.assign(Object.assign({}, participants_count_by_role), { [user.role]: Math.max(0, (participants_count_by_role[user.role] || 0) - 1) }) });
8265
+ });
8266
+ };
8267
+ this.updateFromSessionParticipantJoined = (event) => {
8268
+ this.setCurrentValue(this.sessionSubject, (session) => {
8269
+ if (!session) {
8270
+ this.logger('warn', `Received call.session_participant_joined event but no session is available.`, event);
8271
+ return session;
8272
+ }
8273
+ const { participants, participants_count_by_role } = session;
8274
+ const { user } = event.participant;
8275
+ return Object.assign(Object.assign({}, session), { participants: [...participants, event.participant], participants_count_by_role: Object.assign(Object.assign({}, participants_count_by_role), { [user.role]: (participants_count_by_role[user.role] || 0) + 1 }) });
8276
+ });
8277
+ };
8278
+ this.updateMembers = (event) => {
8279
+ this.setCurrentValue(this.membersSubject, (members) => members.map((member) => {
8280
+ const memberUpdate = event.members.find((m) => m.user_id === member.user_id);
8281
+ return memberUpdate ? memberUpdate : member;
8282
+ }));
8283
+ };
8284
+ this.updateParticipantReaction = (event) => {
8285
+ const { user, custom, type, emoji_code } = event.reaction;
8286
+ this.setParticipants((participants) => {
8287
+ return participants.map((p) => {
8288
+ // skip if the reaction is not for this participant
8289
+ if (p.userId !== user.id)
8290
+ return p;
8291
+ // update the participant with the new reaction
8292
+ return Object.assign(Object.assign({}, p), { reaction: {
8293
+ type,
8294
+ emoji_code,
8295
+ custom,
8296
+ } });
8297
+ });
8298
+ });
8299
+ };
8300
+ this.unblockUser = (event) => {
8301
+ this.setCurrentValue(this.blockedUserIdsSubject, (current) => {
8302
+ if (!current)
8303
+ return current;
8304
+ return current.filter((id) => id !== event.user.id);
8305
+ });
8306
+ };
8307
+ this.blockUser = (event) => {
8308
+ this.setCurrentValue(this.blockedUserIdsSubject, (current) => [
8309
+ ...(current || []),
8310
+ event.user.id,
8311
+ ]);
8312
+ };
8313
+ this.updateOwnCapabilities = (event) => {
8314
+ var _a;
8315
+ if (event.user.id === ((_a = this.localParticipant) === null || _a === void 0 ? void 0 : _a.userId)) {
8316
+ this.setCurrentValue(this.ownCapabilitiesSubject, event.own_capabilities);
8317
+ }
8318
+ };
8319
+ this.logger = getLogger(['CallState']);
8279
8320
  this.participants$ = this.participantsSubject.pipe(map$1((ps) => ps.sort(this.sortParticipantsBy)));
8280
8321
  this.localParticipant$ = this.participants$.pipe(map$1((participants) => participants.find(isStreamVideoLocalParticipant)));
8281
8322
  this.remoteParticipants$ = this.participants$.pipe(map$1((participants) => participants.filter((p) => !p.isLocalParticipant)));
8282
8323
  this.pinnedParticipants$ = this.participants$.pipe(map$1((participants) => participants.filter((p) => !!p.pin)));
8283
8324
  this.dominantSpeaker$ = this.participants$.pipe(map$1((participants) => participants.find((p) => p.isDominantSpeaker)));
8284
- this.hasOngoingScreenShare$ = this.participants$.pipe(map$1((participants) => {
8285
- return participants.some((p) => p.publishedTracks.includes(TrackType.SCREEN_SHARE));
8286
- }), distinctUntilChanged());
8325
+ this.hasOngoingScreenShare$ = this.participants$.pipe(map$1((participants) => participants.some((p) => p.publishedTracks.includes(TrackType.SCREEN_SHARE))), distinctUntilChanged());
8287
8326
  this.startedAt$ = this.startedAtSubject.asObservable();
8288
8327
  this.participantCount$ = this.participantCountSubject.asObservable();
8289
8328
  this.anonymousParticipantCount$ =
8290
8329
  this.anonymousParticipantCountSubject.asObservable();
8291
8330
  this.callStatsReport$ = this.callStatsReportSubject.asObservable();
8292
- this.callRecordingList$ = this.callRecordingListSubject.asObservable();
8293
- this.metadata$ = this.metadataSubject.asObservable();
8294
8331
  this.members$ = this.membersSubject.asObservable();
8295
8332
  this.ownCapabilities$ = this.ownCapabilitiesSubject.asObservable();
8296
8333
  this.callingState$ = this.callingStateSubject.asObservable();
8334
+ this.backstage$ = this.backstageSubject.asObservable();
8335
+ this.blockedUserIds$ = this.blockedUserIdsSubject.asObservable();
8336
+ this.createdAt$ = this.createdAtSubject.asObservable();
8337
+ this.endedAt$ = this.endedAtSubject.asObservable();
8338
+ this.startsAt$ = this.startsAtSubject.asObservable();
8339
+ this.updatedAt$ = this.updatedAtSubject.asObservable();
8340
+ this.createdBy$ = this.createdBySubject.asObservable();
8341
+ this.custom$ = this.customSubject.asObservable();
8342
+ this.egress$ = this.egressSubject.asObservable();
8343
+ this.ingress$ = this.ingressSubject.asObservable();
8344
+ this.recording$ = this.recordingSubject.asObservable();
8345
+ this.session$ = this.sessionSubject.asObservable();
8346
+ this.settings$ = this.settingsSubject.asObservable();
8347
+ this.transcribing$ = this.transcribingSubject.asObservable();
8348
+ this.endedBy$ = this.endedBySubject.asObservable();
8349
+ this.eventHandlers = {
8350
+ // these events are not updating the call state:
8351
+ 'call.permission_request': undefined,
8352
+ 'call.user_muted': undefined,
8353
+ 'connection.error': undefined,
8354
+ 'connection.ok': undefined,
8355
+ 'health.check': undefined,
8356
+ custom: undefined,
8357
+ // events that update call state:
8358
+ 'call.accepted': (e) => this.updateFromCallResponse(e.call),
8359
+ 'call.created': (e) => this.updateFromCallResponse(e.call),
8360
+ 'call.notification': (e) => this.updateFromCallResponse(e.call),
8361
+ 'call.rejected': (e) => this.updateFromCallResponse(e.call),
8362
+ 'call.ring': (e) => this.updateFromCallResponse(e.call),
8363
+ 'call.live_started': (e) => this.updateFromCallResponse(e.call),
8364
+ 'call.updated': (e) => this.updateFromCallResponse(e.call),
8365
+ 'call.session_started': (e) => this.updateFromCallResponse(e.call),
8366
+ 'call.session_ended': (e) => this.updateFromCallResponse(e.call),
8367
+ 'call.ended': (e) => {
8368
+ this.updateFromCallResponse(e.call);
8369
+ this.setCurrentValue(this.endedBySubject, e.user);
8370
+ },
8371
+ 'call.recording_started': () => this.setCurrentValue(this.recordingSubject, true),
8372
+ 'call.recording_stopped': () => this.setCurrentValue(this.recordingSubject, false),
8373
+ 'call.broadcasting_started': this.updateFromBroadcastStarted,
8374
+ 'call.broadcasting_stopped': this.updateFromBroadcastStopped,
8375
+ 'call.session_participant_joined': this.updateFromSessionParticipantJoined,
8376
+ 'call.session_participant_left': this.updateFromSessionParticipantLeft,
8377
+ 'call.blocked_user': this.blockUser,
8378
+ 'call.unblocked_user': this.unblockUser,
8379
+ 'call.permissions_updated': this.updateOwnCapabilities,
8380
+ 'call.member_added': this.updateFromMemberAdded,
8381
+ 'call.member_removed': this.updateFromMemberRemoved,
8382
+ 'call.member_updated': this.updateMembers,
8383
+ 'call.member_updated_permission': this.updateMembers,
8384
+ 'call.reaction_new': this.updateParticipantReaction,
8385
+ };
8297
8386
  }
8298
8387
  /**
8299
8388
  * The server-side counted number of participants connected to the current call.
@@ -8358,24 +8447,12 @@ class CallState {
8358
8447
  get callingState() {
8359
8448
  return this.getCurrentValue(this.callingState$);
8360
8449
  }
8361
- /**
8362
- * The list of call recordings.
8363
- */
8364
- get callRecordingsList() {
8365
- return this.getCurrentValue(this.callRecordingList$);
8366
- }
8367
8450
  /**
8368
8451
  * The call stats report.
8369
8452
  */
8370
8453
  get callStatsReport() {
8371
8454
  return this.getCurrentValue(this.callStatsReport$);
8372
8455
  }
8373
- /**
8374
- * The metadata of the current call.
8375
- */
8376
- get metadata() {
8377
- return this.getCurrentValue(this.metadata$);
8378
- }
8379
8456
  /**
8380
8457
  * The members of the current call.
8381
8458
  */
@@ -8388,6 +8465,96 @@ class CallState {
8388
8465
  get ownCapabilities() {
8389
8466
  return this.getCurrentValue(this.ownCapabilities$);
8390
8467
  }
8468
+ /**
8469
+ * The backstage state.
8470
+ */
8471
+ get backstage() {
8472
+ return this.getCurrentValue(this.backstage$);
8473
+ }
8474
+ /**
8475
+ * Will provide the list of blocked user IDs.
8476
+ */
8477
+ get blockedUserIds() {
8478
+ return this.getCurrentValue(this.blockedUserIds$);
8479
+ }
8480
+ /**
8481
+ * Will provide the time when this call has been created.
8482
+ */
8483
+ get createdAt() {
8484
+ return this.getCurrentValue(this.createdAt$);
8485
+ }
8486
+ /**
8487
+ * Will provide the time when this call has been ended.
8488
+ */
8489
+ get endedAt() {
8490
+ return this.getCurrentValue(this.endedAt$);
8491
+ }
8492
+ /**
8493
+ * Will provide the time when this call has been scheduled to start.
8494
+ */
8495
+ get startsAt() {
8496
+ return this.getCurrentValue(this.startsAt$);
8497
+ }
8498
+ /**
8499
+ * Will provide the time when this call has been updated.
8500
+ */
8501
+ get updatedAt() {
8502
+ return this.getCurrentValue(this.updatedAt$);
8503
+ }
8504
+ /**
8505
+ * Will provide the user who created this call.
8506
+ */
8507
+ get createdBy() {
8508
+ return this.getCurrentValue(this.createdBy$);
8509
+ }
8510
+ /**
8511
+ * Will provide the custom data of this call.
8512
+ */
8513
+ get custom() {
8514
+ return this.getCurrentValue(this.custom$);
8515
+ }
8516
+ /**
8517
+ * Will provide the egress data of this call.
8518
+ */
8519
+ get egress() {
8520
+ return this.getCurrentValue(this.egress$);
8521
+ }
8522
+ /**
8523
+ * Will provide the ingress data of this call.
8524
+ */
8525
+ get ingress() {
8526
+ return this.getCurrentValue(this.ingress$);
8527
+ }
8528
+ /**
8529
+ * Will provide the recording state of this call.
8530
+ */
8531
+ get recording() {
8532
+ return this.getCurrentValue(this.recording$);
8533
+ }
8534
+ /**
8535
+ * Will provide the session data of this call.
8536
+ */
8537
+ get session() {
8538
+ return this.getCurrentValue(this.session$);
8539
+ }
8540
+ /**
8541
+ * Will provide the settings of this call.
8542
+ */
8543
+ get settings() {
8544
+ return this.getCurrentValue(this.settings$);
8545
+ }
8546
+ /**
8547
+ * Will provide the transcribing state of this call.
8548
+ */
8549
+ get transcribing() {
8550
+ return this.getCurrentValue(this.transcribing$);
8551
+ }
8552
+ /**
8553
+ * Will provide the user who ended this call.
8554
+ */
8555
+ get endedBy() {
8556
+ return this.getCurrentValue(this.endedBy$);
8557
+ }
8391
8558
  }
8392
8559
 
8393
8560
  /**
@@ -8459,40 +8626,16 @@ const watchCallEnded = (call) => {
8459
8626
  return __awaiter(this, void 0, void 0, function* () {
8460
8627
  if (event.type !== 'call.ended')
8461
8628
  return;
8462
- if (call.state.callingState === CallingState.RINGING ||
8463
- call.state.callingState === CallingState.JOINED ||
8464
- call.state.callingState === CallingState.JOINING) {
8465
- call.state.setMetadata(event.call);
8629
+ const { callingState } = call.state;
8630
+ if (callingState === CallingState.RINGING ||
8631
+ callingState === CallingState.JOINED ||
8632
+ callingState === CallingState.JOINING) {
8466
8633
  yield call.leave();
8467
8634
  }
8468
8635
  });
8469
8636
  };
8470
8637
  };
8471
- /**
8472
- * An event handler which listens to `call.updated` events
8473
- * and updates the given call state accordingly.
8474
- */
8475
- const watchCallUpdated = (state) => {
8476
- return function onCallUpdated(event) {
8477
- if (event.type !== 'call.updated')
8478
- return;
8479
- state.setMetadata(event.call);
8480
- };
8481
- };
8482
8638
 
8483
- /**
8484
- * Event handler that watches for `call.permissions_updated` events
8485
- */
8486
- const watchCallPermissionsUpdated = (state) => {
8487
- return function onCallPermissionsUpdated(event) {
8488
- if (event.type !== 'call.permissions_updated')
8489
- return;
8490
- const { localParticipant } = state;
8491
- if (event.user.id === (localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.userId)) {
8492
- state.setOwnCapabilities(event.own_capabilities);
8493
- }
8494
- };
8495
- };
8496
8639
  /**
8497
8640
  * Event handler that watches for `callGrantsUpdated` events.
8498
8641
  *
@@ -8606,57 +8749,6 @@ const watchPinsUpdated = (state) => {
8606
8749
  };
8607
8750
  };
8608
8751
 
8609
- /**
8610
- * Watches for `call.member_added` events.
8611
- */
8612
- const watchCallMemberAdded = (state) => {
8613
- return function onCallMemberAdded(event) {
8614
- if (event.type !== 'call.member_added')
8615
- return;
8616
- state.setMembers((members) => [...members, ...event.members]);
8617
- };
8618
- };
8619
- /**
8620
- * Watches for `call.member_removed` events.
8621
- */
8622
- const watchCallMemberRemoved = (state) => {
8623
- return function onCallMemberRemoved(event) {
8624
- if (event.type !== 'call.member_removed')
8625
- return;
8626
- state.setMembers((members) => members.filter((m) => event.members.indexOf(m.user_id) === -1));
8627
- };
8628
- };
8629
- /**
8630
- * Watches for `call.member_updated_permission` events.
8631
- */
8632
- const watchCallMemberUpdatedPermission = (state) => {
8633
- return function onCallMemberUpdated(event) {
8634
- if (event.type !== 'call.member_updated_permission')
8635
- return;
8636
- state.setMembers((members) => members.map((member) => {
8637
- const memberUpdate = event.members.find((m) => m.user_id === member.user_id);
8638
- if (memberUpdate) {
8639
- member.user.role = memberUpdate.role;
8640
- member = Object.assign({}, member);
8641
- }
8642
- return member;
8643
- }));
8644
- };
8645
- };
8646
- /**
8647
- * Watches for `call.member_updated` events.
8648
- */
8649
- const watchCallMemberUpdated = (state) => {
8650
- return function onCallMemberUpdated(event) {
8651
- if (event.type !== 'call.member_updated')
8652
- return;
8653
- state.setMembers((members) => members.map((member) => {
8654
- const memberUpdate = event.members.find((m) => m.user_id === member.user_id);
8655
- return memberUpdate ? memberUpdate : member;
8656
- }));
8657
- };
8658
- };
8659
-
8660
8752
  /**
8661
8753
  * An event responder which handles the `participantJoined` event.
8662
8754
  */
@@ -8738,74 +8830,6 @@ const watchTrackUnpublished = (state) => {
8738
8830
  };
8739
8831
  const unique = (v, i, arr) => arr.indexOf(v) === i;
8740
8832
 
8741
- /**
8742
- * Watches the delivery of CallReactionEvent.
8743
- *
8744
- * @param state the state store to update.
8745
- */
8746
- const watchNewReactions = (state) => {
8747
- return function onNewReactions(event) {
8748
- if (event.type !== 'call.reaction_new')
8749
- return;
8750
- const { reaction } = event;
8751
- const { user, custom, type, emoji_code } = reaction;
8752
- state.setParticipants((participants) => {
8753
- return participants.map((p) => {
8754
- // skip if the reaction is not for this participant
8755
- if (p.userId !== user.id)
8756
- return p;
8757
- // update the participant with the new reaction
8758
- return Object.assign(Object.assign({}, p), { reaction: {
8759
- type,
8760
- emoji_code,
8761
- custom,
8762
- } });
8763
- });
8764
- });
8765
- };
8766
- };
8767
-
8768
- /**
8769
- * Watches for `call.recording_started` events.
8770
- */
8771
- const watchCallRecordingStarted = (state) => {
8772
- return function onCallRecordingStarted(event) {
8773
- if (event.type !== 'call.recording_started')
8774
- return;
8775
- state.setMetadata((metadata) => (Object.assign(Object.assign({}, metadata), { recording: true })));
8776
- };
8777
- };
8778
- /**
8779
- * Watches for `call.recording_stopped` events.
8780
- */
8781
- const watchCallRecordingStopped = (state) => {
8782
- return function onCallRecordingStopped(event) {
8783
- if (event.type !== 'call.recording_stopped')
8784
- return;
8785
- state.setMetadata((metadata) => (Object.assign(Object.assign({}, metadata), { recording: false })));
8786
- };
8787
- };
8788
- /**
8789
- * Watches for `call.broadcasting_started` events.
8790
- */
8791
- const watchCallBroadcastingStarted = (state) => {
8792
- return function onCallBroadcastingStarted(event) {
8793
- if (event.type !== 'call.broadcasting_started')
8794
- return;
8795
- state.setMetadata((metadata) => (Object.assign(Object.assign({}, metadata), { egress: Object.assign(Object.assign({}, metadata.egress), { broadcasting: true, hls: Object.assign(Object.assign({}, metadata.egress.hls), { playlist_url: event.hls_playlist_url }) }) })));
8796
- };
8797
- };
8798
- /**
8799
- * Watches for `call.broadcasting_stopped` events.
8800
- */
8801
- const watchCallBroadcastingStopped = (state) => {
8802
- return function onCallBroadcastingStopped(event) {
8803
- if (event.type !== 'call.broadcasting_stopped')
8804
- return;
8805
- state.setMetadata((metadata) => (Object.assign(Object.assign({}, metadata), { egress: Object.assign(Object.assign({}, metadata.egress), { broadcasting: false }) })));
8806
- };
8807
- };
8808
-
8809
8833
  /**
8810
8834
  * Watches for `dominantSpeakerChanged` events.
8811
8835
  */
@@ -8848,98 +8872,6 @@ const watchAudioLevelChanged = (dispatcher, state) => {
8848
8872
  });
8849
8873
  };
8850
8874
 
8851
- /**
8852
- * Watch for call.session_started events and update the call metadata.
8853
- *
8854
- * @param state the call state.
8855
- */
8856
- const watchCallSessionStarted = (state) => {
8857
- return function onCallSessionStarted(event) {
8858
- if (event.type !== 'call.session_started')
8859
- return;
8860
- state.setMetadata(event.call);
8861
- };
8862
- };
8863
- /**
8864
- * Watch for call.session_ended events and update the call metadata.
8865
- *
8866
- * @param state the call state.
8867
- */
8868
- const watchCallSessionEnded = (state) => {
8869
- return function onCallSessionEnded(event) {
8870
- if (event.type !== 'call.session_ended')
8871
- return;
8872
- state.setMetadata(event.call);
8873
- };
8874
- };
8875
- /**
8876
- * Watch for call.session_participant_joined events and update the call metadata.
8877
- *
8878
- * @param state the call state.
8879
- */
8880
- const watchCallSessionParticipantJoined = (state) => {
8881
- return function onCallParticipantJoined(event) {
8882
- if (event.type !== 'call.session_participant_joined')
8883
- return;
8884
- const { participant } = event;
8885
- state.setMetadata((metadata) => {
8886
- if (!metadata || !metadata.session) {
8887
- state.logger('warn', `Received call.session_participant_joined event but the metadata structure is invalid.`, event);
8888
- return metadata;
8889
- }
8890
- const { session } = metadata;
8891
- const { participants, participants_count_by_role } = session;
8892
- const { user } = participant;
8893
- return Object.assign(Object.assign({}, metadata), { session: Object.assign(Object.assign({}, session), { participants: [...participants, participant], participants_count_by_role: Object.assign(Object.assign({}, participants_count_by_role), { [user.role]: (participants_count_by_role[user.role] || 0) + 1 }) }) });
8894
- });
8895
- };
8896
- };
8897
- /**
8898
- * Watch for call.session_participant_left events and update the call metadata.
8899
- *
8900
- * @param state the call state.
8901
- */
8902
- const watchCallSessionParticipantLeft = (state) => {
8903
- return function onCallParticipantLeft(event) {
8904
- if (event.type !== 'call.session_participant_left')
8905
- return;
8906
- const { user, user_session_id } = event.participant;
8907
- state.setMetadata((metadata) => {
8908
- if (!metadata || !metadata.session) {
8909
- state.logger('warn', `Received call.session_participant_left event but the metadata structure is invalid.`, event);
8910
- return metadata;
8911
- }
8912
- const { session } = metadata;
8913
- const { participants, participants_count_by_role } = session;
8914
- return Object.assign(Object.assign({}, metadata), { session: Object.assign(Object.assign({}, session), { participants: participants.filter((p) => p.user_session_id !== user_session_id), participants_count_by_role: Object.assign(Object.assign({}, participants_count_by_role), { [user.role]: Math.max(0, (participants_count_by_role[user.role] || 0) - 1) }) }) });
8915
- });
8916
- };
8917
- };
8918
-
8919
- /**
8920
- * Event handler that watches for `call.blocked_user` events,
8921
- * updates the call store `blocked_user_ids` property by adding
8922
- * `event.user_id` to the list
8923
- */
8924
- const watchBlockedUser = (state) => (event) => {
8925
- if (event.type !== 'call.blocked_user')
8926
- return;
8927
- state.setMetadata((metadata) => (Object.assign(Object.assign({}, metadata), { blocked_user_ids: [...((metadata === null || metadata === void 0 ? void 0 : metadata.blocked_user_ids) || []), event.user.id] })));
8928
- };
8929
- /**
8930
- * Event handler that watches for `call.unblocked_user` events,
8931
- * updates the call store `blocked_user_ids` property by
8932
- * removing `event.user_id` from the list
8933
- */
8934
- const watchUnblockedUser = (state) => (event) => {
8935
- if (event.type !== 'call.unblocked_user')
8936
- return;
8937
- state.setMetadata((metadata) => {
8938
- const blocked_user_ids = ((metadata === null || metadata === void 0 ? void 0 : metadata.blocked_user_ids) || []).filter((userId) => event.user.id !== userId);
8939
- return Object.assign(Object.assign({}, metadata), { blocked_user_ids });
8940
- });
8941
- };
8942
-
8943
8875
  /**
8944
8876
  * Registers the default event handlers for a call during its lifecycle.
8945
8877
  *
@@ -8948,29 +8880,8 @@ const watchUnblockedUser = (state) => (event) => {
8948
8880
  * @param dispatcher the dispatcher.
8949
8881
  */
8950
8882
  const registerEventHandlers = (call, state, dispatcher) => {
8951
- const coordinatorEvents = {
8952
- 'call.blocked_user': watchBlockedUser(state),
8953
- 'call.broadcasting_started': watchCallBroadcastingStarted(state),
8954
- 'call.broadcasting_stopped': watchCallBroadcastingStopped(state),
8955
- 'call.ended': watchCallEnded(call),
8956
- 'call.live_started': watchCallLiveStarted(state),
8957
- 'call.member_added': watchCallMemberAdded(state),
8958
- 'call.member_removed': watchCallMemberRemoved(state),
8959
- 'call.member_updated': watchCallMemberUpdated(state),
8960
- 'call.member_updated_permission': watchCallMemberUpdatedPermission(state),
8961
- 'call.permissions_updated': watchCallPermissionsUpdated(state),
8962
- 'call.reaction_new': watchNewReactions(state),
8963
- 'call.recording_started': watchCallRecordingStarted(state),
8964
- 'call.recording_stopped': watchCallRecordingStopped(state),
8965
- 'call.session_started': watchCallSessionStarted(state),
8966
- 'call.session_ended': watchCallSessionEnded(state),
8967
- 'call.session_participant_joined': watchCallSessionParticipantJoined(state),
8968
- 'call.session_participant_left': watchCallSessionParticipantLeft(state),
8969
- 'call.unblocked_user': watchUnblockedUser(state),
8970
- 'call.updated': watchCallUpdated(state),
8971
- 'call.user_muted': () => console.log('call.user_muted received'),
8972
- };
8973
8883
  const eventHandlers = [
8884
+ call.on('call.ended', watchCallEnded(call)),
8974
8885
  watchLiveEnded(dispatcher, call),
8975
8886
  watchSfuErrorReports(dispatcher),
8976
8887
  watchChangePublishQuality(dispatcher, call),
@@ -8985,10 +8896,6 @@ const registerEventHandlers = (call, state, dispatcher) => {
8985
8896
  call.on('callGrantsUpdated', watchCallGrantsUpdated(state)),
8986
8897
  call.on('pinsUpdated', watchPinsUpdated(state)),
8987
8898
  ];
8988
- Object.keys(coordinatorEvents).forEach((event) => {
8989
- const eventName = event;
8990
- eventHandlers.push(call.on(eventName, coordinatorEvents[eventName]));
8991
- });
8992
8899
  if (call.ringing) {
8993
8900
  // these events are only relevant when the call is ringing
8994
8901
  eventHandlers.push(registerRingingCallEventHandlers(call));
@@ -9607,7 +9514,592 @@ const getClientDetails = () => {
9607
9514
  };
9608
9515
  };
9609
9516
 
9610
- /**
9517
+ class InputMediaDeviceManagerState {
9518
+ constructor() {
9519
+ this.statusSubject = new BehaviorSubject(undefined);
9520
+ this.mediaStreamSubject = new BehaviorSubject(undefined);
9521
+ this.selectedDeviceSubject = new BehaviorSubject(undefined);
9522
+ /**
9523
+ * Gets the current value of an observable, or undefined if the observable has
9524
+ * not emitted a value yet.
9525
+ *
9526
+ * @param observable$ the observable to get the value from.
9527
+ */
9528
+ this.getCurrentValue = getCurrentValue;
9529
+ /**
9530
+ * Updates the value of the provided Subject.
9531
+ * An `update` can either be a new value or a function which takes
9532
+ * the current value and returns a new value.
9533
+ *
9534
+ * @internal
9535
+ *
9536
+ * @param subject the subject to update.
9537
+ * @param update the update to apply to the subject.
9538
+ * @return the updated value.
9539
+ */
9540
+ this.setCurrentValue = setCurrentValue;
9541
+ this.mediaStream$ = this.mediaStreamSubject.asObservable();
9542
+ this.selectedDevice$ = this.selectedDeviceSubject
9543
+ .asObservable()
9544
+ .pipe(distinctUntilChanged$1());
9545
+ this.status$ = this.statusSubject.asObservable();
9546
+ }
9547
+ /**
9548
+ * The device status
9549
+ */
9550
+ get status() {
9551
+ return this.getCurrentValue(this.status$);
9552
+ }
9553
+ /**
9554
+ * The currently selected device
9555
+ */
9556
+ get selectedDevice() {
9557
+ return this.getCurrentValue(this.selectedDevice$);
9558
+ }
9559
+ /**
9560
+ * The current media stream, or `undefined` if the device is currently disabled.
9561
+ */
9562
+ get mediaStream() {
9563
+ return this.getCurrentValue(this.mediaStream$);
9564
+ }
9565
+ /**
9566
+ * @internal
9567
+ * @param status
9568
+ */
9569
+ setStatus(status) {
9570
+ this.setCurrentValue(this.statusSubject, status);
9571
+ }
9572
+ /**
9573
+ * @internal
9574
+ * @param stream
9575
+ */
9576
+ setMediaStream(stream) {
9577
+ this.setCurrentValue(this.mediaStreamSubject, stream);
9578
+ if (stream) {
9579
+ this.setDevice(this.getDeviceIdFromStream(stream));
9580
+ }
9581
+ }
9582
+ /**
9583
+ * @internal
9584
+ * @param stream
9585
+ */
9586
+ setDevice(deviceId) {
9587
+ this.setCurrentValue(this.selectedDeviceSubject, deviceId);
9588
+ }
9589
+ }
9590
+
9591
+ class CameraManagerState extends InputMediaDeviceManagerState {
9592
+ constructor() {
9593
+ super();
9594
+ this.directionSubject = new BehaviorSubject(undefined);
9595
+ this.direction$ = this.directionSubject
9596
+ .asObservable()
9597
+ .pipe(distinctUntilChanged$1());
9598
+ }
9599
+ /**
9600
+ * The preferred camera direction
9601
+ * front - means the camera facing the user
9602
+ * back - means the camera facing the environment
9603
+ */
9604
+ get direction() {
9605
+ return this.getCurrentValue(this.direction$);
9606
+ }
9607
+ /**
9608
+ * @internal
9609
+ */
9610
+ setDirection(direction) {
9611
+ this.setCurrentValue(this.directionSubject, direction);
9612
+ }
9613
+ /**
9614
+ * @internal
9615
+ */
9616
+ setMediaStream(stream) {
9617
+ var _a;
9618
+ super.setMediaStream(stream);
9619
+ if (stream) {
9620
+ // RN getSettings() doesn't return facingMode, so we don't verify camera direction
9621
+ const direction = isReactNative()
9622
+ ? this.direction
9623
+ : ((_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().facingMode) === 'environment'
9624
+ ? 'back'
9625
+ : 'front';
9626
+ this.setDirection(direction);
9627
+ }
9628
+ }
9629
+ getDeviceIdFromStream(stream) {
9630
+ var _a;
9631
+ return (_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
9632
+ }
9633
+ }
9634
+
9635
+ const getDevices = (constraints) => {
9636
+ return new Observable((subscriber) => {
9637
+ navigator.mediaDevices
9638
+ .getUserMedia(constraints)
9639
+ .then((media) => {
9640
+ // in Firefox, devices can be enumerated after userMedia is requested
9641
+ // and permissions granted. Otherwise, device labels are empty
9642
+ navigator.mediaDevices.enumerateDevices().then((devices) => {
9643
+ subscriber.next(devices);
9644
+ // If we stop the tracks before enumerateDevices -> the labels won't show up in Firefox
9645
+ disposeOfMediaStream(media);
9646
+ subscriber.complete();
9647
+ });
9648
+ })
9649
+ .catch((error) => {
9650
+ getLogger(['devices'])('error', 'Failed to get devices', error);
9651
+ subscriber.error(error);
9652
+ });
9653
+ });
9654
+ };
9655
+ /**
9656
+ * [Tells if the browser supports audio output change on 'audio' elements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId).
9657
+ *
9658
+ * @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.
9659
+ */
9660
+ const checkIfAudioOutputChangeSupported = () => {
9661
+ if (typeof document === 'undefined')
9662
+ return false;
9663
+ const element = document.createElement('audio');
9664
+ return element.sinkId !== undefined;
9665
+ };
9666
+ /**
9667
+ * The default constraints used to request audio devices.
9668
+ */
9669
+ const audioDeviceConstraints = {
9670
+ audio: {
9671
+ autoGainControl: true,
9672
+ noiseSuppression: true,
9673
+ echoCancellation: true,
9674
+ },
9675
+ };
9676
+ /**
9677
+ * The default constraints used to request video devices.
9678
+ */
9679
+ const videoDeviceConstraints = {
9680
+ video: {
9681
+ width: 1280,
9682
+ height: 720,
9683
+ },
9684
+ };
9685
+ // 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
9686
+ const deviceChange$ = new Observable((subscriber) => {
9687
+ var _a, _b;
9688
+ const deviceChangeHandler = () => subscriber.next();
9689
+ (_b = (_a = navigator.mediaDevices).addEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
9690
+ return () => {
9691
+ var _a, _b;
9692
+ return (_b = (_a = navigator.mediaDevices).removeEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
9693
+ };
9694
+ }).pipe(debounceTime(500), concatMap(() => from(navigator.mediaDevices.enumerateDevices())), shareReplay(1));
9695
+ const audioDevices$ = merge(getDevices(audioDeviceConstraints), deviceChange$).pipe(shareReplay(1));
9696
+ const videoDevices$ = merge(getDevices(videoDeviceConstraints), deviceChange$).pipe(shareReplay(1));
9697
+ /**
9698
+ * 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.
9699
+ *
9700
+ * @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.
9701
+ * @returns
9702
+ */
9703
+ const getAudioDevices = () => audioDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'audioinput')));
9704
+ /**
9705
+ * 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.
9706
+ *
9707
+ * @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.
9708
+ * @returns
9709
+ */
9710
+ const getVideoDevices = () => videoDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'videoinput' && d.deviceId.length)));
9711
+ /**
9712
+ * 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)
9713
+ *
9714
+ * @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.
9715
+ * @returns
9716
+ */
9717
+ const getAudioOutputDevices = () => {
9718
+ return audioDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'audiooutput')));
9719
+ };
9720
+ const getStream = (constraints) => __awaiter(void 0, void 0, void 0, function* () {
9721
+ try {
9722
+ return yield navigator.mediaDevices.getUserMedia(constraints);
9723
+ }
9724
+ catch (e) {
9725
+ getLogger(['devices'])('error', `Failed get user media`, {
9726
+ error: e,
9727
+ constraints: constraints,
9728
+ });
9729
+ throw e;
9730
+ }
9731
+ });
9732
+ /**
9733
+ * Returns an audio media stream that fulfills the given constraints.
9734
+ * If no constraints are provided, it uses the browser's default ones.
9735
+ *
9736
+ * @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.
9737
+ * @param trackConstraints the constraints to use when requesting the stream.
9738
+ * @returns the new `MediaStream` fulfilling the given constraints.
9739
+ */
9740
+ const getAudioStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
9741
+ const constraints = {
9742
+ audio: Object.assign(Object.assign({}, audioDeviceConstraints.audio), trackConstraints),
9743
+ };
9744
+ return getStream(constraints);
9745
+ });
9746
+ /**
9747
+ * Returns a video media stream that fulfills the given constraints.
9748
+ * If no constraints are provided, it uses the browser's default ones.
9749
+ *
9750
+ * @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.
9751
+ * @param trackConstraints the constraints to use when requesting the stream.
9752
+ * @returns a new `MediaStream` fulfilling the given constraints.
9753
+ */
9754
+ const getVideoStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
9755
+ const constraints = {
9756
+ video: Object.assign(Object.assign({}, videoDeviceConstraints.video), trackConstraints),
9757
+ };
9758
+ return getStream(constraints);
9759
+ });
9760
+ /**
9761
+ * Prompts the user for a permission to share a screen.
9762
+ * If the user grants the permission, a screen sharing stream is returned. Throws otherwise.
9763
+ *
9764
+ * The callers of this API are responsible to handle the possible errors.
9765
+ *
9766
+ * @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.
9767
+ *
9768
+ * @param options any additional options to pass to the [`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) API.
9769
+ */
9770
+ const getScreenShareStream = (options) => __awaiter(void 0, void 0, void 0, function* () {
9771
+ try {
9772
+ return yield navigator.mediaDevices.getDisplayMedia(Object.assign({ video: true, audio: false }, options));
9773
+ }
9774
+ catch (e) {
9775
+ getLogger(['devices'])('error', 'Failed to get screen share stream', e);
9776
+ throw e;
9777
+ }
9778
+ });
9779
+ const watchForDisconnectedDevice = (kind, deviceId$) => {
9780
+ let devices$;
9781
+ switch (kind) {
9782
+ case 'audioinput':
9783
+ devices$ = getAudioDevices();
9784
+ break;
9785
+ case 'videoinput':
9786
+ devices$ = getVideoDevices();
9787
+ break;
9788
+ case 'audiooutput':
9789
+ devices$ = getAudioOutputDevices();
9790
+ break;
9791
+ }
9792
+ return combineLatest([devices$, deviceId$]).pipe(filter(([devices, deviceId]) => !!deviceId && !devices.find((d) => d.deviceId === deviceId)), map$2(() => true));
9793
+ };
9794
+ /**
9795
+ * Notifies the subscriber if a given 'audioinput' device is disconnected
9796
+ *
9797
+ * @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.
9798
+ * @param deviceId$ an Observable that specifies which device to watch for
9799
+ * @returns
9800
+ */
9801
+ const watchForDisconnectedAudioDevice = (deviceId$) => {
9802
+ return watchForDisconnectedDevice('audioinput', deviceId$);
9803
+ };
9804
+ /**
9805
+ * Notifies the subscriber if a given 'videoinput' device is disconnected
9806
+ *
9807
+ * @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.
9808
+ * @param deviceId$ an Observable that specifies which device to watch for
9809
+ * @returns
9810
+ */
9811
+ const watchForDisconnectedVideoDevice = (deviceId$) => {
9812
+ return watchForDisconnectedDevice('videoinput', deviceId$);
9813
+ };
9814
+ /**
9815
+ * Notifies the subscriber if a given 'audiooutput' device is disconnected
9816
+ *
9817
+ * @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.
9818
+ * @param deviceId$ an Observable that specifies which device to watch for
9819
+ * @returns
9820
+ */
9821
+ const watchForDisconnectedAudioOutputDevice = (deviceId$) => {
9822
+ return watchForDisconnectedDevice('audiooutput', deviceId$);
9823
+ };
9824
+ const watchForAddedDefaultDevice = (kind) => {
9825
+ let devices$;
9826
+ switch (kind) {
9827
+ case 'audioinput':
9828
+ devices$ = getAudioDevices();
9829
+ break;
9830
+ case 'videoinput':
9831
+ devices$ = getVideoDevices();
9832
+ break;
9833
+ case 'audiooutput':
9834
+ devices$ = getAudioOutputDevices();
9835
+ break;
9836
+ default:
9837
+ throw new Error('Unknown MediaDeviceKind', kind);
9838
+ }
9839
+ return devices$.pipe(pairwise(), filter(([prev, current]) => {
9840
+ const prevDefault = prev.find((device) => device.deviceId === 'default');
9841
+ const currentDefault = current.find((device) => device.deviceId === 'default');
9842
+ return !!(current.length > prev.length &&
9843
+ prevDefault &&
9844
+ currentDefault &&
9845
+ prevDefault.groupId !== currentDefault.groupId);
9846
+ }), map$2(() => true));
9847
+ };
9848
+ /**
9849
+ * Notifies the subscriber about newly added default audio input device.
9850
+ * @returns Observable<boolean>
9851
+ */
9852
+ const watchForAddedDefaultAudioDevice = () => watchForAddedDefaultDevice('audioinput');
9853
+ /**
9854
+ * Notifies the subscriber about newly added default audio output device.
9855
+ * @returns Observable<boolean>
9856
+ */
9857
+ const watchForAddedDefaultAudioOutputDevice = () => watchForAddedDefaultDevice('audiooutput');
9858
+ /**
9859
+ * Notifies the subscriber about newly added default video input device.
9860
+ * @returns Observable<boolean>
9861
+ */
9862
+ const watchForAddedDefaultVideoDevice = () => watchForAddedDefaultDevice('videoinput');
9863
+ /**
9864
+ * Deactivates MediaStream (stops and removes tracks) to be later garbage collected
9865
+ *
9866
+ * @param stream MediaStream
9867
+ * @returns void
9868
+ */
9869
+ const disposeOfMediaStream = (stream) => {
9870
+ if (!stream.active)
9871
+ return;
9872
+ stream.getTracks().forEach((track) => {
9873
+ track.stop();
9874
+ stream.removeTrack(track);
9875
+ });
9876
+ // @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the stream
9877
+ if (typeof stream.release === 'function') {
9878
+ // @ts-expect-error
9879
+ stream.release();
9880
+ }
9881
+ };
9882
+
9883
+ class InputMediaDeviceManager {
9884
+ constructor(call, state) {
9885
+ this.call = call;
9886
+ this.state = state;
9887
+ }
9888
+ /**
9889
+ * Lists the available audio/video devices
9890
+ *
9891
+ * Note: It prompts the user for a permission to use devices (if not already granted)
9892
+ *
9893
+ * @returns an Observable that will be updated if a device is connected or disconnected
9894
+ */
9895
+ listDevices() {
9896
+ return this.getDevices();
9897
+ }
9898
+ /**
9899
+ * Starts camera/microphone
9900
+ */
9901
+ enable() {
9902
+ return __awaiter(this, void 0, void 0, function* () {
9903
+ if (this.state.status === 'enabled') {
9904
+ return;
9905
+ }
9906
+ yield this.startStream();
9907
+ this.state.setStatus('enabled');
9908
+ });
9909
+ }
9910
+ /**
9911
+ * Stops camera/microphone
9912
+ * @returns
9913
+ */
9914
+ disable() {
9915
+ return __awaiter(this, void 0, void 0, function* () {
9916
+ if (this.state.status === 'disabled') {
9917
+ return;
9918
+ }
9919
+ yield this.stopStream();
9920
+ this.state.setStatus('disabled');
9921
+ });
9922
+ }
9923
+ /**
9924
+ * If current device statis is disabled, it will enable the device, else it will disable it.
9925
+ * @returns
9926
+ */
9927
+ toggle() {
9928
+ return __awaiter(this, void 0, void 0, function* () {
9929
+ if (this.state.status === 'enabled') {
9930
+ return this.disable();
9931
+ }
9932
+ else {
9933
+ return this.enable();
9934
+ }
9935
+ });
9936
+ }
9937
+ /**
9938
+ * Select device
9939
+ *
9940
+ * Note: this method is not supported in React Native
9941
+ *
9942
+ * @param deviceId
9943
+ */
9944
+ select(deviceId) {
9945
+ return __awaiter(this, void 0, void 0, function* () {
9946
+ if (isReactNative()) {
9947
+ throw new Error('This method is not supported in React Native');
9948
+ }
9949
+ if (deviceId === this.state.selectedDevice) {
9950
+ return;
9951
+ }
9952
+ this.state.setDevice(deviceId);
9953
+ yield this.applySettingsToStream();
9954
+ });
9955
+ }
9956
+ applySettingsToStream() {
9957
+ return __awaiter(this, void 0, void 0, function* () {
9958
+ if (this.state.status === 'enabled') {
9959
+ yield this.stopStream();
9960
+ yield this.startStream();
9961
+ }
9962
+ });
9963
+ }
9964
+ stopStream() {
9965
+ return __awaiter(this, void 0, void 0, function* () {
9966
+ if (!this.state.mediaStream) {
9967
+ return;
9968
+ }
9969
+ if (this.call.state.callingState === CallingState.JOINED) {
9970
+ yield this.stopPublishStream();
9971
+ }
9972
+ else if (this.state.mediaStream) {
9973
+ disposeOfMediaStream(this.state.mediaStream);
9974
+ }
9975
+ this.state.setMediaStream(undefined);
9976
+ });
9977
+ }
9978
+ startStream() {
9979
+ return __awaiter(this, void 0, void 0, function* () {
9980
+ if (this.state.mediaStream) {
9981
+ return;
9982
+ }
9983
+ const constraints = { deviceId: this.state.selectedDevice };
9984
+ const stream = yield this.getStream(constraints);
9985
+ if (this.call.state.callingState === CallingState.JOINED) {
9986
+ yield this.publishStream(stream);
9987
+ }
9988
+ this.state.setMediaStream(stream);
9989
+ });
9990
+ }
9991
+ }
9992
+
9993
+ class CameraManager extends InputMediaDeviceManager {
9994
+ constructor(call) {
9995
+ super(call, new CameraManagerState());
9996
+ }
9997
+ /**
9998
+ * Select the camera direaction
9999
+ * @param direction
10000
+ */
10001
+ selectDirection(direction) {
10002
+ return __awaiter(this, void 0, void 0, function* () {
10003
+ this.state.setDirection(direction);
10004
+ // Providing both device id and direction doesn't work, so we deselect the device
10005
+ this.state.setDevice(undefined);
10006
+ yield this.applySettingsToStream();
10007
+ });
10008
+ }
10009
+ /**
10010
+ * Flips the camera direction: if it's front it will change to back, if it's back, it will change to front.
10011
+ *
10012
+ * Note: if there is no available camera with the desired direction, this method will do nothing.
10013
+ * @returns
10014
+ */
10015
+ flip() {
10016
+ return __awaiter(this, void 0, void 0, function* () {
10017
+ const newDirection = this.state.direction === 'front' ? 'back' : 'front';
10018
+ this.selectDirection(newDirection);
10019
+ });
10020
+ }
10021
+ getDevices() {
10022
+ return getVideoDevices();
10023
+ }
10024
+ getStream(constraints) {
10025
+ // We can't set both device id and facing mode
10026
+ // Device id has higher priority
10027
+ if (!constraints.deviceId && this.state.direction) {
10028
+ constraints.facingMode =
10029
+ this.state.direction === 'front' ? 'user' : 'environment';
10030
+ }
10031
+ return getVideoStream(constraints);
10032
+ }
10033
+ publishStream(stream) {
10034
+ return this.call.publishVideoStream(stream);
10035
+ }
10036
+ stopPublishStream() {
10037
+ return this.call.stopPublish(TrackType.VIDEO);
10038
+ }
10039
+ /**
10040
+ * Disables the video tracks of the camera
10041
+ */
10042
+ pause() {
10043
+ var _a;
10044
+ (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks().forEach((track) => {
10045
+ track.enabled = false;
10046
+ });
10047
+ }
10048
+ /**
10049
+ * (Re)enables the video tracks of the camera
10050
+ */
10051
+ resume() {
10052
+ var _a;
10053
+ (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks().forEach((track) => {
10054
+ track.enabled = true;
10055
+ });
10056
+ }
10057
+ }
10058
+
10059
+ class MicrophoneManagerState extends InputMediaDeviceManagerState {
10060
+ getDeviceIdFromStream(stream) {
10061
+ var _a;
10062
+ return (_a = stream.getAudioTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
10063
+ }
10064
+ }
10065
+
10066
+ class MicrophoneManager extends InputMediaDeviceManager {
10067
+ constructor(call) {
10068
+ super(call, new MicrophoneManagerState());
10069
+ }
10070
+ getDevices() {
10071
+ return getAudioDevices();
10072
+ }
10073
+ getStream(constraints) {
10074
+ return getAudioStream(constraints);
10075
+ }
10076
+ publishStream(stream) {
10077
+ return this.call.publishAudioStream(stream);
10078
+ }
10079
+ stopPublishStream() {
10080
+ return this.call.stopPublish(TrackType.AUDIO);
10081
+ }
10082
+ /**
10083
+ * Disables the audio tracks of the microphone
10084
+ */
10085
+ pause() {
10086
+ var _a;
10087
+ (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().forEach((track) => {
10088
+ track.enabled = false;
10089
+ });
10090
+ }
10091
+ /**
10092
+ * (Re)enables the audio tracks of the microphone
10093
+ */
10094
+ resume() {
10095
+ var _a;
10096
+ (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().forEach((track) => {
10097
+ track.enabled = true;
10098
+ });
10099
+ }
10100
+ }
10101
+
10102
+ /**
9611
10103
  * An object representation of a `Call`.
9612
10104
  */
9613
10105
  class Call {
@@ -9618,7 +10110,7 @@ class Call {
9618
10110
  * Use the [`StreamVideoClient.call`](./StreamVideoClient.md/#call)
9619
10111
  * method to construct a `Call` instance.
9620
10112
  */
9621
- constructor({ type, id, streamClient, metadata, members, ownCapabilities, sortParticipantsBy, clientStore, ringing = false, watching = false, }) {
10113
+ constructor({ type, id, streamClient, members, ownCapabilities, sortParticipantsBy, clientStore, ringing = false, watching = false, }) {
9622
10114
  /**
9623
10115
  * ViewportTracker instance
9624
10116
  */
@@ -9697,7 +10189,7 @@ class Call {
9697
10189
  if ((params === null || params === void 0 ? void 0 : params.ring) && !this.ringing) {
9698
10190
  this.ringingSubject.next(true);
9699
10191
  }
9700
- this.state.setMetadata(response.call);
10192
+ this.state.updateFromCallResponse(response.call);
9701
10193
  this.state.setMembers(response.members);
9702
10194
  this.state.setOwnCapabilities(response.own_capabilities);
9703
10195
  if (this.streamClient._hasConnectionID()) {
@@ -9716,7 +10208,7 @@ class Call {
9716
10208
  if ((data === null || data === void 0 ? void 0 : data.ring) && !this.ringing) {
9717
10209
  this.ringingSubject.next(true);
9718
10210
  }
9719
- this.state.setMetadata(response.call);
10211
+ this.state.updateFromCallResponse(response.call);
9720
10212
  this.state.setMembers(response.members);
9721
10213
  this.state.setOwnCapabilities(response.own_capabilities);
9722
10214
  if (this.streamClient._hasConnectionID()) {
@@ -9773,7 +10265,7 @@ class Call {
9773
10265
  * @returns a promise which resolves once the call join-flow has finished.
9774
10266
  */
9775
10267
  this.join = (data) => __awaiter(this, void 0, void 0, function* () {
9776
- var _e, _f, _g;
10268
+ var _e, _f, _g, _h;
9777
10269
  const callingState = this.state.callingState;
9778
10270
  if ([CallingState.JOINED, CallingState.JOINING].includes(callingState)) {
9779
10271
  this.logger('warn', 'Join method called twice, you should only call this once');
@@ -9797,7 +10289,7 @@ class Call {
9797
10289
  let connectionConfig;
9798
10290
  try {
9799
10291
  const call = yield join(this.streamClient, this.type, this.id, data);
9800
- this.state.setMetadata(call.metadata);
10292
+ this.state.updateFromCallResponse(call.metadata);
9801
10293
  this.state.setMembers(call.members);
9802
10294
  this.state.setOwnCapabilities(call.ownCapabilities);
9803
10295
  connectionConfig = call.connectionConfig;
@@ -9962,7 +10454,7 @@ class Call {
9962
10454
  connectionConfig,
9963
10455
  });
9964
10456
  }
9965
- const audioSettings = (_f = this.data) === null || _f === void 0 ? void 0 : _f.settings.audio;
10457
+ const audioSettings = (_f = this.state.settings) === null || _f === void 0 ? void 0 : _f.audio;
9966
10458
  const isDtxEnabled = !!(audioSettings === null || audioSettings === void 0 ? void 0 : audioSettings.opus_dtx_enabled);
9967
10459
  const isRedEnabled = !!(audioSettings === null || audioSettings === void 0 ? void 0 : audioSettings.redundant_coding_enabled);
9968
10460
  if (!this.publisher) {
@@ -10042,6 +10534,11 @@ class Call {
10042
10534
  this.state.setServerSidePins(pins);
10043
10535
  this.reconnectAttempts = 0; // reset the reconnect attempts counter
10044
10536
  this.state.setCallingState(CallingState.JOINED);
10537
+ // React uses a different device management for now
10538
+ if (((_h = getSdkInfo()) === null || _h === void 0 ? void 0 : _h.type) !== SdkType.REACT) {
10539
+ this.initCamera();
10540
+ this.initMic();
10541
+ }
10045
10542
  // 3. once we have the "joinResponse", and possibly reconciled the local state
10046
10543
  // we schedule a fast subscription update for all remote participants
10047
10544
  // that were visible before we reconnected or migrated to a new SFU.
@@ -10164,9 +10661,9 @@ class Call {
10164
10661
  * @param trackType the track type to stop publishing.
10165
10662
  */
10166
10663
  this.stopPublish = (trackType) => __awaiter(this, void 0, void 0, function* () {
10167
- var _h;
10664
+ var _j;
10168
10665
  this.logger('info', `stopPublish ${TrackType[trackType]}`);
10169
- yield ((_h = this.publisher) === null || _h === void 0 ? void 0 : _h.unpublishStream(trackType));
10666
+ yield ((_j = this.publisher) === null || _j === void 0 ? void 0 : _j.unpublishStream(trackType));
10170
10667
  });
10171
10668
  /**
10172
10669
  * Update track subscription configuration for one or more participants.
@@ -10267,6 +10764,8 @@ class Call {
10267
10764
  *
10268
10765
  *
10269
10766
  * @param deviceId the selected device, pass `undefined` to clear the device selection
10767
+ *
10768
+ * @deprecated use call.microphone.select
10270
10769
  */
10271
10770
  this.setAudioDevice = (deviceId) => {
10272
10771
  if (!this.sfuClient)
@@ -10281,6 +10780,8 @@ class Call {
10281
10780
  * 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.
10282
10781
  *
10283
10782
  * @param deviceId the selected device, pass `undefined` to clear the device selection
10783
+ *
10784
+ * @deprecated use call.camera.select
10284
10785
  */
10285
10786
  this.setVideoDevice = (deviceId) => {
10286
10787
  if (!this.sfuClient)
@@ -10313,8 +10814,8 @@ class Call {
10313
10814
  * @returns
10314
10815
  */
10315
10816
  this.updatePublishQuality = (enabledRids) => __awaiter(this, void 0, void 0, function* () {
10316
- var _j;
10317
- return (_j = this.publisher) === null || _j === void 0 ? void 0 : _j.updateVideoPublishQuality(enabledRids);
10817
+ var _k;
10818
+ return (_k = this.publisher) === null || _k === void 0 ? void 0 : _k.updateVideoPublishQuality(enabledRids);
10318
10819
  });
10319
10820
  this.assertCallJoined = () => {
10320
10821
  return new Promise((resolve) => {
@@ -10509,7 +11010,7 @@ class Call {
10509
11010
  this.update = (updates) => __awaiter(this, void 0, void 0, function* () {
10510
11011
  const response = yield this.streamClient.patch(`${this.streamClientBasePath}`, updates);
10511
11012
  const { call, members, own_capabilities } = response;
10512
- this.state.setMetadata(call);
11013
+ this.state.updateFromCallResponse(call);
10513
11014
  this.state.setMembers(members);
10514
11015
  this.state.setOwnCapabilities(own_capabilities);
10515
11016
  return response;
@@ -10582,19 +11083,20 @@ class Call {
10582
11083
  this.scheduleAutoDrop = () => {
10583
11084
  if (this.dropTimeout)
10584
11085
  clearTimeout(this.dropTimeout);
10585
- const subscription = this.state.metadata$
10586
- .pipe(pairwise(), tap(([prevMeta, currentMeta]) => {
10587
- if (!(currentMeta && this.clientStore.connectedUser))
11086
+ const subscription = this.state.settings$
11087
+ .pipe(pairwise(), tap(([prevSettings, currentSettings]) => {
11088
+ var _a;
11089
+ if (!currentSettings || !this.clientStore.connectedUser)
10588
11090
  return;
10589
- const isOutgoingCall = this.currentUserId === currentMeta.created_by.id;
11091
+ const isOutgoingCall = this.currentUserId === ((_a = this.state.createdBy) === null || _a === void 0 ? void 0 : _a.id);
10590
11092
  const [prevTimeoutMs, timeoutMs] = isOutgoingCall
10591
11093
  ? [
10592
- prevMeta === null || prevMeta === void 0 ? void 0 : prevMeta.settings.ring.auto_cancel_timeout_ms,
10593
- currentMeta.settings.ring.auto_cancel_timeout_ms,
11094
+ prevSettings === null || prevSettings === void 0 ? void 0 : prevSettings.ring.auto_cancel_timeout_ms,
11095
+ currentSettings.ring.auto_cancel_timeout_ms,
10594
11096
  ]
10595
11097
  : [
10596
- prevMeta === null || prevMeta === void 0 ? void 0 : prevMeta.settings.ring.incoming_call_timeout_ms,
10597
- currentMeta.settings.ring.incoming_call_timeout_ms,
11098
+ prevSettings === null || prevSettings === void 0 ? void 0 : prevSettings.ring.incoming_call_timeout_ms,
11099
+ currentSettings.ring.incoming_call_timeout_ms,
10598
11100
  ];
10599
11101
  if (typeof timeoutMs === 'undefined' ||
10600
11102
  timeoutMs === prevTimeoutMs ||
@@ -10611,7 +11113,6 @@ class Call {
10611
11113
  };
10612
11114
  /**
10613
11115
  * Retrieves the list of recordings for the current call or call session.
10614
- * Updates the call state with the returned array of CallRecording objects.
10615
11116
  *
10616
11117
  * If `callSessionId` is provided, it will return the recordings for that call session.
10617
11118
  * Otherwise, all recordings for the current call will be returned.
@@ -10623,9 +11124,7 @@ class Call {
10623
11124
  if (callSessionId) {
10624
11125
  endpoint = `${endpoint}/${callSessionId}`;
10625
11126
  }
10626
- const response = yield this.streamClient.get(`${endpoint}/recordings`);
10627
- this.state.setCallRecordingsList(response.recordings);
10628
- return response;
11127
+ return this.streamClient.get(`${endpoint}/recordings`);
10629
11128
  });
10630
11129
  /**
10631
11130
  * Sends a custom event to all call participants.
@@ -10649,21 +11148,26 @@ class Call {
10649
11148
  if (participantSorter) {
10650
11149
  this.state.setSortParticipantsBy(participantSorter);
10651
11150
  }
10652
- this.state.setMetadata(metadata);
10653
11151
  this.state.setMembers(members || []);
10654
11152
  this.state.setOwnCapabilities(ownCapabilities || []);
10655
11153
  this.state.setCallingState(ringing ? CallingState.RINGING : CallingState.IDLE);
11154
+ this.on('all', (event) => {
11155
+ // update state with the latest event data
11156
+ this.state.updateFromEvent(event);
11157
+ });
10656
11158
  this.leaveCallHooks.push(registerEventHandlers(this, this.state, this.dispatcher));
10657
11159
  this.registerEffects();
10658
11160
  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); }));
11161
+ this.camera = new CameraManager(this);
11162
+ this.microphone = new MicrophoneManager(this);
10659
11163
  }
10660
11164
  registerEffects() {
10661
11165
  this.leaveCallHooks.push(
10662
- // handles updating the permissions context when the metadata changes.
10663
- createSubscription(this.state.metadata$, (metadata) => {
10664
- if (!metadata)
11166
+ // handles updating the permissions context when the settings change.
11167
+ createSubscription(this.state.settings$, (settings) => {
11168
+ if (!settings)
10665
11169
  return;
10666
- this.permissionsContext.setCallSettings(metadata.settings);
11170
+ this.permissionsContext.setCallSettings(settings);
10667
11171
  }),
10668
11172
  // handle the case when the user permissions are modified.
10669
11173
  createSubscription(this.state.ownCapabilities$, (ownCapabilities) => {
@@ -10687,12 +11191,11 @@ class Call {
10687
11191
  }
10688
11192
  }),
10689
11193
  // handles the case when the user is blocked by the call owner.
10690
- createSubscription(this.state.metadata$, (metadata) => __awaiter(this, void 0, void 0, function* () {
10691
- if (!metadata)
11194
+ createSubscription(this.state.blockedUserIds$, (blockedUserIds) => __awaiter(this, void 0, void 0, function* () {
11195
+ if (!blockedUserIds)
10692
11196
  return;
10693
11197
  const currentUserId = this.currentUserId;
10694
- if (currentUserId &&
10695
- metadata.blocked_user_ids.includes(currentUserId)) {
11198
+ if (currentUserId && blockedUserIds.includes(currentUserId)) {
10696
11199
  this.logger('info', 'Leaving call because of being blocked');
10697
11200
  yield this.leave();
10698
11201
  }
@@ -10744,12 +11247,6 @@ class Call {
10744
11247
  }
10745
11248
  }
10746
11249
  }
10747
- /**
10748
- * A getter for the call metadata.
10749
- */
10750
- get data() {
10751
- return this.state.metadata;
10752
- }
10753
11250
  /**
10754
11251
  * A flag indicating whether the call is "ringing" type of call.
10755
11252
  */
@@ -10768,7 +11265,65 @@ class Call {
10768
11265
  */
10769
11266
  get isCreatedByMe() {
10770
11267
  var _a;
10771
- return ((_a = this.state.metadata) === null || _a === void 0 ? void 0 : _a.created_by.id) === this.currentUserId;
11268
+ return ((_a = this.state.createdBy) === null || _a === void 0 ? void 0 : _a.id) === this.currentUserId;
11269
+ }
11270
+ initCamera() {
11271
+ var _a, _b, _c;
11272
+ if (((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.videoStream) ||
11273
+ !this.permissionsContext.hasPermission('send-video')) {
11274
+ return;
11275
+ }
11276
+ // Set camera direction if it's not yet set
11277
+ // This will also start publishing if camera is enabled
11278
+ if (!this.camera.state.direction && !this.camera.state.selectedDevice) {
11279
+ let defaultDirection = 'front';
11280
+ const backendSetting = (_b = this.state.settings) === null || _b === void 0 ? void 0 : _b.video.camera_facing;
11281
+ if (backendSetting) {
11282
+ defaultDirection = backendSetting === 'front' ? 'front' : 'back';
11283
+ }
11284
+ this.camera.selectDirection(defaultDirection);
11285
+ }
11286
+ else if (this.camera.state.status === 'enabled') {
11287
+ // Publish already started media streams (this is the case if there is a lobby screen before join)
11288
+ // Wait for media stream
11289
+ this.camera.state.mediaStream$
11290
+ .pipe(takeWhile((s) => s === undefined, true))
11291
+ .subscribe((stream) => {
11292
+ var _a;
11293
+ if (!((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.videoStream)) {
11294
+ this.publishVideoStream(stream);
11295
+ }
11296
+ });
11297
+ }
11298
+ // Apply backend config (this is the case if there is no lobby screen before join)
11299
+ if (this.camera.state.status === undefined &&
11300
+ ((_c = this.state.settings) === null || _c === void 0 ? void 0 : _c.video.camera_default_on)) {
11301
+ void this.camera.enable();
11302
+ }
11303
+ }
11304
+ initMic() {
11305
+ var _a, _b;
11306
+ if (((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.audioStream) ||
11307
+ !this.permissionsContext.hasPermission('send-audio')) {
11308
+ return;
11309
+ }
11310
+ // Publish already started media streams (this is the case if there is a lobby screen before join)
11311
+ if (this.microphone.state.status === 'enabled') {
11312
+ // Wait for media stream
11313
+ this.microphone.state.mediaStream$
11314
+ .pipe(takeWhile((s) => s === undefined, true))
11315
+ .subscribe((stream) => {
11316
+ var _a;
11317
+ if (!((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.audioStream)) {
11318
+ this.publishAudioStream(stream);
11319
+ }
11320
+ });
11321
+ }
11322
+ // Apply backend config (this is the case if there is no lobby screen before join)
11323
+ if (this.microphone.state.status === undefined &&
11324
+ ((_b = this.state.settings) === null || _b === void 0 ? void 0 : _b.audio.mic_default_on)) {
11325
+ void this.microphone.enable();
11326
+ }
10772
11327
  }
10773
11328
  }
10774
11329
 
@@ -11880,7 +12435,7 @@ class WSConnectionFallback {
11880
12435
  }
11881
12436
  }
11882
12437
 
11883
- const version = '0.2.3';
12438
+ const version = '0.3.1';
11884
12439
 
11885
12440
  const logger = getLogger(['location']);
11886
12441
  const HINT_URL = `https://hint.stream-io-video.com/`;
@@ -12574,12 +13129,12 @@ class StreamVideoClient {
12574
13129
  streamClient: this.streamClient,
12575
13130
  id: c.call.id,
12576
13131
  type: c.call.type,
12577
- metadata: c.call,
12578
13132
  members: c.members,
12579
13133
  ownCapabilities: c.own_capabilities,
12580
13134
  watching: data.watch,
12581
13135
  clientStore: this.writeableStateStore,
12582
13136
  });
13137
+ call.state.updateFromCallResponse(c.call);
12583
13138
  if (data.watch) {
12584
13139
  this.writeableStateStore.registerCall(call);
12585
13140
  }
@@ -12587,9 +13142,9 @@ class StreamVideoClient {
12587
13142
  });
12588
13143
  return Object.assign(Object.assign({}, response), { calls: calls });
12589
13144
  });
12590
- this.queryUsers = () => __awaiter(this, void 0, void 0, function* () {
12591
- console.log('Querying users is not implemented yet.');
12592
- });
13145
+ /**
13146
+ * Returns a list of available data centers available for hosting calls.
13147
+ */
12593
13148
  this.edges = () => __awaiter(this, void 0, void 0, function* () {
12594
13149
  return this.streamClient.get(`/edges`);
12595
13150
  });
@@ -12764,14 +13319,15 @@ class StreamVideoClient {
12764
13319
  return;
12765
13320
  }
12766
13321
  this.logger('info', `New call created and registered: ${call.cid}`);
12767
- this.writeableStateStore.registerCall(new Call({
13322
+ const newCall = new Call({
12768
13323
  streamClient: this.streamClient,
12769
13324
  type: call.type,
12770
13325
  id: call.id,
12771
- metadata: call,
12772
13326
  members,
12773
13327
  clientStore: this.writeableStateStore,
12774
- }));
13328
+ });
13329
+ newCall.state.updateFromCallResponse(call);
13330
+ this.writeableStateStore.registerCall(newCall);
12775
13331
  }));
12776
13332
  this.eventHandlersToUnregister.push(this.on('call.ring', (event) => __awaiter(this, void 0, void 0, function* () {
12777
13333
  if (event.type !== 'call.ring')
@@ -12785,7 +13341,6 @@ class StreamVideoClient {
12785
13341
  // if `call.created` was received before `call.ring`.
12786
13342
  // In that case, we cleanup the already tracked call.
12787
13343
  const prevCall = this.writeableStateStore.findCall(call.type, call.id);
12788
- const prevMetadata = prevCall === null || prevCall === void 0 ? void 0 : prevCall.state.metadata;
12789
13344
  yield (prevCall === null || prevCall === void 0 ? void 0 : prevCall.leave());
12790
13345
  // we create a new call
12791
13346
  const theCall = new Call({
@@ -12795,8 +13350,8 @@ class StreamVideoClient {
12795
13350
  members,
12796
13351
  clientStore: this.writeableStateStore,
12797
13352
  ringing: true,
12798
- metadata: prevMetadata,
12799
13353
  });
13354
+ theCall.state.updateFromCallResponse(call);
12800
13355
  // we fetch the latest metadata for the call from the server
12801
13356
  yield theCall.get();
12802
13357
  this.writeableStateStore.registerCall(theCall);
@@ -12854,254 +13409,6 @@ class StreamVideoServerClient extends StreamVideoClient {
12854
13409
  }
12855
13410
  }
12856
13411
 
12857
- const getDevices = (constraints) => {
12858
- return new Observable((subscriber) => {
12859
- navigator.mediaDevices
12860
- .getUserMedia(constraints)
12861
- .then((media) => {
12862
- // in Firefox, devices can be enumerated after userMedia is requested
12863
- // and permissions granted. Otherwise, device labels are empty
12864
- navigator.mediaDevices.enumerateDevices().then((devices) => {
12865
- subscriber.next(devices);
12866
- // If we stop the tracks before enumerateDevices -> the labels won't show up in Firefox
12867
- disposeOfMediaStream(media);
12868
- subscriber.complete();
12869
- });
12870
- })
12871
- .catch((error) => {
12872
- getLogger(['devices'])('error', 'Failed to get devices', error);
12873
- subscriber.error(error);
12874
- });
12875
- });
12876
- };
12877
- /**
12878
- * [Tells if the browser supports audio output change on 'audio' elements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId).
12879
- *
12880
- * @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.
12881
- */
12882
- const checkIfAudioOutputChangeSupported = () => {
12883
- if (typeof document === 'undefined')
12884
- return false;
12885
- const element = document.createElement('audio');
12886
- return element.sinkId !== undefined;
12887
- };
12888
- /**
12889
- * The default constraints used to request audio devices.
12890
- */
12891
- const audioDeviceConstraints = {
12892
- audio: {
12893
- autoGainControl: true,
12894
- noiseSuppression: true,
12895
- echoCancellation: true,
12896
- },
12897
- };
12898
- /**
12899
- * The default constraints used to request video devices.
12900
- */
12901
- const videoDeviceConstraints = {
12902
- video: {
12903
- width: 1280,
12904
- height: 720,
12905
- },
12906
- };
12907
- // 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
12908
- const deviceChange$ = new Observable((subscriber) => {
12909
- var _a, _b;
12910
- const deviceChangeHandler = () => subscriber.next();
12911
- (_b = (_a = navigator.mediaDevices).addEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
12912
- return () => {
12913
- var _a, _b;
12914
- return (_b = (_a = navigator.mediaDevices).removeEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
12915
- };
12916
- }).pipe(debounceTime(500), concatMap(() => from(navigator.mediaDevices.enumerateDevices())), shareReplay(1));
12917
- const audioDevices$ = merge(getDevices(audioDeviceConstraints), deviceChange$).pipe(shareReplay(1));
12918
- const videoDevices$ = merge(getDevices(videoDeviceConstraints), deviceChange$).pipe(shareReplay(1));
12919
- /**
12920
- * 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.
12921
- *
12922
- * @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.
12923
- * @returns
12924
- */
12925
- const getAudioDevices = () => audioDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'audioinput')));
12926
- /**
12927
- * 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.
12928
- *
12929
- * @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.
12930
- * @returns
12931
- */
12932
- const getVideoDevices = () => videoDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'videoinput' && d.deviceId.length)));
12933
- /**
12934
- * 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)
12935
- *
12936
- * @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.
12937
- * @returns
12938
- */
12939
- const getAudioOutputDevices = () => {
12940
- return audioDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'audiooutput')));
12941
- };
12942
- const getStream = (constraints) => __awaiter(void 0, void 0, void 0, function* () {
12943
- try {
12944
- return yield navigator.mediaDevices.getUserMedia(constraints);
12945
- }
12946
- catch (e) {
12947
- getLogger(['devices'])('error', `Failed get user media`, {
12948
- error: e,
12949
- constraints: constraints,
12950
- });
12951
- throw e;
12952
- }
12953
- });
12954
- /**
12955
- * Returns an audio media stream that fulfills the given constraints.
12956
- * If no constraints are provided, it uses the browser's default ones.
12957
- *
12958
- * @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.
12959
- * @param trackConstraints the constraints to use when requesting the stream.
12960
- * @returns the new `MediaStream` fulfilling the given constraints.
12961
- */
12962
- const getAudioStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
12963
- const constraints = {
12964
- audio: Object.assign(Object.assign({}, audioDeviceConstraints.audio), trackConstraints),
12965
- };
12966
- return getStream(constraints);
12967
- });
12968
- /**
12969
- * Returns a video media stream that fulfills the given constraints.
12970
- * If no constraints are provided, it uses the browser's default ones.
12971
- *
12972
- * @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.
12973
- * @param trackConstraints the constraints to use when requesting the stream.
12974
- * @returns a new `MediaStream` fulfilling the given constraints.
12975
- */
12976
- const getVideoStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
12977
- const constraints = {
12978
- video: Object.assign(Object.assign({}, videoDeviceConstraints.video), trackConstraints),
12979
- };
12980
- return getStream(constraints);
12981
- });
12982
- /**
12983
- * Prompts the user for a permission to share a screen.
12984
- * If the user grants the permission, a screen sharing stream is returned. Throws otherwise.
12985
- *
12986
- * The callers of this API are responsible to handle the possible errors.
12987
- *
12988
- * @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.
12989
- *
12990
- * @param options any additional options to pass to the [`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) API.
12991
- */
12992
- const getScreenShareStream = (options) => __awaiter(void 0, void 0, void 0, function* () {
12993
- try {
12994
- return yield navigator.mediaDevices.getDisplayMedia(Object.assign({ video: true, audio: false }, options));
12995
- }
12996
- catch (e) {
12997
- getLogger(['devices'])('error', 'Failed to get screen share stream', e);
12998
- throw e;
12999
- }
13000
- });
13001
- const watchForDisconnectedDevice = (kind, deviceId$) => {
13002
- let devices$;
13003
- switch (kind) {
13004
- case 'audioinput':
13005
- devices$ = getAudioDevices();
13006
- break;
13007
- case 'videoinput':
13008
- devices$ = getVideoDevices();
13009
- break;
13010
- case 'audiooutput':
13011
- devices$ = getAudioOutputDevices();
13012
- break;
13013
- }
13014
- return combineLatest([devices$, deviceId$]).pipe(filter(([devices, deviceId]) => !!deviceId && !devices.find((d) => d.deviceId === deviceId)), map$2(() => true));
13015
- };
13016
- /**
13017
- * Notifies the subscriber if a given 'audioinput' device is disconnected
13018
- *
13019
- * @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.
13020
- * @param deviceId$ an Observable that specifies which device to watch for
13021
- * @returns
13022
- */
13023
- const watchForDisconnectedAudioDevice = (deviceId$) => {
13024
- return watchForDisconnectedDevice('audioinput', deviceId$);
13025
- };
13026
- /**
13027
- * Notifies the subscriber if a given 'videoinput' device is disconnected
13028
- *
13029
- * @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.
13030
- * @param deviceId$ an Observable that specifies which device to watch for
13031
- * @returns
13032
- */
13033
- const watchForDisconnectedVideoDevice = (deviceId$) => {
13034
- return watchForDisconnectedDevice('videoinput', deviceId$);
13035
- };
13036
- /**
13037
- * Notifies the subscriber if a given 'audiooutput' device is disconnected
13038
- *
13039
- * @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.
13040
- * @param deviceId$ an Observable that specifies which device to watch for
13041
- * @returns
13042
- */
13043
- const watchForDisconnectedAudioOutputDevice = (deviceId$) => {
13044
- return watchForDisconnectedDevice('audiooutput', deviceId$);
13045
- };
13046
- const watchForAddedDefaultDevice = (kind) => {
13047
- let devices$;
13048
- switch (kind) {
13049
- case 'audioinput':
13050
- devices$ = getAudioDevices();
13051
- break;
13052
- case 'videoinput':
13053
- devices$ = getVideoDevices();
13054
- break;
13055
- case 'audiooutput':
13056
- devices$ = getAudioOutputDevices();
13057
- break;
13058
- default:
13059
- throw new Error('Unknown MediaDeviceKind', kind);
13060
- }
13061
- return devices$.pipe(pairwise(), filter(([prev, current]) => {
13062
- const prevDefault = prev.find((device) => device.deviceId === 'default');
13063
- const currentDefault = current.find((device) => device.deviceId === 'default');
13064
- return !!(current.length > prev.length &&
13065
- prevDefault &&
13066
- currentDefault &&
13067
- prevDefault.groupId !== currentDefault.groupId);
13068
- }), map$2(() => true));
13069
- };
13070
- /**
13071
- * Notifies the subscriber about newly added default audio input device.
13072
- * @returns Observable<boolean>
13073
- */
13074
- const watchForAddedDefaultAudioDevice = () => watchForAddedDefaultDevice('audioinput');
13075
- /**
13076
- * Notifies the subscriber about newly added default audio output device.
13077
- * @returns Observable<boolean>
13078
- */
13079
- const watchForAddedDefaultAudioOutputDevice = () => watchForAddedDefaultDevice('audiooutput');
13080
- /**
13081
- * Notifies the subscriber about newly added default video input device.
13082
- * @returns Observable<boolean>
13083
- */
13084
- const watchForAddedDefaultVideoDevice = () => watchForAddedDefaultDevice('videoinput');
13085
- /**
13086
- * Deactivates MediaStream (stops and removes tracks) to be later garbage collected
13087
- *
13088
- * @param stream MediaStream
13089
- * @returns void
13090
- */
13091
- const disposeOfMediaStream = (stream) => {
13092
- if (!stream.active)
13093
- return;
13094
- stream.getTracks().forEach((track) => {
13095
- track.stop();
13096
- stream.removeTrack(track);
13097
- });
13098
- // @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the stream
13099
- if (typeof stream.release === 'function') {
13100
- // @ts-expect-error
13101
- stream.release();
13102
- }
13103
- };
13104
-
13105
13412
  const DETECTION_FREQUENCY_IN_MS = 500;
13106
13413
  const AUDIO_LEVEL_THRESHOLD = 150;
13107
13414
  const FFT_SIZE = 128;
@@ -13182,5 +13489,5 @@ var browsers = /*#__PURE__*/Object.freeze({
13182
13489
  isSafari: isSafari
13183
13490
  });
13184
13491
 
13185
- 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 };
13492
+ export { AudioSettingsDefaultDeviceEnum, AudioSettingsRequestDefaultDeviceEnum, browsers as Browsers, Call, CallState, CallType, CallTypes, CallingState, CameraManager, CreateDeviceRequestPushProviderEnum, DebounceType, ErrorFromResponse, InputMediaDeviceManager, InputMediaDeviceManagerState, MicrophoneManager, OwnCapability, RecordSettingsModeEnum, RecordSettingsQualityEnum, RecordSettingsRequestModeEnum, RecordSettingsRequestQualityEnum, rxUtils as RxUtils, events as SfuEvents, models as SfuModels, StreamSfuClient, StreamVideoClient, StreamVideoReadOnlyStateStore, StreamVideoServerClient, StreamVideoWriteableStateStore, TranscriptionSettingsModeEnum, TranscriptionSettingsRequestModeEnum, VideoSettingsCameraFacingEnum, VideoSettingsRequestCameraFacingEnum, ViewportTracker, VisibilityState, checkIfAudioOutputChangeSupported, combineComparators, conditional, createSoundDetector, defaultSortPreset, descending, disposeOfMediaStream, dominantSpeaker, getAudioDevices, getAudioOutputDevices, getAudioStream, getClientDetails, getDeviceInfo, getLogger, getOSInfo, getScreenShareStream, getSdkInfo, getVideoDevices, getVideoStream, isStreamVideoLocalParticipant, livestreamOrAudioRoomSortPreset, logLevels, logToConsole, name, noopComparator, pinned, publishingAudio, publishingVideo, reactionType, role, screenSharing, setDeviceInfo, setLogLevel, setLogger, setOSInfo, setSdkInfo, speakerLayoutSortPreset, speaking, watchForAddedDefaultAudioDevice, watchForAddedDefaultAudioOutputDevice, watchForAddedDefaultVideoDevice, watchForDisconnectedAudioDevice, watchForDisconnectedAudioOutputDevice, watchForDisconnectedVideoDevice };
13186
13493
  //# sourceMappingURL=index.browser.es.js.map