@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.cjs CHANGED
@@ -45,9 +45,9 @@ const createReactor = (selectors, callback) => {
45
45
  });
46
46
  };
47
47
 
48
- const coreVersion = "0.12.1";
48
+ const coreVersion = "0.13.1";
49
49
 
50
- const initialState$d = {
50
+ const initialState$e = {
51
51
  isNodeSdk: false,
52
52
  wantsToJoin: false,
53
53
  roomName: null,
@@ -58,7 +58,7 @@ const initialState$d = {
58
58
  };
59
59
  const appSlice = toolkit.createSlice({
60
60
  name: "app",
61
- initialState: initialState$d,
61
+ initialState: initialState$e,
62
62
  reducers: {
63
63
  doAppJoin: (state, action) => {
64
64
  const url = new URL(action.payload.roomUrl);
@@ -105,6 +105,43 @@ const signalEvents = {
105
105
  videoEnabled: createSignalEventAction("videoEnabled"),
106
106
  };
107
107
 
108
+ const ROOM_ACTION_PERMISSIONS_BY_ROLE = {
109
+ canLockRoom: ["host"],
110
+ canRequestAudioEnable: ["host"],
111
+ canKickClient: ["host"],
112
+ canEndMeeting: ["host"],
113
+ };
114
+ const initialState$d = {
115
+ roomKey: null,
116
+ roleName: "none",
117
+ };
118
+ const authorizationSlice = toolkit.createSlice({
119
+ name: "authorization",
120
+ initialState: initialState$d,
121
+ reducers: {
122
+ setRoomKey: (state, action) => {
123
+ return Object.assign(Object.assign({}, state), { roomKey: action.payload });
124
+ },
125
+ },
126
+ extraReducers: (builder) => {
127
+ builder.addCase(doAppJoin, (state, action) => {
128
+ return Object.assign(Object.assign({}, state), { roomKey: action.payload.roomKey });
129
+ });
130
+ builder.addCase(signalEvents.roomJoined, (state, action) => {
131
+ var _a, _b;
132
+ 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); });
133
+ return Object.assign(Object.assign({}, state), { roleName: (client === null || client === void 0 ? void 0 : client.role.roleName) || "none" });
134
+ });
135
+ },
136
+ });
137
+ const { setRoomKey } = authorizationSlice.actions;
138
+ const selectRoomKey = (state) => state.authorization.roomKey;
139
+ const selectAuthorizationRoleName = (state) => state.authorization.roleName;
140
+ const selectIsAuthorizedToLockRoom = toolkit.createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canLockRoom.includes(localParticipantRole));
141
+ const selectIsAuthorizedToRequestAudioEnable = toolkit.createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canRequestAudioEnable.includes(localParticipantRole));
142
+ const selectIsAuthorizedToKickClient = toolkit.createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canKickClient.includes(localParticipantRole));
143
+ const selectIsAuthorizedToEndMeeting = toolkit.createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canEndMeeting.includes(localParticipantRole));
144
+
108
145
  /******************************************************************************
109
146
  Copyright (c) Microsoft Corporation.
110
147
 
@@ -327,21 +364,97 @@ createReactor([selectShouldIdentifyDevice, selectDeviceCredentialsRaw], ({ dispa
327
364
  }
328
365
  });
329
366
 
367
+ const initialState$a = {
368
+ chatMessages: [],
369
+ };
370
+ const chatSlice = toolkit.createSlice({
371
+ name: "chat",
372
+ initialState: initialState$a,
373
+ reducers: {},
374
+ extraReducers(builder) {
375
+ builder.addCase(signalEvents.chatMessage, (state, action) => {
376
+ const message = {
377
+ senderId: action.payload.senderId,
378
+ timestamp: action.payload.timestamp,
379
+ text: action.payload.text,
380
+ };
381
+ return Object.assign(Object.assign({}, state), { chatMessages: [...state.chatMessages, message] });
382
+ });
383
+ },
384
+ });
385
+ const doSendChatMessage = createAppThunk((payload) => (_, getState) => {
386
+ const state = getState();
387
+ const socket = selectSignalConnectionRaw(state).socket;
388
+ socket === null || socket === void 0 ? void 0 : socket.emit("chat_message", { text: payload.text });
389
+ });
390
+ const selectChatRaw = (state) => state.chat;
391
+ const selectChatMessages = (state) => state.chat.chatMessages;
392
+
393
+ const initialCloudRecordingState = {
394
+ isRecording: false,
395
+ error: null,
396
+ startedAt: undefined,
397
+ };
398
+ const cloudRecordingSlice = toolkit.createSlice({
399
+ name: "cloudRecording",
400
+ initialState: initialCloudRecordingState,
401
+ reducers: {
402
+ recordingRequestStarted: (state) => {
403
+ return Object.assign(Object.assign({}, state), { status: "requested" });
404
+ },
405
+ },
406
+ extraReducers: (builder) => {
407
+ builder.addCase(signalEvents.cloudRecordingStopped, (state) => {
408
+ return Object.assign(Object.assign({}, state), { isRecording: false, status: undefined });
409
+ });
410
+ builder.addCase(signalEvents.cloudRecordingStarted, (state, action) => {
411
+ const { payload } = action;
412
+ if (!payload.error) {
413
+ return state;
414
+ }
415
+ return Object.assign(Object.assign({}, state), { isRecording: false, status: "error", error: payload.error });
416
+ });
417
+ builder.addCase(signalEvents.newClient, (state, { payload }) => {
418
+ var _a;
419
+ const { client } = payload;
420
+ if (((_a = client.role) === null || _a === void 0 ? void 0 : _a.roleName) === "recorder") {
421
+ return Object.assign(Object.assign({}, state), { isRecording: true, status: "recording", startedAt: client.startedCloudRecordingAt
422
+ ? new Date(client.startedCloudRecordingAt).getTime()
423
+ : new Date().getTime() });
424
+ }
425
+ return state;
426
+ });
427
+ },
428
+ });
429
+ const { recordingRequestStarted } = cloudRecordingSlice.actions;
430
+ const doStartCloudRecording = createAppThunk(() => (dispatch, getState) => {
431
+ const state = getState();
432
+ const socket = selectSignalConnectionRaw(state).socket;
433
+ const status = selectCloudRecordingStatus(state);
434
+ if (status && ["recording", "requested"].includes(status)) {
435
+ return;
436
+ }
437
+ socket === null || socket === void 0 ? void 0 : socket.emit("start_recording", {
438
+ recording: "cloud",
439
+ });
440
+ dispatch(recordingRequestStarted());
441
+ });
442
+ const doStopCloudRecording = createAppThunk(() => (dispatch, getState) => {
443
+ const state = getState();
444
+ const socket = selectSignalConnectionRaw(state).socket;
445
+ socket === null || socket === void 0 ? void 0 : socket.emit("stop_recording");
446
+ });
447
+ const selectCloudRecordingRaw = (state) => state.cloudRecording;
448
+ const selectCloudRecordingStatus = (state) => state.cloudRecording.status;
449
+ const selectCloudRecordingStartedAt = (state) => state.cloudRecording.startedAt;
450
+ const selectCloudRecordingError = (state) => state.cloudRecording.error;
451
+ const selectIsCloudRecording = (state) => state.cloudRecording.isRecording;
452
+
330
453
  function fakeAudioStream() {
331
454
  const audioCtx = new AudioContext();
332
455
  const oscillator = audioCtx.createOscillator();
333
456
  const destination = audioCtx.createMediaStreamDestination();
334
457
  oscillator.connect(destination);
335
- oscillator.frequency.value = 400;
336
- oscillator.type = "sine";
337
- setInterval(() => {
338
- if (oscillator.frequency.value <= 900) {
339
- oscillator.frequency.value += 10;
340
- }
341
- else {
342
- oscillator.frequency.value = 200;
343
- }
344
- }, 20);
345
458
  oscillator.start();
346
459
  return destination.stream;
347
460
  }
@@ -393,7 +506,22 @@ function drawWebcamFrame(canvas) {
393
506
  }
394
507
  function fakeWebcamFrame(canvas) {
395
508
  drawWebcamFrame(canvas);
396
- requestAnimationFrame(() => fakeWebcamFrame(canvas));
509
+ setInterval(() => drawWebcamFrame(canvas), 50);
510
+ }
511
+
512
+ const CANVAS_VIDEO_FPS = 24;
513
+ function getAudioTrack() {
514
+ const audioStream = fakeAudioStream();
515
+ return audioStream.getAudioTracks()[0];
516
+ }
517
+ function getVideoTrack({ canvas }) {
518
+ fakeWebcamFrame(canvas);
519
+ const videoStream = canvas.captureStream(CANVAS_VIDEO_FPS);
520
+ return videoStream.getVideoTracks()[0];
521
+ }
522
+ function getFakeMediaStream({ canvas, hasAudio }) {
523
+ const tracks = [getVideoTrack({ canvas }), ...(hasAudio ? [getAudioTrack()] : [])];
524
+ return new MediaStream(tracks);
397
525
  }
398
526
 
399
527
  function debounce(fn, { delay = 500, edges } = {}) {
@@ -457,6 +585,7 @@ const initialLocalMediaState = {
457
585
  isSettingCameraDevice: false,
458
586
  isSettingMicrophoneDevice: false,
459
587
  isTogglingCamera: false,
588
+ lowDataMode: false,
460
589
  microphoneEnabled: false,
461
590
  status: "",
462
591
  isSwitchingStream: false,
@@ -485,6 +614,10 @@ const localMediaSlice = toolkit.createSlice({
485
614
  setCurrentMicrophoneDeviceId(state, action) {
486
615
  return Object.assign(Object.assign({}, state), { currentMicrophoneDeviceId: action.payload.deviceId });
487
616
  },
617
+ toggleLowDataModeEnabled(state, action) {
618
+ var _a;
619
+ return Object.assign(Object.assign({}, state), { lowDataMode: (_a = action.payload.enabled) !== null && _a !== void 0 ? _a : !state.lowDataMode });
620
+ },
488
621
  setDevices(state, action) {
489
622
  return Object.assign(Object.assign({}, state), { devices: action.payload.devices });
490
623
  },
@@ -563,7 +696,7 @@ const localMediaSlice = toolkit.createSlice({
563
696
  });
564
697
  },
565
698
  });
566
- const { deviceBusy, setCurrentCameraDeviceId, setCurrentMicrophoneDeviceId, toggleCameraEnabled, toggleMicrophoneEnabled, setLocalMediaOptions, setLocalMediaStream, localMediaStopped, localStreamMetadataUpdated, } = localMediaSlice.actions;
699
+ const { deviceBusy, setCurrentCameraDeviceId, setCurrentMicrophoneDeviceId, toggleCameraEnabled, toggleMicrophoneEnabled, toggleLowDataModeEnabled, setLocalMediaOptions, setLocalMediaStream, localMediaStopped, localStreamMetadataUpdated, } = localMediaSlice.actions;
567
700
  const doToggleCamera = createAppAsyncThunk("localMedia/doToggleCamera", (_, { getState, rejectWithValue }) => __awaiter(void 0, void 0, void 0, function* () {
568
701
  const state = getState();
569
702
  const stream = selectLocalMediaStream(state);
@@ -612,6 +745,16 @@ const doToggleMicrophone = createAppAsyncThunk("localMedia/doToggleMicrophone",
612
745
  }
613
746
  audioTrack.enabled = enabled;
614
747
  });
748
+ const doToggleLowDataMode = createAppThunk(() => (dispatch, getState) => {
749
+ const state = getState();
750
+ const stream = selectLocalMediaStream(state);
751
+ if (!stream) {
752
+ return;
753
+ }
754
+ const videoId = selectCurrentCameraDeviceId(state);
755
+ const audioId = selectCurrentMicrophoneDeviceId(state);
756
+ dispatch(doSwitchLocalStream({ audioId, videoId }));
757
+ });
615
758
  const doSetDevice = createAppAsyncThunk("localMedia/reactSetDevice", ({ audio, video }, { getState, rejectWithValue }) => __awaiter(void 0, void 0, void 0, function* () {
616
759
  try {
617
760
  const state = getState();
@@ -635,12 +778,11 @@ const doSetDevice = createAppAsyncThunk("localMedia/reactSetDevice", ({ audio, v
635
778
  }
636
779
  }));
637
780
  const doUpdateDeviceList = createAppAsyncThunk("localMedia/doUpdateDeviceList", (_, { getState, dispatch, rejectWithValue }) => __awaiter(void 0, void 0, void 0, function* () {
638
- var _a, _b;
781
+ var _a, _b, _c, _d;
639
782
  const state = getState();
640
783
  let newDevices = [];
641
784
  let oldDevices = [];
642
785
  const stream = selectLocalMediaStream(state);
643
- const busy = selectBusyDeviceIds(state);
644
786
  try {
645
787
  newDevices = yield navigator.mediaDevices.enumerateDevices();
646
788
  oldDevices = selectLocalMediaDevices(state);
@@ -652,39 +794,17 @@ const doUpdateDeviceList = createAppAsyncThunk("localMedia/doUpdateDeviceList",
652
794
  if (!shouldHandleDeviceUpdate) {
653
795
  return { devices: newDevices };
654
796
  }
655
- const { changedDevices } = media.getUpdatedDevices({
797
+ const { changedDevices, addedDevices } = media.getUpdatedDevices({
656
798
  oldDevices,
657
799
  newDevices,
658
- currentAudioId: selectCurrentMicrophoneDeviceId(state),
659
- currentVideoId: selectCurrentCameraDeviceId(state),
660
800
  });
661
801
  let autoSwitchAudioId = (_a = changedDevices.audioinput) === null || _a === void 0 ? void 0 : _a.deviceId;
662
802
  let autoSwitchVideoId = (_b = changedDevices.videoinput) === null || _b === void 0 ? void 0 : _b.deviceId;
663
- function nextId(devices, id) {
664
- const curIdx = id ? devices.findIndex((d) => d.deviceId === id) : 0;
665
- return (devices[(curIdx + 1) % devices.length] || {}).deviceId;
803
+ if (autoSwitchAudioId === undefined) {
804
+ autoSwitchAudioId = (_c = addedDevices.audioinput) === null || _c === void 0 ? void 0 : _c.deviceId;
666
805
  }
667
- if (autoSwitchVideoId !== undefined) {
668
- const videoDevices = selectLocalMediaDevices(state).filter((d) => d.kind === "videoinput");
669
- const videoId = selectCurrentCameraDeviceId(state);
670
- let nextVideoId = nextId(videoDevices.filter((d) => !busy.includes(d.deviceId)), videoId);
671
- if (!nextVideoId || videoId === nextVideoId) {
672
- nextVideoId = nextId(videoDevices, videoId);
673
- }
674
- if (videoId !== nextVideoId) {
675
- autoSwitchVideoId = nextVideoId;
676
- }
677
- }
678
- if (autoSwitchAudioId !== undefined) {
679
- const audioDevices = selectLocalMediaDevices(state).filter((d) => d.kind === "audioinput");
680
- const audioId = selectCurrentMicrophoneDeviceId(state);
681
- let nextAudioId = nextId(audioDevices.filter((d) => !busy.includes(d.deviceId)), audioId);
682
- if (!nextAudioId || audioId === nextAudioId) {
683
- nextAudioId = nextId(audioDevices, audioId);
684
- }
685
- if (audioId !== nextAudioId) {
686
- autoSwitchAudioId = nextAudioId;
687
- }
806
+ if (autoSwitchVideoId === undefined) {
807
+ autoSwitchVideoId = (_d = addedDevices.videoinput) === null || _d === void 0 ? void 0 : _d.deviceId;
688
808
  }
689
809
  if (autoSwitchAudioId !== undefined || autoSwitchVideoId !== undefined) {
690
810
  dispatch(doSwitchLocalStream({ audioId: autoSwitchAudioId, videoId: autoSwitchVideoId }));
@@ -768,6 +888,7 @@ const selectCurrentCameraDeviceId = (state) => state.localMedia.currentCameraDev
768
888
  const selectCurrentMicrophoneDeviceId = (state) => state.localMedia.currentMicrophoneDeviceId;
769
889
  const selectIsCameraEnabled = (state) => state.localMedia.cameraEnabled;
770
890
  const selectIsMicrophoneEnabled = (state) => state.localMedia.microphoneEnabled;
891
+ const selectIsLowDataModeEnabled = (state) => state.localMedia.lowDataMode;
771
892
  const selectIsSettingCameraDevice = (state) => state.localMedia.isSettingCameraDevice;
772
893
  const selectIsSettingMicrophoneDevice = (state) => state.localMedia.isSettingMicrophoneDevice;
773
894
  const selectIsToggleCamera = (state) => state.localMedia.isTogglingCamera;
@@ -780,14 +901,16 @@ const selectLocalMediaStream = (state) => state.localMedia.stream;
780
901
  const selectMicrophoneDeviceError = (state) => state.localMedia.microphoneDeviceError;
781
902
  const selectLocalMediaStartError = (state) => state.localMedia.startError;
782
903
  const selectLocalMediaIsSwitchingStream = (state) => state.localMedia.isSwitchingStream;
783
- const selectLocalMediaConstraintsOptions = toolkit.createSelector(selectLocalMediaDevices, (devices) => ({
904
+ const selectLocalMediaConstraintsOptions = toolkit.createSelector(selectLocalMediaDevices, selectCurrentCameraDeviceId, selectCurrentMicrophoneDeviceId, selectIsLowDataModeEnabled, (devices, videoId, audioId, lowDataMode) => ({
784
905
  devices,
906
+ videoId,
907
+ audioId,
785
908
  options: {
786
909
  disableAEC: false,
787
910
  disableAGC: false,
788
911
  hd: true,
789
912
  lax: false,
790
- lowDataMode: false,
913
+ lowDataMode,
791
914
  simulcast: true,
792
915
  widescreen: true,
793
916
  },
@@ -825,6 +948,17 @@ startAppListening({
825
948
  dispatch(doToggleMicrophone());
826
949
  },
827
950
  });
951
+ startAppListening({
952
+ predicate: (_action, currentState, previousState) => {
953
+ const oldValue = selectIsLowDataModeEnabled(previousState);
954
+ const newValue = selectIsLowDataModeEnabled(currentState);
955
+ const isReady = selectLocalMediaStatus(previousState) === "started";
956
+ return isReady && oldValue !== newValue;
957
+ },
958
+ effect: (_action, { dispatch }) => {
959
+ dispatch(doToggleLowDataMode());
960
+ },
961
+ });
828
962
  startAppListening({
829
963
  predicate: (_action, currentState, previousState) => {
830
964
  const isToggling = selectIsToggleCamera(currentState);
@@ -888,7 +1022,7 @@ startAppListening({
888
1022
  },
889
1023
  });
890
1024
 
891
- const initialState$a = {
1025
+ const initialState$9 = {
892
1026
  displayName: "",
893
1027
  id: "",
894
1028
  isAudioEnabled: true,
@@ -922,7 +1056,7 @@ const doSetDisplayName = createAppAsyncThunk("localParticipant/doSetDisplayName"
922
1056
  }));
923
1057
  const localParticipantSlice = toolkit.createSlice({
924
1058
  name: "localParticipant",
925
- initialState: initialState$a,
1059
+ initialState: initialState$9,
926
1060
  reducers: {
927
1061
  doSetLocalParticipant: (state, action) => {
928
1062
  return Object.assign(Object.assign({}, state), action.payload);
@@ -952,7 +1086,6 @@ const { doSetLocalParticipant } = localParticipantSlice.actions;
952
1086
  const selectLocalParticipantRaw = (state) => state.localParticipant;
953
1087
  const selectSelfId = (state) => state.localParticipant.id;
954
1088
  const selectLocalParticipantClientClaim = (state) => state.localParticipant.clientClaim;
955
- const selectLocalParticipantRole = (state) => state.localParticipant.roleName;
956
1089
  const selectLocalParticipantIsScreenSharing = (state) => state.localParticipant.isScreenSharing;
957
1090
  startAppListening({
958
1091
  actionCreator: toggleCameraEnabled,
@@ -971,144 +1104,14 @@ startAppListening({
971
1104
  },
972
1105
  });
973
1106
 
974
- const ACTION_PERMISSIONS_BY_ROLE = {
975
- canLockRoom: ["host"],
976
- canRequestAudioEnable: ["host"],
977
- };
978
- const initialState$9 = {
979
- roomKey: null,
980
- roomLocked: false,
981
- };
982
- const authorizationSlice = toolkit.createSlice({
983
- name: "authorization",
984
- initialState: initialState$9,
985
- reducers: {
986
- setRoomKey: (state, action) => {
987
- return Object.assign(Object.assign({}, state), { roomKey: action.payload });
988
- },
989
- },
990
- extraReducers: (builder) => {
991
- builder.addCase(doAppJoin, (state, action) => {
992
- return Object.assign(Object.assign({}, state), { roomKey: action.payload.roomKey });
993
- });
994
- builder.addCase(signalEvents.roomJoined, (state, action) => {
995
- const { error, isLocked } = action.payload;
996
- if (error) {
997
- return state;
998
- }
999
- return Object.assign(Object.assign({}, state), { roomLocked: isLocked });
1000
- });
1001
- builder.addCase(signalEvents.roomLocked, (state, action) => {
1002
- const { isLocked } = action.payload;
1003
- return Object.assign(Object.assign({}, state), { roomLocked: isLocked });
1004
- });
1005
- },
1006
- });
1007
- const { setRoomKey } = authorizationSlice.actions;
1008
- const doLockRoom = createAppAuthorizedThunk((state) => selectIsAuthorizedToLockRoom(state), (payload) => (_, getState) => {
1009
- const state = getState();
1010
- const { socket } = selectSignalConnectionRaw(state);
1011
- socket === null || socket === void 0 ? void 0 : socket.emit("set_lock", { locked: payload.locked });
1012
- });
1013
- const selectAuthorizationRoomKey = (state) => state.authorization.roomKey;
1014
- const selectAuthorizationRoomLocked = (state) => state.authorization.roomLocked;
1015
- const selectIsAuthorizedToLockRoom = toolkit.createSelector(selectLocalParticipantRole, (localParticipantRole) => ACTION_PERMISSIONS_BY_ROLE.canLockRoom.includes(localParticipantRole));
1016
- const selectIsAuthorizedToRequestAudioEnable = toolkit.createSelector(selectLocalParticipantRole, (localParticipantRole) => ACTION_PERMISSIONS_BY_ROLE.canRequestAudioEnable.includes(localParticipantRole));
1017
-
1018
1107
  const initialState$8 = {
1019
- chatMessages: [],
1020
- };
1021
- const chatSlice = toolkit.createSlice({
1022
- name: "chat",
1023
- initialState: initialState$8,
1024
- reducers: {},
1025
- extraReducers(builder) {
1026
- builder.addCase(signalEvents.chatMessage, (state, action) => {
1027
- const message = {
1028
- senderId: action.payload.senderId,
1029
- timestamp: action.payload.timestamp,
1030
- text: action.payload.text,
1031
- };
1032
- return Object.assign(Object.assign({}, state), { chatMessages: [...state.chatMessages, message] });
1033
- });
1034
- },
1035
- });
1036
- const doSendChatMessage = createAppThunk((payload) => (_, getState) => {
1037
- const state = getState();
1038
- const socket = selectSignalConnectionRaw(state).socket;
1039
- socket === null || socket === void 0 ? void 0 : socket.emit("chat_message", { text: payload.text });
1040
- });
1041
- const selectChatRaw = (state) => state.chat;
1042
- const selectChatMessages = (state) => state.chat.chatMessages;
1043
-
1044
- const initialCloudRecordingState = {
1045
- isRecording: false,
1046
- error: null,
1047
- startedAt: undefined,
1048
- };
1049
- const cloudRecordingSlice = toolkit.createSlice({
1050
- name: "cloudRecording",
1051
- initialState: initialCloudRecordingState,
1052
- reducers: {
1053
- recordingRequestStarted: (state) => {
1054
- return Object.assign(Object.assign({}, state), { status: "requested" });
1055
- },
1056
- },
1057
- extraReducers: (builder) => {
1058
- builder.addCase(signalEvents.cloudRecordingStopped, (state) => {
1059
- return Object.assign(Object.assign({}, state), { isRecording: false, status: undefined });
1060
- });
1061
- builder.addCase(signalEvents.cloudRecordingStarted, (state, action) => {
1062
- const { payload } = action;
1063
- if (!payload.error) {
1064
- return state;
1065
- }
1066
- return Object.assign(Object.assign({}, state), { isRecording: false, status: "error", error: payload.error });
1067
- });
1068
- builder.addCase(signalEvents.newClient, (state, { payload }) => {
1069
- var _a;
1070
- const { client } = payload;
1071
- if (((_a = client.role) === null || _a === void 0 ? void 0 : _a.roleName) === "recorder") {
1072
- return Object.assign(Object.assign({}, state), { isRecording: true, status: "recording", startedAt: client.startedCloudRecordingAt
1073
- ? new Date(client.startedCloudRecordingAt).getTime()
1074
- : new Date().getTime() });
1075
- }
1076
- return state;
1077
- });
1078
- },
1079
- });
1080
- const { recordingRequestStarted } = cloudRecordingSlice.actions;
1081
- const doStartCloudRecording = createAppThunk(() => (dispatch, getState) => {
1082
- const state = getState();
1083
- const socket = selectSignalConnectionRaw(state).socket;
1084
- const status = selectCloudRecordingStatus(state);
1085
- if (status && ["recording", "requested"].includes(status)) {
1086
- return;
1087
- }
1088
- socket === null || socket === void 0 ? void 0 : socket.emit("start_recording", {
1089
- recording: "cloud",
1090
- });
1091
- dispatch(recordingRequestStarted());
1092
- });
1093
- const doStopCloudRecording = createAppThunk(() => (dispatch, getState) => {
1094
- const state = getState();
1095
- const socket = selectSignalConnectionRaw(state).socket;
1096
- socket === null || socket === void 0 ? void 0 : socket.emit("stop_recording");
1097
- });
1098
- const selectCloudRecordingRaw = (state) => state.cloudRecording;
1099
- const selectCloudRecordingStatus = (state) => state.cloudRecording.status;
1100
- const selectCloudRecordingStartedAt = (state) => state.cloudRecording.startedAt;
1101
- const selectCloudRecordingError = (state) => state.cloudRecording.error;
1102
- const selectIsCloudRecording = (state) => state.cloudRecording.isRecording;
1103
-
1104
- const initialState$7 = {
1105
1108
  status: "",
1106
1109
  stream: null,
1107
1110
  error: null,
1108
1111
  };
1109
1112
  const localScreenshareSlice = toolkit.createSlice({
1110
1113
  name: "localScreenshare",
1111
- initialState: initialState$7,
1114
+ initialState: initialState$8,
1112
1115
  reducers: {
1113
1116
  stopScreenshare(state, action) {
1114
1117
  return Object.assign(Object.assign({}, state), { status: "", stream: null });
@@ -1177,13 +1180,13 @@ startAppListening({
1177
1180
  },
1178
1181
  });
1179
1182
 
1180
- const initialState$6 = {
1183
+ const initialState$7 = {
1181
1184
  data: null,
1182
1185
  isFetching: false,
1183
1186
  error: null,
1184
1187
  };
1185
1188
  const organizationSlice = toolkit.createSlice({
1186
- initialState: initialState$6,
1189
+ initialState: initialState$7,
1187
1190
  name: "organization",
1188
1191
  reducers: {},
1189
1192
  extraReducers: (builder) => {
@@ -1332,12 +1335,12 @@ function addStream(state, payload) {
1332
1335
  presentationStream: stream,
1333
1336
  });
1334
1337
  }
1335
- const initialState$5 = {
1338
+ const initialState$6 = {
1336
1339
  remoteParticipants: [],
1337
1340
  };
1338
1341
  const remoteParticipantsSlice = toolkit.createSlice({
1339
1342
  name: "remoteParticipants",
1340
- initialState: initialState$5,
1343
+ initialState: initialState$6,
1341
1344
  reducers: {
1342
1345
  streamStatusUpdated: (state, action) => {
1343
1346
  let newState = state;
@@ -1444,6 +1447,47 @@ const selectScreenshares = toolkit.createSelector(selectLocalScreenshareStream,
1444
1447
  return screenshares;
1445
1448
  });
1446
1449
 
1450
+ const initialState$5 = {
1451
+ isLocked: false,
1452
+ };
1453
+ const roomSlice = toolkit.createSlice({
1454
+ name: "room",
1455
+ initialState: initialState$5,
1456
+ reducers: {},
1457
+ extraReducers: (builder) => {
1458
+ builder.addCase(signalEvents.roomJoined, (state, action) => {
1459
+ const { error, isLocked } = action.payload;
1460
+ if (error) {
1461
+ return state;
1462
+ }
1463
+ return Object.assign(Object.assign({}, state), { isLocked: Boolean(isLocked) });
1464
+ });
1465
+ builder.addCase(signalEvents.roomLocked, (state, action) => {
1466
+ const { isLocked } = action.payload;
1467
+ return Object.assign(Object.assign({}, state), { isLocked: Boolean(isLocked) });
1468
+ });
1469
+ },
1470
+ });
1471
+ const doLockRoom = createAppAuthorizedThunk((state) => selectIsAuthorizedToLockRoom(state), (payload) => (_, getState) => {
1472
+ const state = getState();
1473
+ const { socket } = selectSignalConnectionRaw(state);
1474
+ socket === null || socket === void 0 ? void 0 : socket.emit("set_lock", { locked: payload.locked });
1475
+ });
1476
+ const doKickParticipant = createAppAuthorizedThunk((state) => selectIsAuthorizedToKickClient(state), (payload) => (_, getState) => {
1477
+ const state = getState();
1478
+ const { socket } = selectSignalConnectionRaw(state);
1479
+ socket === null || socket === void 0 ? void 0 : socket.emit("kick_client", { clientId: payload.clientId, reasonId: "kick" });
1480
+ });
1481
+ const doEndMeeting = createAppAuthorizedThunk((state) => selectIsAuthorizedToEndMeeting(state), () => (_, getState) => {
1482
+ const state = getState();
1483
+ const clientsToKick = selectRemoteParticipants(state).map((c) => c.id);
1484
+ if (clientsToKick.length) {
1485
+ const { socket } = selectSignalConnectionRaw(state);
1486
+ socket === null || socket === void 0 ? void 0 : socket.emit("kick_client", { clientIds: clientsToKick, reasonId: "end-meeting" });
1487
+ }
1488
+ });
1489
+ const selectRoomIsLocked = (state) => state.room.isLocked;
1490
+
1447
1491
  const initialState$4 = {
1448
1492
  session: null,
1449
1493
  status: "initializing",
@@ -1496,7 +1540,7 @@ const doKnockRoom = createAppThunk(() => (dispatch, getState) => {
1496
1540
  const state = getState();
1497
1541
  const socket = selectSignalConnectionRaw(state).socket;
1498
1542
  const roomName = selectAppRoomName(state);
1499
- const roomKey = selectAuthorizationRoomKey(state);
1543
+ const roomKey = selectRoomKey(state);
1500
1544
  const displayName = selectAppDisplayName(state);
1501
1545
  const userAgent = selectAppUserAgent(state);
1502
1546
  const externalId = selectAppExternalId(state);
@@ -1524,7 +1568,7 @@ const doConnectRoom = createAppThunk(() => (dispatch, getState) => {
1524
1568
  const state = getState();
1525
1569
  const socket = selectSignalConnectionRaw(state).socket;
1526
1570
  const roomName = selectAppRoomName(state);
1527
- const roomKey = selectAuthorizationRoomKey(state);
1571
+ const roomKey = selectRoomKey(state);
1528
1572
  const displayName = selectAppDisplayName(state);
1529
1573
  const userAgent = selectAppUserAgent(state);
1530
1574
  const externalId = selectAppExternalId(state);
@@ -1796,6 +1840,23 @@ startAppListening({
1796
1840
  rtcManager === null || rtcManager === void 0 ? void 0 : rtcManager.removeStream(stream.id, stream, null);
1797
1841
  },
1798
1842
  });
1843
+ startAppListening({
1844
+ actionCreator: doSwitchLocalStream.fulfilled,
1845
+ effect: ({ payload }, { getState }) => {
1846
+ var _a;
1847
+ const stream = selectLocalMediaStream(getState());
1848
+ const { rtcManager } = selectRtcConnectionRaw(getState());
1849
+ if (stream && rtcManager) {
1850
+ const replace = (kind, oldTrack) => {
1851
+ const track = stream.getTracks().find((t) => t.kind === kind);
1852
+ return track && rtcManager.replaceTrack(oldTrack, track);
1853
+ };
1854
+ (_a = payload === null || payload === void 0 ? void 0 : payload.replacedTracks) === null || _a === void 0 ? void 0 : _a.forEach((t) => {
1855
+ replace(t.kind, t);
1856
+ });
1857
+ }
1858
+ },
1859
+ });
1799
1860
  const selectShouldConnectRtc = toolkit.createSelector(selectRtcDispatcherCreated, selectRtcIsCreatingDispatcher, selectSignalConnectionSocket, (dispatcherCreated, isCreatingDispatcher, signalSocket) => {
1800
1861
  if (!dispatcherCreated && !isCreatingDispatcher && signalSocket) {
1801
1862
  return true;
@@ -1961,7 +2022,7 @@ const rtcAnalyticsCustomEvents = {
1961
2022
  userRole: {
1962
2023
  actions: null,
1963
2024
  rtcEventName: "userRole",
1964
- getValue: (state) => selectLocalParticipantRole(state),
2025
+ getValue: (state) => selectAuthorizationRoleName(state),
1965
2026
  getOutput: (value) => ({ userRole: value }),
1966
2027
  },
1967
2028
  };
@@ -2123,6 +2184,7 @@ const rootReducer = toolkit.combineReducers({
2123
2184
  localScreenshare: localScreenshareSlice.reducer,
2124
2185
  organization: organizationSlice.reducer,
2125
2186
  remoteParticipants: remoteParticipantsSlice.reducer,
2187
+ room: roomSlice.reducer,
2126
2188
  roomConnection: roomConnectionSlice.reducer,
2127
2189
  rtcAnalytics: rtcAnalyticsSlice.reducer,
2128
2190
  rtcConnection: rtcConnectionSlice.reducer,
@@ -3197,10 +3259,12 @@ exports.doConnectRtc = doConnectRtc;
3197
3259
  exports.doDisconnectRtc = doDisconnectRtc;
3198
3260
  exports.doEnableAudio = doEnableAudio;
3199
3261
  exports.doEnableVideo = doEnableVideo;
3262
+ exports.doEndMeeting = doEndMeeting;
3200
3263
  exports.doGetDeviceCredentials = doGetDeviceCredentials;
3201
3264
  exports.doHandleAcceptStreams = doHandleAcceptStreams;
3202
3265
  exports.doHandleStreamingStarted = doHandleStreamingStarted;
3203
3266
  exports.doHandleStreamingStopped = doHandleStreamingStopped;
3267
+ exports.doKickParticipant = doKickParticipant;
3204
3268
  exports.doKnockRoom = doKnockRoom;
3205
3269
  exports.doLockRoom = doLockRoom;
3206
3270
  exports.doOrganizationFetch = doOrganizationFetch;
@@ -3225,9 +3289,11 @@ exports.doStopLocalMedia = doStopLocalMedia;
3225
3289
  exports.doStopScreenshare = doStopScreenshare;
3226
3290
  exports.doSwitchLocalStream = doSwitchLocalStream;
3227
3291
  exports.doToggleCamera = doToggleCamera;
3292
+ exports.doToggleLowDataMode = doToggleLowDataMode;
3228
3293
  exports.doUpdateDeviceList = doUpdateDeviceList;
3229
- exports.fakeAudioStream = fakeAudioStream;
3230
- exports.fakeWebcamFrame = fakeWebcamFrame;
3294
+ exports.getAudioTrack = getAudioTrack;
3295
+ exports.getFakeMediaStream = getFakeMediaStream;
3296
+ exports.getVideoTrack = getVideoTrack;
3231
3297
  exports.initialCloudRecordingState = initialCloudRecordingState;
3232
3298
  exports.initialLocalMediaState = initialLocalMediaState;
3233
3299
  exports.isAcceptingStreams = isAcceptingStreams;
@@ -3247,6 +3313,7 @@ exports.recordingRequestStarted = recordingRequestStarted;
3247
3313
  exports.remoteParticipantsSlice = remoteParticipantsSlice;
3248
3314
  exports.resolutionReported = resolutionReported;
3249
3315
  exports.roomConnectionSlice = roomConnectionSlice;
3316
+ exports.roomSlice = roomSlice;
3250
3317
  exports.rootReducer = rootReducer;
3251
3318
  exports.rtcAnalyticsCustomEvents = rtcAnalyticsCustomEvents;
3252
3319
  exports.rtcAnalyticsSlice = rtcAnalyticsSlice;
@@ -3264,8 +3331,7 @@ exports.selectAppRoomName = selectAppRoomName;
3264
3331
  exports.selectAppRoomUrl = selectAppRoomUrl;
3265
3332
  exports.selectAppUserAgent = selectAppUserAgent;
3266
3333
  exports.selectAppWantsToJoin = selectAppWantsToJoin;
3267
- exports.selectAuthorizationRoomKey = selectAuthorizationRoomKey;
3268
- exports.selectAuthorizationRoomLocked = selectAuthorizationRoomLocked;
3334
+ exports.selectAuthorizationRoleName = selectAuthorizationRoleName;
3269
3335
  exports.selectBusyDeviceIds = selectBusyDeviceIds;
3270
3336
  exports.selectCameraDeviceError = selectCameraDeviceError;
3271
3337
  exports.selectCameraDevices = selectCameraDevices;
@@ -3281,11 +3347,14 @@ exports.selectDeviceCredentialsRaw = selectDeviceCredentialsRaw;
3281
3347
  exports.selectDeviceId = selectDeviceId;
3282
3348
  exports.selectHasFetchedDeviceCredentials = selectHasFetchedDeviceCredentials;
3283
3349
  exports.selectIsAcceptingStreams = selectIsAcceptingStreams;
3350
+ exports.selectIsAuthorizedToEndMeeting = selectIsAuthorizedToEndMeeting;
3351
+ exports.selectIsAuthorizedToKickClient = selectIsAuthorizedToKickClient;
3284
3352
  exports.selectIsAuthorizedToLockRoom = selectIsAuthorizedToLockRoom;
3285
3353
  exports.selectIsAuthorizedToRequestAudioEnable = selectIsAuthorizedToRequestAudioEnable;
3286
3354
  exports.selectIsCameraEnabled = selectIsCameraEnabled;
3287
3355
  exports.selectIsCloudRecording = selectIsCloudRecording;
3288
3356
  exports.selectIsLocalMediaStarting = selectIsLocalMediaStarting;
3357
+ exports.selectIsLowDataModeEnabled = selectIsLowDataModeEnabled;
3289
3358
  exports.selectIsMicrophoneEnabled = selectIsMicrophoneEnabled;
3290
3359
  exports.selectIsSettingCameraDevice = selectIsSettingCameraDevice;
3291
3360
  exports.selectIsSettingMicrophoneDevice = selectIsSettingMicrophoneDevice;
@@ -3304,7 +3373,6 @@ exports.selectLocalMediaStream = selectLocalMediaStream;
3304
3373
  exports.selectLocalParticipantClientClaim = selectLocalParticipantClientClaim;
3305
3374
  exports.selectLocalParticipantIsScreenSharing = selectLocalParticipantIsScreenSharing;
3306
3375
  exports.selectLocalParticipantRaw = selectLocalParticipantRaw;
3307
- exports.selectLocalParticipantRole = selectLocalParticipantRole;
3308
3376
  exports.selectLocalScreenshareRaw = selectLocalScreenshareRaw;
3309
3377
  exports.selectLocalScreenshareStatus = selectLocalScreenshareStatus;
3310
3378
  exports.selectLocalScreenshareStream = selectLocalScreenshareStream;
@@ -3319,6 +3387,8 @@ exports.selectRoomConnectionRaw = selectRoomConnectionRaw;
3319
3387
  exports.selectRoomConnectionSession = selectRoomConnectionSession;
3320
3388
  exports.selectRoomConnectionSessionId = selectRoomConnectionSessionId;
3321
3389
  exports.selectRoomConnectionStatus = selectRoomConnectionStatus;
3390
+ exports.selectRoomIsLocked = selectRoomIsLocked;
3391
+ exports.selectRoomKey = selectRoomKey;
3322
3392
  exports.selectRtcConnectionRaw = selectRtcConnectionRaw;
3323
3393
  exports.selectRtcDispatcherCreated = selectRtcDispatcherCreated;
3324
3394
  exports.selectRtcIsCreatingDispatcher = selectRtcIsCreatingDispatcher;
@@ -3360,6 +3430,7 @@ exports.stopScreenshare = stopScreenshare;
3360
3430
  exports.streamStatusUpdated = streamStatusUpdated;
3361
3431
  exports.streamingSlice = streamingSlice;
3362
3432
  exports.toggleCameraEnabled = toggleCameraEnabled;
3433
+ exports.toggleLowDataModeEnabled = toggleLowDataModeEnabled;
3363
3434
  exports.toggleMicrophoneEnabled = toggleMicrophoneEnabled;
3364
3435
  exports.updateReportedValues = updateReportedValues;
3365
3436
  exports.waitingParticipantsSlice = waitingParticipantsSlice;