@whereby.com/core 0.12.1 → 0.13.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.
package/dist/index.mjs CHANGED
@@ -43,9 +43,9 @@ const createReactor = (selectors, callback) => {
43
43
  });
44
44
  };
45
45
 
46
- const coreVersion = "0.12.1";
46
+ const coreVersion = "0.13.1";
47
47
 
48
- const initialState$d = {
48
+ const initialState$e = {
49
49
  isNodeSdk: false,
50
50
  wantsToJoin: false,
51
51
  roomName: null,
@@ -56,7 +56,7 @@ const initialState$d = {
56
56
  };
57
57
  const appSlice = createSlice({
58
58
  name: "app",
59
- initialState: initialState$d,
59
+ initialState: initialState$e,
60
60
  reducers: {
61
61
  doAppJoin: (state, action) => {
62
62
  const url = new URL(action.payload.roomUrl);
@@ -103,6 +103,43 @@ const signalEvents = {
103
103
  videoEnabled: createSignalEventAction("videoEnabled"),
104
104
  };
105
105
 
106
+ const ROOM_ACTION_PERMISSIONS_BY_ROLE = {
107
+ canLockRoom: ["host"],
108
+ canRequestAudioEnable: ["host"],
109
+ canKickClient: ["host"],
110
+ canEndMeeting: ["host"],
111
+ };
112
+ const initialState$d = {
113
+ roomKey: null,
114
+ roleName: "none",
115
+ };
116
+ const authorizationSlice = createSlice({
117
+ name: "authorization",
118
+ initialState: initialState$d,
119
+ reducers: {
120
+ setRoomKey: (state, action) => {
121
+ return Object.assign(Object.assign({}, state), { roomKey: action.payload });
122
+ },
123
+ },
124
+ extraReducers: (builder) => {
125
+ builder.addCase(doAppJoin, (state, action) => {
126
+ return Object.assign(Object.assign({}, state), { roomKey: action.payload.roomKey });
127
+ });
128
+ builder.addCase(signalEvents.roomJoined, (state, action) => {
129
+ var _a, _b;
130
+ const client = (_b = (_a = action.payload) === null || _a === void 0 ? void 0 : _a.room) === null || _b === void 0 ? void 0 : _b.clients.find((c) => { var _a; return c.id === ((_a = action.payload) === null || _a === void 0 ? void 0 : _a.selfId); });
131
+ return Object.assign(Object.assign({}, state), { roleName: (client === null || client === void 0 ? void 0 : client.role.roleName) || "none" });
132
+ });
133
+ },
134
+ });
135
+ const { setRoomKey } = authorizationSlice.actions;
136
+ const selectRoomKey = (state) => state.authorization.roomKey;
137
+ const selectAuthorizationRoleName = (state) => state.authorization.roleName;
138
+ const selectIsAuthorizedToLockRoom = createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canLockRoom.includes(localParticipantRole));
139
+ const selectIsAuthorizedToRequestAudioEnable = createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canRequestAudioEnable.includes(localParticipantRole));
140
+ const selectIsAuthorizedToKickClient = createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canKickClient.includes(localParticipantRole));
141
+ const selectIsAuthorizedToEndMeeting = createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canEndMeeting.includes(localParticipantRole));
142
+
106
143
  /******************************************************************************
107
144
  Copyright (c) Microsoft Corporation.
108
145
 
@@ -325,21 +362,97 @@ createReactor([selectShouldIdentifyDevice, selectDeviceCredentialsRaw], ({ dispa
325
362
  }
326
363
  });
327
364
 
365
+ const initialState$a = {
366
+ chatMessages: [],
367
+ };
368
+ const chatSlice = createSlice({
369
+ name: "chat",
370
+ initialState: initialState$a,
371
+ reducers: {},
372
+ extraReducers(builder) {
373
+ builder.addCase(signalEvents.chatMessage, (state, action) => {
374
+ const message = {
375
+ senderId: action.payload.senderId,
376
+ timestamp: action.payload.timestamp,
377
+ text: action.payload.text,
378
+ };
379
+ return Object.assign(Object.assign({}, state), { chatMessages: [...state.chatMessages, message] });
380
+ });
381
+ },
382
+ });
383
+ const doSendChatMessage = createAppThunk((payload) => (_, getState) => {
384
+ const state = getState();
385
+ const socket = selectSignalConnectionRaw(state).socket;
386
+ socket === null || socket === void 0 ? void 0 : socket.emit("chat_message", { text: payload.text });
387
+ });
388
+ const selectChatRaw = (state) => state.chat;
389
+ const selectChatMessages = (state) => state.chat.chatMessages;
390
+
391
+ const initialCloudRecordingState = {
392
+ isRecording: false,
393
+ error: null,
394
+ startedAt: undefined,
395
+ };
396
+ const cloudRecordingSlice = createSlice({
397
+ name: "cloudRecording",
398
+ initialState: initialCloudRecordingState,
399
+ reducers: {
400
+ recordingRequestStarted: (state) => {
401
+ return Object.assign(Object.assign({}, state), { status: "requested" });
402
+ },
403
+ },
404
+ extraReducers: (builder) => {
405
+ builder.addCase(signalEvents.cloudRecordingStopped, (state) => {
406
+ return Object.assign(Object.assign({}, state), { isRecording: false, status: undefined });
407
+ });
408
+ builder.addCase(signalEvents.cloudRecordingStarted, (state, action) => {
409
+ const { payload } = action;
410
+ if (!payload.error) {
411
+ return state;
412
+ }
413
+ return Object.assign(Object.assign({}, state), { isRecording: false, status: "error", error: payload.error });
414
+ });
415
+ builder.addCase(signalEvents.newClient, (state, { payload }) => {
416
+ var _a;
417
+ const { client } = payload;
418
+ if (((_a = client.role) === null || _a === void 0 ? void 0 : _a.roleName) === "recorder") {
419
+ return Object.assign(Object.assign({}, state), { isRecording: true, status: "recording", startedAt: client.startedCloudRecordingAt
420
+ ? new Date(client.startedCloudRecordingAt).getTime()
421
+ : new Date().getTime() });
422
+ }
423
+ return state;
424
+ });
425
+ },
426
+ });
427
+ const { recordingRequestStarted } = cloudRecordingSlice.actions;
428
+ const doStartCloudRecording = createAppThunk(() => (dispatch, getState) => {
429
+ const state = getState();
430
+ const socket = selectSignalConnectionRaw(state).socket;
431
+ const status = selectCloudRecordingStatus(state);
432
+ if (status && ["recording", "requested"].includes(status)) {
433
+ return;
434
+ }
435
+ socket === null || socket === void 0 ? void 0 : socket.emit("start_recording", {
436
+ recording: "cloud",
437
+ });
438
+ dispatch(recordingRequestStarted());
439
+ });
440
+ const doStopCloudRecording = createAppThunk(() => (dispatch, getState) => {
441
+ const state = getState();
442
+ const socket = selectSignalConnectionRaw(state).socket;
443
+ socket === null || socket === void 0 ? void 0 : socket.emit("stop_recording");
444
+ });
445
+ const selectCloudRecordingRaw = (state) => state.cloudRecording;
446
+ const selectCloudRecordingStatus = (state) => state.cloudRecording.status;
447
+ const selectCloudRecordingStartedAt = (state) => state.cloudRecording.startedAt;
448
+ const selectCloudRecordingError = (state) => state.cloudRecording.error;
449
+ const selectIsCloudRecording = (state) => state.cloudRecording.isRecording;
450
+
328
451
  function fakeAudioStream() {
329
452
  const audioCtx = new AudioContext();
330
453
  const oscillator = audioCtx.createOscillator();
331
454
  const destination = audioCtx.createMediaStreamDestination();
332
455
  oscillator.connect(destination);
333
- oscillator.frequency.value = 400;
334
- oscillator.type = "sine";
335
- setInterval(() => {
336
- if (oscillator.frequency.value <= 900) {
337
- oscillator.frequency.value += 10;
338
- }
339
- else {
340
- oscillator.frequency.value = 200;
341
- }
342
- }, 20);
343
456
  oscillator.start();
344
457
  return destination.stream;
345
458
  }
@@ -391,7 +504,22 @@ function drawWebcamFrame(canvas) {
391
504
  }
392
505
  function fakeWebcamFrame(canvas) {
393
506
  drawWebcamFrame(canvas);
394
- requestAnimationFrame(() => fakeWebcamFrame(canvas));
507
+ setInterval(() => drawWebcamFrame(canvas), 50);
508
+ }
509
+
510
+ const CANVAS_VIDEO_FPS = 24;
511
+ function getAudioTrack() {
512
+ const audioStream = fakeAudioStream();
513
+ return audioStream.getAudioTracks()[0];
514
+ }
515
+ function getVideoTrack({ canvas }) {
516
+ fakeWebcamFrame(canvas);
517
+ const videoStream = canvas.captureStream(CANVAS_VIDEO_FPS);
518
+ return videoStream.getVideoTracks()[0];
519
+ }
520
+ function getFakeMediaStream({ canvas, hasAudio }) {
521
+ const tracks = [getVideoTrack({ canvas }), ...(hasAudio ? [getAudioTrack()] : [])];
522
+ return new MediaStream(tracks);
395
523
  }
396
524
 
397
525
  function debounce(fn, { delay = 500, edges } = {}) {
@@ -455,6 +583,7 @@ const initialLocalMediaState = {
455
583
  isSettingCameraDevice: false,
456
584
  isSettingMicrophoneDevice: false,
457
585
  isTogglingCamera: false,
586
+ lowDataMode: false,
458
587
  microphoneEnabled: false,
459
588
  status: "",
460
589
  isSwitchingStream: false,
@@ -483,6 +612,10 @@ const localMediaSlice = createSlice({
483
612
  setCurrentMicrophoneDeviceId(state, action) {
484
613
  return Object.assign(Object.assign({}, state), { currentMicrophoneDeviceId: action.payload.deviceId });
485
614
  },
615
+ toggleLowDataModeEnabled(state, action) {
616
+ var _a;
617
+ return Object.assign(Object.assign({}, state), { lowDataMode: (_a = action.payload.enabled) !== null && _a !== void 0 ? _a : !state.lowDataMode });
618
+ },
486
619
  setDevices(state, action) {
487
620
  return Object.assign(Object.assign({}, state), { devices: action.payload.devices });
488
621
  },
@@ -561,7 +694,7 @@ const localMediaSlice = createSlice({
561
694
  });
562
695
  },
563
696
  });
564
- const { deviceBusy, setCurrentCameraDeviceId, setCurrentMicrophoneDeviceId, toggleCameraEnabled, toggleMicrophoneEnabled, setLocalMediaOptions, setLocalMediaStream, localMediaStopped, localStreamMetadataUpdated, } = localMediaSlice.actions;
697
+ const { deviceBusy, setCurrentCameraDeviceId, setCurrentMicrophoneDeviceId, toggleCameraEnabled, toggleMicrophoneEnabled, toggleLowDataModeEnabled, setLocalMediaOptions, setLocalMediaStream, localMediaStopped, localStreamMetadataUpdated, } = localMediaSlice.actions;
565
698
  const doToggleCamera = createAppAsyncThunk("localMedia/doToggleCamera", (_, { getState, rejectWithValue }) => __awaiter(void 0, void 0, void 0, function* () {
566
699
  const state = getState();
567
700
  const stream = selectLocalMediaStream(state);
@@ -610,6 +743,16 @@ const doToggleMicrophone = createAppAsyncThunk("localMedia/doToggleMicrophone",
610
743
  }
611
744
  audioTrack.enabled = enabled;
612
745
  });
746
+ const doToggleLowDataMode = createAppThunk(() => (dispatch, getState) => {
747
+ const state = getState();
748
+ const stream = selectLocalMediaStream(state);
749
+ if (!stream) {
750
+ return;
751
+ }
752
+ const videoId = selectCurrentCameraDeviceId(state);
753
+ const audioId = selectCurrentMicrophoneDeviceId(state);
754
+ dispatch(doSwitchLocalStream({ audioId, videoId }));
755
+ });
613
756
  const doSetDevice = createAppAsyncThunk("localMedia/reactSetDevice", ({ audio, video }, { getState, rejectWithValue }) => __awaiter(void 0, void 0, void 0, function* () {
614
757
  try {
615
758
  const state = getState();
@@ -633,12 +776,11 @@ const doSetDevice = createAppAsyncThunk("localMedia/reactSetDevice", ({ audio, v
633
776
  }
634
777
  }));
635
778
  const doUpdateDeviceList = createAppAsyncThunk("localMedia/doUpdateDeviceList", (_, { getState, dispatch, rejectWithValue }) => __awaiter(void 0, void 0, void 0, function* () {
636
- var _a, _b;
779
+ var _a, _b, _c, _d;
637
780
  const state = getState();
638
781
  let newDevices = [];
639
782
  let oldDevices = [];
640
783
  const stream = selectLocalMediaStream(state);
641
- const busy = selectBusyDeviceIds(state);
642
784
  try {
643
785
  newDevices = yield navigator.mediaDevices.enumerateDevices();
644
786
  oldDevices = selectLocalMediaDevices(state);
@@ -650,39 +792,17 @@ const doUpdateDeviceList = createAppAsyncThunk("localMedia/doUpdateDeviceList",
650
792
  if (!shouldHandleDeviceUpdate) {
651
793
  return { devices: newDevices };
652
794
  }
653
- const { changedDevices } = getUpdatedDevices({
795
+ const { changedDevices, addedDevices } = getUpdatedDevices({
654
796
  oldDevices,
655
797
  newDevices,
656
- currentAudioId: selectCurrentMicrophoneDeviceId(state),
657
- currentVideoId: selectCurrentCameraDeviceId(state),
658
798
  });
659
799
  let autoSwitchAudioId = (_a = changedDevices.audioinput) === null || _a === void 0 ? void 0 : _a.deviceId;
660
800
  let autoSwitchVideoId = (_b = changedDevices.videoinput) === null || _b === void 0 ? void 0 : _b.deviceId;
661
- function nextId(devices, id) {
662
- const curIdx = id ? devices.findIndex((d) => d.deviceId === id) : 0;
663
- return (devices[(curIdx + 1) % devices.length] || {}).deviceId;
801
+ if (autoSwitchAudioId === undefined) {
802
+ autoSwitchAudioId = (_c = addedDevices.audioinput) === null || _c === void 0 ? void 0 : _c.deviceId;
664
803
  }
665
- if (autoSwitchVideoId !== undefined) {
666
- const videoDevices = selectLocalMediaDevices(state).filter((d) => d.kind === "videoinput");
667
- const videoId = selectCurrentCameraDeviceId(state);
668
- let nextVideoId = nextId(videoDevices.filter((d) => !busy.includes(d.deviceId)), videoId);
669
- if (!nextVideoId || videoId === nextVideoId) {
670
- nextVideoId = nextId(videoDevices, videoId);
671
- }
672
- if (videoId !== nextVideoId) {
673
- autoSwitchVideoId = nextVideoId;
674
- }
675
- }
676
- if (autoSwitchAudioId !== undefined) {
677
- const audioDevices = selectLocalMediaDevices(state).filter((d) => d.kind === "audioinput");
678
- const audioId = selectCurrentMicrophoneDeviceId(state);
679
- let nextAudioId = nextId(audioDevices.filter((d) => !busy.includes(d.deviceId)), audioId);
680
- if (!nextAudioId || audioId === nextAudioId) {
681
- nextAudioId = nextId(audioDevices, audioId);
682
- }
683
- if (audioId !== nextAudioId) {
684
- autoSwitchAudioId = nextAudioId;
685
- }
804
+ if (autoSwitchVideoId === undefined) {
805
+ autoSwitchVideoId = (_d = addedDevices.videoinput) === null || _d === void 0 ? void 0 : _d.deviceId;
686
806
  }
687
807
  if (autoSwitchAudioId !== undefined || autoSwitchVideoId !== undefined) {
688
808
  dispatch(doSwitchLocalStream({ audioId: autoSwitchAudioId, videoId: autoSwitchVideoId }));
@@ -766,6 +886,7 @@ const selectCurrentCameraDeviceId = (state) => state.localMedia.currentCameraDev
766
886
  const selectCurrentMicrophoneDeviceId = (state) => state.localMedia.currentMicrophoneDeviceId;
767
887
  const selectIsCameraEnabled = (state) => state.localMedia.cameraEnabled;
768
888
  const selectIsMicrophoneEnabled = (state) => state.localMedia.microphoneEnabled;
889
+ const selectIsLowDataModeEnabled = (state) => state.localMedia.lowDataMode;
769
890
  const selectIsSettingCameraDevice = (state) => state.localMedia.isSettingCameraDevice;
770
891
  const selectIsSettingMicrophoneDevice = (state) => state.localMedia.isSettingMicrophoneDevice;
771
892
  const selectIsToggleCamera = (state) => state.localMedia.isTogglingCamera;
@@ -778,14 +899,16 @@ const selectLocalMediaStream = (state) => state.localMedia.stream;
778
899
  const selectMicrophoneDeviceError = (state) => state.localMedia.microphoneDeviceError;
779
900
  const selectLocalMediaStartError = (state) => state.localMedia.startError;
780
901
  const selectLocalMediaIsSwitchingStream = (state) => state.localMedia.isSwitchingStream;
781
- const selectLocalMediaConstraintsOptions = createSelector(selectLocalMediaDevices, (devices) => ({
902
+ const selectLocalMediaConstraintsOptions = createSelector(selectLocalMediaDevices, selectCurrentCameraDeviceId, selectCurrentMicrophoneDeviceId, selectIsLowDataModeEnabled, (devices, videoId, audioId, lowDataMode) => ({
782
903
  devices,
904
+ videoId,
905
+ audioId,
783
906
  options: {
784
907
  disableAEC: false,
785
908
  disableAGC: false,
786
909
  hd: true,
787
910
  lax: false,
788
- lowDataMode: false,
911
+ lowDataMode,
789
912
  simulcast: true,
790
913
  widescreen: true,
791
914
  },
@@ -823,6 +946,17 @@ startAppListening({
823
946
  dispatch(doToggleMicrophone());
824
947
  },
825
948
  });
949
+ startAppListening({
950
+ predicate: (_action, currentState, previousState) => {
951
+ const oldValue = selectIsLowDataModeEnabled(previousState);
952
+ const newValue = selectIsLowDataModeEnabled(currentState);
953
+ const isReady = selectLocalMediaStatus(previousState) === "started";
954
+ return isReady && oldValue !== newValue;
955
+ },
956
+ effect: (_action, { dispatch }) => {
957
+ dispatch(doToggleLowDataMode());
958
+ },
959
+ });
826
960
  startAppListening({
827
961
  predicate: (_action, currentState, previousState) => {
828
962
  const isToggling = selectIsToggleCamera(currentState);
@@ -886,7 +1020,7 @@ startAppListening({
886
1020
  },
887
1021
  });
888
1022
 
889
- const initialState$a = {
1023
+ const initialState$9 = {
890
1024
  displayName: "",
891
1025
  id: "",
892
1026
  isAudioEnabled: true,
@@ -920,7 +1054,7 @@ const doSetDisplayName = createAppAsyncThunk("localParticipant/doSetDisplayName"
920
1054
  }));
921
1055
  const localParticipantSlice = createSlice({
922
1056
  name: "localParticipant",
923
- initialState: initialState$a,
1057
+ initialState: initialState$9,
924
1058
  reducers: {
925
1059
  doSetLocalParticipant: (state, action) => {
926
1060
  return Object.assign(Object.assign({}, state), action.payload);
@@ -950,7 +1084,6 @@ const { doSetLocalParticipant } = localParticipantSlice.actions;
950
1084
  const selectLocalParticipantRaw = (state) => state.localParticipant;
951
1085
  const selectSelfId = (state) => state.localParticipant.id;
952
1086
  const selectLocalParticipantClientClaim = (state) => state.localParticipant.clientClaim;
953
- const selectLocalParticipantRole = (state) => state.localParticipant.roleName;
954
1087
  const selectLocalParticipantIsScreenSharing = (state) => state.localParticipant.isScreenSharing;
955
1088
  startAppListening({
956
1089
  actionCreator: toggleCameraEnabled,
@@ -969,144 +1102,14 @@ startAppListening({
969
1102
  },
970
1103
  });
971
1104
 
972
- const ACTION_PERMISSIONS_BY_ROLE = {
973
- canLockRoom: ["host"],
974
- canRequestAudioEnable: ["host"],
975
- };
976
- const initialState$9 = {
977
- roomKey: null,
978
- roomLocked: false,
979
- };
980
- const authorizationSlice = createSlice({
981
- name: "authorization",
982
- initialState: initialState$9,
983
- reducers: {
984
- setRoomKey: (state, action) => {
985
- return Object.assign(Object.assign({}, state), { roomKey: action.payload });
986
- },
987
- },
988
- extraReducers: (builder) => {
989
- builder.addCase(doAppJoin, (state, action) => {
990
- return Object.assign(Object.assign({}, state), { roomKey: action.payload.roomKey });
991
- });
992
- builder.addCase(signalEvents.roomJoined, (state, action) => {
993
- const { error, isLocked } = action.payload;
994
- if (error) {
995
- return state;
996
- }
997
- return Object.assign(Object.assign({}, state), { roomLocked: isLocked });
998
- });
999
- builder.addCase(signalEvents.roomLocked, (state, action) => {
1000
- const { isLocked } = action.payload;
1001
- return Object.assign(Object.assign({}, state), { roomLocked: isLocked });
1002
- });
1003
- },
1004
- });
1005
- const { setRoomKey } = authorizationSlice.actions;
1006
- const doLockRoom = createAppAuthorizedThunk((state) => selectIsAuthorizedToLockRoom(state), (payload) => (_, getState) => {
1007
- const state = getState();
1008
- const { socket } = selectSignalConnectionRaw(state);
1009
- socket === null || socket === void 0 ? void 0 : socket.emit("set_lock", { locked: payload.locked });
1010
- });
1011
- const selectAuthorizationRoomKey = (state) => state.authorization.roomKey;
1012
- const selectAuthorizationRoomLocked = (state) => state.authorization.roomLocked;
1013
- const selectIsAuthorizedToLockRoom = createSelector(selectLocalParticipantRole, (localParticipantRole) => ACTION_PERMISSIONS_BY_ROLE.canLockRoom.includes(localParticipantRole));
1014
- const selectIsAuthorizedToRequestAudioEnable = createSelector(selectLocalParticipantRole, (localParticipantRole) => ACTION_PERMISSIONS_BY_ROLE.canRequestAudioEnable.includes(localParticipantRole));
1015
-
1016
1105
  const initialState$8 = {
1017
- chatMessages: [],
1018
- };
1019
- const chatSlice = createSlice({
1020
- name: "chat",
1021
- initialState: initialState$8,
1022
- reducers: {},
1023
- extraReducers(builder) {
1024
- builder.addCase(signalEvents.chatMessage, (state, action) => {
1025
- const message = {
1026
- senderId: action.payload.senderId,
1027
- timestamp: action.payload.timestamp,
1028
- text: action.payload.text,
1029
- };
1030
- return Object.assign(Object.assign({}, state), { chatMessages: [...state.chatMessages, message] });
1031
- });
1032
- },
1033
- });
1034
- const doSendChatMessage = createAppThunk((payload) => (_, getState) => {
1035
- const state = getState();
1036
- const socket = selectSignalConnectionRaw(state).socket;
1037
- socket === null || socket === void 0 ? void 0 : socket.emit("chat_message", { text: payload.text });
1038
- });
1039
- const selectChatRaw = (state) => state.chat;
1040
- const selectChatMessages = (state) => state.chat.chatMessages;
1041
-
1042
- const initialCloudRecordingState = {
1043
- isRecording: false,
1044
- error: null,
1045
- startedAt: undefined,
1046
- };
1047
- const cloudRecordingSlice = createSlice({
1048
- name: "cloudRecording",
1049
- initialState: initialCloudRecordingState,
1050
- reducers: {
1051
- recordingRequestStarted: (state) => {
1052
- return Object.assign(Object.assign({}, state), { status: "requested" });
1053
- },
1054
- },
1055
- extraReducers: (builder) => {
1056
- builder.addCase(signalEvents.cloudRecordingStopped, (state) => {
1057
- return Object.assign(Object.assign({}, state), { isRecording: false, status: undefined });
1058
- });
1059
- builder.addCase(signalEvents.cloudRecordingStarted, (state, action) => {
1060
- const { payload } = action;
1061
- if (!payload.error) {
1062
- return state;
1063
- }
1064
- return Object.assign(Object.assign({}, state), { isRecording: false, status: "error", error: payload.error });
1065
- });
1066
- builder.addCase(signalEvents.newClient, (state, { payload }) => {
1067
- var _a;
1068
- const { client } = payload;
1069
- if (((_a = client.role) === null || _a === void 0 ? void 0 : _a.roleName) === "recorder") {
1070
- return Object.assign(Object.assign({}, state), { isRecording: true, status: "recording", startedAt: client.startedCloudRecordingAt
1071
- ? new Date(client.startedCloudRecordingAt).getTime()
1072
- : new Date().getTime() });
1073
- }
1074
- return state;
1075
- });
1076
- },
1077
- });
1078
- const { recordingRequestStarted } = cloudRecordingSlice.actions;
1079
- const doStartCloudRecording = createAppThunk(() => (dispatch, getState) => {
1080
- const state = getState();
1081
- const socket = selectSignalConnectionRaw(state).socket;
1082
- const status = selectCloudRecordingStatus(state);
1083
- if (status && ["recording", "requested"].includes(status)) {
1084
- return;
1085
- }
1086
- socket === null || socket === void 0 ? void 0 : socket.emit("start_recording", {
1087
- recording: "cloud",
1088
- });
1089
- dispatch(recordingRequestStarted());
1090
- });
1091
- const doStopCloudRecording = createAppThunk(() => (dispatch, getState) => {
1092
- const state = getState();
1093
- const socket = selectSignalConnectionRaw(state).socket;
1094
- socket === null || socket === void 0 ? void 0 : socket.emit("stop_recording");
1095
- });
1096
- const selectCloudRecordingRaw = (state) => state.cloudRecording;
1097
- const selectCloudRecordingStatus = (state) => state.cloudRecording.status;
1098
- const selectCloudRecordingStartedAt = (state) => state.cloudRecording.startedAt;
1099
- const selectCloudRecordingError = (state) => state.cloudRecording.error;
1100
- const selectIsCloudRecording = (state) => state.cloudRecording.isRecording;
1101
-
1102
- const initialState$7 = {
1103
1106
  status: "",
1104
1107
  stream: null,
1105
1108
  error: null,
1106
1109
  };
1107
1110
  const localScreenshareSlice = createSlice({
1108
1111
  name: "localScreenshare",
1109
- initialState: initialState$7,
1112
+ initialState: initialState$8,
1110
1113
  reducers: {
1111
1114
  stopScreenshare(state, action) {
1112
1115
  return Object.assign(Object.assign({}, state), { status: "", stream: null });
@@ -1175,13 +1178,13 @@ startAppListening({
1175
1178
  },
1176
1179
  });
1177
1180
 
1178
- const initialState$6 = {
1181
+ const initialState$7 = {
1179
1182
  data: null,
1180
1183
  isFetching: false,
1181
1184
  error: null,
1182
1185
  };
1183
1186
  const organizationSlice = createSlice({
1184
- initialState: initialState$6,
1187
+ initialState: initialState$7,
1185
1188
  name: "organization",
1186
1189
  reducers: {},
1187
1190
  extraReducers: (builder) => {
@@ -1330,12 +1333,12 @@ function addStream(state, payload) {
1330
1333
  presentationStream: stream,
1331
1334
  });
1332
1335
  }
1333
- const initialState$5 = {
1336
+ const initialState$6 = {
1334
1337
  remoteParticipants: [],
1335
1338
  };
1336
1339
  const remoteParticipantsSlice = createSlice({
1337
1340
  name: "remoteParticipants",
1338
- initialState: initialState$5,
1341
+ initialState: initialState$6,
1339
1342
  reducers: {
1340
1343
  streamStatusUpdated: (state, action) => {
1341
1344
  let newState = state;
@@ -1442,6 +1445,47 @@ const selectScreenshares = createSelector(selectLocalScreenshareStream, selectRe
1442
1445
  return screenshares;
1443
1446
  });
1444
1447
 
1448
+ const initialState$5 = {
1449
+ isLocked: false,
1450
+ };
1451
+ const roomSlice = createSlice({
1452
+ name: "room",
1453
+ initialState: initialState$5,
1454
+ reducers: {},
1455
+ extraReducers: (builder) => {
1456
+ builder.addCase(signalEvents.roomJoined, (state, action) => {
1457
+ const { error, isLocked } = action.payload;
1458
+ if (error) {
1459
+ return state;
1460
+ }
1461
+ return Object.assign(Object.assign({}, state), { isLocked: Boolean(isLocked) });
1462
+ });
1463
+ builder.addCase(signalEvents.roomLocked, (state, action) => {
1464
+ const { isLocked } = action.payload;
1465
+ return Object.assign(Object.assign({}, state), { isLocked: Boolean(isLocked) });
1466
+ });
1467
+ },
1468
+ });
1469
+ const doLockRoom = createAppAuthorizedThunk((state) => selectIsAuthorizedToLockRoom(state), (payload) => (_, getState) => {
1470
+ const state = getState();
1471
+ const { socket } = selectSignalConnectionRaw(state);
1472
+ socket === null || socket === void 0 ? void 0 : socket.emit("set_lock", { locked: payload.locked });
1473
+ });
1474
+ const doKickParticipant = createAppAuthorizedThunk((state) => selectIsAuthorizedToKickClient(state), (payload) => (_, getState) => {
1475
+ const state = getState();
1476
+ const { socket } = selectSignalConnectionRaw(state);
1477
+ socket === null || socket === void 0 ? void 0 : socket.emit("kick_client", { clientId: payload.clientId, reasonId: "kick" });
1478
+ });
1479
+ const doEndMeeting = createAppAuthorizedThunk((state) => selectIsAuthorizedToEndMeeting(state), () => (_, getState) => {
1480
+ const state = getState();
1481
+ const clientsToKick = selectRemoteParticipants(state).map((c) => c.id);
1482
+ if (clientsToKick.length) {
1483
+ const { socket } = selectSignalConnectionRaw(state);
1484
+ socket === null || socket === void 0 ? void 0 : socket.emit("kick_client", { clientIds: clientsToKick, reasonId: "end-meeting" });
1485
+ }
1486
+ });
1487
+ const selectRoomIsLocked = (state) => state.room.isLocked;
1488
+
1445
1489
  const initialState$4 = {
1446
1490
  session: null,
1447
1491
  status: "initializing",
@@ -1494,7 +1538,7 @@ const doKnockRoom = createAppThunk(() => (dispatch, getState) => {
1494
1538
  const state = getState();
1495
1539
  const socket = selectSignalConnectionRaw(state).socket;
1496
1540
  const roomName = selectAppRoomName(state);
1497
- const roomKey = selectAuthorizationRoomKey(state);
1541
+ const roomKey = selectRoomKey(state);
1498
1542
  const displayName = selectAppDisplayName(state);
1499
1543
  const userAgent = selectAppUserAgent(state);
1500
1544
  const externalId = selectAppExternalId(state);
@@ -1522,7 +1566,7 @@ const doConnectRoom = createAppThunk(() => (dispatch, getState) => {
1522
1566
  const state = getState();
1523
1567
  const socket = selectSignalConnectionRaw(state).socket;
1524
1568
  const roomName = selectAppRoomName(state);
1525
- const roomKey = selectAuthorizationRoomKey(state);
1569
+ const roomKey = selectRoomKey(state);
1526
1570
  const displayName = selectAppDisplayName(state);
1527
1571
  const userAgent = selectAppUserAgent(state);
1528
1572
  const externalId = selectAppExternalId(state);
@@ -1794,6 +1838,23 @@ startAppListening({
1794
1838
  rtcManager === null || rtcManager === void 0 ? void 0 : rtcManager.removeStream(stream.id, stream, null);
1795
1839
  },
1796
1840
  });
1841
+ startAppListening({
1842
+ actionCreator: doSwitchLocalStream.fulfilled,
1843
+ effect: ({ payload }, { getState }) => {
1844
+ var _a;
1845
+ const stream = selectLocalMediaStream(getState());
1846
+ const { rtcManager } = selectRtcConnectionRaw(getState());
1847
+ if (stream && rtcManager) {
1848
+ const replace = (kind, oldTrack) => {
1849
+ const track = stream.getTracks().find((t) => t.kind === kind);
1850
+ return track && rtcManager.replaceTrack(oldTrack, track);
1851
+ };
1852
+ (_a = payload === null || payload === void 0 ? void 0 : payload.replacedTracks) === null || _a === void 0 ? void 0 : _a.forEach((t) => {
1853
+ replace(t.kind, t);
1854
+ });
1855
+ }
1856
+ },
1857
+ });
1797
1858
  const selectShouldConnectRtc = createSelector(selectRtcDispatcherCreated, selectRtcIsCreatingDispatcher, selectSignalConnectionSocket, (dispatcherCreated, isCreatingDispatcher, signalSocket) => {
1798
1859
  if (!dispatcherCreated && !isCreatingDispatcher && signalSocket) {
1799
1860
  return true;
@@ -1959,7 +2020,7 @@ const rtcAnalyticsCustomEvents = {
1959
2020
  userRole: {
1960
2021
  actions: null,
1961
2022
  rtcEventName: "userRole",
1962
- getValue: (state) => selectLocalParticipantRole(state),
2023
+ getValue: (state) => selectAuthorizationRoleName(state),
1963
2024
  getOutput: (value) => ({ userRole: value }),
1964
2025
  },
1965
2026
  };
@@ -2121,6 +2182,7 @@ const rootReducer = combineReducers({
2121
2182
  localScreenshare: localScreenshareSlice.reducer,
2122
2183
  organization: organizationSlice.reducer,
2123
2184
  remoteParticipants: remoteParticipantsSlice.reducer,
2185
+ room: roomSlice.reducer,
2124
2186
  roomConnection: roomConnectionSlice.reducer,
2125
2187
  rtcAnalytics: rtcAnalyticsSlice.reducer,
2126
2188
  rtcConnection: rtcConnectionSlice.reducer,
@@ -3162,4 +3224,4 @@ function createServices() {
3162
3224
  };
3163
3225
  }
3164
3226
 
3165
- export { ApiClient, Credentials, CredentialsService, LocalParticipant, OrganizationApiClient, OrganizationService, OrganizationServiceCache, RoomService, addAppListener, appLeft, appSlice, authorizationSlice, chatSlice, cloudRecordingSlice, createAppAsyncThunk, createAppAuthorizedThunk, createAppThunk, createReactor, createServices, createStore, createWebRtcEmitter, debounce, deviceBusy, deviceCredentialsSlice, deviceIdentified, deviceIdentifying, doAcceptWaitingParticipant, doAppJoin, doConnectRoom, doConnectRtc, doDisconnectRtc, doEnableAudio, doEnableVideo, doGetDeviceCredentials, doHandleAcceptStreams, doHandleStreamingStarted, doHandleStreamingStopped, doKnockRoom, doLockRoom, doOrganizationFetch, doRejectWaitingParticipant, doRequestAudioEnable, doRtcAnalyticsCustomEventsInitialize, doRtcManagerCreated, doRtcManagerInitialize, doRtcReportStreamResolution, doSendChatMessage, doSetDevice, doSetDisplayName, doSetLocalParticipant, doSignalDisconnect, doSignalIdentifyDevice, doSignalSocketConnect, doStartCloudRecording, doStartLocalMedia, doStartScreenshare, doStopCloudRecording, doStopLocalMedia, doStopScreenshare, doSwitchLocalStream, doToggleCamera, doUpdateDeviceList, fakeAudioStream, fakeWebcamFrame, initialCloudRecordingState, initialLocalMediaState, isAcceptingStreams, listenerMiddleware, localMediaSlice, localMediaStopped, localParticipantSlice, localScreenshareSlice, localStreamMetadataUpdated, observeStore, organizationSlice, parseRoomUrlAndSubdomain, parseUnverifiedRoomKeyData, participantStreamAdded, participantStreamIdAdded, recordingRequestStarted, remoteParticipantsSlice, resolutionReported, roomConnectionSlice, rootReducer, rtcAnalyticsCustomEvents, rtcAnalyticsSlice, rtcConnectionSlice, rtcDisconnected, rtcDispatcherCreated, rtcManagerCreated, rtcManagerDestroyed, rtcManagerInitialized, selectAppDisplayName, selectAppExternalId, selectAppIsNodeSdk, selectAppRaw, selectAppRoomName, selectAppRoomUrl, selectAppUserAgent, selectAppWantsToJoin, selectAuthorizationRoomKey, selectAuthorizationRoomLocked, selectBusyDeviceIds, selectCameraDeviceError, selectCameraDevices, selectChatMessages, selectChatRaw, selectCloudRecordingError, selectCloudRecordingRaw, selectCloudRecordingStartedAt, selectCloudRecordingStatus, selectCurrentCameraDeviceId, selectCurrentMicrophoneDeviceId, selectDeviceCredentialsRaw, selectDeviceId, selectHasFetchedDeviceCredentials, selectIsAcceptingStreams, selectIsAuthorizedToLockRoom, selectIsAuthorizedToRequestAudioEnable, selectIsCameraEnabled, selectIsCloudRecording, selectIsLocalMediaStarting, selectIsMicrophoneEnabled, selectIsSettingCameraDevice, selectIsSettingMicrophoneDevice, selectIsToggleCamera, selectLocalMediaConstraintsOptions, selectLocalMediaDevices, selectLocalMediaIsSwitchingStream, selectLocalMediaOptions, selectLocalMediaOwnsStream, selectLocalMediaRaw, selectLocalMediaShouldStartWithOptions, selectLocalMediaShouldStop, selectLocalMediaStartError, selectLocalMediaStatus, selectLocalMediaStream, selectLocalParticipantClientClaim, selectLocalParticipantIsScreenSharing, selectLocalParticipantRaw, selectLocalParticipantRole, selectLocalScreenshareRaw, selectLocalScreenshareStatus, selectLocalScreenshareStream, selectMicrophoneDeviceError, selectMicrophoneDevices, selectOrganizationId, selectOrganizationRaw, selectRemoteParticipants, selectRemoteParticipantsRaw, selectRoomConnectionError, selectRoomConnectionRaw, selectRoomConnectionSession, selectRoomConnectionSessionId, selectRoomConnectionStatus, selectRtcConnectionRaw, selectRtcDispatcherCreated, selectRtcIsCreatingDispatcher, selectRtcManager, selectRtcManagerInitialized, selectRtcStatus, selectScreenshares, selectSelfId, selectShouldConnectRoom, selectShouldConnectRtc, selectShouldConnectSignal, selectShouldDisconnectRtc, selectShouldFetchDeviceCredentials, selectShouldFetchOrganization, selectShouldIdentifyDevice, selectShouldInitializeRtc, selectSignalConnectionDeviceIdentified, selectSignalConnectionRaw, selectSignalConnectionSocket, selectSignalIsIdentifyingDevice, selectSignalStatus, selectSpeakerDevices, selectStreamingRaw, selectStreamsToAccept, selectWaitingParticipants, selectWaitingParticipantsRaw, setCurrentCameraDeviceId, setCurrentMicrophoneDeviceId, setLocalMediaOptions, setLocalMediaStream, setRoomKey, signalConnectionSlice, socketConnected, socketConnecting, socketDisconnected, socketReconnecting, startAppListening, stopScreenshare, streamStatusUpdated, streamingSlice, toggleCameraEnabled, toggleMicrophoneEnabled, updateReportedValues, waitingParticipantsSlice };
3227
+ export { ApiClient, Credentials, CredentialsService, LocalParticipant, OrganizationApiClient, OrganizationService, OrganizationServiceCache, RoomService, addAppListener, appLeft, appSlice, authorizationSlice, chatSlice, cloudRecordingSlice, createAppAsyncThunk, createAppAuthorizedThunk, createAppThunk, createReactor, createServices, createStore, createWebRtcEmitter, debounce, deviceBusy, deviceCredentialsSlice, deviceIdentified, deviceIdentifying, doAcceptWaitingParticipant, doAppJoin, doConnectRoom, doConnectRtc, doDisconnectRtc, doEnableAudio, doEnableVideo, doEndMeeting, doGetDeviceCredentials, doHandleAcceptStreams, doHandleStreamingStarted, doHandleStreamingStopped, doKickParticipant, doKnockRoom, doLockRoom, doOrganizationFetch, doRejectWaitingParticipant, doRequestAudioEnable, doRtcAnalyticsCustomEventsInitialize, doRtcManagerCreated, doRtcManagerInitialize, doRtcReportStreamResolution, doSendChatMessage, doSetDevice, doSetDisplayName, doSetLocalParticipant, doSignalDisconnect, doSignalIdentifyDevice, doSignalSocketConnect, doStartCloudRecording, doStartLocalMedia, doStartScreenshare, doStopCloudRecording, doStopLocalMedia, doStopScreenshare, doSwitchLocalStream, doToggleCamera, doToggleLowDataMode, doUpdateDeviceList, getAudioTrack, getFakeMediaStream, getVideoTrack, initialCloudRecordingState, initialLocalMediaState, isAcceptingStreams, listenerMiddleware, localMediaSlice, localMediaStopped, localParticipantSlice, localScreenshareSlice, localStreamMetadataUpdated, observeStore, organizationSlice, parseRoomUrlAndSubdomain, parseUnverifiedRoomKeyData, participantStreamAdded, participantStreamIdAdded, recordingRequestStarted, remoteParticipantsSlice, resolutionReported, roomConnectionSlice, roomSlice, rootReducer, rtcAnalyticsCustomEvents, rtcAnalyticsSlice, rtcConnectionSlice, rtcDisconnected, rtcDispatcherCreated, rtcManagerCreated, rtcManagerDestroyed, rtcManagerInitialized, selectAppDisplayName, selectAppExternalId, selectAppIsNodeSdk, selectAppRaw, selectAppRoomName, selectAppRoomUrl, selectAppUserAgent, selectAppWantsToJoin, selectAuthorizationRoleName, selectBusyDeviceIds, selectCameraDeviceError, selectCameraDevices, selectChatMessages, selectChatRaw, selectCloudRecordingError, selectCloudRecordingRaw, selectCloudRecordingStartedAt, selectCloudRecordingStatus, selectCurrentCameraDeviceId, selectCurrentMicrophoneDeviceId, selectDeviceCredentialsRaw, selectDeviceId, selectHasFetchedDeviceCredentials, selectIsAcceptingStreams, selectIsAuthorizedToEndMeeting, selectIsAuthorizedToKickClient, selectIsAuthorizedToLockRoom, selectIsAuthorizedToRequestAudioEnable, selectIsCameraEnabled, selectIsCloudRecording, selectIsLocalMediaStarting, selectIsLowDataModeEnabled, selectIsMicrophoneEnabled, selectIsSettingCameraDevice, selectIsSettingMicrophoneDevice, selectIsToggleCamera, selectLocalMediaConstraintsOptions, selectLocalMediaDevices, selectLocalMediaIsSwitchingStream, selectLocalMediaOptions, selectLocalMediaOwnsStream, selectLocalMediaRaw, selectLocalMediaShouldStartWithOptions, selectLocalMediaShouldStop, selectLocalMediaStartError, selectLocalMediaStatus, selectLocalMediaStream, selectLocalParticipantClientClaim, selectLocalParticipantIsScreenSharing, selectLocalParticipantRaw, selectLocalScreenshareRaw, selectLocalScreenshareStatus, selectLocalScreenshareStream, selectMicrophoneDeviceError, selectMicrophoneDevices, selectOrganizationId, selectOrganizationRaw, selectRemoteParticipants, selectRemoteParticipantsRaw, selectRoomConnectionError, selectRoomConnectionRaw, selectRoomConnectionSession, selectRoomConnectionSessionId, selectRoomConnectionStatus, selectRoomIsLocked, selectRoomKey, selectRtcConnectionRaw, selectRtcDispatcherCreated, selectRtcIsCreatingDispatcher, selectRtcManager, selectRtcManagerInitialized, selectRtcStatus, selectScreenshares, selectSelfId, selectShouldConnectRoom, selectShouldConnectRtc, selectShouldConnectSignal, selectShouldDisconnectRtc, selectShouldFetchDeviceCredentials, selectShouldFetchOrganization, selectShouldIdentifyDevice, selectShouldInitializeRtc, selectSignalConnectionDeviceIdentified, selectSignalConnectionRaw, selectSignalConnectionSocket, selectSignalIsIdentifyingDevice, selectSignalStatus, selectSpeakerDevices, selectStreamingRaw, selectStreamsToAccept, selectWaitingParticipants, selectWaitingParticipantsRaw, setCurrentCameraDeviceId, setCurrentMicrophoneDeviceId, setLocalMediaOptions, setLocalMediaStream, setRoomKey, signalConnectionSlice, socketConnected, socketConnecting, socketDisconnected, socketReconnecting, startAppListening, stopScreenshare, streamStatusUpdated, streamingSlice, toggleCameraEnabled, toggleLowDataModeEnabled, toggleMicrophoneEnabled, updateReportedValues, waitingParticipantsSlice };