@whereby.com/core 0.25.1 → 0.27.0

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
@@ -2,8 +2,8 @@
2
2
 
3
3
  var toolkit = require('@reduxjs/toolkit');
4
4
  var media = require('@whereby.com/media');
5
- var events$1 = require('events');
6
5
  var Chrome111_js = require('mediasoup-client/lib/handlers/Chrome111.js');
6
+ var events$1 = require('events');
7
7
  var nodeBtoa = require('btoa');
8
8
  var axios = require('axios');
9
9
 
@@ -23,6 +23,37 @@ function createAppAuthorizedThunk(authorizationSelector, thunk) {
23
23
  return thunk(payload)(dispatch, getState, extra);
24
24
  });
25
25
  }
26
+ function createRoomConnectedThunk(thunk) {
27
+ return createAppThunk((payload) => (dispatch, getState, extra) => {
28
+ const connectionStatus = getState().roomConnection.status;
29
+ if (connectionStatus !== "connected") {
30
+ console.warn("Action cannot be performed outside of a connected room");
31
+ return false;
32
+ }
33
+ return thunk(payload)(dispatch, getState, extra);
34
+ });
35
+ }
36
+ function createAsyncRoomConnectedThunk(typePrefix, payloadCreator) {
37
+ return createAppAsyncThunk(typePrefix, (arg, thunkApi) => {
38
+ const { getState } = thunkApi;
39
+ const connectionStatus = getState().roomConnection.status;
40
+ if (connectionStatus !== "connected") {
41
+ console.warn("Action cannot be performed outside of a connected room");
42
+ return Promise.reject("Action cannot be performed outside of a connected room");
43
+ }
44
+ return payloadCreator(arg, thunkApi);
45
+ });
46
+ }
47
+ function createAuthorizedRoomConnectedThunk(authorizationSelector, thunk) {
48
+ return createAppThunk((payload) => (dispatch, getState, extra) => {
49
+ const connectionStatus = getState().roomConnection.status;
50
+ if (connectionStatus !== "connected") {
51
+ console.warn("Action cannot be performed outside of a connected room");
52
+ return false;
53
+ }
54
+ return createAppAuthorizedThunk(authorizationSelector, thunk)(payload)(dispatch, getState, extra);
55
+ });
56
+ }
26
57
 
27
58
  const listenerMiddleware = toolkit.createListenerMiddleware();
28
59
  const startAppListening = listenerMiddleware.startListening;
@@ -45,9 +76,9 @@ const createReactor = (selectors, callback) => {
45
76
  });
46
77
  };
47
78
 
48
- const coreVersion = "0.25.1";
79
+ const coreVersion = "0.27.0";
49
80
 
50
- const initialState$f = {
81
+ const initialState$g = {
51
82
  isNodeSdk: false,
52
83
  isActive: false,
53
84
  isDialIn: false,
@@ -59,7 +90,7 @@ const initialState$f = {
59
90
  };
60
91
  const appSlice = toolkit.createSlice({
61
92
  name: "app",
62
- initialState: initialState$f,
93
+ initialState: initialState$g,
63
94
  reducers: {
64
95
  doAppStart: (state, action) => {
65
96
  const url = new URL(action.payload.roomUrl);
@@ -110,6 +141,7 @@ const signalEvents = {
110
141
  spotlightRemoved: createSignalEventAction("spotlightRemoved"),
111
142
  streamingStopped: createSignalEventAction("streamingStopped"),
112
143
  videoEnabled: createSignalEventAction("videoEnabled"),
144
+ videoEnableRequested: createSignalEventAction("videoEnableRequested"),
113
145
  liveTranscriptionStarted: createSignalEventAction("liveTranscriptionStarted"),
114
146
  liveTranscriptionStopped: createSignalEventAction("liveTranscriptionStopped"),
115
147
  };
@@ -117,18 +149,19 @@ const signalEvents = {
117
149
  const ROOM_ACTION_PERMISSIONS_BY_ROLE = {
118
150
  canLockRoom: ["host"],
119
151
  canRequestAudioEnable: ["host"],
152
+ canRequestVideoEnable: ["host"],
120
153
  canKickClient: ["host"],
121
154
  canEndMeeting: ["host"],
122
155
  canAskToSpeak: ["host"],
123
156
  canSpotlight: ["host"],
124
157
  };
125
- const initialState$e = {
158
+ const initialState$f = {
126
159
  roomKey: null,
127
160
  roleName: "none",
128
161
  };
129
162
  const authorizationSlice = toolkit.createSlice({
130
163
  name: "authorization",
131
- initialState: initialState$e,
164
+ initialState: initialState$f,
132
165
  reducers: {
133
166
  setRoomKey: (state, action) => {
134
167
  return Object.assign(Object.assign({}, state), { roomKey: action.payload });
@@ -150,6 +183,7 @@ const selectRoomKey = (state) => state.authorization.roomKey;
150
183
  const selectAuthorizationRoleName = (state) => state.authorization.roleName;
151
184
  const selectIsAuthorizedToLockRoom = toolkit.createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canLockRoom.includes(localParticipantRole));
152
185
  const selectIsAuthorizedToRequestAudioEnable = toolkit.createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canRequestAudioEnable.includes(localParticipantRole));
186
+ const selectIsAuthorizedToRequestVideoEnable = toolkit.createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canRequestVideoEnable.includes(localParticipantRole));
153
187
  const selectIsAuthorizedToKickClient = toolkit.createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canKickClient.includes(localParticipantRole));
154
188
  const selectIsAuthorizedToEndMeeting = toolkit.createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canEndMeeting.includes(localParticipantRole));
155
189
  const selectIsAuthorizedToAskToSpeak = toolkit.createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canAskToSpeak.includes(localParticipantRole));
@@ -199,13 +233,13 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
199
233
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
200
234
  };
201
235
 
202
- const initialState$d = {
236
+ const initialState$e = {
203
237
  isFetching: false,
204
238
  data: null,
205
239
  };
206
240
  const deviceCredentialsSlice = toolkit.createSlice({
207
241
  name: "deviceCredentials",
208
- initialState: initialState$d,
242
+ initialState: initialState$e,
209
243
  reducers: {},
210
244
  extraReducers: (builder) => {
211
245
  builder.addCase(doGetDeviceCredentials.pending, (state) => {
@@ -270,6 +304,7 @@ function forwardSocketEvents(socket, dispatch) {
270
304
  socket.on("spotlight_removed", (payload) => dispatch(signalEvents.spotlightRemoved(payload)));
271
305
  socket.on("live_transcription_started", (payload) => dispatch(signalEvents.liveTranscriptionStarted(payload)));
272
306
  socket.on("live_transcription_stopped", (payload) => dispatch(signalEvents.liveTranscriptionStopped(payload)));
307
+ socket.on("video_enable_requested", (payload) => dispatch(signalEvents.videoEnableRequested(payload)));
273
308
  }
274
309
  const SIGNAL_BASE_URL = "wss://signal.appearin.net" ;
275
310
  function createSocket() {
@@ -280,7 +315,7 @@ function createSocket() {
280
315
  };
281
316
  return new media.ServerSocket(socketHost, socketOverrides);
282
317
  }
283
- const initialState$c = {
318
+ const initialState$d = {
284
319
  deviceIdentified: false,
285
320
  isIdentifyingDevice: false,
286
321
  status: "ready",
@@ -288,7 +323,7 @@ const initialState$c = {
288
323
  };
289
324
  const signalConnectionSlice = toolkit.createSlice({
290
325
  name: "signalConnection",
291
- initialState: initialState$c,
326
+ initialState: initialState$d,
292
327
  reducers: {
293
328
  socketConnecting: (state) => {
294
329
  return Object.assign(Object.assign({}, state), { status: "connecting" });
@@ -297,7 +332,7 @@ const signalConnectionSlice = toolkit.createSlice({
297
332
  return Object.assign(Object.assign({}, state), { socket: action.payload, status: "connected" });
298
333
  },
299
334
  socketDisconnected: (state) => {
300
- return Object.assign(Object.assign({}, state), { deviceIdentified: false, status: "disconnected" });
335
+ return Object.assign(Object.assign({}, state), { socket: null, deviceIdentified: false, status: "disconnected" });
301
336
  },
302
337
  socketReconnecting: (state) => {
303
338
  return Object.assign(Object.assign({}, state), { status: "reconnecting" });
@@ -392,12 +427,12 @@ startAppListening({
392
427
  },
393
428
  });
394
429
 
395
- const initialState$b = {
430
+ const initialState$c = {
396
431
  chatMessages: [],
397
432
  };
398
433
  const chatSlice = toolkit.createSlice({
399
434
  name: "chat",
400
- initialState: initialState$b,
435
+ initialState: initialState$c,
401
436
  reducers: {},
402
437
  extraReducers(builder) {
403
438
  builder.addCase(signalEvents.chatMessage, (state, action) => {
@@ -410,7 +445,7 @@ const chatSlice = toolkit.createSlice({
410
445
  });
411
446
  },
412
447
  });
413
- const doSendChatMessage = createAppThunk((payload) => (_, getState) => {
448
+ const doSendChatMessage = createRoomConnectedThunk((payload) => (_, getState) => {
414
449
  const state = getState();
415
450
  const socket = selectSignalConnectionRaw(state).socket;
416
451
  socket === null || socket === void 0 ? void 0 : socket.emit("chat_message", { text: payload.text });
@@ -455,7 +490,7 @@ const cloudRecordingSlice = toolkit.createSlice({
455
490
  },
456
491
  });
457
492
  const { recordingRequestStarted } = cloudRecordingSlice.actions;
458
- const doStartCloudRecording = createAppThunk(() => (dispatch, getState) => {
493
+ const doStartCloudRecording = createRoomConnectedThunk(() => (dispatch, getState) => {
459
494
  const state = getState();
460
495
  const socket = selectSignalConnectionRaw(state).socket;
461
496
  const status = selectCloudRecordingStatus(state);
@@ -467,7 +502,7 @@ const doStartCloudRecording = createAppThunk(() => (dispatch, getState) => {
467
502
  });
468
503
  dispatch(recordingRequestStarted());
469
504
  });
470
- const doStopCloudRecording = createAppThunk(() => (dispatch, getState) => {
505
+ const doStopCloudRecording = createRoomConnectedThunk(() => (dispatch, getState) => {
471
506
  const state = getState();
472
507
  const socket = selectSignalConnectionRaw(state).socket;
473
508
  socket === null || socket === void 0 ? void 0 : socket.emit("stop_recording");
@@ -478,6 +513,60 @@ const selectCloudRecordingStartedAt = (state) => state.cloudRecording.startedAt;
478
513
  const selectCloudRecordingError = (state) => state.cloudRecording.error;
479
514
  const selectIsCloudRecording = (state) => state.cloudRecording.isRecording;
480
515
 
516
+ const initialState$b = {
517
+ data: null,
518
+ isFetching: false,
519
+ error: null,
520
+ };
521
+ const organizationSlice = toolkit.createSlice({
522
+ initialState: initialState$b,
523
+ name: "organization",
524
+ reducers: {},
525
+ extraReducers: (builder) => {
526
+ builder.addCase(doOrganizationFetch.pending, (state) => {
527
+ return Object.assign(Object.assign({}, state), { isFetching: true });
528
+ });
529
+ builder.addCase(doOrganizationFetch.fulfilled, (state, action) => {
530
+ if (!action.payload)
531
+ return Object.assign(Object.assign({}, state), { isFetching: true });
532
+ return Object.assign(Object.assign({}, state), { isFetching: false, data: action.payload });
533
+ });
534
+ builder.addCase(doOrganizationFetch.rejected, (state) => {
535
+ return Object.assign(Object.assign({}, state), { isFetching: false, error: true });
536
+ });
537
+ },
538
+ });
539
+ const doOrganizationFetch = createAppAsyncThunk("organization/doOrganizationFetch", (_, { extra, getState }) => __awaiter(void 0, void 0, void 0, function* () {
540
+ try {
541
+ const roomUrl = selectAppRoomUrl(getState());
542
+ const organization = yield extra.services.fetchOrganizationFromRoomUrl(roomUrl || "");
543
+ if (!organization) {
544
+ throw new Error("Invalid room url");
545
+ }
546
+ return organization;
547
+ }
548
+ catch (error) {
549
+ console.error(error);
550
+ }
551
+ }));
552
+ const selectOrganizationRaw = (state) => state.organization;
553
+ const selectOrganizationId = (state) => { var _a; return (_a = state.organization.data) === null || _a === void 0 ? void 0 : _a.organizationId; };
554
+ const selectShouldFetchOrganization = toolkit.createSelector(selectAppIsActive, selectOrganizationRaw, selectDeviceCredentialsRaw, (appIsActive, organization, deviceCredentials) => {
555
+ if (appIsActive &&
556
+ !organization.data &&
557
+ !organization.isFetching &&
558
+ !organization.error &&
559
+ !deviceCredentials.isFetching) {
560
+ return true;
561
+ }
562
+ return false;
563
+ });
564
+ createReactor([selectShouldFetchOrganization], ({ dispatch }, shouldFetchOrganization) => {
565
+ if (shouldFetchOrganization) {
566
+ dispatch(doOrganizationFetch());
567
+ }
568
+ });
569
+
481
570
  function fakeAudioStream() {
482
571
  const audioCtx = new AudioContext();
483
572
  const oscillator = audioCtx.createOscillator();
@@ -1057,6 +1146,15 @@ startAppListening({
1057
1146
  }
1058
1147
  },
1059
1148
  });
1149
+ startAppListening({
1150
+ actionCreator: signalEvents.videoEnableRequested,
1151
+ effect: ({ payload }, { dispatch }) => {
1152
+ const { enable } = payload;
1153
+ if (!enable) {
1154
+ dispatch(toggleCameraEnabled({ enabled: false }));
1155
+ }
1156
+ },
1157
+ });
1060
1158
 
1061
1159
  const NON_PERSON_ROLES = ["recorder", "streamer"];
1062
1160
 
@@ -1077,7 +1175,7 @@ const localParticipantSlice = toolkit.createSlice({
1077
1175
  name: "localParticipant",
1078
1176
  initialState: initialState$a,
1079
1177
  reducers: {
1080
- doSetDisplayName: (state, action) => {
1178
+ setDisplayName: (state, action) => {
1081
1179
  return Object.assign(Object.assign({}, state), { displayName: action.payload.displayName });
1082
1180
  },
1083
1181
  },
@@ -1101,8 +1199,17 @@ const localParticipantSlice = toolkit.createSlice({
1101
1199
  });
1102
1200
  },
1103
1201
  });
1104
- const { doSetDisplayName } = localParticipantSlice.actions;
1105
- const doEnableAudio = createAppAsyncThunk("localParticipant/doEnableAudio", (payload, { dispatch, getState }) => __awaiter(void 0, void 0, void 0, function* () {
1202
+ const { setDisplayName } = localParticipantSlice.actions;
1203
+ const doSetDisplayName = createRoomConnectedThunk((payload) => (dispatch, getState) => {
1204
+ const state = getState();
1205
+ const socket = selectSignalConnectionRaw(state).socket;
1206
+ socket === null || socket === void 0 ? void 0 : socket.emit("send_client_metadata", {
1207
+ type: "UserData",
1208
+ payload: { displayName: payload.displayName },
1209
+ });
1210
+ dispatch(setDisplayName({ displayName: payload.displayName }));
1211
+ });
1212
+ const doEnableAudio = createAsyncRoomConnectedThunk("localParticipant/doEnableAudio", (payload, { dispatch, getState }) => __awaiter(void 0, void 0, void 0, function* () {
1106
1213
  const state = getState();
1107
1214
  const socket = selectSignalConnectionRaw(state).socket;
1108
1215
  socket === null || socket === void 0 ? void 0 : socket.emit("enable_audio", { enabled: payload.enabled });
@@ -1111,13 +1218,13 @@ const doEnableAudio = createAppAsyncThunk("localParticipant/doEnableAudio", (pay
1111
1218
  }
1112
1219
  return payload.enabled;
1113
1220
  }));
1114
- const doEnableVideo = createAppAsyncThunk("localParticipant/doEnableVideo", (payload, { getState }) => __awaiter(void 0, void 0, void 0, function* () {
1221
+ const doEnableVideo = createAsyncRoomConnectedThunk("localParticipant/doEnableVideo", (payload, { getState }) => __awaiter(void 0, void 0, void 0, function* () {
1115
1222
  const state = getState();
1116
1223
  const socket = selectSignalConnectionRaw(state).socket;
1117
1224
  socket === null || socket === void 0 ? void 0 : socket.emit("enable_video", { enabled: payload.enabled });
1118
1225
  return payload.enabled;
1119
1226
  }));
1120
- const doSetLocalStickyReaction = createAppAsyncThunk("localParticipant/doSetLocalStickyReaction", (payload, { getState, rejectWithValue }) => __awaiter(void 0, void 0, void 0, function* () {
1227
+ const doSetLocalStickyReaction = createAsyncRoomConnectedThunk("localParticipant/doSetLocalStickyReaction", (payload, { getState, rejectWithValue }) => __awaiter(void 0, void 0, void 0, function* () {
1121
1228
  var _a;
1122
1229
  const state = getState();
1123
1230
  const currentStickyReaction = selectLocalParticipantStickyReaction(state);
@@ -1129,7 +1236,7 @@ const doSetLocalStickyReaction = createAppAsyncThunk("localParticipant/doSetLoca
1129
1236
  const stickyReaction = enabled ? { reaction: "✋", timestamp: new Date().toISOString() } : null;
1130
1237
  return stickyReaction;
1131
1238
  }));
1132
- const doSendClientMetadata = createAppThunk(() => (_, getState) => {
1239
+ const doSendClientMetadata = createRoomConnectedThunk(() => (_, getState) => {
1133
1240
  const state = getState();
1134
1241
  const socket = selectSignalConnectionRaw(state).socket;
1135
1242
  const payload = {
@@ -1183,86 +1290,179 @@ createReactor([selectLocalParticipantDisplayName, selectLocalParticipantStickyRe
1183
1290
  });
1184
1291
 
1185
1292
  const initialState$9 = {
1186
- status: "inactive",
1187
- stream: null,
1293
+ session: null,
1294
+ status: "ready",
1188
1295
  error: null,
1189
1296
  };
1190
- const localScreenshareSlice = toolkit.createSlice({
1191
- name: "localScreenshare",
1297
+ const roomConnectionSlice = toolkit.createSlice({
1192
1298
  initialState: initialState$9,
1299
+ name: "roomConnection",
1193
1300
  reducers: {
1194
- stopScreenshare(state, action) {
1195
- return Object.assign(Object.assign({}, state), { status: "inactive", stream: null });
1301
+ connectionStatusChanged: (state, action) => {
1302
+ return Object.assign(Object.assign({}, state), { status: action.payload });
1196
1303
  },
1197
1304
  },
1198
1305
  extraReducers: (builder) => {
1199
- builder.addCase(doStartScreenshare.pending, (state) => {
1200
- return Object.assign(Object.assign({}, state), { status: "starting" });
1306
+ builder.addCase(signalEvents.roomJoined, (state, action) => {
1307
+ var _a, _b;
1308
+ const { error, isLocked } = action.payload;
1309
+ if (error === "room_locked" && isLocked) {
1310
+ return Object.assign(Object.assign({}, state), { status: "room_locked" });
1311
+ }
1312
+ if (error) {
1313
+ return Object.assign(Object.assign({}, state), { status: "disconnected", error });
1314
+ }
1315
+ return Object.assign(Object.assign({}, state), { status: "connected", session: (_b = (_a = action.payload.room) === null || _a === void 0 ? void 0 : _a.session) !== null && _b !== void 0 ? _b : null });
1201
1316
  });
1202
- builder.addCase(doStartScreenshare.fulfilled, (state, { payload: { stream } }) => {
1203
- return Object.assign(Object.assign({}, state), { status: "active", stream });
1317
+ builder.addCase(signalEvents.disconnect, (state) => {
1318
+ if (["kicked", "left"].includes(state.status)) {
1319
+ return Object.assign({}, state);
1320
+ }
1321
+ return Object.assign(Object.assign({}, state), { status: "disconnected" });
1204
1322
  });
1205
- builder.addCase(doStartScreenshare.rejected, (state, { payload }) => {
1206
- return Object.assign(Object.assign({}, state), { error: payload, status: "inactive", stream: null });
1323
+ builder.addCase(signalEvents.newClient, (state, action) => {
1324
+ var _a, _b;
1325
+ return Object.assign(Object.assign({}, state), { session: (_b = (_a = action.payload.room) === null || _a === void 0 ? void 0 : _a.session) !== null && _b !== void 0 ? _b : null });
1326
+ });
1327
+ builder.addCase(signalEvents.roomSessionEnded, (state, action) => {
1328
+ var _a;
1329
+ if (((_a = state.session) === null || _a === void 0 ? void 0 : _a.id) !== action.payload.roomSessionId) {
1330
+ return state;
1331
+ }
1332
+ return Object.assign(Object.assign({}, state), { session: null });
1333
+ });
1334
+ builder.addCase(signalEvents.clientKicked, (state) => {
1335
+ return Object.assign(Object.assign({}, state), { status: "kicked" });
1336
+ });
1337
+ builder.addCase(signalEvents.roomLeft, (state) => {
1338
+ return Object.assign(Object.assign({}, state), { status: "left" });
1339
+ });
1340
+ builder.addCase(socketReconnecting, (state) => {
1341
+ return Object.assign(Object.assign({}, state), { status: "reconnecting" });
1207
1342
  });
1208
1343
  },
1209
1344
  });
1210
- const { stopScreenshare } = localScreenshareSlice.actions;
1211
- const doStartScreenshare = createAppAsyncThunk("localScreenshare/doStartScreenshare", (_, { dispatch, getState, rejectWithValue }) => __awaiter(void 0, void 0, void 0, function* () {
1212
- var _a;
1213
- try {
1214
- const state = getState();
1215
- const screenshareStream = selectLocalScreenshareStream(state);
1216
- if (screenshareStream) {
1217
- return { stream: screenshareStream };
1218
- }
1219
- const stream = yield navigator.mediaDevices.getDisplayMedia();
1220
- const onEnded = () => {
1221
- dispatch(doStopScreenshare());
1222
- };
1223
- if ("oninactive" in stream) {
1224
- stream.addEventListener("inactive", onEnded);
1225
- }
1226
- else {
1227
- (_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.addEventListener("ended", onEnded);
1228
- }
1229
- return { stream };
1230
- }
1231
- catch (error) {
1232
- return rejectWithValue(error);
1233
- }
1234
- }));
1235
- const doStopScreenshare = createAppThunk(() => (dispatch, getState) => {
1345
+ const { connectionStatusChanged } = roomConnectionSlice.actions;
1346
+ const doKnockRoom = createAppThunk(() => (dispatch, getState) => {
1236
1347
  const state = getState();
1237
- const screenshareStream = selectLocalScreenshareStream(state);
1238
- if (!screenshareStream) {
1239
- return;
1240
- }
1241
- screenshareStream.getTracks().forEach((track) => track.stop());
1242
- dispatch(stopScreenshare({ stream: screenshareStream }));
1348
+ const socket = selectSignalConnectionRaw(state).socket;
1349
+ const roomName = selectAppRoomName(state);
1350
+ const roomKey = selectRoomKey(state);
1351
+ const displayName = selectAppDisplayName(state);
1352
+ const isDialIn = selectAppIsDialIn(state);
1353
+ const userAgent = selectAppUserAgent(state);
1354
+ const externalId = selectAppExternalId(state);
1355
+ const organizationId = selectOrganizationId(state);
1356
+ socket === null || socket === void 0 ? void 0 : socket.emit("knock_room", {
1357
+ avatarUrl: null,
1358
+ config: {
1359
+ isAudioEnabled: true,
1360
+ isVideoEnabled: true,
1361
+ },
1362
+ deviceCapabilities: { canScreenshare: true },
1363
+ displayName,
1364
+ isCoLocated: false,
1365
+ isDialIn,
1366
+ isDevicePermissionDenied: false,
1367
+ kickFromOtherRooms: false,
1368
+ organizationId,
1369
+ roomKey,
1370
+ roomName,
1371
+ userAgent,
1372
+ externalId,
1373
+ });
1374
+ dispatch(connectionStatusChanged("knocking"));
1243
1375
  });
1244
- const selectLocalScreenshareRaw = (state) => state.localScreenshare;
1245
- const selectLocalScreenshareStatus = (state) => state.localScreenshare.status;
1246
- const selectLocalScreenshareStream = (state) => state.localScreenshare.stream;
1247
- startAppListening({
1248
- actionCreator: localMediaStopped,
1249
- effect: (_, { getState }) => {
1250
- const state = getState();
1251
- const screenshareStream = selectLocalScreenshareStream(state);
1252
- if (!screenshareStream) {
1253
- return;
1254
- }
1255
- screenshareStream === null || screenshareStream === void 0 ? void 0 : screenshareStream.getTracks().forEach((track) => {
1256
- track.stop();
1257
- });
1258
- },
1376
+ const doConnectRoom = createAppThunk(() => (dispatch, getState) => {
1377
+ const state = getState();
1378
+ const socket = selectSignalConnectionRaw(state).socket;
1379
+ const roomName = selectAppRoomName(state);
1380
+ const roomKey = selectRoomKey(state);
1381
+ const displayName = selectAppDisplayName(state);
1382
+ const userAgent = selectAppUserAgent(state);
1383
+ const externalId = selectAppExternalId(state);
1384
+ const isDialIn = selectAppIsDialIn(state);
1385
+ const organizationId = selectOrganizationId(state);
1386
+ const isCameraEnabled = selectIsCameraEnabled(getState());
1387
+ const isMicrophoneEnabled = selectIsMicrophoneEnabled(getState());
1388
+ const clientClaim = selectLocalParticipantClientClaim(getState());
1389
+ socket === null || socket === void 0 ? void 0 : socket.emit("join_room", Object.assign({ avatarUrl: null, config: {
1390
+ isAudioEnabled: isMicrophoneEnabled,
1391
+ isVideoEnabled: isCameraEnabled,
1392
+ }, deviceCapabilities: { canScreenshare: true }, displayName, isCoLocated: false, isDialIn, isDevicePermissionDenied: false, kickFromOtherRooms: false, organizationId,
1393
+ roomKey,
1394
+ roomName,
1395
+ userAgent,
1396
+ externalId }, (clientClaim && { clientClaim })));
1397
+ dispatch(connectionStatusChanged("connecting"));
1259
1398
  });
1260
-
1261
- function createRtcEventAction(name) {
1262
- return toolkit.createAction(`rtcConnection/event/${name}`);
1263
- }
1264
- const rtcEvents = {
1265
- rtcManagerCreated: createRtcEventAction("rtcManagerCreated"),
1399
+ const selectRoomConnectionRaw = (state) => state.roomConnection;
1400
+ const selectRoomConnectionSession = (state) => state.roomConnection.session;
1401
+ const selectRoomConnectionSessionId = (state) => { var _a; return (_a = state.roomConnection.session) === null || _a === void 0 ? void 0 : _a.id; };
1402
+ const selectRoomConnectionStatus = (state) => state.roomConnection.status;
1403
+ const selectRoomConnectionError = (state) => state.roomConnection.error;
1404
+ const selectShouldConnectRoom = toolkit.createSelector([
1405
+ selectAppIsActive,
1406
+ selectOrganizationId,
1407
+ selectRoomConnectionStatus,
1408
+ selectSignalConnectionDeviceIdentified,
1409
+ selectLocalMediaStatus,
1410
+ selectRoomConnectionError,
1411
+ ], (appIsActive, hasOrganizationIdFetched, roomConnectionStatus, signalConnectionDeviceIdentified, localMediaStatus, roomConnectionError) => {
1412
+ if (appIsActive &&
1413
+ localMediaStatus === "started" &&
1414
+ signalConnectionDeviceIdentified &&
1415
+ !!hasOrganizationIdFetched &&
1416
+ ["ready", "reconnecting", "disconnected"].includes(roomConnectionStatus) &&
1417
+ !roomConnectionError) {
1418
+ return true;
1419
+ }
1420
+ return false;
1421
+ });
1422
+ createReactor([selectShouldConnectRoom], ({ dispatch }, shouldConnectRoom) => {
1423
+ if (shouldConnectRoom) {
1424
+ dispatch(doConnectRoom());
1425
+ }
1426
+ });
1427
+ startAppListening({
1428
+ actionCreator: signalEvents.knockHandled,
1429
+ effect: ({ payload }, { dispatch, getState }) => {
1430
+ const { clientId, resolution } = payload;
1431
+ const state = getState();
1432
+ const selfId = selectSelfId(state);
1433
+ if (clientId !== selfId) {
1434
+ return;
1435
+ }
1436
+ if (resolution === "accepted") {
1437
+ dispatch(setRoomKey(payload.metadata.roomKey));
1438
+ dispatch(doConnectRoom());
1439
+ }
1440
+ else if (resolution === "rejected") {
1441
+ dispatch(connectionStatusChanged("knock_rejected"));
1442
+ }
1443
+ },
1444
+ });
1445
+ startAppListening({
1446
+ actionCreator: doAppStop,
1447
+ effect: (_, { dispatch, getState }) => {
1448
+ const state = getState();
1449
+ const roomConnectionStatus = selectRoomConnectionStatus(state);
1450
+ if (roomConnectionStatus === "connected") {
1451
+ const socket = selectSignalConnectionRaw(state).socket;
1452
+ socket === null || socket === void 0 ? void 0 : socket.emit("leave_room");
1453
+ dispatch(connectionStatusChanged("leaving"));
1454
+ }
1455
+ else {
1456
+ doSignalDisconnect();
1457
+ }
1458
+ },
1459
+ });
1460
+
1461
+ function createRtcEventAction(name) {
1462
+ return toolkit.createAction(`rtcConnection/event/${name}`);
1463
+ }
1464
+ const rtcEvents = {
1465
+ rtcManagerCreated: createRtcEventAction("rtcManagerCreated"),
1266
1466
  rtcManagerDestroyed: createRtcEventAction("rtcManagerDestroyed"),
1267
1467
  streamAdded: createRtcEventAction("streamAdded"),
1268
1468
  };
@@ -1438,7 +1638,7 @@ const remoteParticipantsSlice = toolkit.createSlice({
1438
1638
  },
1439
1639
  });
1440
1640
  const { participantStreamAdded, participantStreamIdAdded, streamStatusUpdated } = remoteParticipantsSlice.actions;
1441
- const doRequestAudioEnable = createAppAuthorizedThunk((state) => selectIsAuthorizedToRequestAudioEnable(state), (payload) => (_, getState) => {
1641
+ const doRequestAudioEnable = createAuthorizedRoomConnectedThunk((state) => selectIsAuthorizedToRequestAudioEnable(state), (payload) => (_, getState) => {
1442
1642
  const state = getState();
1443
1643
  const canEnableRemoteAudio = selectIsAuthorizedToAskToSpeak(state);
1444
1644
  if (payload.enable && !canEnableRemoteAudio) {
@@ -1448,6 +1648,11 @@ const doRequestAudioEnable = createAppAuthorizedThunk((state) => selectIsAuthori
1448
1648
  const socket = selectSignalConnectionRaw(state).socket;
1449
1649
  socket === null || socket === void 0 ? void 0 : socket.emit("request_audio_enable", payload);
1450
1650
  });
1651
+ const doRequestVideoEnable = createAuthorizedRoomConnectedThunk((state) => selectIsAuthorizedToRequestVideoEnable(state), (payload) => (_, getState) => {
1652
+ const state = getState();
1653
+ const socket = selectSignalConnectionRaw(state).socket;
1654
+ socket === null || socket === void 0 ? void 0 : socket.emit("request_video_enable", payload);
1655
+ });
1451
1656
  const selectRemoteParticipantsRaw = (state) => state.remoteParticipants;
1452
1657
  const selectRemoteClients = (state) => state.remoteParticipants.remoteParticipants;
1453
1658
  const selectRemoteParticipants = toolkit.createSelector(selectRemoteClients, (clients) => clients.filter((c) => !NON_PERSON_ROLES.includes(c.roleName)));
@@ -1460,373 +1665,388 @@ const selectNumParticipants = toolkit.createSelector(selectRemoteParticipants, s
1460
1665
  });
1461
1666
 
1462
1667
  const initialState$7 = {
1463
- data: null,
1464
- isFetching: false,
1668
+ status: "inactive",
1669
+ stream: null,
1465
1670
  error: null,
1466
1671
  };
1467
- const organizationSlice = toolkit.createSlice({
1672
+ const localScreenshareSlice = toolkit.createSlice({
1673
+ name: "localScreenshare",
1468
1674
  initialState: initialState$7,
1469
- name: "organization",
1470
- reducers: {},
1675
+ reducers: {
1676
+ stopScreenshare(state, action) {
1677
+ return Object.assign(Object.assign({}, state), { status: "inactive", stream: null });
1678
+ },
1679
+ },
1471
1680
  extraReducers: (builder) => {
1472
- builder.addCase(doOrganizationFetch.pending, (state) => {
1473
- return Object.assign(Object.assign({}, state), { isFetching: true });
1681
+ builder.addCase(doStartScreenshare.pending, (state) => {
1682
+ return Object.assign(Object.assign({}, state), { status: "starting" });
1474
1683
  });
1475
- builder.addCase(doOrganizationFetch.fulfilled, (state, action) => {
1476
- if (!action.payload)
1477
- return Object.assign(Object.assign({}, state), { isFetching: true });
1478
- return Object.assign(Object.assign({}, state), { isFetching: false, data: action.payload });
1684
+ builder.addCase(doStartScreenshare.fulfilled, (state, { payload: { stream } }) => {
1685
+ return Object.assign(Object.assign({}, state), { status: "active", stream });
1479
1686
  });
1480
- builder.addCase(doOrganizationFetch.rejected, (state) => {
1481
- return Object.assign(Object.assign({}, state), { isFetching: false, error: true });
1687
+ builder.addCase(doStartScreenshare.rejected, (state, { payload }) => {
1688
+ return Object.assign(Object.assign({}, state), { error: payload, status: "inactive", stream: null });
1482
1689
  });
1483
1690
  },
1484
1691
  });
1485
- const doOrganizationFetch = createAppAsyncThunk("organization/doOrganizationFetch", (_, { extra, getState }) => __awaiter(void 0, void 0, void 0, function* () {
1692
+ const { stopScreenshare } = localScreenshareSlice.actions;
1693
+ const doStartScreenshare = createAsyncRoomConnectedThunk("localScreenshare/doStartScreenshare", (_, { dispatch, getState, rejectWithValue }) => __awaiter(void 0, void 0, void 0, function* () {
1694
+ var _a;
1486
1695
  try {
1487
- const roomUrl = selectAppRoomUrl(getState());
1488
- const organization = yield extra.services.fetchOrganizationFromRoomUrl(roomUrl || "");
1489
- if (!organization) {
1490
- throw new Error("Invalid room url");
1696
+ const state = getState();
1697
+ const screenshareStream = selectLocalScreenshareStream(state);
1698
+ if (screenshareStream) {
1699
+ return { stream: screenshareStream };
1491
1700
  }
1492
- return organization;
1701
+ const stream = yield navigator.mediaDevices.getDisplayMedia();
1702
+ const onEnded = () => {
1703
+ dispatch(doStopScreenshare());
1704
+ };
1705
+ if ("oninactive" in stream) {
1706
+ stream.addEventListener("inactive", onEnded);
1707
+ }
1708
+ else {
1709
+ (_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.addEventListener("ended", onEnded);
1710
+ }
1711
+ return { stream };
1493
1712
  }
1494
1713
  catch (error) {
1495
- console.error(error);
1714
+ return rejectWithValue(error);
1496
1715
  }
1497
1716
  }));
1498
- const selectOrganizationRaw = (state) => state.organization;
1499
- const selectOrganizationId = (state) => { var _a; return (_a = state.organization.data) === null || _a === void 0 ? void 0 : _a.organizationId; };
1500
- const selectShouldFetchOrganization = toolkit.createSelector(selectAppIsActive, selectOrganizationRaw, selectDeviceCredentialsRaw, (appIsActive, organization, deviceCredentials) => {
1501
- if (appIsActive &&
1502
- !organization.data &&
1503
- !organization.isFetching &&
1504
- !organization.error &&
1505
- !deviceCredentials.isFetching) {
1506
- return true;
1717
+ const doStopScreenshare = createRoomConnectedThunk(() => (dispatch, getState) => {
1718
+ const state = getState();
1719
+ const screenshareStream = selectLocalScreenshareStream(state);
1720
+ if (!screenshareStream) {
1721
+ return;
1507
1722
  }
1508
- return false;
1723
+ screenshareStream.getTracks().forEach((track) => track.stop());
1724
+ dispatch(stopScreenshare({ stream: screenshareStream }));
1509
1725
  });
1510
- createReactor([selectShouldFetchOrganization], ({ dispatch }, shouldFetchOrganization) => {
1511
- if (shouldFetchOrganization) {
1512
- dispatch(doOrganizationFetch());
1513
- }
1726
+ const selectLocalScreenshareRaw = (state) => state.localScreenshare;
1727
+ const selectLocalScreenshareStatus = (state) => state.localScreenshare.status;
1728
+ const selectLocalScreenshareStream = (state) => state.localScreenshare.stream;
1729
+ startAppListening({
1730
+ actionCreator: localMediaStopped,
1731
+ effect: (_, { getState }) => {
1732
+ const state = getState();
1733
+ const screenshareStream = selectLocalScreenshareStream(state);
1734
+ if (!screenshareStream) {
1735
+ return;
1736
+ }
1737
+ screenshareStream === null || screenshareStream === void 0 ? void 0 : screenshareStream.getTracks().forEach((track) => {
1738
+ track.stop();
1739
+ });
1740
+ },
1514
1741
  });
1515
1742
 
1743
+ const createWebRtcEmitter = (dispatch) => {
1744
+ return {
1745
+ emit: (eventName, data) => {
1746
+ if (eventName === "rtc_manager_created") {
1747
+ dispatch(doRtcManagerCreated(data));
1748
+ }
1749
+ else if (eventName === "stream_added") {
1750
+ dispatch(rtcEvents.streamAdded(data));
1751
+ }
1752
+ else if (eventName === "rtc_manager_destroyed") {
1753
+ dispatch(rtcManagerDestroyed());
1754
+ }
1755
+ else ;
1756
+ },
1757
+ };
1758
+ };
1516
1759
  const initialState$6 = {
1517
- session: null,
1518
- status: "ready",
1760
+ dispatcherCreated: false,
1519
1761
  error: null,
1762
+ isCreatingDispatcher: false,
1763
+ reportedStreamResolutions: {},
1764
+ rtcManager: null,
1765
+ rtcManagerDispatcher: null,
1766
+ rtcManagerInitialized: false,
1767
+ status: "inactive",
1768
+ isAcceptingStreams: false,
1520
1769
  };
1521
- const roomConnectionSlice = toolkit.createSlice({
1770
+ const rtcConnectionSlice = toolkit.createSlice({
1771
+ name: "rtcConnection",
1522
1772
  initialState: initialState$6,
1523
- name: "roomConnection",
1524
1773
  reducers: {
1525
- connectionStatusChanged: (state, action) => {
1526
- return Object.assign(Object.assign({}, state), { status: action.payload });
1774
+ isAcceptingStreams: (state, action) => {
1775
+ return Object.assign(Object.assign({}, state), { isAcceptingStreams: action.payload });
1776
+ },
1777
+ resolutionReported: (state, action) => {
1778
+ const { streamId, width, height } = action.payload;
1779
+ return Object.assign(Object.assign({}, state), { reportedStreamResolutions: Object.assign(Object.assign({}, state.reportedStreamResolutions), { [streamId]: { width, height } }) });
1780
+ },
1781
+ rtcDisconnected: () => {
1782
+ return Object.assign({}, initialState$6);
1783
+ },
1784
+ rtcDispatcherCreated: (state, action) => {
1785
+ return Object.assign(Object.assign({}, state), { dispatcherCreated: true, rtcManagerDispatcher: action.payload });
1786
+ },
1787
+ rtcManagerCreated: (state, action) => {
1788
+ return Object.assign(Object.assign({}, state), { rtcManager: action.payload, status: "ready" });
1789
+ },
1790
+ rtcManagerDestroyed: (state) => {
1791
+ return Object.assign(Object.assign({}, state), { rtcManager: null });
1792
+ },
1793
+ rtcManagerInitialized: (state) => {
1794
+ return Object.assign(Object.assign({}, state), { rtcManagerInitialized: true });
1527
1795
  },
1528
1796
  },
1529
1797
  extraReducers: (builder) => {
1530
- builder.addCase(signalEvents.roomJoined, (state, action) => {
1531
- var _a, _b;
1532
- const { error, isLocked } = action.payload;
1533
- if (error === "room_locked" && isLocked) {
1534
- return Object.assign(Object.assign({}, state), { status: "room_locked" });
1535
- }
1536
- if (error) {
1537
- return Object.assign(Object.assign({}, state), { status: "disconnected", error });
1538
- }
1539
- return Object.assign(Object.assign({}, state), { status: "connected", session: (_b = (_a = action.payload.room) === null || _a === void 0 ? void 0 : _a.session) !== null && _b !== void 0 ? _b : null });
1540
- });
1541
- builder.addCase(signalEvents.disconnect, (state) => {
1542
- if (["kicked", "left"].includes(state.status)) {
1543
- return Object.assign({}, state);
1544
- }
1545
- return Object.assign(Object.assign({}, state), { status: "disconnected" });
1546
- });
1547
- builder.addCase(signalEvents.newClient, (state, action) => {
1548
- var _a, _b;
1549
- return Object.assign(Object.assign({}, state), { session: (_b = (_a = action.payload.room) === null || _a === void 0 ? void 0 : _a.session) !== null && _b !== void 0 ? _b : null });
1550
- });
1551
- builder.addCase(signalEvents.roomSessionEnded, (state, action) => {
1552
- var _a;
1553
- if (((_a = state.session) === null || _a === void 0 ? void 0 : _a.id) !== action.payload.roomSessionId) {
1554
- return state;
1555
- }
1556
- return Object.assign(Object.assign({}, state), { session: null });
1557
- });
1558
- builder.addCase(signalEvents.clientKicked, (state) => {
1559
- return Object.assign(Object.assign({}, state), { status: "kicked" });
1560
- });
1561
- builder.addCase(signalEvents.roomLeft, (state) => {
1562
- return Object.assign(Object.assign({}, state), { status: "left" });
1563
- });
1564
1798
  builder.addCase(socketReconnecting, (state) => {
1565
1799
  return Object.assign(Object.assign({}, state), { status: "reconnecting" });
1566
1800
  });
1801
+ builder.addCase(signalEvents.roomJoined, (state) => {
1802
+ return Object.assign(Object.assign({}, state), { status: state.status === "reconnecting" ? "ready" : state.status });
1803
+ });
1567
1804
  },
1568
1805
  });
1569
- const { connectionStatusChanged } = roomConnectionSlice.actions;
1570
- const doKnockRoom = createAppThunk(() => (dispatch, getState) => {
1806
+ const { resolutionReported, rtcDispatcherCreated, rtcDisconnected, rtcManagerCreated, rtcManagerDestroyed, rtcManagerInitialized, isAcceptingStreams, } = rtcConnectionSlice.actions;
1807
+ const doConnectRtc = createAppThunk(() => (dispatch, getState) => {
1571
1808
  const state = getState();
1572
1809
  const socket = selectSignalConnectionRaw(state).socket;
1573
- const roomName = selectAppRoomName(state);
1574
- const roomKey = selectRoomKey(state);
1575
- const displayName = selectAppDisplayName(state);
1576
- const isDialIn = selectAppIsDialIn(state);
1577
- const userAgent = selectAppUserAgent(state);
1578
- const externalId = selectAppExternalId(state);
1579
- const organizationId = selectOrganizationId(state);
1580
- socket === null || socket === void 0 ? void 0 : socket.emit("knock_room", {
1581
- avatarUrl: null,
1582
- config: {
1583
- isAudioEnabled: true,
1584
- isVideoEnabled: true,
1810
+ const dispatcher = selectRtcConnectionRaw(state).rtcManagerDispatcher;
1811
+ const isCameraEnabled = selectIsCameraEnabled(state);
1812
+ const isMicrophoneEnabled = selectIsMicrophoneEnabled(state);
1813
+ const isNodeSdk = selectAppIsNodeSdk(state);
1814
+ if (dispatcher || !socket) {
1815
+ return;
1816
+ }
1817
+ const webrtcProvider = {
1818
+ getMediaConstraints: () => ({
1819
+ audio: isMicrophoneEnabled,
1820
+ video: isCameraEnabled,
1821
+ }),
1822
+ deferrable(clientId) {
1823
+ return !clientId;
1824
+ },
1825
+ };
1826
+ const rtcManagerDispatcher = new media.RtcManagerDispatcher({
1827
+ emitter: createWebRtcEmitter(dispatch),
1828
+ serverSocket: socket,
1829
+ webrtcProvider,
1830
+ features: {
1831
+ isNodeSdk,
1832
+ lowDataModeEnabled: false,
1833
+ sfuServerOverrideHost: undefined,
1834
+ turnServerOverrideHost: undefined,
1835
+ useOnlyTURN: undefined,
1836
+ vp9On: false,
1837
+ h264On: false,
1838
+ simulcastScreenshareOn: false,
1839
+ deviceHandlerFactory: isNodeSdk ? Chrome111_js.Chrome111.createFactory() : undefined,
1585
1840
  },
1586
- deviceCapabilities: { canScreenshare: true },
1587
- displayName,
1588
- isCoLocated: false,
1589
- isDialIn,
1590
- isDevicePermissionDenied: false,
1591
- kickFromOtherRooms: false,
1592
- organizationId,
1593
- roomKey,
1594
- roomName,
1595
- userAgent,
1596
- externalId,
1597
1841
  });
1598
- dispatch(connectionStatusChanged("knocking"));
1599
- });
1600
- const doConnectRoom = createAppThunk(() => (dispatch, getState) => {
1601
- const state = getState();
1602
- const socket = selectSignalConnectionRaw(state).socket;
1603
- const roomName = selectAppRoomName(state);
1604
- const roomKey = selectRoomKey(state);
1605
- const displayName = selectAppDisplayName(state);
1606
- const userAgent = selectAppUserAgent(state);
1607
- const externalId = selectAppExternalId(state);
1608
- const isDialIn = selectAppIsDialIn(state);
1609
- const organizationId = selectOrganizationId(state);
1610
- const isCameraEnabled = selectIsCameraEnabled(getState());
1611
- const isMicrophoneEnabled = selectIsMicrophoneEnabled(getState());
1612
- const clientClaim = selectLocalParticipantClientClaim(getState());
1613
- socket === null || socket === void 0 ? void 0 : socket.emit("join_room", Object.assign({ avatarUrl: null, config: {
1614
- isAudioEnabled: isMicrophoneEnabled,
1615
- isVideoEnabled: isCameraEnabled,
1616
- }, deviceCapabilities: { canScreenshare: true }, displayName, isCoLocated: false, isDialIn, isDevicePermissionDenied: false, kickFromOtherRooms: false, organizationId,
1617
- roomKey,
1618
- roomName,
1619
- userAgent,
1620
- externalId }, (clientClaim && { clientClaim })));
1621
- dispatch(connectionStatusChanged("connecting"));
1842
+ dispatch(rtcDispatcherCreated(rtcManagerDispatcher));
1622
1843
  });
1623
- const selectRoomConnectionRaw = (state) => state.roomConnection;
1624
- const selectRoomConnectionSession = (state) => state.roomConnection.session;
1625
- const selectRoomConnectionSessionId = (state) => { var _a; return (_a = state.roomConnection.session) === null || _a === void 0 ? void 0 : _a.id; };
1626
- const selectRoomConnectionStatus = (state) => state.roomConnection.status;
1627
- const selectRoomConnectionError = (state) => state.roomConnection.error;
1628
- const selectShouldConnectRoom = toolkit.createSelector([
1629
- selectAppIsActive,
1630
- selectOrganizationId,
1631
- selectRoomConnectionStatus,
1632
- selectSignalConnectionDeviceIdentified,
1633
- selectLocalMediaStatus,
1634
- selectRoomConnectionError,
1635
- ], (appIsActive, hasOrganizationIdFetched, roomConnectionStatus, signalConnectionDeviceIdentified, localMediaStatus, roomConnectionError) => {
1636
- if (appIsActive &&
1637
- localMediaStatus === "started" &&
1638
- signalConnectionDeviceIdentified &&
1639
- !!hasOrganizationIdFetched &&
1640
- ["ready", "reconnecting", "disconnected"].includes(roomConnectionStatus) &&
1641
- !roomConnectionError) {
1642
- return true;
1844
+ const doDisconnectRtc = createAppThunk(() => (dispatch, getState) => {
1845
+ const { rtcManager } = selectRtcConnectionRaw(getState());
1846
+ if (rtcManager) {
1847
+ rtcManager.disconnectAll();
1643
1848
  }
1644
- return false;
1849
+ dispatch(rtcDisconnected());
1645
1850
  });
1646
- createReactor([selectShouldConnectRoom], ({ dispatch }, shouldConnectRoom) => {
1647
- if (shouldConnectRoom) {
1648
- dispatch(doConnectRoom());
1851
+ const doHandleAcceptStreams = createAppThunk((payload) => (dispatch, getState) => {
1852
+ var _a;
1853
+ dispatch(isAcceptingStreams(true));
1854
+ const state = getState();
1855
+ const rtcManager = selectRtcConnectionRaw(state).rtcManager;
1856
+ const remoteClients = selectRemoteClients(state);
1857
+ if (!rtcManager) {
1858
+ throw new Error("No rtc manager");
1649
1859
  }
1650
- });
1651
- startAppListening({
1652
- actionCreator: signalEvents.knockHandled,
1653
- effect: ({ payload }, { dispatch, getState }) => {
1654
- const { clientId, resolution } = payload;
1655
- const state = getState();
1656
- const selfId = selectSelfId(state);
1657
- if (clientId !== selfId) {
1658
- return;
1860
+ const activeBreakout = false;
1861
+ const shouldAcceptNewClients = (_a = rtcManager.shouldAcceptStreamsFromBothSides) === null || _a === void 0 ? void 0 : _a.call(rtcManager);
1862
+ const updates = [];
1863
+ for (const { clientId, streamId, state } of payload) {
1864
+ const participant = remoteClients.find((p) => p.id === clientId);
1865
+ if (!participant)
1866
+ continue;
1867
+ if (state === "to_accept" ||
1868
+ (state === "new_accept" && shouldAcceptNewClients) ||
1869
+ (state === "old_accept" && !shouldAcceptNewClients)) {
1870
+ const enforceTurnProtocol = participant.isDialIn ? "onlytls" : undefined;
1871
+ rtcManager.acceptNewStream({
1872
+ streamId: streamId === "0" ? clientId : streamId,
1873
+ clientId,
1874
+ shouldAddLocalVideo: streamId === "0",
1875
+ activeBreakout,
1876
+ enforceTurnProtocol,
1877
+ });
1659
1878
  }
1660
- if (resolution === "accepted") {
1661
- dispatch(setRoomKey(payload.metadata.roomKey));
1662
- dispatch(doConnectRoom());
1879
+ else if (state === "new_accept" || state === "old_accept") ;
1880
+ else if (state === "to_unaccept") {
1881
+ rtcManager === null || rtcManager === void 0 ? void 0 : rtcManager.disconnect(streamId === "0" ? clientId : streamId, activeBreakout);
1663
1882
  }
1664
- else if (resolution === "rejected") {
1665
- dispatch(connectionStatusChanged("knock_rejected"));
1883
+ else if (state !== "done_accept") {
1884
+ continue;
1666
1885
  }
1667
- },
1886
+ else ;
1887
+ updates.push({ clientId, streamId, state: state.replace(/to_|new_|old_/, "done_") });
1888
+ }
1889
+ dispatch(streamStatusUpdated(updates));
1890
+ dispatch(isAcceptingStreams(false));
1668
1891
  });
1892
+ const doRtcReportStreamResolution = createAppThunk(({ streamId, width, height }) => (dispatch, getState) => {
1893
+ const { reportedStreamResolutions, rtcManager } = selectRtcConnectionRaw(getState());
1894
+ const localStream = selectLocalMediaStream(getState());
1895
+ if (!rtcManager || (localStream === null || localStream === void 0 ? void 0 : localStream.id) === streamId) {
1896
+ return;
1897
+ }
1898
+ const old = reportedStreamResolutions[streamId];
1899
+ if (!old || old.width !== width || old.height !== height) {
1900
+ rtcManager.updateStreamResolution(streamId, null, { width: width || 1, height: height || 1 });
1901
+ }
1902
+ dispatch(resolutionReported({ streamId, width, height }));
1903
+ });
1904
+ const doRtcManagerCreated = createAppThunk((payload) => (dispatch) => {
1905
+ const { rtcManager } = payload;
1906
+ dispatch(rtcManagerCreated(rtcManager));
1907
+ });
1908
+ const doRtcManagerInitialize = createAppThunk(() => (dispatch, getState) => {
1909
+ const localMediaStream = selectLocalMediaStream(getState());
1910
+ const rtcManager = selectRtcConnectionRaw(getState()).rtcManager;
1911
+ const isCameraEnabled = selectIsCameraEnabled(getState());
1912
+ const isMicrophoneEnabled = selectIsMicrophoneEnabled(getState());
1913
+ if (localMediaStream && rtcManager) {
1914
+ rtcManager.addNewStream("0", localMediaStream, !isMicrophoneEnabled, !isCameraEnabled);
1915
+ }
1916
+ dispatch(rtcManagerInitialized());
1917
+ });
1918
+ const selectRtcConnectionRaw = (state) => state.rtcConnection;
1919
+ const selectRtcManagerInitialized = (state) => state.rtcConnection.rtcManagerInitialized;
1920
+ const selectRtcManager = (state) => state.rtcConnection.rtcManager;
1921
+ const selectRtcDispatcherCreated = (state) => state.rtcConnection.dispatcherCreated;
1922
+ const selectRtcIsCreatingDispatcher = (state) => state.rtcConnection.isCreatingDispatcher;
1923
+ const selectRtcStatus = (state) => state.rtcConnection.status;
1924
+ const selectIsAcceptingStreams = (state) => state.rtcConnection.isAcceptingStreams;
1669
1925
  startAppListening({
1670
- actionCreator: doAppStop,
1671
- effect: (_, { dispatch, getState }) => {
1672
- const state = getState();
1673
- const roomConnectionStatus = selectRoomConnectionStatus(state);
1674
- if (roomConnectionStatus === "connected") {
1675
- const socket = selectSignalConnectionRaw(state).socket;
1676
- socket === null || socket === void 0 ? void 0 : socket.emit("leave_room");
1677
- dispatch(connectionStatusChanged("leaving"));
1678
- }
1679
- else {
1680
- doSignalDisconnect();
1681
- }
1926
+ actionCreator: doSetDevice.fulfilled,
1927
+ effect: ({ payload }, { getState }) => {
1928
+ const { replacedTracks } = payload;
1929
+ const { rtcManager } = selectRtcConnectionRaw(getState());
1930
+ const stream = selectLocalMediaStream(getState());
1931
+ const replace = (kind, oldTrack) => {
1932
+ const track = stream === null || stream === void 0 ? void 0 : stream.getTracks().find((t) => t.kind === kind);
1933
+ return track && (rtcManager === null || rtcManager === void 0 ? void 0 : rtcManager.replaceTrack(oldTrack, track));
1934
+ };
1935
+ replacedTracks === null || replacedTracks === void 0 ? void 0 : replacedTracks.forEach((t) => {
1936
+ replace(t.kind, t);
1937
+ });
1682
1938
  },
1683
1939
  });
1684
-
1685
- const emitter = new events$1.EventEmitter();
1686
- function createNotificationEvent(payload) {
1687
- const notificationEvent = Object.assign(Object.assign({}, payload), { timestamp: Date.now() });
1688
- return notificationEvent;
1689
- }
1690
- const initialNotificationsState = {
1691
- emitter,
1692
- events: [],
1693
- };
1694
- const notificationsSlice = toolkit.createSlice({
1695
- name: "notifications",
1696
- initialState: initialNotificationsState,
1697
- reducers: {
1698
- addNotification: (state, action) => {
1699
- return Object.assign(Object.assign({}, state), { events: [...state.events, Object.assign({}, action.payload)] });
1700
- },
1701
- doClearNotifications: (state) => {
1702
- return Object.assign(Object.assign({}, state), { events: [] });
1703
- },
1940
+ startAppListening({
1941
+ actionCreator: doStartScreenshare.fulfilled,
1942
+ effect: ({ payload }, { getState }) => {
1943
+ const { stream } = payload;
1944
+ const { rtcManager } = selectRtcConnectionRaw(getState());
1945
+ rtcManager === null || rtcManager === void 0 ? void 0 : rtcManager.addNewStream(stream.id, stream, false, true);
1704
1946
  },
1705
1947
  });
1706
- const { doClearNotifications } = notificationsSlice.actions;
1707
- const doSetNotification = createAppThunk((payload) => (dispatch, getState) => {
1708
- dispatch(notificationsSlice.actions.addNotification(payload));
1709
- const state = getState();
1710
- const emitter = selectNotificationsEmitter(state);
1711
- emitter.emit(payload.type, payload);
1712
- emitter.emit("*", payload);
1713
- });
1714
- const selectNotificationsRaw = (state) => state.notifications;
1715
- const selectNotificationsEvents = (state) => state.notifications.events;
1716
- const selectNotificationsEmitter = (state) => state.notifications.emitter;
1717
1948
  startAppListening({
1718
- actionCreator: signalEvents.chatMessage,
1719
- effect: ({ payload }, { dispatch, getState }) => {
1720
- const state = getState();
1721
- const client = selectRemoteParticipants(state).find(({ id }) => id === payload.senderId);
1722
- if (!client) {
1723
- console.warn("Could not find remote client that sent chat message");
1724
- return;
1725
- }
1726
- dispatch(doSetNotification(createNotificationEvent({
1727
- type: "chatMessageReceived",
1728
- message: `${client.displayName} says: ${payload.text}`,
1729
- props: {
1730
- client,
1731
- chatMessage: {
1732
- senderId: payload.senderId,
1733
- timestamp: payload.timestamp,
1734
- text: payload.text,
1735
- },
1736
- },
1737
- })));
1949
+ actionCreator: doAppStop,
1950
+ effect: (_, { getState }) => {
1951
+ const rtcManager = selectRtcManager(getState());
1952
+ rtcManager === null || rtcManager === void 0 ? void 0 : rtcManager.rtcStatsDisconnect();
1738
1953
  },
1739
1954
  });
1740
1955
  startAppListening({
1741
- actionCreator: signalEvents.audioEnableRequested,
1742
- effect: ({ payload }, { dispatch, getState }) => {
1743
- const { enable, requestedByClientId } = payload;
1744
- const state = getState();
1745
- const client = selectRemoteParticipants(state).find(({ id }) => id === requestedByClientId);
1746
- if (!client) {
1747
- console.warn("Could not find remote client that requested a local audio change");
1748
- return;
1749
- }
1750
- dispatch(doSetNotification(createNotificationEvent({
1751
- type: enable ? "requestAudioEnable" : "requestAudioDisable",
1752
- message: enable
1753
- ? `${client.displayName} has requested for you to speak`
1754
- : `${client.displayName} has muted your microphone`,
1755
- props: {
1756
- client,
1757
- enable,
1758
- },
1759
- })));
1956
+ actionCreator: stopScreenshare,
1957
+ effect: ({ payload }, { getState }) => {
1958
+ const { stream } = payload;
1959
+ const { rtcManager } = selectRtcConnectionRaw(getState());
1960
+ rtcManager === null || rtcManager === void 0 ? void 0 : rtcManager.removeStream(stream.id, stream, null);
1760
1961
  },
1761
1962
  });
1762
1963
  startAppListening({
1763
- actionCreator: signalEvents.clientMetadataReceived,
1764
- effect: (action, { dispatch, getOriginalState, getState }) => {
1964
+ actionCreator: doSwitchLocalStream.fulfilled,
1965
+ effect: ({ payload }, { getState }) => {
1765
1966
  var _a;
1766
- const { error, payload } = action.payload;
1767
- if (error || !payload) {
1768
- return;
1769
- }
1770
- const { clientId, stickyReaction } = payload;
1771
- const state = getState();
1772
- const canAskToSpeak = selectIsAuthorizedToAskToSpeak(state);
1773
- if (!canAskToSpeak) {
1774
- return;
1775
- }
1776
- const client = selectRemoteParticipants(state).find(({ id }) => id === clientId);
1777
- if (!client) {
1778
- console.warn("Could not find remote client that provided updated metadata");
1779
- return;
1780
- }
1781
- const previousState = getOriginalState();
1782
- const previousClient = selectRemoteParticipants(previousState).find(({ id }) => id === clientId);
1783
- if ((!stickyReaction && !(previousClient === null || previousClient === void 0 ? void 0 : previousClient.stickyReaction)) ||
1784
- (stickyReaction === null || stickyReaction === void 0 ? void 0 : stickyReaction.timestamp) === ((_a = previousClient === null || previousClient === void 0 ? void 0 : previousClient.stickyReaction) === null || _a === void 0 ? void 0 : _a.timestamp)) {
1785
- return;
1967
+ const stream = selectLocalMediaStream(getState());
1968
+ const { rtcManager } = selectRtcConnectionRaw(getState());
1969
+ if (stream && rtcManager) {
1970
+ const replace = (kind, oldTrack) => {
1971
+ const track = stream.getTracks().find((t) => t.kind === kind);
1972
+ return track && rtcManager.replaceTrack(oldTrack, track);
1973
+ };
1974
+ (_a = payload === null || payload === void 0 ? void 0 : payload.replacedTracks) === null || _a === void 0 ? void 0 : _a.forEach((t) => {
1975
+ replace(t.kind, t);
1976
+ });
1786
1977
  }
1787
- dispatch(doSetNotification(createNotificationEvent({
1788
- type: stickyReaction ? "remoteHandRaised" : "remoteHandLowered",
1789
- message: `${client.displayName} ${stickyReaction ? "raised" : "lowered"} their hand`,
1790
- props: {
1791
- client,
1792
- stickyReaction,
1793
- },
1794
- })));
1795
1978
  },
1796
1979
  });
1797
- createReactor([selectSignalStatus], ({ dispatch, getState }, signalStatus) => {
1798
- const state = getState();
1799
- const roomConnectionStatus = selectRoomConnectionStatus(state);
1800
- if (["left", "kicked"].includes(roomConnectionStatus)) {
1801
- return;
1980
+ const selectShouldConnectRtc = toolkit.createSelector(selectRtcStatus, selectAppIsActive, selectRtcDispatcherCreated, selectRtcIsCreatingDispatcher, selectSignalConnectionSocket, (rtcStatus, appIsActive, dispatcherCreated, isCreatingDispatcher, signalSocket) => {
1981
+ if (appIsActive && rtcStatus === "inactive" && !dispatcherCreated && !isCreatingDispatcher && signalSocket) {
1982
+ return true;
1983
+ }
1984
+ return false;
1985
+ });
1986
+ createReactor([selectShouldConnectRtc], ({ dispatch }, shouldConnectRtc) => {
1987
+ if (shouldConnectRtc) {
1988
+ dispatch(doConnectRtc());
1989
+ }
1990
+ });
1991
+ const selectShouldInitializeRtc = toolkit.createSelector(selectRtcManager, selectRtcManagerInitialized, selectLocalMediaStatus, (rtcManager, rtcManagerInitialized, localMediaStatus) => {
1992
+ if (localMediaStatus === "started" && rtcManager && !rtcManagerInitialized) {
1993
+ return true;
1802
1994
  }
1803
- if (signalStatus === "disconnected") {
1804
- dispatch(doSetNotification(createNotificationEvent({
1805
- type: "signalTrouble",
1806
- message: `Network connection lost. Trying to reconnect you...`,
1807
- props: {},
1808
- })));
1995
+ return false;
1996
+ });
1997
+ createReactor([selectShouldInitializeRtc], ({ dispatch }, shouldInitializeRtc) => {
1998
+ if (shouldInitializeRtc) {
1999
+ dispatch(doRtcManagerInitialize());
1809
2000
  }
1810
- else if (signalStatus === "connected") {
1811
- dispatch(doSetNotification(createNotificationEvent({
1812
- type: "signalOk",
1813
- message: `Network connection available`,
1814
- props: {},
1815
- })));
2001
+ });
2002
+ const selectShouldDisconnectRtc = toolkit.createSelector(selectRtcStatus, selectAppIsActive, (status, appIsActive) => {
2003
+ if (!appIsActive && !["inactive", "disconnected"].includes(status)) {
2004
+ return true;
1816
2005
  }
2006
+ return false;
1817
2007
  });
1818
- startAppListening({
1819
- actionCreator: signalEvents.clientUnableToJoin,
1820
- effect: (action, { dispatch }) => {
1821
- var _a;
1822
- if (((_a = action.payload) === null || _a === void 0 ? void 0 : _a.error) === "room_full") {
1823
- dispatch(doSetNotification(createNotificationEvent({
1824
- type: "clientUnableToJoinFullRoom",
1825
- message: "Someone tried to join but the room is full and at capacity.",
1826
- props: {},
1827
- })));
2008
+ createReactor([selectShouldDisconnectRtc], ({ dispatch }, shouldDisconnectRtc) => {
2009
+ if (shouldDisconnectRtc) {
2010
+ dispatch(doDisconnectRtc());
2011
+ }
2012
+ });
2013
+ const selectStreamsToAccept = toolkit.createSelector(selectRtcStatus, selectRemoteClients, (rtcStatus, remoteParticipants) => {
2014
+ if (rtcStatus !== "ready") {
2015
+ return [];
2016
+ }
2017
+ const upd = [];
2018
+ for (const client of remoteParticipants) {
2019
+ const { streams, id: clientId, newJoiner } = client;
2020
+ for (let i = 0; i < streams.length; i++) {
2021
+ let streamId = streams[i].id;
2022
+ let state = streams[i].state;
2023
+ if ((streams === null || streams === void 0 ? void 0 : streams.length) > 1 && streams[1].id === "0") {
2024
+ if (i === 0) {
2025
+ streamId = streams[1].id;
2026
+ state = streams[1].state;
2027
+ }
2028
+ else if (i === 1) {
2029
+ streamId = streams[0].id;
2030
+ state = streams[0].state;
2031
+ }
2032
+ }
2033
+ {
2034
+ if (state === "done_accept")
2035
+ continue;
2036
+ upd.push({
2037
+ clientId,
2038
+ streamId,
2039
+ state: `${newJoiner && streamId === "0" ? "new" : "to"}_accept`,
2040
+ });
2041
+ }
1828
2042
  }
1829
- },
2043
+ }
2044
+ return upd;
2045
+ });
2046
+ createReactor([selectStreamsToAccept, selectIsAcceptingStreams], ({ dispatch }, streamsToAccept, isAcceptingStreams) => {
2047
+ if (0 < streamsToAccept.length && !isAcceptingStreams) {
2048
+ dispatch(doHandleAcceptStreams(streamsToAccept));
2049
+ }
1830
2050
  });
1831
2051
 
1832
2052
  function isStreamerClient(client) {
@@ -1938,313 +2158,278 @@ const selectAllClientViews = toolkit.createSelector(selectLocalParticipantView,
1938
2158
  return [...(localParticipant ? [localParticipant] : []), ...remoteParticipants];
1939
2159
  });
1940
2160
 
1941
- const createWebRtcEmitter = (dispatch) => {
1942
- return {
1943
- emit: (eventName, data) => {
1944
- if (eventName === "rtc_manager_created") {
1945
- dispatch(doRtcManagerCreated(data));
1946
- }
1947
- else if (eventName === "stream_added") {
1948
- dispatch(rtcEvents.streamAdded(data));
1949
- }
1950
- else if (eventName === "rtc_manager_destroyed") {
1951
- dispatch(rtcManagerDestroyed());
1952
- }
1953
- else ;
1954
- },
1955
- };
1956
- };
1957
2161
  const initialState$4 = {
1958
- dispatcherCreated: false,
1959
- error: null,
1960
- isCreatingDispatcher: false,
1961
- reportedStreamResolutions: {},
1962
- rtcManager: null,
1963
- rtcManagerDispatcher: null,
1964
- rtcManagerInitialized: false,
1965
- status: "inactive",
1966
- isAcceptingStreams: false,
2162
+ running: false,
1967
2163
  };
1968
- const rtcConnectionSlice = toolkit.createSlice({
1969
- name: "rtcConnection",
2164
+ const connectionMonitorSlice = toolkit.createSlice({
2165
+ name: "connectionMonitor",
1970
2166
  initialState: initialState$4,
1971
2167
  reducers: {
1972
- isAcceptingStreams: (state, action) => {
1973
- return Object.assign(Object.assign({}, state), { isAcceptingStreams: action.payload });
1974
- },
1975
- resolutionReported: (state, action) => {
1976
- const { streamId, width, height } = action.payload;
1977
- return Object.assign(Object.assign({}, state), { reportedStreamResolutions: Object.assign(Object.assign({}, state.reportedStreamResolutions), { [streamId]: { width, height } }) });
2168
+ connectionMonitorStarted: (state, action) => {
2169
+ return Object.assign(Object.assign({}, state), { running: true, stopCallbackFunction: action.payload.stopIssueSubscription });
1978
2170
  },
1979
- rtcDisconnected: () => {
2171
+ connectionMonitorStopped: () => {
1980
2172
  return Object.assign({}, initialState$4);
1981
2173
  },
1982
- rtcDispatcherCreated: (state, action) => {
1983
- return Object.assign(Object.assign({}, state), { dispatcherCreated: true, rtcManagerDispatcher: action.payload });
1984
- },
1985
- rtcManagerCreated: (state, action) => {
1986
- return Object.assign(Object.assign({}, state), { rtcManager: action.payload, status: "ready" });
1987
- },
1988
- rtcManagerDestroyed: (state) => {
1989
- return Object.assign(Object.assign({}, state), { rtcManager: null });
1990
- },
1991
- rtcManagerInitialized: (state) => {
1992
- return Object.assign(Object.assign({}, state), { rtcManagerInitialized: true });
1993
- },
1994
- },
1995
- extraReducers: (builder) => {
1996
- builder.addCase(socketReconnecting, (state) => {
1997
- return Object.assign(Object.assign({}, state), { status: "reconnecting" });
1998
- });
1999
- builder.addCase(signalEvents.roomJoined, (state) => {
2000
- return Object.assign(Object.assign({}, state), { status: state.status === "reconnecting" ? "ready" : state.status });
2001
- });
2002
2174
  },
2003
2175
  });
2004
- const { resolutionReported, rtcDispatcherCreated, rtcDisconnected, rtcManagerCreated, rtcManagerDestroyed, rtcManagerInitialized, isAcceptingStreams, } = rtcConnectionSlice.actions;
2005
- const doConnectRtc = createAppThunk(() => (dispatch, getState) => {
2006
- const state = getState();
2007
- const socket = selectSignalConnectionRaw(state).socket;
2008
- const dispatcher = selectRtcConnectionRaw(state).rtcManagerDispatcher;
2009
- const isCameraEnabled = selectIsCameraEnabled(state);
2010
- const isMicrophoneEnabled = selectIsMicrophoneEnabled(state);
2011
- const isNodeSdk = selectAppIsNodeSdk(state);
2012
- if (dispatcher || !socket) {
2013
- return;
2014
- }
2015
- const webrtcProvider = {
2016
- getMediaConstraints: () => ({
2017
- audio: isMicrophoneEnabled,
2018
- video: isCameraEnabled,
2019
- }),
2020
- deferrable(clientId) {
2021
- return !clientId;
2022
- },
2023
- };
2024
- const rtcManagerDispatcher = new media.RtcManagerDispatcher({
2025
- emitter: createWebRtcEmitter(dispatch),
2026
- serverSocket: socket,
2027
- webrtcProvider,
2028
- features: {
2029
- isNodeSdk,
2030
- lowDataModeEnabled: false,
2031
- sfuServerOverrideHost: undefined,
2032
- turnServerOverrideHost: undefined,
2033
- useOnlyTURN: undefined,
2034
- vp9On: false,
2035
- h264On: false,
2036
- simulcastScreenshareOn: false,
2037
- deviceHandlerFactory: isNodeSdk ? Chrome111_js.Chrome111.createFactory() : undefined,
2176
+ const { connectionMonitorStarted, connectionMonitorStopped } = connectionMonitorSlice.actions;
2177
+ const doStartConnectionMonitor = createAppThunk(() => (dispatch, getState) => {
2178
+ media.setClientProvider(() => {
2179
+ const state = getState();
2180
+ const clientViews = selectAllClientViews(state).map((clientView) => {
2181
+ var _a, _b;
2182
+ return ({
2183
+ id: clientView.id,
2184
+ clientId: clientView.clientId,
2185
+ isLocalClient: clientView.isLocalClient,
2186
+ audio: {
2187
+ enabled: clientView.isAudioEnabled,
2188
+ track: (_a = clientView.stream) === null || _a === void 0 ? void 0 : _a.getAudioTracks()[0],
2189
+ },
2190
+ video: {
2191
+ enabled: clientView.isVideoEnabled,
2192
+ track: (_b = clientView.stream) === null || _b === void 0 ? void 0 : _b.getVideoTracks()[0],
2193
+ },
2194
+ isPresentation: clientView.isPresentation,
2195
+ });
2196
+ });
2197
+ return clientViews;
2198
+ });
2199
+ const issueMonitorSubscription = media.subscribeIssues({
2200
+ onUpdatedIssues: (issuesAndMetricsByClients) => {
2201
+ var _a;
2202
+ const state = getState();
2203
+ const rtcManager = selectRtcManager(state);
2204
+ if (!rtcManager) {
2205
+ return;
2206
+ }
2207
+ let lossSend = 0;
2208
+ let lossReceive = 0;
2209
+ let bitrateSend = 0;
2210
+ let bitrateReceive = 0;
2211
+ Object.entries(issuesAndMetricsByClients.aggregated.metrics).forEach(([key, value]) => {
2212
+ if (/loc.*packetloss/.test(key))
2213
+ lossSend = Math.max(lossSend, value.curMax);
2214
+ if (/rem.*packetloss/.test(key))
2215
+ lossReceive = Math.max(lossReceive, value.curMax);
2216
+ if (/loc.*bitrate/.test(key))
2217
+ bitrateSend += value.curSum;
2218
+ if (/rem.*bitrate/.test(key))
2219
+ bitrateReceive += value.curSum;
2220
+ });
2221
+ rtcManager.sendStatsCustomEvent("insightsStats", {
2222
+ ls: Math.round(lossSend * 1000) / 1000,
2223
+ lr: Math.round(lossReceive * 1000) / 1000,
2224
+ bs: Math.round(bitrateSend),
2225
+ br: Math.round(bitrateReceive),
2226
+ cpu: (_a = issuesAndMetricsByClients.aggregated.metrics["global-cpu-pressure"]) === null || _a === void 0 ? void 0 : _a.curSum,
2227
+ _time: Date.now(),
2228
+ });
2038
2229
  },
2039
2230
  });
2040
- dispatch(rtcDispatcherCreated(rtcManagerDispatcher));
2041
- });
2042
- const doDisconnectRtc = createAppThunk(() => (dispatch, getState) => {
2043
- const { rtcManager } = selectRtcConnectionRaw(getState());
2044
- if (rtcManager) {
2045
- rtcManager.disconnectAll();
2046
- }
2047
- dispatch(rtcDisconnected());
2231
+ dispatch(connectionMonitorStarted({ stopIssueSubscription: issueMonitorSubscription.stop }));
2048
2232
  });
2049
- const doHandleAcceptStreams = createAppThunk((payload) => (dispatch, getState) => {
2050
- var _a;
2051
- dispatch(isAcceptingStreams(true));
2233
+ const doStopConnectionMonitor = createAppThunk(() => (dispatch, getState) => {
2052
2234
  const state = getState();
2053
- const rtcManager = selectRtcConnectionRaw(state).rtcManager;
2054
- const remoteClients = selectRemoteClients(state);
2055
- if (!rtcManager) {
2056
- throw new Error("No rtc manager");
2057
- }
2058
- const activeBreakout = false;
2059
- const shouldAcceptNewClients = (_a = rtcManager.shouldAcceptStreamsFromBothSides) === null || _a === void 0 ? void 0 : _a.call(rtcManager);
2060
- const updates = [];
2061
- for (const { clientId, streamId, state } of payload) {
2062
- const participant = remoteClients.find((p) => p.id === clientId);
2063
- if (!participant)
2064
- continue;
2065
- if (state === "to_accept" ||
2066
- (state === "new_accept" && shouldAcceptNewClients) ||
2067
- (state === "old_accept" && !shouldAcceptNewClients)) {
2068
- const enforceTurnProtocol = participant.isDialIn ? "onlytls" : undefined;
2069
- rtcManager.acceptNewStream({
2070
- streamId: streamId === "0" ? clientId : streamId,
2071
- clientId,
2072
- shouldAddLocalVideo: streamId === "0",
2073
- activeBreakout,
2074
- enforceTurnProtocol,
2075
- });
2076
- }
2077
- else if (state === "new_accept" || state === "old_accept") ;
2078
- else if (state === "to_unaccept") {
2079
- rtcManager === null || rtcManager === void 0 ? void 0 : rtcManager.disconnect(streamId === "0" ? clientId : streamId, activeBreakout);
2080
- }
2081
- else if (state !== "done_accept") {
2082
- continue;
2083
- }
2084
- else ;
2085
- updates.push({ clientId, streamId, state: state.replace(/to_|new_|old_/, "done_") });
2235
+ const stopCallbackFn = selectStopCallbackFunction(state);
2236
+ if (stopCallbackFn) {
2237
+ stopCallbackFn();
2086
2238
  }
2087
- dispatch(streamStatusUpdated(updates));
2088
- dispatch(isAcceptingStreams(false));
2239
+ dispatch(connectionMonitorStopped());
2089
2240
  });
2090
- const doRtcReportStreamResolution = createAppThunk(({ streamId, width, height }) => (dispatch, getState) => {
2091
- const { reportedStreamResolutions, rtcManager } = selectRtcConnectionRaw(getState());
2092
- const localStream = selectLocalMediaStream(getState());
2093
- if (!rtcManager || (localStream === null || localStream === void 0 ? void 0 : localStream.id) === streamId) {
2094
- return;
2095
- }
2096
- const old = reportedStreamResolutions[streamId];
2097
- if (!old || old.width !== width || old.height !== height) {
2098
- rtcManager.updateStreamResolution(streamId, null, { width: width || 1, height: height || 1 });
2241
+ const selectConnectionMonitorIsRunning = (state) => state.connectionMonitor.running;
2242
+ const selectStopCallbackFunction = (state) => state.connectionMonitor.stopCallbackFunction;
2243
+ const selectShouldStartConnectionMonitor = toolkit.createSelector(selectRoomConnectionStatus, selectConnectionMonitorIsRunning, (roomConnectionStatus, isRunning) => {
2244
+ if (!isRunning && roomConnectionStatus === "connected") {
2245
+ return true;
2099
2246
  }
2100
- dispatch(resolutionReported({ streamId, width, height }));
2101
- });
2102
- const doRtcManagerCreated = createAppThunk((payload) => (dispatch) => {
2103
- const { rtcManager } = payload;
2104
- dispatch(rtcManagerCreated(rtcManager));
2247
+ return false;
2105
2248
  });
2106
- const doRtcManagerInitialize = createAppThunk(() => (dispatch, getState) => {
2107
- const localMediaStream = selectLocalMediaStream(getState());
2108
- const rtcManager = selectRtcConnectionRaw(getState()).rtcManager;
2109
- const isCameraEnabled = selectIsCameraEnabled(getState());
2110
- const isMicrophoneEnabled = selectIsMicrophoneEnabled(getState());
2111
- if (localMediaStream && rtcManager) {
2112
- rtcManager.addNewStream("0", localMediaStream, !isMicrophoneEnabled, !isCameraEnabled);
2249
+ const selectShouldStopConnectionMonitor = toolkit.createSelector(selectRoomConnectionStatus, selectConnectionMonitorIsRunning, (roomConnectionStatus, isRunning) => {
2250
+ if (isRunning && ["kicked", "left"].includes(roomConnectionStatus)) {
2251
+ return true;
2252
+ }
2253
+ return false;
2254
+ });
2255
+ createReactor([selectShouldStartConnectionMonitor], ({ dispatch }, shouldStartConnectionMonitor) => {
2256
+ if (shouldStartConnectionMonitor) {
2257
+ dispatch(doStartConnectionMonitor());
2113
2258
  }
2114
- dispatch(rtcManagerInitialized());
2115
2259
  });
2116
- const selectRtcConnectionRaw = (state) => state.rtcConnection;
2117
- const selectRtcManagerInitialized = (state) => state.rtcConnection.rtcManagerInitialized;
2118
- const selectRtcManager = (state) => state.rtcConnection.rtcManager;
2119
- const selectRtcDispatcherCreated = (state) => state.rtcConnection.dispatcherCreated;
2120
- const selectRtcIsCreatingDispatcher = (state) => state.rtcConnection.isCreatingDispatcher;
2121
- const selectRtcStatus = (state) => state.rtcConnection.status;
2122
- const selectIsAcceptingStreams = (state) => state.rtcConnection.isAcceptingStreams;
2123
- startAppListening({
2124
- actionCreator: doSetDevice.fulfilled,
2125
- effect: ({ payload }, { getState }) => {
2126
- const { replacedTracks } = payload;
2127
- const { rtcManager } = selectRtcConnectionRaw(getState());
2128
- const stream = selectLocalMediaStream(getState());
2129
- const replace = (kind, oldTrack) => {
2130
- const track = stream === null || stream === void 0 ? void 0 : stream.getTracks().find((t) => t.kind === kind);
2131
- return track && (rtcManager === null || rtcManager === void 0 ? void 0 : rtcManager.replaceTrack(oldTrack, track));
2132
- };
2133
- replacedTracks === null || replacedTracks === void 0 ? void 0 : replacedTracks.forEach((t) => {
2134
- replace(t.kind, t);
2135
- });
2260
+ createReactor([selectShouldStopConnectionMonitor], ({ dispatch }, shouldStartConnectionMonitor) => {
2261
+ if (shouldStartConnectionMonitor) {
2262
+ dispatch(doStopConnectionMonitor());
2263
+ }
2264
+ });
2265
+
2266
+ const emitter = new events$1.EventEmitter();
2267
+ function createNotificationEvent(payload) {
2268
+ const notificationEvent = Object.assign(Object.assign({}, payload), { timestamp: Date.now() });
2269
+ return notificationEvent;
2270
+ }
2271
+ const initialNotificationsState = {
2272
+ emitter,
2273
+ events: [],
2274
+ };
2275
+ const notificationsSlice = toolkit.createSlice({
2276
+ name: "notifications",
2277
+ initialState: initialNotificationsState,
2278
+ reducers: {
2279
+ addNotification: (state, action) => {
2280
+ return Object.assign(Object.assign({}, state), { events: [...state.events, Object.assign({}, action.payload)] });
2281
+ },
2282
+ doClearNotifications: (state) => {
2283
+ return Object.assign(Object.assign({}, state), { events: [] });
2284
+ },
2136
2285
  },
2137
2286
  });
2287
+ const { doClearNotifications } = notificationsSlice.actions;
2288
+ const doSetNotification = createAppThunk((payload) => (dispatch, getState) => {
2289
+ dispatch(notificationsSlice.actions.addNotification(payload));
2290
+ const state = getState();
2291
+ const emitter = selectNotificationsEmitter(state);
2292
+ emitter.emit(payload.type, payload);
2293
+ emitter.emit("*", payload);
2294
+ });
2295
+ const selectNotificationsRaw = (state) => state.notifications;
2296
+ const selectNotificationsEvents = (state) => state.notifications.events;
2297
+ const selectNotificationsEmitter = (state) => state.notifications.emitter;
2138
2298
  startAppListening({
2139
- actionCreator: doStartScreenshare.fulfilled,
2140
- effect: ({ payload }, { getState }) => {
2141
- const { stream } = payload;
2142
- const { rtcManager } = selectRtcConnectionRaw(getState());
2143
- rtcManager === null || rtcManager === void 0 ? void 0 : rtcManager.addNewStream(stream.id, stream, false, true);
2299
+ actionCreator: signalEvents.chatMessage,
2300
+ effect: ({ payload }, { dispatch, getState }) => {
2301
+ const state = getState();
2302
+ const client = selectRemoteParticipants(state).find(({ id }) => id === payload.senderId);
2303
+ if (!client) {
2304
+ console.warn("Could not find remote client that sent chat message");
2305
+ return;
2306
+ }
2307
+ dispatch(doSetNotification(createNotificationEvent({
2308
+ type: "chatMessageReceived",
2309
+ message: `${client.displayName} says: ${payload.text}`,
2310
+ props: {
2311
+ client,
2312
+ chatMessage: {
2313
+ senderId: payload.senderId,
2314
+ timestamp: payload.timestamp,
2315
+ text: payload.text,
2316
+ },
2317
+ },
2318
+ })));
2144
2319
  },
2145
2320
  });
2146
2321
  startAppListening({
2147
- actionCreator: doAppStop,
2148
- effect: (_, { getState }) => {
2149
- const rtcManager = selectRtcManager(getState());
2150
- rtcManager === null || rtcManager === void 0 ? void 0 : rtcManager.rtcStatsDisconnect();
2322
+ actionCreator: signalEvents.audioEnableRequested,
2323
+ effect: ({ payload }, { dispatch, getState }) => {
2324
+ const { enable, requestedByClientId } = payload;
2325
+ const state = getState();
2326
+ const client = selectRemoteParticipants(state).find(({ id }) => id === requestedByClientId);
2327
+ if (!client) {
2328
+ console.warn("Could not find remote client that requested a local audio change");
2329
+ return;
2330
+ }
2331
+ dispatch(doSetNotification(createNotificationEvent({
2332
+ type: enable ? "requestAudioEnable" : "requestAudioDisable",
2333
+ message: enable
2334
+ ? `${client.displayName} has requested for you to speak`
2335
+ : `${client.displayName} has muted your microphone`,
2336
+ props: {
2337
+ client,
2338
+ enable,
2339
+ },
2340
+ })));
2151
2341
  },
2152
2342
  });
2153
2343
  startAppListening({
2154
- actionCreator: stopScreenshare,
2155
- effect: ({ payload }, { getState }) => {
2156
- const { stream } = payload;
2157
- const { rtcManager } = selectRtcConnectionRaw(getState());
2158
- rtcManager === null || rtcManager === void 0 ? void 0 : rtcManager.removeStream(stream.id, stream, null);
2344
+ actionCreator: signalEvents.videoEnableRequested,
2345
+ effect: ({ payload }, { dispatch, getState }) => {
2346
+ const { enable, requestedByClientId } = payload;
2347
+ const state = getState();
2348
+ const client = selectRemoteParticipants(state).find(({ id }) => id === requestedByClientId);
2349
+ if (!client) {
2350
+ console.warn("Could not find remote client that requested a local video change");
2351
+ return;
2352
+ }
2353
+ dispatch(doSetNotification(createNotificationEvent({
2354
+ type: enable ? "requestVideoEnable" : "requestVideoDisable",
2355
+ message: enable
2356
+ ? `${client.displayName} has requested for you to start video`
2357
+ : `${client.displayName} has stopped your video`,
2358
+ props: {
2359
+ client,
2360
+ enable,
2361
+ },
2362
+ })));
2159
2363
  },
2160
2364
  });
2161
2365
  startAppListening({
2162
- actionCreator: doSwitchLocalStream.fulfilled,
2163
- effect: ({ payload }, { getState }) => {
2366
+ actionCreator: signalEvents.clientMetadataReceived,
2367
+ effect: (action, { dispatch, getOriginalState, getState }) => {
2164
2368
  var _a;
2165
- const stream = selectLocalMediaStream(getState());
2166
- const { rtcManager } = selectRtcConnectionRaw(getState());
2167
- if (stream && rtcManager) {
2168
- const replace = (kind, oldTrack) => {
2169
- const track = stream.getTracks().find((t) => t.kind === kind);
2170
- return track && rtcManager.replaceTrack(oldTrack, track);
2171
- };
2172
- (_a = payload === null || payload === void 0 ? void 0 : payload.replacedTracks) === null || _a === void 0 ? void 0 : _a.forEach((t) => {
2173
- replace(t.kind, t);
2174
- });
2369
+ const { error, payload } = action.payload;
2370
+ if (error || !payload) {
2371
+ return;
2372
+ }
2373
+ const { clientId, stickyReaction } = payload;
2374
+ const state = getState();
2375
+ const canAskToSpeak = selectIsAuthorizedToAskToSpeak(state);
2376
+ if (!canAskToSpeak) {
2377
+ return;
2378
+ }
2379
+ const client = selectRemoteParticipants(state).find(({ id }) => id === clientId);
2380
+ if (!client) {
2381
+ console.warn("Could not find remote client that provided updated metadata");
2382
+ return;
2383
+ }
2384
+ const previousState = getOriginalState();
2385
+ const previousClient = selectRemoteParticipants(previousState).find(({ id }) => id === clientId);
2386
+ if ((!stickyReaction && !(previousClient === null || previousClient === void 0 ? void 0 : previousClient.stickyReaction)) ||
2387
+ (stickyReaction === null || stickyReaction === void 0 ? void 0 : stickyReaction.timestamp) === ((_a = previousClient === null || previousClient === void 0 ? void 0 : previousClient.stickyReaction) === null || _a === void 0 ? void 0 : _a.timestamp)) {
2388
+ return;
2175
2389
  }
2390
+ dispatch(doSetNotification(createNotificationEvent({
2391
+ type: stickyReaction ? "remoteHandRaised" : "remoteHandLowered",
2392
+ message: `${client.displayName} ${stickyReaction ? "raised" : "lowered"} their hand`,
2393
+ props: {
2394
+ client,
2395
+ stickyReaction,
2396
+ },
2397
+ })));
2176
2398
  },
2177
2399
  });
2178
- const selectShouldConnectRtc = toolkit.createSelector(selectRtcDispatcherCreated, selectRtcIsCreatingDispatcher, selectSignalConnectionSocket, (dispatcherCreated, isCreatingDispatcher, signalSocket) => {
2179
- if (!dispatcherCreated && !isCreatingDispatcher && signalSocket) {
2180
- return true;
2181
- }
2182
- return false;
2183
- });
2184
- createReactor([selectShouldConnectRtc], ({ dispatch }, shouldConnectRtc) => {
2185
- if (shouldConnectRtc) {
2186
- dispatch(doConnectRtc());
2187
- }
2188
- });
2189
- const selectShouldInitializeRtc = toolkit.createSelector(selectRtcManager, selectRtcManagerInitialized, selectLocalMediaStatus, (rtcManager, rtcManagerInitialized, localMediaStatus) => {
2190
- if (localMediaStatus === "started" && rtcManager && !rtcManagerInitialized) {
2191
- return true;
2192
- }
2193
- return false;
2194
- });
2195
- createReactor([selectShouldInitializeRtc], ({ dispatch }, shouldInitializeRtc) => {
2196
- if (shouldInitializeRtc) {
2197
- dispatch(doRtcManagerInitialize());
2400
+ createReactor([selectSignalStatus], ({ dispatch, getState }, signalStatus) => {
2401
+ const state = getState();
2402
+ const roomConnectionStatus = selectRoomConnectionStatus(state);
2403
+ if (["left", "kicked"].includes(roomConnectionStatus)) {
2404
+ return;
2198
2405
  }
2199
- });
2200
- const selectShouldDisconnectRtc = toolkit.createSelector(selectRtcStatus, selectAppIsActive, (status, appIsActive) => {
2201
- if (!appIsActive && !["inactive", "disconnected"].includes(status)) {
2202
- return true;
2406
+ if (signalStatus === "disconnected") {
2407
+ dispatch(doSetNotification(createNotificationEvent({
2408
+ type: "signalTrouble",
2409
+ message: `Network connection lost. Trying to reconnect you...`,
2410
+ props: {},
2411
+ })));
2203
2412
  }
2204
- return false;
2205
- });
2206
- createReactor([selectShouldDisconnectRtc], ({ dispatch }, shouldDisconnectRtc) => {
2207
- if (shouldDisconnectRtc) {
2208
- dispatch(doDisconnectRtc());
2413
+ else if (signalStatus === "connected") {
2414
+ dispatch(doSetNotification(createNotificationEvent({
2415
+ type: "signalOk",
2416
+ message: `Network connection available`,
2417
+ props: {},
2418
+ })));
2209
2419
  }
2210
2420
  });
2211
- const selectStreamsToAccept = toolkit.createSelector(selectRtcStatus, selectRemoteClients, (rtcStatus, remoteParticipants) => {
2212
- if (rtcStatus !== "ready") {
2213
- return [];
2214
- }
2215
- const upd = [];
2216
- for (const client of remoteParticipants) {
2217
- const { streams, id: clientId, newJoiner } = client;
2218
- for (let i = 0; i < streams.length; i++) {
2219
- let streamId = streams[i].id;
2220
- let state = streams[i].state;
2221
- if ((streams === null || streams === void 0 ? void 0 : streams.length) > 1 && streams[1].id === "0") {
2222
- if (i === 0) {
2223
- streamId = streams[1].id;
2224
- state = streams[1].state;
2225
- }
2226
- else if (i === 1) {
2227
- streamId = streams[0].id;
2228
- state = streams[0].state;
2229
- }
2230
- }
2231
- {
2232
- if (state === "done_accept")
2233
- continue;
2234
- upd.push({
2235
- clientId,
2236
- streamId,
2237
- state: `${newJoiner && streamId === "0" ? "new" : "to"}_accept`,
2238
- });
2239
- }
2421
+ startAppListening({
2422
+ actionCreator: signalEvents.clientUnableToJoin,
2423
+ effect: (action, { dispatch }) => {
2424
+ var _a;
2425
+ if (((_a = action.payload) === null || _a === void 0 ? void 0 : _a.error) === "room_full") {
2426
+ dispatch(doSetNotification(createNotificationEvent({
2427
+ type: "clientUnableToJoinFullRoom",
2428
+ message: "Someone tried to join but the room is full and at capacity.",
2429
+ props: {},
2430
+ })));
2240
2431
  }
2241
- }
2242
- return upd;
2243
- });
2244
- createReactor([selectStreamsToAccept, selectIsAcceptingStreams], ({ dispatch }, streamsToAccept, isAcceptingStreams) => {
2245
- if (0 < streamsToAccept.length && !isAcceptingStreams) {
2246
- dispatch(doHandleAcceptStreams(streamsToAccept));
2247
- }
2432
+ },
2248
2433
  });
2249
2434
 
2250
2435
  const rtcAnalyticsCustomEvents = {
@@ -2285,7 +2470,7 @@ const rtcAnalyticsCustomEvents = {
2285
2470
  getOutput: () => ({}),
2286
2471
  },
2287
2472
  displayName: {
2288
- actions: [doSetDisplayName],
2473
+ actions: [setDisplayName],
2289
2474
  rtcEventName: "displayName",
2290
2475
  getValue: (state) => selectAppDisplayName(state),
2291
2476
  getOutput: (value) => ({ displayName: value }),
@@ -2586,7 +2771,7 @@ const waitingParticipantsSlice = toolkit.createSlice({
2586
2771
  });
2587
2772
  },
2588
2773
  });
2589
- const doAcceptWaitingParticipant = createAppThunk((payload) => (dispatch, getState) => {
2774
+ const doAcceptWaitingParticipant = createRoomConnectedThunk((payload) => (dispatch, getState) => {
2590
2775
  const { participantId } = payload;
2591
2776
  const state = getState();
2592
2777
  const socket = selectSignalConnectionSocket(state);
@@ -2596,7 +2781,7 @@ const doAcceptWaitingParticipant = createAppThunk((payload) => (dispatch, getSta
2596
2781
  response: {},
2597
2782
  });
2598
2783
  });
2599
- const doRejectWaitingParticipant = createAppThunk((payload) => (dispatch, getState) => {
2784
+ const doRejectWaitingParticipant = createRoomConnectedThunk((payload) => (dispatch, getState) => {
2600
2785
  const { participantId } = payload;
2601
2786
  const state = getState();
2602
2787
  const socket = selectSignalConnectionSocket(state);
@@ -2616,6 +2801,7 @@ const appReducer = toolkit.combineReducers({
2616
2801
  authorization: authorizationSlice.reducer,
2617
2802
  chat: chatSlice.reducer,
2618
2803
  cloudRecording: cloudRecordingSlice.reducer,
2804
+ connectionMonitor: connectionMonitorSlice.reducer,
2619
2805
  deviceCredentials: deviceCredentialsSlice.reducer,
2620
2806
  localMedia: localMediaSlice.reducer,
2621
2807
  localParticipant: localParticipantSlice.reducer,
@@ -3693,10 +3879,16 @@ exports.appSlice = appSlice;
3693
3879
  exports.authorizationSlice = authorizationSlice;
3694
3880
  exports.chatSlice = chatSlice;
3695
3881
  exports.cloudRecordingSlice = cloudRecordingSlice;
3882
+ exports.connectionMonitorSlice = connectionMonitorSlice;
3883
+ exports.connectionMonitorStarted = connectionMonitorStarted;
3884
+ exports.connectionMonitorStopped = connectionMonitorStopped;
3696
3885
  exports.createAppAsyncThunk = createAppAsyncThunk;
3697
3886
  exports.createAppAuthorizedThunk = createAppAuthorizedThunk;
3698
3887
  exports.createAppThunk = createAppThunk;
3888
+ exports.createAsyncRoomConnectedThunk = createAsyncRoomConnectedThunk;
3889
+ exports.createAuthorizedRoomConnectedThunk = createAuthorizedRoomConnectedThunk;
3699
3890
  exports.createReactor = createReactor;
3891
+ exports.createRoomConnectedThunk = createRoomConnectedThunk;
3700
3892
  exports.createServices = createServices;
3701
3893
  exports.createStore = createStore;
3702
3894
  exports.createWebRtcEmitter = createWebRtcEmitter;
@@ -3726,6 +3918,7 @@ exports.doOrganizationFetch = doOrganizationFetch;
3726
3918
  exports.doRejectWaitingParticipant = doRejectWaitingParticipant;
3727
3919
  exports.doRemoveSpotlight = doRemoveSpotlight;
3728
3920
  exports.doRequestAudioEnable = doRequestAudioEnable;
3921
+ exports.doRequestVideoEnable = doRequestVideoEnable;
3729
3922
  exports.doRtcAnalyticsCustomEventsInitialize = doRtcAnalyticsCustomEventsInitialize;
3730
3923
  exports.doRtcManagerCreated = doRtcManagerCreated;
3731
3924
  exports.doRtcManagerInitialize = doRtcManagerInitialize;
@@ -3741,9 +3934,11 @@ exports.doSignalDisconnect = doSignalDisconnect;
3741
3934
  exports.doSignalIdentifyDevice = doSignalIdentifyDevice;
3742
3935
  exports.doSpotlightParticipant = doSpotlightParticipant;
3743
3936
  exports.doStartCloudRecording = doStartCloudRecording;
3937
+ exports.doStartConnectionMonitor = doStartConnectionMonitor;
3744
3938
  exports.doStartLocalMedia = doStartLocalMedia;
3745
3939
  exports.doStartScreenshare = doStartScreenshare;
3746
3940
  exports.doStopCloudRecording = doStopCloudRecording;
3941
+ exports.doStopConnectionMonitor = doStopConnectionMonitor;
3747
3942
  exports.doStopLocalMedia = doStopLocalMedia;
3748
3943
  exports.doStopScreenshare = doStopScreenshare;
3749
3944
  exports.doSwitchLocalStream = doSwitchLocalStream;
@@ -3757,7 +3952,7 @@ exports.hasValue = hasValue;
3757
3952
  exports.initialCloudRecordingState = initialCloudRecordingState;
3758
3953
  exports.initialLocalMediaState = initialLocalMediaState;
3759
3954
  exports.initialNotificationsState = initialNotificationsState;
3760
- exports.initialState = initialState$f;
3955
+ exports.initialState = initialState$g;
3761
3956
  exports.isAcceptingStreams = isAcceptingStreams;
3762
3957
  exports.isClientSpotlighted = isClientSpotlighted;
3763
3958
  exports.listenerMiddleware = listenerMiddleware;
@@ -3809,6 +4004,7 @@ exports.selectCloudRecordingError = selectCloudRecordingError;
3809
4004
  exports.selectCloudRecordingRaw = selectCloudRecordingRaw;
3810
4005
  exports.selectCloudRecordingStartedAt = selectCloudRecordingStartedAt;
3811
4006
  exports.selectCloudRecordingStatus = selectCloudRecordingStatus;
4007
+ exports.selectConnectionMonitorIsRunning = selectConnectionMonitorIsRunning;
3812
4008
  exports.selectCurrentCameraDeviceId = selectCurrentCameraDeviceId;
3813
4009
  exports.selectCurrentMicrophoneDeviceId = selectCurrentMicrophoneDeviceId;
3814
4010
  exports.selectCurrentSpeakerDeviceId = selectCurrentSpeakerDeviceId;
@@ -3821,6 +4017,7 @@ exports.selectIsAuthorizedToEndMeeting = selectIsAuthorizedToEndMeeting;
3821
4017
  exports.selectIsAuthorizedToKickClient = selectIsAuthorizedToKickClient;
3822
4018
  exports.selectIsAuthorizedToLockRoom = selectIsAuthorizedToLockRoom;
3823
4019
  exports.selectIsAuthorizedToRequestAudioEnable = selectIsAuthorizedToRequestAudioEnable;
4020
+ exports.selectIsAuthorizedToRequestVideoEnable = selectIsAuthorizedToRequestVideoEnable;
3824
4021
  exports.selectIsAuthorizedToSpotlight = selectIsAuthorizedToSpotlight;
3825
4022
  exports.selectIsCameraEnabled = selectIsCameraEnabled;
3826
4023
  exports.selectIsCloudRecording = selectIsCloudRecording;
@@ -3887,6 +4084,8 @@ exports.selectShouldFetchDeviceCredentials = selectShouldFetchDeviceCredentials;
3887
4084
  exports.selectShouldFetchOrganization = selectShouldFetchOrganization;
3888
4085
  exports.selectShouldIdentifyDevice = selectShouldIdentifyDevice;
3889
4086
  exports.selectShouldInitializeRtc = selectShouldInitializeRtc;
4087
+ exports.selectShouldStartConnectionMonitor = selectShouldStartConnectionMonitor;
4088
+ exports.selectShouldStopConnectionMonitor = selectShouldStopConnectionMonitor;
3890
4089
  exports.selectSignalConnectionDeviceIdentified = selectSignalConnectionDeviceIdentified;
3891
4090
  exports.selectSignalConnectionRaw = selectSignalConnectionRaw;
3892
4091
  exports.selectSignalConnectionSocket = selectSignalConnectionSocket;
@@ -3896,6 +4095,7 @@ exports.selectSpeakerDevices = selectSpeakerDevices;
3896
4095
  exports.selectSpotlightedClientViews = selectSpotlightedClientViews;
3897
4096
  exports.selectSpotlights = selectSpotlights;
3898
4097
  exports.selectSpotlightsRaw = selectSpotlightsRaw;
4098
+ exports.selectStopCallbackFunction = selectStopCallbackFunction;
3899
4099
  exports.selectStreamingRaw = selectStreamingRaw;
3900
4100
  exports.selectStreamsToAccept = selectStreamsToAccept;
3901
4101
  exports.selectWaitingParticipants = selectWaitingParticipants;
@@ -3903,6 +4103,7 @@ exports.selectWaitingParticipantsRaw = selectWaitingParticipantsRaw;
3903
4103
  exports.setCurrentCameraDeviceId = setCurrentCameraDeviceId;
3904
4104
  exports.setCurrentMicrophoneDeviceId = setCurrentMicrophoneDeviceId;
3905
4105
  exports.setCurrentSpeakerDeviceId = setCurrentSpeakerDeviceId;
4106
+ exports.setDisplayName = setDisplayName;
3906
4107
  exports.setLocalMediaOptions = setLocalMediaOptions;
3907
4108
  exports.setLocalMediaStream = setLocalMediaStream;
3908
4109
  exports.setRoomKey = setRoomKey;