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