@whereby.com/core 0.6.0 → 0.8.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/cjs/index.cjs +3188 -0
- package/dist/cjs/utils.cjs +113 -0
- package/dist/index.d.ts +1539 -530
- package/dist/index.mjs +2998 -0
- package/dist/utils.d.ts +0 -10
- package/dist/{utils.js → utils.mjs} +20 -3
- package/package.json +10 -10
- package/dist/debounce-B-cWYxqK.js +0 -20
- package/dist/index.js +0 -9571
|
@@ -0,0 +1,3188 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var toolkit = require('@reduxjs/toolkit');
|
|
4
|
+
var media = require('@whereby.com/media');
|
|
5
|
+
var Chrome111_js = require('mediasoup-client/lib/handlers/Chrome111.js');
|
|
6
|
+
var nodeBtoa = require('btoa');
|
|
7
|
+
var axios = require('axios');
|
|
8
|
+
var EventEmitter = require('events');
|
|
9
|
+
|
|
10
|
+
function createAppAsyncThunk(typePrefix, payloadCreator) {
|
|
11
|
+
return toolkit.createAsyncThunk(typePrefix, payloadCreator);
|
|
12
|
+
}
|
|
13
|
+
function createAppThunk(thunk) {
|
|
14
|
+
return thunk;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const listenerMiddleware = toolkit.createListenerMiddleware();
|
|
18
|
+
const startAppListening = listenerMiddleware.startListening;
|
|
19
|
+
const addAppListener = toolkit.addListener;
|
|
20
|
+
const createReactor = (selectors, callback) => {
|
|
21
|
+
return startAppListening({
|
|
22
|
+
predicate: (_, currentState, previousState) => {
|
|
23
|
+
const previousValues = selectors.map((selector) => selector(previousState));
|
|
24
|
+
const currentValues = selectors.map((selector) => selector(currentState));
|
|
25
|
+
return previousValues.some((previousValue, index) => previousValue !== currentValues[index]);
|
|
26
|
+
},
|
|
27
|
+
effect: (action, { dispatch, getState, extra }) => {
|
|
28
|
+
const selectorResults = selectors.map((selector) => selector(getState()));
|
|
29
|
+
callback({
|
|
30
|
+
dispatch,
|
|
31
|
+
getState,
|
|
32
|
+
extra,
|
|
33
|
+
}, ...selectorResults);
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const initialState$c = {
|
|
39
|
+
isNodeSdk: false,
|
|
40
|
+
wantsToJoin: false,
|
|
41
|
+
roomName: null,
|
|
42
|
+
roomKey: null,
|
|
43
|
+
roomUrl: null,
|
|
44
|
+
displayName: null,
|
|
45
|
+
sdkVersion: null,
|
|
46
|
+
externalId: null,
|
|
47
|
+
};
|
|
48
|
+
const appSlice = toolkit.createSlice({
|
|
49
|
+
name: "app",
|
|
50
|
+
initialState: initialState$c,
|
|
51
|
+
reducers: {
|
|
52
|
+
doAppJoin: (state, action) => {
|
|
53
|
+
const url = new URL(action.payload.roomUrl);
|
|
54
|
+
return Object.assign(Object.assign(Object.assign({}, state), action.payload), { roomName: url.pathname, wantsToJoin: true });
|
|
55
|
+
},
|
|
56
|
+
appLeft: (state) => {
|
|
57
|
+
return Object.assign(Object.assign({}, state), { wantsToJoin: false });
|
|
58
|
+
},
|
|
59
|
+
setRoomKey: (state, action) => {
|
|
60
|
+
return Object.assign(Object.assign({}, state), { roomKey: action.payload });
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
const { doAppJoin, appLeft, setRoomKey } = appSlice.actions;
|
|
65
|
+
const selectAppRaw = (state) => state.app;
|
|
66
|
+
const selectAppWantsToJoin = (state) => state.app.wantsToJoin;
|
|
67
|
+
const selectAppRoomName = (state) => state.app.roomName;
|
|
68
|
+
const selectAppRoomUrl = (state) => state.app.roomUrl;
|
|
69
|
+
const selectAppRoomKey = (state) => state.app.roomKey;
|
|
70
|
+
const selectAppDisplayName = (state) => state.app.displayName;
|
|
71
|
+
const selectAppSdkVersion = (state) => state.app.sdkVersion;
|
|
72
|
+
const selectAppExternalId = (state) => state.app.externalId;
|
|
73
|
+
const selectAppIsNodeSdk = (state) => state.app.isNodeSdk;
|
|
74
|
+
|
|
75
|
+
function createSignalEventAction(name) {
|
|
76
|
+
return toolkit.createAction(`signalConnection/event/${name}`);
|
|
77
|
+
}
|
|
78
|
+
const signalEvents = {
|
|
79
|
+
audioEnabled: createSignalEventAction("audioEnabled"),
|
|
80
|
+
chatMessage: createSignalEventAction("chatMessage"),
|
|
81
|
+
clientLeft: createSignalEventAction("clientLeft"),
|
|
82
|
+
clientKicked: createSignalEventAction("clientKicked"),
|
|
83
|
+
clientMetadataReceived: createSignalEventAction("clientMetadataReceived"),
|
|
84
|
+
cloudRecordingStarted: createSignalEventAction("cloudRecordingStarted"),
|
|
85
|
+
cloudRecordingStopped: createSignalEventAction("cloudRecordingStopped"),
|
|
86
|
+
disconnect: createSignalEventAction("disconnect"),
|
|
87
|
+
knockerLeft: createSignalEventAction("knockerLeft"),
|
|
88
|
+
knockHandled: createSignalEventAction("knockHandled"),
|
|
89
|
+
newClient: createSignalEventAction("newClient"),
|
|
90
|
+
roomJoined: createSignalEventAction("roomJoined"),
|
|
91
|
+
roomKnocked: createSignalEventAction("roomKnocked"),
|
|
92
|
+
roomSessionEnded: createSignalEventAction("roomSessionEnded"),
|
|
93
|
+
screenshareStarted: createSignalEventAction("screenshareStarted"),
|
|
94
|
+
screenshareStopped: createSignalEventAction("screenshareStopped"),
|
|
95
|
+
streamingStopped: createSignalEventAction("streamingStopped"),
|
|
96
|
+
videoEnabled: createSignalEventAction("videoEnabled"),
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/******************************************************************************
|
|
100
|
+
Copyright (c) Microsoft Corporation.
|
|
101
|
+
|
|
102
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
103
|
+
purpose with or without fee is hereby granted.
|
|
104
|
+
|
|
105
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
106
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
107
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
108
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
109
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
110
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
111
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
112
|
+
***************************************************************************** */
|
|
113
|
+
/* global Reflect, Promise, SuppressedError, Symbol */
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
function __rest(s, e) {
|
|
117
|
+
var t = {};
|
|
118
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
119
|
+
t[p] = s[p];
|
|
120
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
121
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
122
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
123
|
+
t[p[i]] = s[p[i]];
|
|
124
|
+
}
|
|
125
|
+
return t;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
129
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
130
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
131
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
132
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
133
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
134
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
139
|
+
var e = new Error(message);
|
|
140
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const initialState$b = {
|
|
144
|
+
isFetching: false,
|
|
145
|
+
data: null,
|
|
146
|
+
};
|
|
147
|
+
const deviceCredentialsSlice = toolkit.createSlice({
|
|
148
|
+
name: "deviceCredentials",
|
|
149
|
+
initialState: initialState$b,
|
|
150
|
+
reducers: {},
|
|
151
|
+
extraReducers: (builder) => {
|
|
152
|
+
builder.addCase(doGetDeviceCredentials.pending, (state) => {
|
|
153
|
+
return Object.assign(Object.assign({}, state), { isFetching: true });
|
|
154
|
+
});
|
|
155
|
+
builder.addCase(doGetDeviceCredentials.fulfilled, (state, action) => {
|
|
156
|
+
return Object.assign(Object.assign({}, state), { isFetching: false, data: action.payload });
|
|
157
|
+
});
|
|
158
|
+
builder.addCase(doGetDeviceCredentials.rejected, (state) => {
|
|
159
|
+
return Object.assign(Object.assign({}, state), { isFetching: true });
|
|
160
|
+
});
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
const doGetDeviceCredentials = createAppAsyncThunk("deviceCredentials/doGetDeviceCredentials", (payload, { extra }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
164
|
+
try {
|
|
165
|
+
const deviceCredentials = yield extra.services.credentialsService.getCredentials();
|
|
166
|
+
return deviceCredentials;
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
console.error(error);
|
|
170
|
+
}
|
|
171
|
+
}));
|
|
172
|
+
const selectDeviceCredentialsRaw = (state) => state.deviceCredentials;
|
|
173
|
+
const selectHasFetchedDeviceCredentials = (state) => { var _a; return !!((_a = state.deviceCredentials.data) === null || _a === void 0 ? void 0 : _a.credentials); };
|
|
174
|
+
const selectDeviceId = (state) => { var _a, _b; return (_b = (_a = state.deviceCredentials.data) === null || _a === void 0 ? void 0 : _a.credentials) === null || _b === void 0 ? void 0 : _b.uuid; };
|
|
175
|
+
const selectShouldFetchDeviceCredentials = toolkit.createSelector(selectAppWantsToJoin, selectDeviceCredentialsRaw, (wantsToJoin, deviceCredentials) => {
|
|
176
|
+
if (wantsToJoin && !deviceCredentials.isFetching && !deviceCredentials.data) {
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
return false;
|
|
180
|
+
});
|
|
181
|
+
createReactor([selectShouldFetchDeviceCredentials], ({ dispatch }, shouldFetchDeviceCredentials) => {
|
|
182
|
+
if (shouldFetchDeviceCredentials) {
|
|
183
|
+
dispatch(doGetDeviceCredentials());
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
function forwardSocketEvents(socket, dispatch) {
|
|
188
|
+
socket.on("room_joined", (payload) => dispatch(signalEvents.roomJoined(payload)));
|
|
189
|
+
socket.on("new_client", (payload) => dispatch(signalEvents.newClient(payload)));
|
|
190
|
+
socket.on("client_left", (payload) => dispatch(signalEvents.clientLeft(payload)));
|
|
191
|
+
socket.on("client_kicked", (payload) => dispatch(signalEvents.clientKicked(payload)));
|
|
192
|
+
socket.on("audio_enabled", (payload) => dispatch(signalEvents.audioEnabled(payload)));
|
|
193
|
+
socket.on("video_enabled", (payload) => dispatch(signalEvents.videoEnabled(payload)));
|
|
194
|
+
socket.on("client_metadata_received", (payload) => dispatch(signalEvents.clientMetadataReceived(payload)));
|
|
195
|
+
socket.on("chat_message", (payload) => dispatch(signalEvents.chatMessage(payload)));
|
|
196
|
+
socket.on("disconnect", () => dispatch(signalEvents.disconnect()));
|
|
197
|
+
socket.on("room_knocked", (payload) => dispatch(signalEvents.roomKnocked(payload)));
|
|
198
|
+
socket.on("room_session_ended", (payload) => dispatch(signalEvents.roomSessionEnded(payload)));
|
|
199
|
+
socket.on("knocker_left", (payload) => dispatch(signalEvents.knockerLeft(payload)));
|
|
200
|
+
socket.on("knock_handled", (payload) => dispatch(signalEvents.knockHandled(payload)));
|
|
201
|
+
socket.on("screenshare_started", (payload) => dispatch(signalEvents.screenshareStarted(payload)));
|
|
202
|
+
socket.on("screenshare_stopped", (payload) => dispatch(signalEvents.screenshareStopped(payload)));
|
|
203
|
+
socket.on("cloud_recording_started", (payload) => dispatch(signalEvents.cloudRecordingStarted(payload)));
|
|
204
|
+
socket.on("cloud_recording_stopped", () => dispatch(signalEvents.cloudRecordingStopped()));
|
|
205
|
+
socket.on("streaming_stopped", () => dispatch(signalEvents.streamingStopped()));
|
|
206
|
+
}
|
|
207
|
+
const SIGNAL_BASE_URL = "wss://signal.appearin.net" ;
|
|
208
|
+
function createSocket() {
|
|
209
|
+
const parsedUrl = new URL(SIGNAL_BASE_URL);
|
|
210
|
+
const socketHost = parsedUrl.origin;
|
|
211
|
+
const socketOverrides = {
|
|
212
|
+
autoConnect: false,
|
|
213
|
+
};
|
|
214
|
+
return new media.ServerSocket(socketHost, socketOverrides);
|
|
215
|
+
}
|
|
216
|
+
const initialState$a = {
|
|
217
|
+
deviceIdentified: false,
|
|
218
|
+
isIdentifyingDevice: false,
|
|
219
|
+
status: "",
|
|
220
|
+
socket: null,
|
|
221
|
+
};
|
|
222
|
+
const signalConnectionSlice = toolkit.createSlice({
|
|
223
|
+
name: "signalConnection",
|
|
224
|
+
initialState: initialState$a,
|
|
225
|
+
reducers: {
|
|
226
|
+
socketConnecting: (state) => {
|
|
227
|
+
return Object.assign(Object.assign({}, state), { status: "connecting" });
|
|
228
|
+
},
|
|
229
|
+
socketConnected: (state, action) => {
|
|
230
|
+
return Object.assign(Object.assign({}, state), { socket: action.payload, status: "connected" });
|
|
231
|
+
},
|
|
232
|
+
socketDisconnected: (state) => {
|
|
233
|
+
return Object.assign(Object.assign({}, state), { status: "disconnected" });
|
|
234
|
+
},
|
|
235
|
+
socketReconnecting: (state) => {
|
|
236
|
+
return Object.assign(Object.assign({}, state), { status: "reconnect" });
|
|
237
|
+
},
|
|
238
|
+
deviceIdentifying: (state) => {
|
|
239
|
+
return Object.assign(Object.assign({}, state), { isIdentifyingDevice: true });
|
|
240
|
+
},
|
|
241
|
+
deviceIdentified: (state) => {
|
|
242
|
+
return Object.assign(Object.assign({}, state), { deviceIdentified: true, isIdentifyingDevice: false });
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
extraReducers: (builder) => {
|
|
246
|
+
builder.addCase(signalEvents.disconnect, (state) => {
|
|
247
|
+
return Object.assign(Object.assign({}, state), { status: "disconnected" });
|
|
248
|
+
});
|
|
249
|
+
},
|
|
250
|
+
});
|
|
251
|
+
const { deviceIdentifying, deviceIdentified, socketConnected, socketConnecting, socketDisconnected } = signalConnectionSlice.actions;
|
|
252
|
+
const doSignalSocketConnect = createAppThunk(() => {
|
|
253
|
+
return (dispatch, getState) => {
|
|
254
|
+
if (selectSignalConnectionSocket(getState())) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
dispatch(socketConnecting());
|
|
258
|
+
const socket = createSocket();
|
|
259
|
+
socket.on("connect", () => dispatch(socketConnected(socket)));
|
|
260
|
+
socket.on("device_identified", () => dispatch(deviceIdentified()));
|
|
261
|
+
socket.getManager().on("reconnect", () => dispatch(doSignalReconnect()));
|
|
262
|
+
forwardSocketEvents(socket, dispatch);
|
|
263
|
+
socket.connect();
|
|
264
|
+
};
|
|
265
|
+
});
|
|
266
|
+
const doSignalIdentifyDevice = createAppThunk(({ deviceCredentials }) => (dispatch, getState) => {
|
|
267
|
+
const state = getState();
|
|
268
|
+
const signalSocket = selectSignalConnectionSocket(state);
|
|
269
|
+
if (!signalSocket) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
signalSocket.emit("identify_device", { deviceCredentials });
|
|
273
|
+
dispatch(deviceIdentifying());
|
|
274
|
+
});
|
|
275
|
+
const doSignalDisconnect = createAppThunk(() => (dispatch, getState) => {
|
|
276
|
+
const socket = selectSignalConnectionRaw(getState()).socket;
|
|
277
|
+
socket === null || socket === void 0 ? void 0 : socket.emit("leave_room");
|
|
278
|
+
socket === null || socket === void 0 ? void 0 : socket.disconnect();
|
|
279
|
+
dispatch(socketDisconnected());
|
|
280
|
+
});
|
|
281
|
+
const doSignalReconnect = createAppThunk(() => (dispatch, getState) => {
|
|
282
|
+
const deviceCredentialsRaw = selectDeviceCredentialsRaw(getState());
|
|
283
|
+
dispatch(socketReconnecting());
|
|
284
|
+
if (deviceCredentialsRaw.data) {
|
|
285
|
+
dispatch(doSignalIdentifyDevice({ deviceCredentials: deviceCredentialsRaw.data }));
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
const { socketReconnecting } = signalConnectionSlice.actions;
|
|
289
|
+
const selectSignalConnectionRaw = (state) => state.signalConnection;
|
|
290
|
+
const selectSignalIsIdentifyingDevice = (state) => state.signalConnection.isIdentifyingDevice;
|
|
291
|
+
const selectSignalConnectionDeviceIdentified = (state) => state.signalConnection.deviceIdentified;
|
|
292
|
+
const selectSignalStatus = (state) => state.signalConnection.status;
|
|
293
|
+
const selectSignalConnectionSocket = (state) => state.signalConnection.socket;
|
|
294
|
+
startAppListening({
|
|
295
|
+
actionCreator: appLeft,
|
|
296
|
+
effect: (_, { dispatch }) => {
|
|
297
|
+
dispatch(doSignalDisconnect());
|
|
298
|
+
},
|
|
299
|
+
});
|
|
300
|
+
const selectShouldConnectSignal = toolkit.createSelector(selectAppWantsToJoin, selectSignalStatus, (wantsToJoin, signalStatus) => {
|
|
301
|
+
if (wantsToJoin && ["", "reconnect"].includes(signalStatus)) {
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
304
|
+
return false;
|
|
305
|
+
});
|
|
306
|
+
createReactor([selectShouldConnectSignal], ({ dispatch }, shouldConnectSignal) => {
|
|
307
|
+
if (shouldConnectSignal) {
|
|
308
|
+
dispatch(doSignalSocketConnect());
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
const selectShouldIdentifyDevice = toolkit.createSelector(selectDeviceCredentialsRaw, selectSignalStatus, selectSignalConnectionDeviceIdentified, selectSignalIsIdentifyingDevice, (deviceCredentialsRaw, signalStatus, deviceIdentified, isIdentifyingDevice) => {
|
|
312
|
+
if (deviceCredentialsRaw.data && signalStatus === "connected" && !deviceIdentified && !isIdentifyingDevice) {
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
return false;
|
|
316
|
+
});
|
|
317
|
+
createReactor([selectShouldIdentifyDevice, selectDeviceCredentialsRaw], ({ dispatch }, shouldIdentifyDevice, deviceCredentialsRaw) => {
|
|
318
|
+
if (shouldIdentifyDevice && deviceCredentialsRaw.data) {
|
|
319
|
+
dispatch(doSignalIdentifyDevice({ deviceCredentials: deviceCredentialsRaw.data }));
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
const initialState$9 = {
|
|
324
|
+
chatMessages: [],
|
|
325
|
+
};
|
|
326
|
+
const chatSlice = toolkit.createSlice({
|
|
327
|
+
name: "chat",
|
|
328
|
+
initialState: initialState$9,
|
|
329
|
+
reducers: {},
|
|
330
|
+
extraReducers(builder) {
|
|
331
|
+
builder.addCase(signalEvents.chatMessage, (state, action) => {
|
|
332
|
+
const message = {
|
|
333
|
+
senderId: action.payload.senderId,
|
|
334
|
+
timestamp: action.payload.timestamp,
|
|
335
|
+
text: action.payload.text,
|
|
336
|
+
};
|
|
337
|
+
return Object.assign(Object.assign({}, state), { chatMessages: [...state.chatMessages, message] });
|
|
338
|
+
});
|
|
339
|
+
},
|
|
340
|
+
});
|
|
341
|
+
const doSendChatMessage = createAppThunk((payload) => (_, getState) => {
|
|
342
|
+
const state = getState();
|
|
343
|
+
const socket = selectSignalConnectionRaw(state).socket;
|
|
344
|
+
socket === null || socket === void 0 ? void 0 : socket.emit("chat_message", { text: payload.text });
|
|
345
|
+
});
|
|
346
|
+
const selectChatRaw = (state) => state.chat;
|
|
347
|
+
const selectChatMessages = (state) => state.chat.chatMessages;
|
|
348
|
+
|
|
349
|
+
const initialCloudRecordingState = {
|
|
350
|
+
isRecording: false,
|
|
351
|
+
error: null,
|
|
352
|
+
startedAt: undefined,
|
|
353
|
+
};
|
|
354
|
+
const cloudRecordingSlice = toolkit.createSlice({
|
|
355
|
+
name: "cloudRecording",
|
|
356
|
+
initialState: initialCloudRecordingState,
|
|
357
|
+
reducers: {
|
|
358
|
+
recordingRequestStarted: (state) => {
|
|
359
|
+
return Object.assign(Object.assign({}, state), { status: "requested" });
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
extraReducers: (builder) => {
|
|
363
|
+
builder.addCase(signalEvents.cloudRecordingStopped, (state) => {
|
|
364
|
+
return Object.assign(Object.assign({}, state), { isRecording: false, status: undefined });
|
|
365
|
+
});
|
|
366
|
+
builder.addCase(signalEvents.cloudRecordingStarted, (state, action) => {
|
|
367
|
+
const { payload } = action;
|
|
368
|
+
if (!payload.error) {
|
|
369
|
+
return state;
|
|
370
|
+
}
|
|
371
|
+
return Object.assign(Object.assign({}, state), { isRecording: false, status: "error", error: payload.error });
|
|
372
|
+
});
|
|
373
|
+
builder.addCase(signalEvents.newClient, (state, { payload }) => {
|
|
374
|
+
var _a;
|
|
375
|
+
const { client } = payload;
|
|
376
|
+
if (((_a = client.role) === null || _a === void 0 ? void 0 : _a.roleName) === "recorder") {
|
|
377
|
+
return Object.assign(Object.assign({}, state), { isRecording: true, status: "recording", startedAt: client.startedCloudRecordingAt
|
|
378
|
+
? new Date(client.startedCloudRecordingAt).getTime()
|
|
379
|
+
: new Date().getTime() });
|
|
380
|
+
}
|
|
381
|
+
return state;
|
|
382
|
+
});
|
|
383
|
+
},
|
|
384
|
+
});
|
|
385
|
+
const { recordingRequestStarted } = cloudRecordingSlice.actions;
|
|
386
|
+
const doStartCloudRecording = createAppThunk(() => (dispatch, getState) => {
|
|
387
|
+
const state = getState();
|
|
388
|
+
const socket = selectSignalConnectionRaw(state).socket;
|
|
389
|
+
const status = selectCloudRecordingStatus(state);
|
|
390
|
+
if (status && ["recording", "requested"].includes(status)) {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
socket === null || socket === void 0 ? void 0 : socket.emit("start_recording", {
|
|
394
|
+
recording: "cloud",
|
|
395
|
+
});
|
|
396
|
+
dispatch(recordingRequestStarted());
|
|
397
|
+
});
|
|
398
|
+
const doStopCloudRecording = createAppThunk(() => (dispatch, getState) => {
|
|
399
|
+
const state = getState();
|
|
400
|
+
const socket = selectSignalConnectionRaw(state).socket;
|
|
401
|
+
socket === null || socket === void 0 ? void 0 : socket.emit("stop_recording");
|
|
402
|
+
});
|
|
403
|
+
const selectCloudRecordingRaw = (state) => state.cloudRecording;
|
|
404
|
+
const selectCloudRecordingStatus = (state) => state.cloudRecording.status;
|
|
405
|
+
const selectCloudRecordingStartedAt = (state) => state.cloudRecording.startedAt;
|
|
406
|
+
const selectCloudRecordingError = (state) => state.cloudRecording.error;
|
|
407
|
+
const selectIsCloudRecording = (state) => state.cloudRecording.isRecording;
|
|
408
|
+
|
|
409
|
+
function debounce(fn, { delay = 500, edges } = {}) {
|
|
410
|
+
let timeout;
|
|
411
|
+
let nCalls = 0;
|
|
412
|
+
return (...args) => {
|
|
413
|
+
nCalls += 1;
|
|
414
|
+
if (edges && nCalls === 1) {
|
|
415
|
+
fn(...args);
|
|
416
|
+
}
|
|
417
|
+
clearTimeout(timeout);
|
|
418
|
+
timeout = setTimeout(() => {
|
|
419
|
+
if (!edges || nCalls > 1) {
|
|
420
|
+
fn(...args);
|
|
421
|
+
}
|
|
422
|
+
timeout = undefined;
|
|
423
|
+
nCalls = 0;
|
|
424
|
+
}, delay);
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const initialLocalMediaState = {
|
|
429
|
+
busyDeviceIds: [],
|
|
430
|
+
cameraEnabled: false,
|
|
431
|
+
devices: [],
|
|
432
|
+
isSettingCameraDevice: false,
|
|
433
|
+
isSettingMicrophoneDevice: false,
|
|
434
|
+
isTogglingCamera: false,
|
|
435
|
+
microphoneEnabled: false,
|
|
436
|
+
status: "",
|
|
437
|
+
isSwitchingStream: false,
|
|
438
|
+
};
|
|
439
|
+
const localMediaSlice = toolkit.createSlice({
|
|
440
|
+
name: "localMedia",
|
|
441
|
+
initialState: initialLocalMediaState,
|
|
442
|
+
reducers: {
|
|
443
|
+
deviceBusy(state, action) {
|
|
444
|
+
if (state.busyDeviceIds.includes(action.payload.deviceId)) {
|
|
445
|
+
return state;
|
|
446
|
+
}
|
|
447
|
+
return Object.assign(Object.assign({}, state), { busyDeviceIds: [...state.busyDeviceIds, action.payload.deviceId] });
|
|
448
|
+
},
|
|
449
|
+
toggleCameraEnabled(state, action) {
|
|
450
|
+
var _a;
|
|
451
|
+
return Object.assign(Object.assign({}, state), { cameraEnabled: (_a = action.payload.enabled) !== null && _a !== void 0 ? _a : !state.cameraEnabled });
|
|
452
|
+
},
|
|
453
|
+
setCurrentCameraDeviceId(state, action) {
|
|
454
|
+
return Object.assign(Object.assign({}, state), { currentCameraDeviceId: action.payload.deviceId });
|
|
455
|
+
},
|
|
456
|
+
toggleMicrophoneEnabled(state, action) {
|
|
457
|
+
var _a;
|
|
458
|
+
return Object.assign(Object.assign({}, state), { microphoneEnabled: (_a = action.payload.enabled) !== null && _a !== void 0 ? _a : !state.microphoneEnabled });
|
|
459
|
+
},
|
|
460
|
+
setCurrentMicrophoneDeviceId(state, action) {
|
|
461
|
+
return Object.assign(Object.assign({}, state), { currentMicrophoneDeviceId: action.payload.deviceId });
|
|
462
|
+
},
|
|
463
|
+
setDevices(state, action) {
|
|
464
|
+
return Object.assign(Object.assign({}, state), { devices: action.payload.devices });
|
|
465
|
+
},
|
|
466
|
+
setLocalMediaStream(state, action) {
|
|
467
|
+
return Object.assign(Object.assign({}, state), { stream: action.payload.stream });
|
|
468
|
+
},
|
|
469
|
+
setLocalMediaOptions(state, action) {
|
|
470
|
+
return Object.assign(Object.assign({}, state), { options: action.payload.options });
|
|
471
|
+
},
|
|
472
|
+
localMediaStopped(state) {
|
|
473
|
+
return Object.assign(Object.assign({}, state), { status: "stopped", stream: undefined });
|
|
474
|
+
},
|
|
475
|
+
localStreamMetadataUpdated(state, action) {
|
|
476
|
+
const { audio, video } = action.payload;
|
|
477
|
+
return Object.assign(Object.assign({}, state), { currentCameraDeviceId: video.deviceId, currentMicrophoneDeviceId: audio.deviceId, busyDeviceIds: state.busyDeviceIds.filter((id) => id !== audio.deviceId && id !== video.deviceId) });
|
|
478
|
+
},
|
|
479
|
+
},
|
|
480
|
+
extraReducers: (builder) => {
|
|
481
|
+
builder.addCase(doAppJoin, (state, action) => {
|
|
482
|
+
return Object.assign(Object.assign({}, state), { options: action.payload.localMediaOptions });
|
|
483
|
+
});
|
|
484
|
+
builder.addCase(doSetDevice.pending, (state, action) => {
|
|
485
|
+
const { audio, video } = action.meta.arg;
|
|
486
|
+
return Object.assign(Object.assign({}, state), { isSettingCameraDevice: video, isSettingMicrophoneDevice: audio });
|
|
487
|
+
});
|
|
488
|
+
builder.addCase(doSetDevice.fulfilled, (state, action) => {
|
|
489
|
+
const { audio, video } = action.meta.arg;
|
|
490
|
+
return Object.assign(Object.assign({}, state), { isSettingCameraDevice: video ? false : state.isSettingCameraDevice, isSettingMicrophoneDevice: audio ? false : state.isSettingMicrophoneDevice });
|
|
491
|
+
});
|
|
492
|
+
builder.addCase(doSetDevice.rejected, (state, action) => {
|
|
493
|
+
const { audio, video } = action.meta.arg;
|
|
494
|
+
return Object.assign(Object.assign({}, state), { isSettingCameraDevice: video ? false : state.isSettingCameraDevice, isSettingMicrophoneDevice: audio ? false : state.isSettingMicrophoneDevice, cameraDeviceError: video ? action.error : state.cameraDeviceError, microphoneDeviceError: audio ? action.error : state.microphoneDeviceError });
|
|
495
|
+
});
|
|
496
|
+
builder.addCase(doToggleCamera.pending, (state) => {
|
|
497
|
+
return Object.assign(Object.assign({}, state), { isTogglingCamera: true });
|
|
498
|
+
});
|
|
499
|
+
builder.addCase(doToggleCamera.fulfilled, (state) => {
|
|
500
|
+
return Object.assign(Object.assign({}, state), { isTogglingCamera: false });
|
|
501
|
+
});
|
|
502
|
+
builder.addCase(doUpdateDeviceList.fulfilled, (state, action) => {
|
|
503
|
+
return Object.assign(Object.assign({}, state), { devices: action.payload.devices });
|
|
504
|
+
});
|
|
505
|
+
builder.addCase(doStartLocalMedia.pending, (state) => {
|
|
506
|
+
return Object.assign(Object.assign({}, state), { status: "starting" });
|
|
507
|
+
});
|
|
508
|
+
builder.addCase(doStartLocalMedia.fulfilled, (state, { payload: { stream, onDeviceChange } }) => {
|
|
509
|
+
let cameraDeviceId = undefined;
|
|
510
|
+
let cameraEnabled = false;
|
|
511
|
+
let microphoneDeviceId = undefined;
|
|
512
|
+
let microphoneEnabled = false;
|
|
513
|
+
const audioTrack = stream.getAudioTracks()[0];
|
|
514
|
+
const videoTrack = stream.getVideoTracks()[0];
|
|
515
|
+
if (audioTrack) {
|
|
516
|
+
microphoneDeviceId = audioTrack.getSettings().deviceId;
|
|
517
|
+
microphoneEnabled = audioTrack.enabled;
|
|
518
|
+
}
|
|
519
|
+
if (videoTrack) {
|
|
520
|
+
cameraEnabled = videoTrack.enabled;
|
|
521
|
+
cameraDeviceId = videoTrack.getSettings().deviceId;
|
|
522
|
+
}
|
|
523
|
+
return Object.assign(Object.assign({}, state), { stream, status: "started", currentCameraDeviceId: cameraDeviceId, currentMicrophoneDeviceId: microphoneDeviceId, cameraEnabled,
|
|
524
|
+
microphoneEnabled,
|
|
525
|
+
onDeviceChange });
|
|
526
|
+
});
|
|
527
|
+
builder.addCase(doStartLocalMedia.rejected, (state, action) => {
|
|
528
|
+
return Object.assign(Object.assign({}, state), { status: "error", startError: action.error });
|
|
529
|
+
});
|
|
530
|
+
builder.addCase(doSwitchLocalStream.pending, (state) => {
|
|
531
|
+
return Object.assign(Object.assign({}, state), { isSwitchingStream: true });
|
|
532
|
+
});
|
|
533
|
+
builder.addCase(doSwitchLocalStream.fulfilled, (state) => {
|
|
534
|
+
return Object.assign(Object.assign({}, state), { isSwitchingStream: false });
|
|
535
|
+
});
|
|
536
|
+
builder.addCase(doSwitchLocalStream.rejected, (state) => {
|
|
537
|
+
return Object.assign(Object.assign({}, state), { isSwitchingStream: false });
|
|
538
|
+
});
|
|
539
|
+
},
|
|
540
|
+
});
|
|
541
|
+
const { deviceBusy, setCurrentCameraDeviceId, setCurrentMicrophoneDeviceId, toggleCameraEnabled, toggleMicrophoneEnabled, setLocalMediaOptions, setLocalMediaStream, localMediaStopped, localStreamMetadataUpdated, } = localMediaSlice.actions;
|
|
542
|
+
const doToggleCamera = createAppAsyncThunk("localMedia/doToggleCamera", (_, { getState, rejectWithValue }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
543
|
+
const state = getState();
|
|
544
|
+
const stream = selectLocalMediaStream(state);
|
|
545
|
+
if (!stream) {
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
let track = stream.getVideoTracks()[0];
|
|
549
|
+
const enabled = selectIsCameraEnabled(state);
|
|
550
|
+
try {
|
|
551
|
+
if (enabled) {
|
|
552
|
+
if (track) {
|
|
553
|
+
track.enabled = true;
|
|
554
|
+
}
|
|
555
|
+
else {
|
|
556
|
+
const constraintsOptions = selectLocalMediaConstraintsOptions(state);
|
|
557
|
+
const cameraDeviceId = selectCurrentCameraDeviceId(state);
|
|
558
|
+
yield media.getStream(Object.assign(Object.assign({}, constraintsOptions), { audioId: false, videoId: cameraDeviceId, type: "exact" }), { replaceStream: stream });
|
|
559
|
+
track = stream.getVideoTracks()[0];
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
else {
|
|
563
|
+
if (!track) {
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
track.enabled = false;
|
|
567
|
+
track.stop();
|
|
568
|
+
stream.removeTrack(track);
|
|
569
|
+
}
|
|
570
|
+
stream.dispatchEvent(new CustomEvent("stopresumevideo", { detail: { track, enable: enabled } }));
|
|
571
|
+
}
|
|
572
|
+
catch (error) {
|
|
573
|
+
return rejectWithValue(error);
|
|
574
|
+
}
|
|
575
|
+
}));
|
|
576
|
+
const doToggleMicrophone = createAppAsyncThunk("localMedia/doToggleMicrophone", (_, { getState }) => {
|
|
577
|
+
var _a;
|
|
578
|
+
const state = getState();
|
|
579
|
+
const stream = selectLocalMediaStream(state);
|
|
580
|
+
if (!stream) {
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
const enabled = selectIsMicrophoneEnabled(state);
|
|
584
|
+
const audioTrack = (_a = stream.getAudioTracks()) === null || _a === void 0 ? void 0 : _a[0];
|
|
585
|
+
if (!audioTrack) {
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
audioTrack.enabled = enabled;
|
|
589
|
+
});
|
|
590
|
+
const doSetDevice = createAppAsyncThunk("localMedia/reactSetDevice", ({ audio, video }, { getState, rejectWithValue }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
591
|
+
try {
|
|
592
|
+
const state = getState();
|
|
593
|
+
const stream = selectLocalMediaStream(state);
|
|
594
|
+
if (!stream) {
|
|
595
|
+
throw new Error("No stream");
|
|
596
|
+
}
|
|
597
|
+
const audioId = audio ? selectCurrentMicrophoneDeviceId(state) : false;
|
|
598
|
+
const videoId = video ? selectCurrentCameraDeviceId(state) : false;
|
|
599
|
+
const constraintsOptions = selectLocalMediaConstraintsOptions(state);
|
|
600
|
+
const { replacedTracks } = yield media.getStream(Object.assign(Object.assign({}, constraintsOptions), { audioId,
|
|
601
|
+
videoId, type: "exact" }), { replaceStream: stream });
|
|
602
|
+
const isAudioEnabled = selectIsMicrophoneEnabled(state);
|
|
603
|
+
stream.getAudioTracks().forEach((track) => (track.enabled = isAudioEnabled));
|
|
604
|
+
const isVideoEnabled = selectIsCameraEnabled(state);
|
|
605
|
+
stream.getVideoTracks().forEach((track) => (track.enabled = isVideoEnabled));
|
|
606
|
+
return { replacedTracks };
|
|
607
|
+
}
|
|
608
|
+
catch (error) {
|
|
609
|
+
return rejectWithValue(error);
|
|
610
|
+
}
|
|
611
|
+
}));
|
|
612
|
+
const doUpdateDeviceList = createAppAsyncThunk("localMedia/doUpdateDeviceList", (_, { getState, dispatch, rejectWithValue }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
613
|
+
var _a, _b;
|
|
614
|
+
const state = getState();
|
|
615
|
+
let newDevices = [];
|
|
616
|
+
let oldDevices = [];
|
|
617
|
+
const stream = selectLocalMediaStream(state);
|
|
618
|
+
const busy = selectBusyDeviceIds(state);
|
|
619
|
+
try {
|
|
620
|
+
newDevices = yield navigator.mediaDevices.enumerateDevices();
|
|
621
|
+
oldDevices = selectLocalMediaDevices(state);
|
|
622
|
+
const shouldHandleDeviceUpdate = stream &&
|
|
623
|
+
!selectLocalMediaIsSwitchingStream(state) &&
|
|
624
|
+
newDevices &&
|
|
625
|
+
oldDevices &&
|
|
626
|
+
oldDevices.find((d) => d.deviceId);
|
|
627
|
+
if (!shouldHandleDeviceUpdate) {
|
|
628
|
+
return { devices: newDevices };
|
|
629
|
+
}
|
|
630
|
+
const { changedDevices } = media.getUpdatedDevices({
|
|
631
|
+
oldDevices,
|
|
632
|
+
newDevices,
|
|
633
|
+
currentAudioId: selectCurrentMicrophoneDeviceId(state),
|
|
634
|
+
currentVideoId: selectCurrentCameraDeviceId(state),
|
|
635
|
+
});
|
|
636
|
+
let autoSwitchAudioId = (_a = changedDevices.audioinput) === null || _a === void 0 ? void 0 : _a.deviceId;
|
|
637
|
+
let autoSwitchVideoId = (_b = changedDevices.videoinput) === null || _b === void 0 ? void 0 : _b.deviceId;
|
|
638
|
+
function nextId(devices, id) {
|
|
639
|
+
const curIdx = id ? devices.findIndex((d) => d.deviceId === id) : 0;
|
|
640
|
+
return (devices[(curIdx + 1) % devices.length] || {}).deviceId;
|
|
641
|
+
}
|
|
642
|
+
if (autoSwitchVideoId !== undefined) {
|
|
643
|
+
const videoDevices = selectLocalMediaDevices(state).filter((d) => d.kind === "videoinput");
|
|
644
|
+
const videoId = selectCurrentCameraDeviceId(state);
|
|
645
|
+
let nextVideoId = nextId(videoDevices.filter((d) => !busy.includes(d.deviceId)), videoId);
|
|
646
|
+
if (!nextVideoId || videoId === nextVideoId) {
|
|
647
|
+
nextVideoId = nextId(videoDevices, videoId);
|
|
648
|
+
}
|
|
649
|
+
if (videoId !== nextVideoId) {
|
|
650
|
+
autoSwitchVideoId = nextVideoId;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
if (autoSwitchAudioId !== undefined) {
|
|
654
|
+
const audioDevices = selectLocalMediaDevices(state).filter((d) => d.kind === "audioinput");
|
|
655
|
+
const audioId = selectCurrentMicrophoneDeviceId(state);
|
|
656
|
+
let nextAudioId = nextId(audioDevices.filter((d) => !busy.includes(d.deviceId)), audioId);
|
|
657
|
+
if (!nextAudioId || audioId === nextAudioId) {
|
|
658
|
+
nextAudioId = nextId(audioDevices, audioId);
|
|
659
|
+
}
|
|
660
|
+
if (audioId !== nextAudioId) {
|
|
661
|
+
autoSwitchAudioId = nextAudioId;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
if (autoSwitchAudioId !== undefined || autoSwitchVideoId !== undefined) {
|
|
665
|
+
dispatch(doSwitchLocalStream({ audioId: autoSwitchAudioId, videoId: autoSwitchVideoId }));
|
|
666
|
+
}
|
|
667
|
+
return { devices: newDevices };
|
|
668
|
+
}
|
|
669
|
+
catch (error) {
|
|
670
|
+
return rejectWithValue(error);
|
|
671
|
+
}
|
|
672
|
+
}));
|
|
673
|
+
const doSwitchLocalStream = createAppAsyncThunk("localMedia/doSwitchLocalStream", ({ audioId, videoId }, { dispatch, getState, rejectWithValue }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
674
|
+
const state = getState();
|
|
675
|
+
const replaceStream = selectLocalMediaStream(state);
|
|
676
|
+
const constraintsOptions = selectLocalMediaConstraintsOptions(state);
|
|
677
|
+
const onlySwitchingOne = !!(videoId && !audioId) || !!(!videoId && audioId);
|
|
678
|
+
if (!replaceStream) {
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
try {
|
|
682
|
+
const { replacedTracks } = yield media.getStream(Object.assign(Object.assign({}, constraintsOptions), { audioId: audioId === undefined ? false : audioId, videoId: videoId === undefined ? false : videoId, type: "exact" }), { replaceStream });
|
|
683
|
+
const deviceId = audioId || videoId;
|
|
684
|
+
if (onlySwitchingOne && deviceId) {
|
|
685
|
+
dispatch(deviceBusy({
|
|
686
|
+
deviceId,
|
|
687
|
+
}));
|
|
688
|
+
}
|
|
689
|
+
return { replacedTracks };
|
|
690
|
+
}
|
|
691
|
+
catch (error) {
|
|
692
|
+
console.error(error);
|
|
693
|
+
const deviceId = audioId || videoId;
|
|
694
|
+
if (onlySwitchingOne && deviceId) {
|
|
695
|
+
dispatch(deviceBusy({
|
|
696
|
+
deviceId,
|
|
697
|
+
}));
|
|
698
|
+
}
|
|
699
|
+
return rejectWithValue(error);
|
|
700
|
+
}
|
|
701
|
+
}));
|
|
702
|
+
const doStartLocalMedia = createAppAsyncThunk("localMedia/doStartLocalMedia", (payload, { getState, dispatch, rejectWithValue }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
703
|
+
const onDeviceChange = debounce(() => {
|
|
704
|
+
dispatch(doUpdateDeviceList());
|
|
705
|
+
}, { delay: 500 });
|
|
706
|
+
if (navigator.mediaDevices) {
|
|
707
|
+
navigator.mediaDevices.addEventListener("devicechange", onDeviceChange);
|
|
708
|
+
}
|
|
709
|
+
if ("getTracks" in payload) {
|
|
710
|
+
return Promise.resolve({ stream: payload, onDeviceChange });
|
|
711
|
+
}
|
|
712
|
+
if (!(payload.audio || payload.video)) {
|
|
713
|
+
return { stream: new MediaStream(), onDeviceChange };
|
|
714
|
+
}
|
|
715
|
+
else {
|
|
716
|
+
dispatch(setLocalMediaOptions({ options: payload }));
|
|
717
|
+
}
|
|
718
|
+
try {
|
|
719
|
+
yield dispatch(doUpdateDeviceList());
|
|
720
|
+
const state = getState();
|
|
721
|
+
const constraintsOptions = selectLocalMediaConstraintsOptions(state);
|
|
722
|
+
const { stream } = yield media.getStream(Object.assign(Object.assign({}, constraintsOptions), { audioId: payload.audio, videoId: payload.video }));
|
|
723
|
+
return { stream, onDeviceChange };
|
|
724
|
+
}
|
|
725
|
+
catch (error) {
|
|
726
|
+
return rejectWithValue(error);
|
|
727
|
+
}
|
|
728
|
+
}));
|
|
729
|
+
const doStopLocalMedia = createAppThunk(() => (dispatch, getState) => {
|
|
730
|
+
const stream = selectLocalMediaStream(getState());
|
|
731
|
+
const onDeviceChange = selectLocalMediaRaw(getState()).onDeviceChange;
|
|
732
|
+
stream === null || stream === void 0 ? void 0 : stream.getTracks().forEach((track) => {
|
|
733
|
+
track.stop();
|
|
734
|
+
});
|
|
735
|
+
if (navigator.mediaDevices && onDeviceChange) {
|
|
736
|
+
navigator.mediaDevices.removeEventListener("devicechange", onDeviceChange);
|
|
737
|
+
}
|
|
738
|
+
dispatch(localMediaStopped());
|
|
739
|
+
});
|
|
740
|
+
const selectBusyDeviceIds = (state) => state.localMedia.busyDeviceIds;
|
|
741
|
+
const selectCameraDeviceError = (state) => state.localMedia.cameraDeviceError;
|
|
742
|
+
const selectCurrentCameraDeviceId = (state) => state.localMedia.currentCameraDeviceId;
|
|
743
|
+
const selectCurrentMicrophoneDeviceId = (state) => state.localMedia.currentMicrophoneDeviceId;
|
|
744
|
+
const selectIsCameraEnabled = (state) => state.localMedia.cameraEnabled;
|
|
745
|
+
const selectIsMicrophoneEnabled = (state) => state.localMedia.microphoneEnabled;
|
|
746
|
+
const selectIsSettingCameraDevice = (state) => state.localMedia.isSettingCameraDevice;
|
|
747
|
+
const selectIsSettingMicrophoneDevice = (state) => state.localMedia.isSettingMicrophoneDevice;
|
|
748
|
+
const selectIsToggleCamera = (state) => state.localMedia.isTogglingCamera;
|
|
749
|
+
const selectLocalMediaDevices = (state) => state.localMedia.devices;
|
|
750
|
+
const selectLocalMediaOptions = (state) => state.localMedia.options;
|
|
751
|
+
const selectLocalMediaOwnsStream = toolkit.createSelector(selectLocalMediaOptions, (options) => !!options);
|
|
752
|
+
const selectLocalMediaRaw = (state) => state.localMedia;
|
|
753
|
+
const selectLocalMediaStatus = (state) => state.localMedia.status;
|
|
754
|
+
const selectLocalMediaStream = (state) => state.localMedia.stream;
|
|
755
|
+
const selectMicrophoneDeviceError = (state) => state.localMedia.microphoneDeviceError;
|
|
756
|
+
const selectLocalMediaStartError = (state) => state.localMedia.startError;
|
|
757
|
+
const selectLocalMediaIsSwitchingStream = (state) => state.localMedia.isSwitchingStream;
|
|
758
|
+
const selectLocalMediaConstraintsOptions = toolkit.createSelector(selectLocalMediaDevices, (devices) => ({
|
|
759
|
+
devices,
|
|
760
|
+
options: {
|
|
761
|
+
disableAEC: false,
|
|
762
|
+
disableAGC: false,
|
|
763
|
+
hd: true,
|
|
764
|
+
lax: false,
|
|
765
|
+
lowDataMode: false,
|
|
766
|
+
simulcast: true,
|
|
767
|
+
widescreen: true,
|
|
768
|
+
},
|
|
769
|
+
}));
|
|
770
|
+
const selectIsLocalMediaStarting = toolkit.createSelector(selectLocalMediaStatus, (status) => status === "starting");
|
|
771
|
+
const selectCameraDevices = toolkit.createSelector(selectLocalMediaDevices, selectBusyDeviceIds, (devices, busyDeviceIds) => devices.filter((d) => d.kind === "videoinput").filter((d) => !busyDeviceIds.includes(d.deviceId)));
|
|
772
|
+
const selectMicrophoneDevices = toolkit.createSelector(selectLocalMediaDevices, selectBusyDeviceIds, (devices, busyDeviceIds) => devices.filter((d) => d.kind === "audioinput").filter((d) => !busyDeviceIds.includes(d.deviceId)));
|
|
773
|
+
const selectSpeakerDevices = toolkit.createSelector(selectLocalMediaDevices, (devices) => devices.filter((d) => d.kind === "audiooutput"));
|
|
774
|
+
const selectLocalMediaShouldStartWithOptions = toolkit.createSelector(selectAppWantsToJoin, selectLocalMediaStatus, selectLocalMediaOptions, selectAppIsNodeSdk, (appWantsToJoin, localMediaStatus, localMediaOptions, isNodeSdk) => {
|
|
775
|
+
if (appWantsToJoin && localMediaStatus === "" && !isNodeSdk && localMediaOptions) {
|
|
776
|
+
return localMediaOptions;
|
|
777
|
+
}
|
|
778
|
+
});
|
|
779
|
+
createReactor([selectLocalMediaShouldStartWithOptions], ({ dispatch }, options) => {
|
|
780
|
+
if (options) {
|
|
781
|
+
dispatch(doStartLocalMedia(options));
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
const selectLocalMediaShouldStop = toolkit.createSelector(selectAppWantsToJoin, selectLocalMediaStatus, selectLocalMediaOptions, (appWantsToJoin, localMediaStatus, localMediaOptions) => {
|
|
785
|
+
return !appWantsToJoin && localMediaStatus !== "" && !!localMediaOptions;
|
|
786
|
+
});
|
|
787
|
+
createReactor([selectLocalMediaShouldStop], ({ dispatch }, localMediaShouldStop) => {
|
|
788
|
+
if (localMediaShouldStop) {
|
|
789
|
+
dispatch(doStopLocalMedia());
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
startAppListening({
|
|
793
|
+
predicate: (_action, currentState, previousState) => {
|
|
794
|
+
const oldValue = selectIsMicrophoneEnabled(previousState);
|
|
795
|
+
const newValue = selectIsMicrophoneEnabled(currentState);
|
|
796
|
+
const isReady = selectLocalMediaStatus(previousState) === "started";
|
|
797
|
+
return isReady && oldValue !== newValue;
|
|
798
|
+
},
|
|
799
|
+
effect: (_, { dispatch }) => {
|
|
800
|
+
dispatch(doToggleMicrophone());
|
|
801
|
+
},
|
|
802
|
+
});
|
|
803
|
+
startAppListening({
|
|
804
|
+
predicate: (_action, currentState, previousState) => {
|
|
805
|
+
const isToggling = selectIsToggleCamera(currentState);
|
|
806
|
+
if (isToggling) {
|
|
807
|
+
return false;
|
|
808
|
+
}
|
|
809
|
+
const oldValue = selectIsCameraEnabled(previousState);
|
|
810
|
+
const newValue = selectIsCameraEnabled(currentState);
|
|
811
|
+
const isReady = selectLocalMediaStatus(previousState) === "started";
|
|
812
|
+
return isReady && oldValue !== newValue;
|
|
813
|
+
},
|
|
814
|
+
effect: (_action, { dispatch }) => {
|
|
815
|
+
dispatch(doToggleCamera());
|
|
816
|
+
},
|
|
817
|
+
});
|
|
818
|
+
startAppListening({
|
|
819
|
+
predicate: (_action, currentState, previousState) => {
|
|
820
|
+
const oldValue = selectCurrentCameraDeviceId(previousState);
|
|
821
|
+
const newValue = selectCurrentCameraDeviceId(currentState);
|
|
822
|
+
const isReady = selectLocalMediaStatus(previousState) === "started";
|
|
823
|
+
return isReady && oldValue !== newValue;
|
|
824
|
+
},
|
|
825
|
+
effect: (_action, { dispatch }) => {
|
|
826
|
+
dispatch(doSetDevice({ audio: false, video: true }));
|
|
827
|
+
},
|
|
828
|
+
});
|
|
829
|
+
startAppListening({
|
|
830
|
+
predicate: (_action, currentState, previousState) => {
|
|
831
|
+
const oldValue = selectCurrentMicrophoneDeviceId(previousState);
|
|
832
|
+
const newValue = selectCurrentMicrophoneDeviceId(currentState);
|
|
833
|
+
const isReady = selectLocalMediaStatus(previousState) === "started";
|
|
834
|
+
return isReady && oldValue !== newValue;
|
|
835
|
+
},
|
|
836
|
+
effect: (_action, { dispatch }) => {
|
|
837
|
+
dispatch(doSetDevice({ audio: true, video: false }));
|
|
838
|
+
},
|
|
839
|
+
});
|
|
840
|
+
startAppListening({
|
|
841
|
+
matcher: toolkit.isAnyOf(doStartLocalMedia.fulfilled, doUpdateDeviceList.fulfilled, doSwitchLocalStream.fulfilled, doSwitchLocalStream.rejected),
|
|
842
|
+
effect: (_action, { dispatch, getState }) => {
|
|
843
|
+
const state = getState();
|
|
844
|
+
const stream = selectLocalMediaStream(state);
|
|
845
|
+
const devices = selectLocalMediaDevices(state);
|
|
846
|
+
if (!stream)
|
|
847
|
+
return;
|
|
848
|
+
const deviceData = media.getDeviceData({
|
|
849
|
+
audioTrack: stream.getAudioTracks()[0],
|
|
850
|
+
videoTrack: stream.getVideoTracks()[0],
|
|
851
|
+
devices,
|
|
852
|
+
});
|
|
853
|
+
dispatch(localStreamMetadataUpdated(deviceData));
|
|
854
|
+
},
|
|
855
|
+
});
|
|
856
|
+
|
|
857
|
+
const initialState$8 = {
|
|
858
|
+
displayName: "",
|
|
859
|
+
id: "",
|
|
860
|
+
isAudioEnabled: true,
|
|
861
|
+
isVideoEnabled: true,
|
|
862
|
+
isLocalParticipant: true,
|
|
863
|
+
stream: undefined,
|
|
864
|
+
isScreenSharing: false,
|
|
865
|
+
roleName: "",
|
|
866
|
+
clientClaim: undefined,
|
|
867
|
+
};
|
|
868
|
+
const doEnableAudio = createAppAsyncThunk("localParticipant/doEnableAudio", (payload, { getState }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
869
|
+
const state = getState();
|
|
870
|
+
const socket = selectSignalConnectionRaw(state).socket;
|
|
871
|
+
socket === null || socket === void 0 ? void 0 : socket.emit("enable_audio", { enabled: payload.enabled });
|
|
872
|
+
return payload.enabled;
|
|
873
|
+
}));
|
|
874
|
+
const doEnableVideo = createAppAsyncThunk("localParticipant/doEnableVideo", (payload, { getState }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
875
|
+
const state = getState();
|
|
876
|
+
const socket = selectSignalConnectionRaw(state).socket;
|
|
877
|
+
socket === null || socket === void 0 ? void 0 : socket.emit("enable_video", { enabled: payload.enabled });
|
|
878
|
+
return payload.enabled;
|
|
879
|
+
}));
|
|
880
|
+
const doSetDisplayName = createAppAsyncThunk("localParticipant/doSetDisplayName", (payload, { getState }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
881
|
+
const state = getState();
|
|
882
|
+
const socket = selectSignalConnectionRaw(state).socket;
|
|
883
|
+
socket === null || socket === void 0 ? void 0 : socket.emit("send_client_metadata", {
|
|
884
|
+
type: "UserData",
|
|
885
|
+
payload,
|
|
886
|
+
});
|
|
887
|
+
return payload.displayName;
|
|
888
|
+
}));
|
|
889
|
+
const localParticipantSlice = toolkit.createSlice({
|
|
890
|
+
name: "localParticipant",
|
|
891
|
+
initialState: initialState$8,
|
|
892
|
+
reducers: {
|
|
893
|
+
doSetLocalParticipant: (state, action) => {
|
|
894
|
+
return Object.assign(Object.assign({}, state), action.payload);
|
|
895
|
+
},
|
|
896
|
+
},
|
|
897
|
+
extraReducers: (builder) => {
|
|
898
|
+
builder.addCase(doAppJoin, (state, action) => {
|
|
899
|
+
return Object.assign(Object.assign({}, state), { displayName: action.payload.displayName });
|
|
900
|
+
});
|
|
901
|
+
builder.addCase(doEnableAudio.fulfilled, (state, action) => {
|
|
902
|
+
return Object.assign(Object.assign({}, state), { isAudioEnabled: action.payload });
|
|
903
|
+
});
|
|
904
|
+
builder.addCase(doEnableVideo.fulfilled, (state, action) => {
|
|
905
|
+
return Object.assign(Object.assign({}, state), { isVideoEnabled: action.payload });
|
|
906
|
+
});
|
|
907
|
+
builder.addCase(doSetDisplayName.fulfilled, (state, action) => {
|
|
908
|
+
return Object.assign(Object.assign({}, state), { displayName: action.payload });
|
|
909
|
+
});
|
|
910
|
+
builder.addCase(signalEvents.roomJoined, (state, action) => {
|
|
911
|
+
var _a, _b;
|
|
912
|
+
const client = (_b = (_a = action.payload) === null || _a === void 0 ? void 0 : _a.room) === null || _b === void 0 ? void 0 : _b.clients.find((c) => { var _a; return c.id === ((_a = action.payload) === null || _a === void 0 ? void 0 : _a.selfId); });
|
|
913
|
+
return Object.assign(Object.assign({}, state), { id: action.payload.selfId, clientClaim: action.payload.clientClaim, roleName: (client === null || client === void 0 ? void 0 : client.role.roleName) || "" });
|
|
914
|
+
});
|
|
915
|
+
},
|
|
916
|
+
});
|
|
917
|
+
const { doSetLocalParticipant } = localParticipantSlice.actions;
|
|
918
|
+
const selectLocalParticipantRaw = (state) => state.localParticipant;
|
|
919
|
+
const selectSelfId = (state) => state.localParticipant.id;
|
|
920
|
+
const selectLocalParticipantClientClaim = (state) => state.localParticipant.clientClaim;
|
|
921
|
+
const selectLocalParticipantRole = (state) => state.localParticipant.roleName;
|
|
922
|
+
const selectLocalParticipantIsScreenSharing = (state) => state.localParticipant.isScreenSharing;
|
|
923
|
+
startAppListening({
|
|
924
|
+
actionCreator: toggleCameraEnabled,
|
|
925
|
+
effect: ({ payload }, { dispatch, getState }) => {
|
|
926
|
+
const { enabled } = payload;
|
|
927
|
+
const { isVideoEnabled } = selectLocalParticipantRaw(getState());
|
|
928
|
+
dispatch(doEnableVideo({ enabled: enabled || !isVideoEnabled }));
|
|
929
|
+
},
|
|
930
|
+
});
|
|
931
|
+
startAppListening({
|
|
932
|
+
actionCreator: toggleMicrophoneEnabled,
|
|
933
|
+
effect: ({ payload }, { dispatch, getState }) => {
|
|
934
|
+
const { enabled } = payload;
|
|
935
|
+
const { isAudioEnabled } = selectLocalParticipantRaw(getState());
|
|
936
|
+
dispatch(doEnableAudio({ enabled: enabled || !isAudioEnabled }));
|
|
937
|
+
},
|
|
938
|
+
});
|
|
939
|
+
|
|
940
|
+
const initialState$7 = {
|
|
941
|
+
status: "",
|
|
942
|
+
stream: null,
|
|
943
|
+
error: null,
|
|
944
|
+
};
|
|
945
|
+
const localScreenshareSlice = toolkit.createSlice({
|
|
946
|
+
name: "localScreenshare",
|
|
947
|
+
initialState: initialState$7,
|
|
948
|
+
reducers: {
|
|
949
|
+
stopScreenshare(state, action) {
|
|
950
|
+
return Object.assign(Object.assign({}, state), { status: "", stream: null });
|
|
951
|
+
},
|
|
952
|
+
},
|
|
953
|
+
extraReducers: (builder) => {
|
|
954
|
+
builder.addCase(doStartScreenshare.pending, (state) => {
|
|
955
|
+
return Object.assign(Object.assign({}, state), { status: "starting" });
|
|
956
|
+
});
|
|
957
|
+
builder.addCase(doStartScreenshare.fulfilled, (state, { payload: { stream } }) => {
|
|
958
|
+
return Object.assign(Object.assign({}, state), { status: "active", stream });
|
|
959
|
+
});
|
|
960
|
+
builder.addCase(doStartScreenshare.rejected, (state, { payload }) => {
|
|
961
|
+
return Object.assign(Object.assign({}, state), { error: payload, status: "", stream: null });
|
|
962
|
+
});
|
|
963
|
+
},
|
|
964
|
+
});
|
|
965
|
+
const { stopScreenshare } = localScreenshareSlice.actions;
|
|
966
|
+
const doStartScreenshare = createAppAsyncThunk("localScreenshare/doStartScreenshare", (_, { dispatch, getState, rejectWithValue }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
967
|
+
var _a;
|
|
968
|
+
try {
|
|
969
|
+
const state = getState();
|
|
970
|
+
const screenshareStream = selectLocalScreenshareStream(state);
|
|
971
|
+
if (screenshareStream) {
|
|
972
|
+
return { stream: screenshareStream };
|
|
973
|
+
}
|
|
974
|
+
const stream = yield navigator.mediaDevices.getDisplayMedia();
|
|
975
|
+
const onEnded = () => {
|
|
976
|
+
dispatch(doStopScreenshare());
|
|
977
|
+
};
|
|
978
|
+
if ("oninactive" in stream) {
|
|
979
|
+
stream.addEventListener("inactive", onEnded);
|
|
980
|
+
}
|
|
981
|
+
else {
|
|
982
|
+
(_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.addEventListener("ended", onEnded);
|
|
983
|
+
}
|
|
984
|
+
return { stream };
|
|
985
|
+
}
|
|
986
|
+
catch (error) {
|
|
987
|
+
return rejectWithValue(error);
|
|
988
|
+
}
|
|
989
|
+
}));
|
|
990
|
+
const doStopScreenshare = createAppThunk(() => (dispatch, getState) => {
|
|
991
|
+
const state = getState();
|
|
992
|
+
const screenshareStream = selectLocalScreenshareStream(state);
|
|
993
|
+
if (!screenshareStream) {
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
screenshareStream.getTracks().forEach((track) => track.stop());
|
|
997
|
+
dispatch(stopScreenshare({ stream: screenshareStream }));
|
|
998
|
+
});
|
|
999
|
+
const selectLocalScreenshareRaw = (state) => state.localScreenshare;
|
|
1000
|
+
const selectLocalScreenshareStatus = (state) => state.localScreenshare.status;
|
|
1001
|
+
const selectLocalScreenshareStream = (state) => state.localScreenshare.stream;
|
|
1002
|
+
startAppListening({
|
|
1003
|
+
actionCreator: localMediaStopped,
|
|
1004
|
+
effect: (_, { getState }) => {
|
|
1005
|
+
const state = getState();
|
|
1006
|
+
const screenshareStream = selectLocalScreenshareStream(state);
|
|
1007
|
+
if (!screenshareStream) {
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
1010
|
+
screenshareStream === null || screenshareStream === void 0 ? void 0 : screenshareStream.getTracks().forEach((track) => {
|
|
1011
|
+
track.stop();
|
|
1012
|
+
});
|
|
1013
|
+
},
|
|
1014
|
+
});
|
|
1015
|
+
|
|
1016
|
+
const initialState$6 = {
|
|
1017
|
+
data: null,
|
|
1018
|
+
isFetching: false,
|
|
1019
|
+
error: null,
|
|
1020
|
+
};
|
|
1021
|
+
const organizationSlice = toolkit.createSlice({
|
|
1022
|
+
initialState: initialState$6,
|
|
1023
|
+
name: "organization",
|
|
1024
|
+
reducers: {},
|
|
1025
|
+
extraReducers: (builder) => {
|
|
1026
|
+
builder.addCase(doOrganizationFetch.pending, (state) => {
|
|
1027
|
+
return Object.assign(Object.assign({}, state), { isFetching: true });
|
|
1028
|
+
});
|
|
1029
|
+
builder.addCase(doOrganizationFetch.fulfilled, (state, action) => {
|
|
1030
|
+
if (!action.payload)
|
|
1031
|
+
return Object.assign(Object.assign({}, state), { isFetching: true });
|
|
1032
|
+
return Object.assign(Object.assign({}, state), { isFetching: false, data: action.payload });
|
|
1033
|
+
});
|
|
1034
|
+
builder.addCase(doOrganizationFetch.rejected, (state) => {
|
|
1035
|
+
return Object.assign(Object.assign({}, state), { isFetching: false, error: true });
|
|
1036
|
+
});
|
|
1037
|
+
},
|
|
1038
|
+
});
|
|
1039
|
+
const doOrganizationFetch = createAppAsyncThunk("organization/doOrganizationFetch", (_, { extra, getState }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1040
|
+
try {
|
|
1041
|
+
const roomUrl = selectAppRoomUrl(getState());
|
|
1042
|
+
const organization = yield extra.services.fetchOrganizationFromRoomUrl(roomUrl || "");
|
|
1043
|
+
if (!organization) {
|
|
1044
|
+
throw new Error("Invalid room url");
|
|
1045
|
+
}
|
|
1046
|
+
return organization;
|
|
1047
|
+
}
|
|
1048
|
+
catch (error) {
|
|
1049
|
+
console.error(error);
|
|
1050
|
+
}
|
|
1051
|
+
}));
|
|
1052
|
+
const selectOrganizationRaw = (state) => state.organization;
|
|
1053
|
+
const selectOrganizationId = (state) => { var _a; return (_a = state.organization.data) === null || _a === void 0 ? void 0 : _a.organizationId; };
|
|
1054
|
+
const selectShouldFetchOrganization = toolkit.createSelector(selectAppWantsToJoin, selectOrganizationRaw, selectDeviceCredentialsRaw, (wantsToJoin, organization, deviceCredentials) => {
|
|
1055
|
+
if (wantsToJoin &&
|
|
1056
|
+
!organization.data &&
|
|
1057
|
+
!organization.isFetching &&
|
|
1058
|
+
!organization.error &&
|
|
1059
|
+
!deviceCredentials.isFetching) {
|
|
1060
|
+
return true;
|
|
1061
|
+
}
|
|
1062
|
+
return false;
|
|
1063
|
+
});
|
|
1064
|
+
createReactor([selectShouldFetchOrganization], ({ dispatch }, shouldFetchOrganization) => {
|
|
1065
|
+
if (shouldFetchOrganization) {
|
|
1066
|
+
dispatch(doOrganizationFetch());
|
|
1067
|
+
}
|
|
1068
|
+
});
|
|
1069
|
+
|
|
1070
|
+
function createRtcEventAction(name) {
|
|
1071
|
+
return toolkit.createAction(`rtcConnection/event/${name}`);
|
|
1072
|
+
}
|
|
1073
|
+
const rtcEvents = {
|
|
1074
|
+
rtcManagerCreated: createRtcEventAction("rtcManagerCreated"),
|
|
1075
|
+
rtcManagerDestroyed: createRtcEventAction("rtcManagerDestroyed"),
|
|
1076
|
+
streamAdded: createRtcEventAction("streamAdded"),
|
|
1077
|
+
};
|
|
1078
|
+
|
|
1079
|
+
const NON_PERSON_ROLES = ["recorder", "streamer"];
|
|
1080
|
+
function createParticipant(client, newJoiner = false) {
|
|
1081
|
+
const { streams } = client, rest = __rest(client, ["streams"]);
|
|
1082
|
+
return Object.assign(Object.assign({}, rest), { stream: null, streams: streams.map((streamId) => ({ id: streamId, state: newJoiner ? "new_accept" : "to_accept" })), isLocalParticipant: false, presentationStream: null, newJoiner });
|
|
1083
|
+
}
|
|
1084
|
+
function findParticipant(state, participantId) {
|
|
1085
|
+
const index = state.remoteParticipants.findIndex((c) => c.id === participantId);
|
|
1086
|
+
return { index, participant: state.remoteParticipants[index] };
|
|
1087
|
+
}
|
|
1088
|
+
function updateParticipant(state, participantId, updates) {
|
|
1089
|
+
const { participant, index } = findParticipant(state, participantId);
|
|
1090
|
+
if (!participant) {
|
|
1091
|
+
console.error(`Did not find client for update ${participantId}`);
|
|
1092
|
+
return state;
|
|
1093
|
+
}
|
|
1094
|
+
return Object.assign(Object.assign({}, state), { remoteParticipants: [
|
|
1095
|
+
...state.remoteParticipants.slice(0, index),
|
|
1096
|
+
Object.assign(Object.assign({}, participant), updates),
|
|
1097
|
+
...state.remoteParticipants.slice(index + 1),
|
|
1098
|
+
] });
|
|
1099
|
+
}
|
|
1100
|
+
function addParticipant(state, participant) {
|
|
1101
|
+
const { participant: foundParticipant } = findParticipant(state, participant.id);
|
|
1102
|
+
if (foundParticipant) {
|
|
1103
|
+
console.warn(`Client already existing ${participant.id}. Ignoring`);
|
|
1104
|
+
return state;
|
|
1105
|
+
}
|
|
1106
|
+
return Object.assign(Object.assign({}, state), { remoteParticipants: [...state.remoteParticipants, participant] });
|
|
1107
|
+
}
|
|
1108
|
+
function updateStreamState(state, participantId, streamId, state_) {
|
|
1109
|
+
const { participant } = findParticipant(state, participantId);
|
|
1110
|
+
if (!participant) {
|
|
1111
|
+
console.error(`No client ${participantId} found to update stream ${streamId} ${state_}`);
|
|
1112
|
+
return state;
|
|
1113
|
+
}
|
|
1114
|
+
const idIdx = participant.streams.findIndex((s) => s.id === streamId);
|
|
1115
|
+
const streams = [...participant.streams];
|
|
1116
|
+
streams[idIdx] = Object.assign(Object.assign({}, streams[idIdx]), { state: state_ });
|
|
1117
|
+
return updateParticipant(state, participantId, { streams });
|
|
1118
|
+
}
|
|
1119
|
+
function removeClient(state, participantId) {
|
|
1120
|
+
return Object.assign(Object.assign({}, state), { remoteParticipants: state.remoteParticipants.filter((c) => c.id !== participantId) });
|
|
1121
|
+
}
|
|
1122
|
+
function addStreamId(state, participantId, streamId) {
|
|
1123
|
+
const { participant } = findParticipant(state, participantId);
|
|
1124
|
+
if (!participant || participant.streams.find((s) => s.id === streamId)) {
|
|
1125
|
+
console.warn(`No participant ${participantId} or stream ${streamId} already exists`);
|
|
1126
|
+
return state;
|
|
1127
|
+
}
|
|
1128
|
+
return updateParticipant(state, participantId, {
|
|
1129
|
+
streams: [...participant.streams, { id: streamId, state: "to_accept" }],
|
|
1130
|
+
});
|
|
1131
|
+
}
|
|
1132
|
+
function removeStreamId(state, participantId, streamId) {
|
|
1133
|
+
var _a, _b;
|
|
1134
|
+
const { participant } = findParticipant(state, participantId);
|
|
1135
|
+
if (!participant) {
|
|
1136
|
+
console.error(`No participant ${participantId} found to remove stream ${streamId}`);
|
|
1137
|
+
return state;
|
|
1138
|
+
}
|
|
1139
|
+
const currentStreamId = participant.stream && participant.stream.id;
|
|
1140
|
+
const presentationId = ((_a = participant.presentationStream) === null || _a === void 0 ? void 0 : _a.inboundId) || ((_b = participant.presentationStream) === null || _b === void 0 ? void 0 : _b.id);
|
|
1141
|
+
const idIdx = participant.streams.findIndex((s) => s.id === streamId);
|
|
1142
|
+
return updateParticipant(state, participantId, Object.assign(Object.assign({ streams: participant.streams.filter((_, i) => i !== idIdx) }, (currentStreamId === streamId && { stream: null })), (presentationId === streamId && { presentationStream: null })));
|
|
1143
|
+
}
|
|
1144
|
+
function addStream(state, payload) {
|
|
1145
|
+
const { clientId, stream, streamType } = payload;
|
|
1146
|
+
let { streamId } = payload;
|
|
1147
|
+
const { participant } = findParticipant(state, clientId);
|
|
1148
|
+
if (!participant) {
|
|
1149
|
+
console.error(`Did not find client ${clientId} for adding stream`);
|
|
1150
|
+
return state;
|
|
1151
|
+
}
|
|
1152
|
+
const remoteParticipants = state.remoteParticipants;
|
|
1153
|
+
if (!streamId) {
|
|
1154
|
+
streamId = stream.id;
|
|
1155
|
+
}
|
|
1156
|
+
const remoteParticipant = remoteParticipants.find((p) => p.id === clientId);
|
|
1157
|
+
if (!remoteParticipant) {
|
|
1158
|
+
return state;
|
|
1159
|
+
}
|
|
1160
|
+
const remoteParticipantStream = remoteParticipant.streams.find((s) => s.id === streamId);
|
|
1161
|
+
if ((remoteParticipant.stream &&
|
|
1162
|
+
(remoteParticipant.stream.id === streamId || remoteParticipant.stream.inboundId === streamId)) ||
|
|
1163
|
+
(!remoteParticipant.stream && streamType === "webcam") ||
|
|
1164
|
+
(!remoteParticipant.stream && !streamType && !remoteParticipantStream)) {
|
|
1165
|
+
return updateParticipant(state, clientId, { stream });
|
|
1166
|
+
}
|
|
1167
|
+
return updateParticipant(state, clientId, {
|
|
1168
|
+
presentationStream: stream,
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
1171
|
+
const initialState$5 = {
|
|
1172
|
+
remoteParticipants: [],
|
|
1173
|
+
};
|
|
1174
|
+
const remoteParticipantsSlice = toolkit.createSlice({
|
|
1175
|
+
name: "remoteParticipants",
|
|
1176
|
+
initialState: initialState$5,
|
|
1177
|
+
reducers: {
|
|
1178
|
+
streamStatusUpdated: (state, action) => {
|
|
1179
|
+
let newState = state;
|
|
1180
|
+
for (const { clientId, streamId, state } of action.payload) {
|
|
1181
|
+
newState = updateStreamState(newState, clientId, streamId, state);
|
|
1182
|
+
}
|
|
1183
|
+
return newState;
|
|
1184
|
+
},
|
|
1185
|
+
participantStreamAdded: (state, action) => {
|
|
1186
|
+
const { clientId, stream } = action.payload;
|
|
1187
|
+
return updateParticipant(state, clientId, {
|
|
1188
|
+
stream,
|
|
1189
|
+
});
|
|
1190
|
+
},
|
|
1191
|
+
participantStreamIdAdded: (state, action) => {
|
|
1192
|
+
const { clientId, streamId } = action.payload;
|
|
1193
|
+
return addStreamId(state, clientId, streamId);
|
|
1194
|
+
},
|
|
1195
|
+
},
|
|
1196
|
+
extraReducers: (builder) => {
|
|
1197
|
+
builder.addCase(signalEvents.roomJoined, (state, action) => {
|
|
1198
|
+
var _a;
|
|
1199
|
+
if (!((_a = action.payload) === null || _a === void 0 ? void 0 : _a.room))
|
|
1200
|
+
return state;
|
|
1201
|
+
const selfId = action.payload.selfId;
|
|
1202
|
+
const { clients } = action.payload.room;
|
|
1203
|
+
return Object.assign(Object.assign({}, state), { remoteParticipants: clients
|
|
1204
|
+
.filter((c) => c.id !== selfId)
|
|
1205
|
+
.filter((c) => !NON_PERSON_ROLES.includes(c.role.roleName))
|
|
1206
|
+
.map((c) => createParticipant(c)) });
|
|
1207
|
+
});
|
|
1208
|
+
builder.addCase(rtcEvents.streamAdded, (state, action) => {
|
|
1209
|
+
return addStream(state, action.payload);
|
|
1210
|
+
});
|
|
1211
|
+
builder.addCase(signalEvents.newClient, (state, action) => {
|
|
1212
|
+
const { client } = action.payload;
|
|
1213
|
+
if (NON_PERSON_ROLES.includes(client.role.roleName)) {
|
|
1214
|
+
return state;
|
|
1215
|
+
}
|
|
1216
|
+
return addParticipant(state, createParticipant(client, true));
|
|
1217
|
+
});
|
|
1218
|
+
builder.addCase(signalEvents.clientLeft, (state, action) => {
|
|
1219
|
+
const { clientId } = action.payload;
|
|
1220
|
+
return removeClient(state, clientId);
|
|
1221
|
+
});
|
|
1222
|
+
builder.addCase(signalEvents.audioEnabled, (state, action) => {
|
|
1223
|
+
const { clientId, isAudioEnabled } = action.payload;
|
|
1224
|
+
return updateParticipant(state, clientId, {
|
|
1225
|
+
isAudioEnabled,
|
|
1226
|
+
});
|
|
1227
|
+
});
|
|
1228
|
+
builder.addCase(signalEvents.videoEnabled, (state, action) => {
|
|
1229
|
+
const { clientId, isVideoEnabled } = action.payload;
|
|
1230
|
+
return updateParticipant(state, clientId, {
|
|
1231
|
+
isVideoEnabled,
|
|
1232
|
+
});
|
|
1233
|
+
});
|
|
1234
|
+
builder.addCase(signalEvents.clientMetadataReceived, (state, action) => {
|
|
1235
|
+
const { clientId, displayName } = action.payload.payload;
|
|
1236
|
+
return updateParticipant(state, clientId, {
|
|
1237
|
+
displayName,
|
|
1238
|
+
});
|
|
1239
|
+
});
|
|
1240
|
+
builder.addCase(signalEvents.screenshareStarted, (state, action) => {
|
|
1241
|
+
const { clientId, streamId } = action.payload;
|
|
1242
|
+
return addStreamId(state, clientId, streamId);
|
|
1243
|
+
});
|
|
1244
|
+
builder.addCase(signalEvents.screenshareStopped, (state, action) => {
|
|
1245
|
+
const { clientId, streamId } = action.payload;
|
|
1246
|
+
return removeStreamId(state, clientId, streamId);
|
|
1247
|
+
});
|
|
1248
|
+
},
|
|
1249
|
+
});
|
|
1250
|
+
const { participantStreamAdded, participantStreamIdAdded, streamStatusUpdated } = remoteParticipantsSlice.actions;
|
|
1251
|
+
const selectRemoteParticipantsRaw = (state) => state.remoteParticipants;
|
|
1252
|
+
const selectRemoteParticipants = (state) => state.remoteParticipants.remoteParticipants;
|
|
1253
|
+
const selectScreenshares = toolkit.createSelector(selectLocalScreenshareStream, selectRemoteParticipants, (localScreenshareStream, remoteParticipants) => {
|
|
1254
|
+
const screenshares = [];
|
|
1255
|
+
if (localScreenshareStream) {
|
|
1256
|
+
screenshares.push({
|
|
1257
|
+
id: localScreenshareStream.id,
|
|
1258
|
+
participantId: "local",
|
|
1259
|
+
hasAudioTrack: localScreenshareStream.getAudioTracks().length > 0,
|
|
1260
|
+
stream: localScreenshareStream,
|
|
1261
|
+
isLocal: true,
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
for (const participant of remoteParticipants) {
|
|
1265
|
+
if (participant.presentationStream) {
|
|
1266
|
+
screenshares.push({
|
|
1267
|
+
id: participant.presentationStream.id,
|
|
1268
|
+
participantId: participant.id,
|
|
1269
|
+
hasAudioTrack: participant.presentationStream.getAudioTracks().length > 0,
|
|
1270
|
+
stream: participant.presentationStream,
|
|
1271
|
+
isLocal: false,
|
|
1272
|
+
});
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
return screenshares;
|
|
1276
|
+
});
|
|
1277
|
+
|
|
1278
|
+
const initialState$4 = {
|
|
1279
|
+
session: null,
|
|
1280
|
+
status: "initializing",
|
|
1281
|
+
error: null,
|
|
1282
|
+
};
|
|
1283
|
+
const roomConnectionSlice = toolkit.createSlice({
|
|
1284
|
+
initialState: initialState$4,
|
|
1285
|
+
name: "roomConnection",
|
|
1286
|
+
reducers: {
|
|
1287
|
+
connectionStatusChanged: (state, action) => {
|
|
1288
|
+
return Object.assign(Object.assign({}, state), { status: action.payload });
|
|
1289
|
+
},
|
|
1290
|
+
},
|
|
1291
|
+
extraReducers: (builder) => {
|
|
1292
|
+
builder.addCase(signalEvents.roomJoined, (state, action) => {
|
|
1293
|
+
var _a, _b;
|
|
1294
|
+
const { error, isLocked } = action.payload;
|
|
1295
|
+
if (error === "room_locked" && isLocked) {
|
|
1296
|
+
return Object.assign(Object.assign({}, state), { status: "room_locked" });
|
|
1297
|
+
}
|
|
1298
|
+
if (error) {
|
|
1299
|
+
return Object.assign(Object.assign({}, state), { status: "disconnected", error });
|
|
1300
|
+
}
|
|
1301
|
+
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 });
|
|
1302
|
+
});
|
|
1303
|
+
builder.addCase(signalEvents.disconnect, (state) => {
|
|
1304
|
+
return Object.assign(Object.assign({}, state), { status: "disconnected" });
|
|
1305
|
+
});
|
|
1306
|
+
builder.addCase(signalEvents.newClient, (state, action) => {
|
|
1307
|
+
var _a, _b;
|
|
1308
|
+
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 });
|
|
1309
|
+
});
|
|
1310
|
+
builder.addCase(signalEvents.roomSessionEnded, (state, action) => {
|
|
1311
|
+
var _a;
|
|
1312
|
+
if (((_a = state.session) === null || _a === void 0 ? void 0 : _a.id) !== action.payload.roomSessionId) {
|
|
1313
|
+
return state;
|
|
1314
|
+
}
|
|
1315
|
+
return Object.assign(Object.assign({}, state), { session: null });
|
|
1316
|
+
});
|
|
1317
|
+
builder.addCase(signalEvents.clientKicked, (state) => {
|
|
1318
|
+
return Object.assign(Object.assign({}, state), { status: "kicked" });
|
|
1319
|
+
});
|
|
1320
|
+
builder.addCase(socketReconnecting, (state) => {
|
|
1321
|
+
return Object.assign(Object.assign({}, state), { status: "reconnect" });
|
|
1322
|
+
});
|
|
1323
|
+
},
|
|
1324
|
+
});
|
|
1325
|
+
const { connectionStatusChanged } = roomConnectionSlice.actions;
|
|
1326
|
+
const doKnockRoom = createAppThunk(() => (dispatch, getState) => {
|
|
1327
|
+
const state = getState();
|
|
1328
|
+
const socket = selectSignalConnectionRaw(state).socket;
|
|
1329
|
+
const roomName = selectAppRoomName(state);
|
|
1330
|
+
const roomKey = selectAppRoomKey(state);
|
|
1331
|
+
const displayName = selectAppDisplayName(state);
|
|
1332
|
+
const sdkVersion = selectAppSdkVersion(state);
|
|
1333
|
+
const externalId = selectAppExternalId(state);
|
|
1334
|
+
const organizationId = selectOrganizationId(state);
|
|
1335
|
+
socket === null || socket === void 0 ? void 0 : socket.emit("knock_room", {
|
|
1336
|
+
avatarUrl: null,
|
|
1337
|
+
config: {
|
|
1338
|
+
isAudioEnabled: true,
|
|
1339
|
+
isVideoEnabled: true,
|
|
1340
|
+
},
|
|
1341
|
+
deviceCapabilities: { canScreenshare: true },
|
|
1342
|
+
displayName,
|
|
1343
|
+
isCoLocated: false,
|
|
1344
|
+
isDevicePermissionDenied: false,
|
|
1345
|
+
kickFromOtherRooms: false,
|
|
1346
|
+
organizationId,
|
|
1347
|
+
roomKey,
|
|
1348
|
+
roomName,
|
|
1349
|
+
selfId: "",
|
|
1350
|
+
userAgent: `browser-sdk:${sdkVersion || "unknown"}`,
|
|
1351
|
+
externalId,
|
|
1352
|
+
});
|
|
1353
|
+
dispatch(connectionStatusChanged("knocking"));
|
|
1354
|
+
});
|
|
1355
|
+
const doConnectRoom = createAppThunk(() => (dispatch, getState) => {
|
|
1356
|
+
const state = getState();
|
|
1357
|
+
const socket = selectSignalConnectionRaw(state).socket;
|
|
1358
|
+
const roomName = selectAppRoomName(state);
|
|
1359
|
+
const roomKey = selectAppRoomKey(state);
|
|
1360
|
+
const displayName = selectAppDisplayName(state);
|
|
1361
|
+
const sdkVersion = selectAppSdkVersion(state);
|
|
1362
|
+
const externalId = selectAppExternalId(state);
|
|
1363
|
+
const organizationId = selectOrganizationId(state);
|
|
1364
|
+
const isCameraEnabled = selectIsCameraEnabled(getState());
|
|
1365
|
+
const isMicrophoneEnabled = selectIsMicrophoneEnabled(getState());
|
|
1366
|
+
const selfId = selectSelfId(getState());
|
|
1367
|
+
const clientClaim = selectLocalParticipantClientClaim(getState());
|
|
1368
|
+
socket === null || socket === void 0 ? void 0 : socket.emit("join_room", Object.assign(Object.assign({ avatarUrl: null, config: {
|
|
1369
|
+
isAudioEnabled: isMicrophoneEnabled,
|
|
1370
|
+
isVideoEnabled: isCameraEnabled,
|
|
1371
|
+
}, deviceCapabilities: { canScreenshare: true }, displayName, isCoLocated: false, isDevicePermissionDenied: false, kickFromOtherRooms: false, organizationId,
|
|
1372
|
+
roomKey,
|
|
1373
|
+
roomName,
|
|
1374
|
+
selfId }, (!!clientClaim && { clientClaim })), { userAgent: `browser-sdk:${sdkVersion || "unknown"}`, externalId }));
|
|
1375
|
+
dispatch(connectionStatusChanged("connecting"));
|
|
1376
|
+
});
|
|
1377
|
+
const selectRoomConnectionRaw = (state) => state.roomConnection;
|
|
1378
|
+
const selectRoomConnectionSession = (state) => state.roomConnection.session;
|
|
1379
|
+
const selectRoomConnectionSessionId = (state) => { var _a; return (_a = state.roomConnection.session) === null || _a === void 0 ? void 0 : _a.id; };
|
|
1380
|
+
const selectRoomConnectionStatus = (state) => state.roomConnection.status;
|
|
1381
|
+
const selectRoomConnectionError = (state) => state.roomConnection.error;
|
|
1382
|
+
const selectShouldConnectRoom = toolkit.createSelector([
|
|
1383
|
+
selectOrganizationId,
|
|
1384
|
+
selectRoomConnectionStatus,
|
|
1385
|
+
selectSignalConnectionDeviceIdentified,
|
|
1386
|
+
selectLocalMediaStatus,
|
|
1387
|
+
selectAppIsNodeSdk,
|
|
1388
|
+
], (hasOrganizationIdFetched, roomConnectionStatus, signalConnectionDeviceIdentified, localMediaStatus, isNodeSdk) => {
|
|
1389
|
+
if ((localMediaStatus === "started" || isNodeSdk) &&
|
|
1390
|
+
signalConnectionDeviceIdentified &&
|
|
1391
|
+
!!hasOrganizationIdFetched &&
|
|
1392
|
+
["initializing", "reconnect"].includes(roomConnectionStatus)) {
|
|
1393
|
+
return true;
|
|
1394
|
+
}
|
|
1395
|
+
return false;
|
|
1396
|
+
});
|
|
1397
|
+
createReactor([selectShouldConnectRoom], ({ dispatch }, shouldConnectRoom) => {
|
|
1398
|
+
if (shouldConnectRoom) {
|
|
1399
|
+
dispatch(doConnectRoom());
|
|
1400
|
+
}
|
|
1401
|
+
});
|
|
1402
|
+
startAppListening({
|
|
1403
|
+
actionCreator: signalEvents.knockHandled,
|
|
1404
|
+
effect: ({ payload }, { dispatch, getState }) => {
|
|
1405
|
+
const { clientId, resolution } = payload;
|
|
1406
|
+
const state = getState();
|
|
1407
|
+
const selfId = selectSelfId(state);
|
|
1408
|
+
if (clientId !== selfId) {
|
|
1409
|
+
return;
|
|
1410
|
+
}
|
|
1411
|
+
if (resolution === "accepted") {
|
|
1412
|
+
dispatch(setRoomKey(payload.metadata.roomKey));
|
|
1413
|
+
dispatch(doConnectRoom());
|
|
1414
|
+
}
|
|
1415
|
+
else if (resolution === "rejected") {
|
|
1416
|
+
dispatch(connectionStatusChanged("knock_rejected"));
|
|
1417
|
+
}
|
|
1418
|
+
},
|
|
1419
|
+
});
|
|
1420
|
+
|
|
1421
|
+
const createWebRtcEmitter = (dispatch) => {
|
|
1422
|
+
return {
|
|
1423
|
+
emit: (eventName, data) => {
|
|
1424
|
+
if (eventName === "rtc_manager_created") {
|
|
1425
|
+
dispatch(doRtcManagerCreated(data));
|
|
1426
|
+
}
|
|
1427
|
+
else if (eventName === "stream_added") {
|
|
1428
|
+
dispatch(rtcEvents.streamAdded(data));
|
|
1429
|
+
}
|
|
1430
|
+
else if (eventName === "rtc_manager_destroyed") {
|
|
1431
|
+
dispatch(rtcManagerDestroyed());
|
|
1432
|
+
}
|
|
1433
|
+
else ;
|
|
1434
|
+
},
|
|
1435
|
+
};
|
|
1436
|
+
};
|
|
1437
|
+
const initialState$3 = {
|
|
1438
|
+
dispatcherCreated: false,
|
|
1439
|
+
error: null,
|
|
1440
|
+
isCreatingDispatcher: false,
|
|
1441
|
+
reportedStreamResolutions: {},
|
|
1442
|
+
rtcManager: null,
|
|
1443
|
+
rtcManagerDispatcher: null,
|
|
1444
|
+
rtcManagerInitialized: false,
|
|
1445
|
+
status: "",
|
|
1446
|
+
isAcceptingStreams: false,
|
|
1447
|
+
};
|
|
1448
|
+
const rtcConnectionSlice = toolkit.createSlice({
|
|
1449
|
+
name: "rtcConnection",
|
|
1450
|
+
initialState: initialState$3,
|
|
1451
|
+
reducers: {
|
|
1452
|
+
isAcceptingStreams: (state, action) => {
|
|
1453
|
+
return Object.assign(Object.assign({}, state), { isAcceptingStreams: action.payload });
|
|
1454
|
+
},
|
|
1455
|
+
resolutionReported: (state, action) => {
|
|
1456
|
+
const { streamId, width, height } = action.payload;
|
|
1457
|
+
return Object.assign(Object.assign({}, state), { reportedStreamResolutions: Object.assign(Object.assign({}, state.reportedStreamResolutions), { [streamId]: { width, height } }) });
|
|
1458
|
+
},
|
|
1459
|
+
rtcDisconnected: () => {
|
|
1460
|
+
return Object.assign({}, initialState$3);
|
|
1461
|
+
},
|
|
1462
|
+
rtcDispatcherCreated: (state, action) => {
|
|
1463
|
+
return Object.assign(Object.assign({}, state), { dispatcherCreated: true, rtcManagerDispatcher: action.payload });
|
|
1464
|
+
},
|
|
1465
|
+
rtcManagerCreated: (state, action) => {
|
|
1466
|
+
return Object.assign(Object.assign({}, state), { rtcManager: action.payload, status: "ready" });
|
|
1467
|
+
},
|
|
1468
|
+
rtcManagerDestroyed: (state) => {
|
|
1469
|
+
return Object.assign(Object.assign({}, state), { rtcManager: null });
|
|
1470
|
+
},
|
|
1471
|
+
rtcManagerInitialized: (state) => {
|
|
1472
|
+
return Object.assign(Object.assign({}, state), { rtcManagerInitialized: true });
|
|
1473
|
+
},
|
|
1474
|
+
},
|
|
1475
|
+
extraReducers: (builder) => {
|
|
1476
|
+
builder.addCase(socketReconnecting, (state) => {
|
|
1477
|
+
return Object.assign(Object.assign({}, state), { status: "reconnect" });
|
|
1478
|
+
});
|
|
1479
|
+
builder.addCase(signalEvents.roomJoined, (state) => {
|
|
1480
|
+
return Object.assign(Object.assign({}, state), { status: state.status === "reconnect" ? "ready" : state.status });
|
|
1481
|
+
});
|
|
1482
|
+
},
|
|
1483
|
+
});
|
|
1484
|
+
const { resolutionReported, rtcDispatcherCreated, rtcDisconnected, rtcManagerCreated, rtcManagerDestroyed, rtcManagerInitialized, isAcceptingStreams, } = rtcConnectionSlice.actions;
|
|
1485
|
+
const doConnectRtc = createAppThunk(() => (dispatch, getState) => {
|
|
1486
|
+
const state = getState();
|
|
1487
|
+
const socket = selectSignalConnectionRaw(state).socket;
|
|
1488
|
+
const dispatcher = selectRtcConnectionRaw(state).rtcManagerDispatcher;
|
|
1489
|
+
const isCameraEnabled = selectIsCameraEnabled(state);
|
|
1490
|
+
const isMicrophoneEnabled = selectIsMicrophoneEnabled(state);
|
|
1491
|
+
const isNodeSdk = selectAppIsNodeSdk(state);
|
|
1492
|
+
if (dispatcher || !socket) {
|
|
1493
|
+
return;
|
|
1494
|
+
}
|
|
1495
|
+
const webrtcProvider = {
|
|
1496
|
+
getMediaConstraints: () => ({
|
|
1497
|
+
audio: isMicrophoneEnabled,
|
|
1498
|
+
video: isCameraEnabled,
|
|
1499
|
+
}),
|
|
1500
|
+
deferrable(clientId) {
|
|
1501
|
+
return !clientId;
|
|
1502
|
+
},
|
|
1503
|
+
};
|
|
1504
|
+
const rtcManagerDispatcher = new media.RtcManagerDispatcher({
|
|
1505
|
+
emitter: createWebRtcEmitter(dispatch),
|
|
1506
|
+
serverSocket: socket,
|
|
1507
|
+
webrtcProvider,
|
|
1508
|
+
features: {
|
|
1509
|
+
lowDataModeEnabled: false,
|
|
1510
|
+
sfuServerOverrideHost: undefined,
|
|
1511
|
+
turnServerOverrideHost: undefined,
|
|
1512
|
+
useOnlyTURN: undefined,
|
|
1513
|
+
vp9On: false,
|
|
1514
|
+
h264On: false,
|
|
1515
|
+
simulcastScreenshareOn: false,
|
|
1516
|
+
deviceHandlerFactory: isNodeSdk ? Chrome111_js.Chrome111.createFactory() : undefined,
|
|
1517
|
+
},
|
|
1518
|
+
});
|
|
1519
|
+
dispatch(rtcDispatcherCreated(rtcManagerDispatcher));
|
|
1520
|
+
});
|
|
1521
|
+
const doDisconnectRtc = createAppThunk(() => (dispatch, getState) => {
|
|
1522
|
+
const { rtcManager } = selectRtcConnectionRaw(getState());
|
|
1523
|
+
if (rtcManager) {
|
|
1524
|
+
rtcManager.disconnectAll();
|
|
1525
|
+
}
|
|
1526
|
+
dispatch(rtcDisconnected());
|
|
1527
|
+
});
|
|
1528
|
+
const doHandleAcceptStreams = createAppThunk((payload) => (dispatch, getState) => {
|
|
1529
|
+
var _a;
|
|
1530
|
+
dispatch(isAcceptingStreams(true));
|
|
1531
|
+
const state = getState();
|
|
1532
|
+
const rtcManager = selectRtcConnectionRaw(state).rtcManager;
|
|
1533
|
+
const remoteParticipants = selectRemoteParticipants(state);
|
|
1534
|
+
if (!rtcManager) {
|
|
1535
|
+
throw new Error("No rtc manager");
|
|
1536
|
+
}
|
|
1537
|
+
const activeBreakout = false;
|
|
1538
|
+
const shouldAcceptNewClients = (_a = rtcManager.shouldAcceptStreamsFromBothSides) === null || _a === void 0 ? void 0 : _a.call(rtcManager);
|
|
1539
|
+
const updates = [];
|
|
1540
|
+
for (const { clientId, streamId, state } of payload) {
|
|
1541
|
+
const participant = remoteParticipants.find((p) => p.id === clientId);
|
|
1542
|
+
if (!participant)
|
|
1543
|
+
continue;
|
|
1544
|
+
if (state === "to_accept" ||
|
|
1545
|
+
(state === "new_accept" && shouldAcceptNewClients) ||
|
|
1546
|
+
(state === "old_accept" && !shouldAcceptNewClients)) {
|
|
1547
|
+
rtcManager.acceptNewStream({
|
|
1548
|
+
streamId: streamId === "0" ? clientId : streamId,
|
|
1549
|
+
clientId,
|
|
1550
|
+
shouldAddLocalVideo: streamId === "0",
|
|
1551
|
+
activeBreakout,
|
|
1552
|
+
});
|
|
1553
|
+
}
|
|
1554
|
+
else if (state === "new_accept" || state === "old_accept") ;
|
|
1555
|
+
else if (state === "to_unaccept") {
|
|
1556
|
+
rtcManager === null || rtcManager === void 0 ? void 0 : rtcManager.disconnect(streamId === "0" ? clientId : streamId, activeBreakout);
|
|
1557
|
+
}
|
|
1558
|
+
else if (state !== "done_accept") {
|
|
1559
|
+
continue;
|
|
1560
|
+
}
|
|
1561
|
+
else ;
|
|
1562
|
+
updates.push({ clientId, streamId, state: state.replace(/to_|new_|old_/, "done_") });
|
|
1563
|
+
}
|
|
1564
|
+
dispatch(streamStatusUpdated(updates));
|
|
1565
|
+
dispatch(isAcceptingStreams(false));
|
|
1566
|
+
});
|
|
1567
|
+
const doRtcReportStreamResolution = createAppThunk(({ streamId, width, height }) => (dispatch, getState) => {
|
|
1568
|
+
const { reportedStreamResolutions, rtcManager } = selectRtcConnectionRaw(getState());
|
|
1569
|
+
const localStream = selectLocalMediaStream(getState());
|
|
1570
|
+
if (!rtcManager || (localStream === null || localStream === void 0 ? void 0 : localStream.id) === streamId) {
|
|
1571
|
+
return;
|
|
1572
|
+
}
|
|
1573
|
+
const old = reportedStreamResolutions[streamId];
|
|
1574
|
+
if (!old || old.width !== width || old.height !== height) {
|
|
1575
|
+
rtcManager.updateStreamResolution(streamId, null, { width: width || 1, height: height || 1 });
|
|
1576
|
+
}
|
|
1577
|
+
dispatch(resolutionReported({ streamId, width, height }));
|
|
1578
|
+
});
|
|
1579
|
+
const doRtcManagerCreated = createAppThunk((payload) => (dispatch) => {
|
|
1580
|
+
const { rtcManager } = payload;
|
|
1581
|
+
dispatch(rtcManagerCreated(rtcManager));
|
|
1582
|
+
});
|
|
1583
|
+
const doRtcManagerInitialize = createAppThunk(() => (dispatch, getState) => {
|
|
1584
|
+
const localMediaStream = selectLocalMediaStream(getState());
|
|
1585
|
+
const rtcManager = selectRtcConnectionRaw(getState()).rtcManager;
|
|
1586
|
+
const isCameraEnabled = selectIsCameraEnabled(getState());
|
|
1587
|
+
const isMicrophoneEnabled = selectIsMicrophoneEnabled(getState());
|
|
1588
|
+
if (localMediaStream && rtcManager) {
|
|
1589
|
+
rtcManager.addNewStream("0", localMediaStream, !isMicrophoneEnabled, !isCameraEnabled);
|
|
1590
|
+
}
|
|
1591
|
+
dispatch(rtcManagerInitialized());
|
|
1592
|
+
});
|
|
1593
|
+
const selectRtcConnectionRaw = (state) => state.rtcConnection;
|
|
1594
|
+
const selectRtcManagerInitialized = (state) => state.rtcConnection.rtcManagerInitialized;
|
|
1595
|
+
const selectRtcManager = (state) => state.rtcConnection.rtcManager;
|
|
1596
|
+
const selectRtcDispatcherCreated = (state) => state.rtcConnection.dispatcherCreated;
|
|
1597
|
+
const selectRtcIsCreatingDispatcher = (state) => state.rtcConnection.isCreatingDispatcher;
|
|
1598
|
+
const selectRtcStatus = (state) => state.rtcConnection.status;
|
|
1599
|
+
const selectIsAcceptingStreams = (state) => state.rtcConnection.isAcceptingStreams;
|
|
1600
|
+
startAppListening({
|
|
1601
|
+
actionCreator: doSetDevice.fulfilled,
|
|
1602
|
+
effect: ({ payload }, { getState }) => {
|
|
1603
|
+
const { replacedTracks } = payload;
|
|
1604
|
+
const { rtcManager } = selectRtcConnectionRaw(getState());
|
|
1605
|
+
const stream = selectLocalMediaStream(getState());
|
|
1606
|
+
const replace = (kind, oldTrack) => {
|
|
1607
|
+
const track = stream === null || stream === void 0 ? void 0 : stream.getTracks().find((t) => t.kind === kind);
|
|
1608
|
+
return track && (rtcManager === null || rtcManager === void 0 ? void 0 : rtcManager.replaceTrack(oldTrack, track));
|
|
1609
|
+
};
|
|
1610
|
+
replacedTracks === null || replacedTracks === void 0 ? void 0 : replacedTracks.forEach((t) => {
|
|
1611
|
+
replace(t.kind, t);
|
|
1612
|
+
});
|
|
1613
|
+
},
|
|
1614
|
+
});
|
|
1615
|
+
startAppListening({
|
|
1616
|
+
actionCreator: doStartScreenshare.fulfilled,
|
|
1617
|
+
effect: ({ payload }, { getState }) => {
|
|
1618
|
+
const { stream } = payload;
|
|
1619
|
+
const { rtcManager } = selectRtcConnectionRaw(getState());
|
|
1620
|
+
rtcManager === null || rtcManager === void 0 ? void 0 : rtcManager.addNewStream(stream.id, stream, false, true);
|
|
1621
|
+
},
|
|
1622
|
+
});
|
|
1623
|
+
startAppListening({
|
|
1624
|
+
actionCreator: stopScreenshare,
|
|
1625
|
+
effect: ({ payload }, { getState }) => {
|
|
1626
|
+
const { stream } = payload;
|
|
1627
|
+
const { rtcManager } = selectRtcConnectionRaw(getState());
|
|
1628
|
+
rtcManager === null || rtcManager === void 0 ? void 0 : rtcManager.removeStream(stream.id, stream, null);
|
|
1629
|
+
},
|
|
1630
|
+
});
|
|
1631
|
+
const selectShouldConnectRtc = toolkit.createSelector(selectRtcDispatcherCreated, selectRtcIsCreatingDispatcher, selectSignalConnectionSocket, (dispatcherCreated, isCreatingDispatcher, signalSocket) => {
|
|
1632
|
+
if (!dispatcherCreated && !isCreatingDispatcher && signalSocket) {
|
|
1633
|
+
return true;
|
|
1634
|
+
}
|
|
1635
|
+
return false;
|
|
1636
|
+
});
|
|
1637
|
+
createReactor([selectShouldConnectRtc], ({ dispatch }, shouldConnectRtc) => {
|
|
1638
|
+
if (shouldConnectRtc) {
|
|
1639
|
+
dispatch(doConnectRtc());
|
|
1640
|
+
}
|
|
1641
|
+
});
|
|
1642
|
+
const selectShouldInitializeRtc = toolkit.createSelector(selectRtcManager, selectRtcManagerInitialized, selectLocalMediaStatus, (rtcManager, rtcManagerInitialized, localMediaStatus) => {
|
|
1643
|
+
if (localMediaStatus === "started" && rtcManager && !rtcManagerInitialized) {
|
|
1644
|
+
return true;
|
|
1645
|
+
}
|
|
1646
|
+
return false;
|
|
1647
|
+
});
|
|
1648
|
+
createReactor([selectShouldInitializeRtc], ({ dispatch }, shouldInitializeRtc) => {
|
|
1649
|
+
if (shouldInitializeRtc) {
|
|
1650
|
+
dispatch(doRtcManagerInitialize());
|
|
1651
|
+
}
|
|
1652
|
+
});
|
|
1653
|
+
const selectShouldDisconnectRtc = toolkit.createSelector(selectRtcStatus, selectAppWantsToJoin, (status, wantsToJoin) => {
|
|
1654
|
+
if (!wantsToJoin && !["", "disconnected"].includes(status)) {
|
|
1655
|
+
return true;
|
|
1656
|
+
}
|
|
1657
|
+
return false;
|
|
1658
|
+
});
|
|
1659
|
+
createReactor([selectShouldDisconnectRtc], ({ dispatch }, shouldDisconnectRtc) => {
|
|
1660
|
+
if (shouldDisconnectRtc) {
|
|
1661
|
+
dispatch(doDisconnectRtc());
|
|
1662
|
+
}
|
|
1663
|
+
});
|
|
1664
|
+
const selectStreamsToAccept = toolkit.createSelector(selectRtcStatus, selectRemoteParticipants, (rtcStatus, remoteParticipants) => {
|
|
1665
|
+
if (rtcStatus !== "ready") {
|
|
1666
|
+
return [];
|
|
1667
|
+
}
|
|
1668
|
+
const upd = [];
|
|
1669
|
+
for (const client of remoteParticipants) {
|
|
1670
|
+
const { streams, id: clientId, newJoiner } = client;
|
|
1671
|
+
for (let i = 0; i < streams.length; i++) {
|
|
1672
|
+
let streamId = streams[i].id;
|
|
1673
|
+
let state = streams[i].state;
|
|
1674
|
+
if ((streams === null || streams === void 0 ? void 0 : streams.length) > 1 && streams[1].id === "0") {
|
|
1675
|
+
if (i === 0) {
|
|
1676
|
+
streamId = streams[1].id;
|
|
1677
|
+
state = streams[1].state;
|
|
1678
|
+
}
|
|
1679
|
+
else if (i === 1) {
|
|
1680
|
+
streamId = streams[0].id;
|
|
1681
|
+
state = streams[0].state;
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
{
|
|
1685
|
+
if (state === "done_accept")
|
|
1686
|
+
continue;
|
|
1687
|
+
upd.push({
|
|
1688
|
+
clientId,
|
|
1689
|
+
streamId,
|
|
1690
|
+
state: `${newJoiner && streamId === "0" ? "new" : "to"}_accept`,
|
|
1691
|
+
});
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
return upd;
|
|
1696
|
+
});
|
|
1697
|
+
createReactor([selectStreamsToAccept, selectIsAcceptingStreams], ({ dispatch }, streamsToAccept, isAcceptingStreams) => {
|
|
1698
|
+
if (0 < streamsToAccept.length && !isAcceptingStreams) {
|
|
1699
|
+
dispatch(doHandleAcceptStreams(streamsToAccept));
|
|
1700
|
+
}
|
|
1701
|
+
});
|
|
1702
|
+
|
|
1703
|
+
const rtcAnalyticsCustomEvents = {
|
|
1704
|
+
audioEnabled: {
|
|
1705
|
+
actions: [doEnableAudio.fulfilled],
|
|
1706
|
+
rtcEventName: "audioEnabled",
|
|
1707
|
+
getValue: (state) => selectIsMicrophoneEnabled(state),
|
|
1708
|
+
getOutput: (value) => ({ enabled: value }),
|
|
1709
|
+
},
|
|
1710
|
+
videoEnabled: {
|
|
1711
|
+
actions: [doEnableVideo.fulfilled],
|
|
1712
|
+
rtcEventName: "videoEnabled",
|
|
1713
|
+
getValue: (state) => selectIsCameraEnabled(state),
|
|
1714
|
+
getOutput: (value) => ({ enabled: value }),
|
|
1715
|
+
},
|
|
1716
|
+
localStream: {
|
|
1717
|
+
actions: [doSetDevice.fulfilled],
|
|
1718
|
+
rtcEventName: "localStream",
|
|
1719
|
+
getValue: (state) => {
|
|
1720
|
+
var _a;
|
|
1721
|
+
return (_a = selectLocalMediaStream(state)) === null || _a === void 0 ? void 0 : _a.getTracks().map((track) => ({ id: track.id, kind: track.kind, label: track.label }));
|
|
1722
|
+
},
|
|
1723
|
+
getOutput: (value) => ({ stream: value }),
|
|
1724
|
+
},
|
|
1725
|
+
localScreenshareStream: {
|
|
1726
|
+
actions: [doStartScreenshare.fulfilled],
|
|
1727
|
+
rtcEventName: "localScreenshareStream",
|
|
1728
|
+
getValue: (state) => {
|
|
1729
|
+
var _a;
|
|
1730
|
+
return (_a = selectLocalScreenshareStream(state)) === null || _a === void 0 ? void 0 : _a.getTracks().map((track) => ({ id: track.id, kind: track.kind, label: track.label }));
|
|
1731
|
+
},
|
|
1732
|
+
getOutput: (value) => ({ tracks: value }),
|
|
1733
|
+
},
|
|
1734
|
+
localScreenshareStreamStopped: {
|
|
1735
|
+
actions: [stopScreenshare],
|
|
1736
|
+
rtcEventName: "localScreenshareStream",
|
|
1737
|
+
getValue: () => () => null,
|
|
1738
|
+
getOutput: () => ({}),
|
|
1739
|
+
},
|
|
1740
|
+
displayName: {
|
|
1741
|
+
actions: [doSetDisplayName.fulfilled],
|
|
1742
|
+
rtcEventName: "displayName",
|
|
1743
|
+
getValue: (state) => selectAppDisplayName(state),
|
|
1744
|
+
getOutput: (value) => ({ displayName: value }),
|
|
1745
|
+
},
|
|
1746
|
+
clientId: {
|
|
1747
|
+
actions: null,
|
|
1748
|
+
rtcEventName: "clientId",
|
|
1749
|
+
getValue: (state) => selectSelfId(state),
|
|
1750
|
+
getOutput: (value) => ({ clientId: value }),
|
|
1751
|
+
},
|
|
1752
|
+
deviceId: {
|
|
1753
|
+
actions: null,
|
|
1754
|
+
rtcEventName: "deviceId",
|
|
1755
|
+
getValue: (state) => selectDeviceId(state),
|
|
1756
|
+
getOutput: (value) => ({ deviceId: value }),
|
|
1757
|
+
},
|
|
1758
|
+
externalId: {
|
|
1759
|
+
actions: null,
|
|
1760
|
+
rtcEventName: "externalId",
|
|
1761
|
+
getValue: (state) => selectAppExternalId(state),
|
|
1762
|
+
getOutput: (value) => ({ externalId: value }),
|
|
1763
|
+
},
|
|
1764
|
+
organizationId: {
|
|
1765
|
+
actions: null,
|
|
1766
|
+
rtcEventName: "organizationId",
|
|
1767
|
+
getValue: (state) => selectOrganizationId(state),
|
|
1768
|
+
getOutput: (value) => ({ organizationId: value }),
|
|
1769
|
+
},
|
|
1770
|
+
signalConnectionStatus: {
|
|
1771
|
+
actions: null,
|
|
1772
|
+
rtcEventName: "signalConnectionStatus",
|
|
1773
|
+
getValue: (state) => selectSignalStatus(state),
|
|
1774
|
+
getOutput: (value) => ({ status: value }),
|
|
1775
|
+
},
|
|
1776
|
+
roomSessionId: {
|
|
1777
|
+
actions: [
|
|
1778
|
+
signalEvents.newClient,
|
|
1779
|
+
signalEvents.roomJoined,
|
|
1780
|
+
signalEvents.roomSessionEnded,
|
|
1781
|
+
signalEvents.clientLeft,
|
|
1782
|
+
],
|
|
1783
|
+
rtcEventName: "roomSessionId",
|
|
1784
|
+
getValue: (state) => selectRoomConnectionSessionId(state),
|
|
1785
|
+
getOutput: (value) => ({ roomSessionId: value }),
|
|
1786
|
+
},
|
|
1787
|
+
rtcConnectionStatus: {
|
|
1788
|
+
actions: null,
|
|
1789
|
+
rtcEventName: "rtcConnectionStatus",
|
|
1790
|
+
getValue: (state) => selectRtcStatus(state),
|
|
1791
|
+
getOutput: (value) => ({ status: value }),
|
|
1792
|
+
},
|
|
1793
|
+
userRole: {
|
|
1794
|
+
actions: null,
|
|
1795
|
+
rtcEventName: "userRole",
|
|
1796
|
+
getValue: (state) => selectLocalParticipantRole(state),
|
|
1797
|
+
getOutput: (value) => ({ userRole: value }),
|
|
1798
|
+
},
|
|
1799
|
+
};
|
|
1800
|
+
const rtcCustomEventActions = Object.values(rtcAnalyticsCustomEvents)
|
|
1801
|
+
.flatMap(({ actions }) => { var _a; return (_a = actions === null || actions === void 0 ? void 0 : actions.map((action) => action)) !== null && _a !== void 0 ? _a : null; })
|
|
1802
|
+
.filter((action) => action !== null);
|
|
1803
|
+
const makeComparable = (value) => {
|
|
1804
|
+
if (typeof value === "object")
|
|
1805
|
+
return JSON.stringify(value);
|
|
1806
|
+
return value;
|
|
1807
|
+
};
|
|
1808
|
+
const initialState$2 = {
|
|
1809
|
+
reportedValues: {},
|
|
1810
|
+
};
|
|
1811
|
+
const rtcAnalyticsSlice = toolkit.createSlice({
|
|
1812
|
+
initialState: initialState$2,
|
|
1813
|
+
name: "rtcAnalytics",
|
|
1814
|
+
reducers: {
|
|
1815
|
+
updateReportedValues(state, action) {
|
|
1816
|
+
return Object.assign(Object.assign({}, state), { reportedValues: Object.assign(Object.assign({}, state.reportedValues), { [action.payload.rtcEventName]: action.payload.value }) });
|
|
1817
|
+
},
|
|
1818
|
+
},
|
|
1819
|
+
});
|
|
1820
|
+
const doRtcAnalyticsCustomEventsInitialize = createAppThunk(() => (dispatch, getState) => {
|
|
1821
|
+
const state = getState();
|
|
1822
|
+
const rtcManager = selectRtcConnectionRaw(state).rtcManager;
|
|
1823
|
+
if (!rtcManager)
|
|
1824
|
+
return;
|
|
1825
|
+
rtcManager.sendStatsCustomEvent("insightsStats", {
|
|
1826
|
+
_time: Date.now(),
|
|
1827
|
+
ls: 0,
|
|
1828
|
+
lr: 0,
|
|
1829
|
+
bs: 0,
|
|
1830
|
+
br: 0,
|
|
1831
|
+
cpu: 0,
|
|
1832
|
+
});
|
|
1833
|
+
Object.values(rtcAnalyticsCustomEvents).forEach(({ rtcEventName, getValue, getOutput }) => {
|
|
1834
|
+
var _a;
|
|
1835
|
+
const value = getValue(state);
|
|
1836
|
+
const output = Object.assign(Object.assign({}, getOutput(value)), { _time: Date.now() });
|
|
1837
|
+
const comparableValue = makeComparable(value);
|
|
1838
|
+
if (((_a = state.rtcAnalytics.reportedValues) === null || _a === void 0 ? void 0 : _a[rtcEventName]) !== comparableValue) {
|
|
1839
|
+
rtcManager.sendStatsCustomEvent(rtcEventName, output);
|
|
1840
|
+
dispatch(updateReportedValues({ rtcEventName, value }));
|
|
1841
|
+
}
|
|
1842
|
+
});
|
|
1843
|
+
});
|
|
1844
|
+
const { updateReportedValues } = rtcAnalyticsSlice.actions;
|
|
1845
|
+
startAppListening({
|
|
1846
|
+
matcher: toolkit.isAnyOf(...rtcCustomEventActions),
|
|
1847
|
+
effect: ({ type }, { getState, dispatch }) => {
|
|
1848
|
+
var _a;
|
|
1849
|
+
const state = getState();
|
|
1850
|
+
const rtcManager = selectRtcConnectionRaw(state).rtcManager;
|
|
1851
|
+
if (!rtcManager)
|
|
1852
|
+
return;
|
|
1853
|
+
const rtcCustomEvent = Object.values(rtcAnalyticsCustomEvents).find(({ actions }) => actions === null || actions === void 0 ? void 0 : actions.map((a) => a.type).includes(type));
|
|
1854
|
+
if (!rtcCustomEvent)
|
|
1855
|
+
return;
|
|
1856
|
+
const { getValue, getOutput, rtcEventName } = rtcCustomEvent;
|
|
1857
|
+
const value = getValue(state);
|
|
1858
|
+
const comparableValue = makeComparable(value);
|
|
1859
|
+
const output = Object.assign(Object.assign({}, getOutput(value)), { _time: Date.now() });
|
|
1860
|
+
if (((_a = state.rtcAnalytics.reportedValues) === null || _a === void 0 ? void 0 : _a[rtcEventName]) !== comparableValue) {
|
|
1861
|
+
rtcManager.sendStatsCustomEvent(rtcEventName, output);
|
|
1862
|
+
dispatch(updateReportedValues({ rtcEventName, value }));
|
|
1863
|
+
}
|
|
1864
|
+
},
|
|
1865
|
+
});
|
|
1866
|
+
createReactor([selectRtcManagerInitialized], ({ dispatch }, selectRtcManagerInitialized) => {
|
|
1867
|
+
if (selectRtcManagerInitialized) {
|
|
1868
|
+
dispatch(doRtcAnalyticsCustomEventsInitialize());
|
|
1869
|
+
}
|
|
1870
|
+
});
|
|
1871
|
+
|
|
1872
|
+
const initialState$1 = {
|
|
1873
|
+
isStreaming: false,
|
|
1874
|
+
error: null,
|
|
1875
|
+
startedAt: undefined,
|
|
1876
|
+
};
|
|
1877
|
+
const streamingSlice = toolkit.createSlice({
|
|
1878
|
+
name: "streaming",
|
|
1879
|
+
initialState: initialState$1,
|
|
1880
|
+
reducers: {
|
|
1881
|
+
doHandleStreamingStarted: (state) => {
|
|
1882
|
+
return Object.assign(Object.assign({}, state), { isStreaming: true, error: null, startedAt: new Date().getTime() });
|
|
1883
|
+
},
|
|
1884
|
+
doHandleStreamingStopped: (state) => {
|
|
1885
|
+
return Object.assign(Object.assign({}, state), { isStreaming: false });
|
|
1886
|
+
},
|
|
1887
|
+
},
|
|
1888
|
+
});
|
|
1889
|
+
const { doHandleStreamingStarted, doHandleStreamingStopped } = streamingSlice.actions;
|
|
1890
|
+
const selectStreamingRaw = (state) => state.streaming;
|
|
1891
|
+
|
|
1892
|
+
const initialState = {
|
|
1893
|
+
waitingParticipants: [],
|
|
1894
|
+
};
|
|
1895
|
+
const waitingParticipantsSlice = toolkit.createSlice({
|
|
1896
|
+
name: "waitingParticipants",
|
|
1897
|
+
initialState,
|
|
1898
|
+
reducers: {},
|
|
1899
|
+
extraReducers: (builder) => {
|
|
1900
|
+
builder.addCase(signalEvents.roomJoined, (state, { payload }) => {
|
|
1901
|
+
var _a;
|
|
1902
|
+
if ((_a = payload.room) === null || _a === void 0 ? void 0 : _a.knockers.length) {
|
|
1903
|
+
return Object.assign(Object.assign({}, state), { waitingParticipants: payload.room.knockers.map((knocker) => ({
|
|
1904
|
+
id: knocker.clientId,
|
|
1905
|
+
displayName: knocker.displayName,
|
|
1906
|
+
})) });
|
|
1907
|
+
}
|
|
1908
|
+
else {
|
|
1909
|
+
return state;
|
|
1910
|
+
}
|
|
1911
|
+
});
|
|
1912
|
+
builder.addCase(signalEvents.roomKnocked, (state, action) => {
|
|
1913
|
+
const { clientId, displayName } = action.payload;
|
|
1914
|
+
return Object.assign(Object.assign({}, state), { waitingParticipants: [...state.waitingParticipants, { id: clientId, displayName }] });
|
|
1915
|
+
});
|
|
1916
|
+
builder.addCase(signalEvents.knockerLeft, (state, action) => {
|
|
1917
|
+
const { clientId } = action.payload;
|
|
1918
|
+
return Object.assign(Object.assign({}, state), { waitingParticipants: state.waitingParticipants.filter((p) => p.id !== clientId) });
|
|
1919
|
+
});
|
|
1920
|
+
},
|
|
1921
|
+
});
|
|
1922
|
+
const doAcceptWaitingParticipant = createAppThunk((payload) => (dispatch, getState) => {
|
|
1923
|
+
const { participantId } = payload;
|
|
1924
|
+
const state = getState();
|
|
1925
|
+
const socket = selectSignalConnectionSocket(state);
|
|
1926
|
+
socket === null || socket === void 0 ? void 0 : socket.emit("handle_knock", {
|
|
1927
|
+
action: "accept",
|
|
1928
|
+
clientId: participantId,
|
|
1929
|
+
response: {},
|
|
1930
|
+
});
|
|
1931
|
+
});
|
|
1932
|
+
const doRejectWaitingParticipant = createAppThunk((payload) => (dispatch, getState) => {
|
|
1933
|
+
const { participantId } = payload;
|
|
1934
|
+
const state = getState();
|
|
1935
|
+
const socket = selectSignalConnectionSocket(state);
|
|
1936
|
+
socket === null || socket === void 0 ? void 0 : socket.emit("handle_knock", {
|
|
1937
|
+
action: "reject",
|
|
1938
|
+
clientId: participantId,
|
|
1939
|
+
response: {},
|
|
1940
|
+
});
|
|
1941
|
+
});
|
|
1942
|
+
const selectWaitingParticipantsRaw = (state) => state.waitingParticipants;
|
|
1943
|
+
const selectWaitingParticipants = (state) => state.waitingParticipants.waitingParticipants;
|
|
1944
|
+
|
|
1945
|
+
var _a;
|
|
1946
|
+
const IS_DEV = (_a = undefined === "true") !== null && _a !== void 0 ? _a : false;
|
|
1947
|
+
const rootReducer = toolkit.combineReducers({
|
|
1948
|
+
app: appSlice.reducer,
|
|
1949
|
+
chat: chatSlice.reducer,
|
|
1950
|
+
cloudRecording: cloudRecordingSlice.reducer,
|
|
1951
|
+
deviceCredentials: deviceCredentialsSlice.reducer,
|
|
1952
|
+
localMedia: localMediaSlice.reducer,
|
|
1953
|
+
localParticipant: localParticipantSlice.reducer,
|
|
1954
|
+
localScreenshare: localScreenshareSlice.reducer,
|
|
1955
|
+
organization: organizationSlice.reducer,
|
|
1956
|
+
remoteParticipants: remoteParticipantsSlice.reducer,
|
|
1957
|
+
roomConnection: roomConnectionSlice.reducer,
|
|
1958
|
+
rtcAnalytics: rtcAnalyticsSlice.reducer,
|
|
1959
|
+
rtcConnection: rtcConnectionSlice.reducer,
|
|
1960
|
+
signalConnection: signalConnectionSlice.reducer,
|
|
1961
|
+
streaming: streamingSlice.reducer,
|
|
1962
|
+
waitingParticipants: waitingParticipantsSlice.reducer,
|
|
1963
|
+
});
|
|
1964
|
+
const createStore = ({ preloadedState, injectServices, }) => {
|
|
1965
|
+
return toolkit.configureStore({
|
|
1966
|
+
devTools: IS_DEV,
|
|
1967
|
+
reducer: rootReducer,
|
|
1968
|
+
middleware: (getDefaultMiddleware) => getDefaultMiddleware({
|
|
1969
|
+
thunk: {
|
|
1970
|
+
extraArgument: { services: injectServices },
|
|
1971
|
+
},
|
|
1972
|
+
serializableCheck: false,
|
|
1973
|
+
}).prepend(listenerMiddleware.middleware),
|
|
1974
|
+
preloadedState,
|
|
1975
|
+
});
|
|
1976
|
+
};
|
|
1977
|
+
const observeStore = (store, select, onChange) => {
|
|
1978
|
+
let currentState;
|
|
1979
|
+
function handleChange() {
|
|
1980
|
+
const nextState = select(store.getState());
|
|
1981
|
+
if (nextState !== currentState) {
|
|
1982
|
+
currentState = nextState;
|
|
1983
|
+
onChange(currentState);
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
const unsubscribe = store.subscribe(handleChange);
|
|
1987
|
+
handleChange();
|
|
1988
|
+
return unsubscribe;
|
|
1989
|
+
};
|
|
1990
|
+
|
|
1991
|
+
class Response {
|
|
1992
|
+
constructor(initialValues = {}) {
|
|
1993
|
+
this.data = initialValues.data === undefined ? {} : initialValues.data;
|
|
1994
|
+
this.headers = initialValues.headers || {};
|
|
1995
|
+
this.status = initialValues.status || 200;
|
|
1996
|
+
this.statusText = initialValues.statusText || "OK";
|
|
1997
|
+
this.url = initialValues.url || null;
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
function assertTruthy(value, parameterName) {
|
|
2002
|
+
media.assert.ok(value, `${parameterName} is required`);
|
|
2003
|
+
return value;
|
|
2004
|
+
}
|
|
2005
|
+
function assertBoolean(value, parameterName) {
|
|
2006
|
+
media.assert.ok(typeof value === "boolean", `${parameterName}<boolean> is required`);
|
|
2007
|
+
return value;
|
|
2008
|
+
}
|
|
2009
|
+
function assertNumber(value, parameterName) {
|
|
2010
|
+
media.assert.ok(typeof value === "number", `${parameterName}<number> is required`);
|
|
2011
|
+
return value;
|
|
2012
|
+
}
|
|
2013
|
+
function assertString(value, parameterName) {
|
|
2014
|
+
media.assert.ok(typeof value === "string", `${parameterName}<string> is required`);
|
|
2015
|
+
return value;
|
|
2016
|
+
}
|
|
2017
|
+
function assertInstanceOf(value, type, parameterName) {
|
|
2018
|
+
const resolvedParameterName = parameterName || type.name[0].toLowerCase() + type.name.substring(1);
|
|
2019
|
+
media.assert.ok(value instanceof type, `${resolvedParameterName}<${type.name}> is required`);
|
|
2020
|
+
return value;
|
|
2021
|
+
}
|
|
2022
|
+
function assertRoomName(roomName, parameterName = "roomName") {
|
|
2023
|
+
assertString(roomName, parameterName);
|
|
2024
|
+
media.assert.ok(typeof roomName === "string" && roomName[0] === "/", `${parameterName} must begin with a '/'`);
|
|
2025
|
+
return roomName;
|
|
2026
|
+
}
|
|
2027
|
+
function assertArray(array, parameterName) {
|
|
2028
|
+
media.assert.ok(Array.isArray(array), `${parameterName}<array> is required`);
|
|
2029
|
+
return array;
|
|
2030
|
+
}
|
|
2031
|
+
function assertOneOf(value, allowedValues, parameterName) {
|
|
2032
|
+
assertTruthy(value, "value");
|
|
2033
|
+
assertArray(allowedValues, "allowedValues");
|
|
2034
|
+
const isAllowed = allowedValues.includes(value);
|
|
2035
|
+
if (!isAllowed) {
|
|
2036
|
+
throw new Error(`${parameterName}<string> must be one of the following: ${allowedValues.join(", ")}`);
|
|
2037
|
+
}
|
|
2038
|
+
return value;
|
|
2039
|
+
}
|
|
2040
|
+
function assertRecord(ref, name) {
|
|
2041
|
+
if (ref === null || ref === undefined || typeof ref !== "object" || Array.isArray(ref)) {
|
|
2042
|
+
throw new Error(`${name} must be a record. ${JSON.stringify(ref)}`);
|
|
2043
|
+
}
|
|
2044
|
+
return ref;
|
|
2045
|
+
}
|
|
2046
|
+
function assertNullOrType(ref, type, name, message) {
|
|
2047
|
+
assertString(name, "name");
|
|
2048
|
+
const errorMessage = message || `${name} must be null or of type ${type}`;
|
|
2049
|
+
media.assert.ok(ref === null || typeof ref === type, errorMessage);
|
|
2050
|
+
}
|
|
2051
|
+
function assertNullOrString(ref, name, message) {
|
|
2052
|
+
assertString(name, "name");
|
|
2053
|
+
assertNullOrType(ref, "string", name, message);
|
|
2054
|
+
}
|
|
2055
|
+
|
|
2056
|
+
function _getAbsoluteUrl({ baseUrl, url }) {
|
|
2057
|
+
return baseUrl ? baseUrl + url : url;
|
|
2058
|
+
}
|
|
2059
|
+
class HttpClient {
|
|
2060
|
+
constructor({ baseUrl }) {
|
|
2061
|
+
assertString(baseUrl, "baseUrl");
|
|
2062
|
+
this._baseUrl = baseUrl;
|
|
2063
|
+
}
|
|
2064
|
+
_requestAxios(url, options) {
|
|
2065
|
+
const axiosOptions = Object.assign({}, options, {
|
|
2066
|
+
url,
|
|
2067
|
+
baseURL: this._baseUrl,
|
|
2068
|
+
});
|
|
2069
|
+
return axios.request(axiosOptions);
|
|
2070
|
+
}
|
|
2071
|
+
request(url, options) {
|
|
2072
|
+
assertString(url, "url");
|
|
2073
|
+
media.assert.ok(url[0] === "/", 'url<String> only accepts relative URLs beginning with "/".');
|
|
2074
|
+
media.assert.ok(options, "options are required");
|
|
2075
|
+
return this._requestAxios(url, options)
|
|
2076
|
+
.then((response) => {
|
|
2077
|
+
const { data, headers, status, statusText, config } = response;
|
|
2078
|
+
const requestUrl = config && config.url ? _getAbsoluteUrl({ baseUrl: config.baseURL, url: config.url }) : null;
|
|
2079
|
+
return new Response({
|
|
2080
|
+
data,
|
|
2081
|
+
headers,
|
|
2082
|
+
status,
|
|
2083
|
+
statusText,
|
|
2084
|
+
url: requestUrl,
|
|
2085
|
+
});
|
|
2086
|
+
})
|
|
2087
|
+
.catch((error) => {
|
|
2088
|
+
const responseObject = error.response;
|
|
2089
|
+
if (!responseObject) {
|
|
2090
|
+
throw new Error("Could not make the request.");
|
|
2091
|
+
}
|
|
2092
|
+
const { data, headers, status, statusText, config } = responseObject;
|
|
2093
|
+
const requestUrl = config && config.url ? _getAbsoluteUrl({ baseUrl: config.baseURL, url: config.url }) : null;
|
|
2094
|
+
return Promise.reject(new Response({
|
|
2095
|
+
data,
|
|
2096
|
+
headers,
|
|
2097
|
+
status,
|
|
2098
|
+
statusText,
|
|
2099
|
+
url: requestUrl,
|
|
2100
|
+
}));
|
|
2101
|
+
});
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
class MultipartHttpClient {
|
|
2106
|
+
constructor({ httpClient }) {
|
|
2107
|
+
media.assert.ok(httpClient, "httpClient is required");
|
|
2108
|
+
this._httpClient = httpClient;
|
|
2109
|
+
}
|
|
2110
|
+
static dataToFormData(data) {
|
|
2111
|
+
media.assert.ok(data, "data is required");
|
|
2112
|
+
const fd = new FormData();
|
|
2113
|
+
Object.keys(data).forEach((key) => {
|
|
2114
|
+
const value = data[key];
|
|
2115
|
+
fd.append(key, value);
|
|
2116
|
+
});
|
|
2117
|
+
return fd;
|
|
2118
|
+
}
|
|
2119
|
+
request(url, options = {}) {
|
|
2120
|
+
const headers = Object.assign(options.headers || {}, {
|
|
2121
|
+
"Content-Type": undefined,
|
|
2122
|
+
});
|
|
2123
|
+
return this._httpClient.request(url, Object.assign(options, {
|
|
2124
|
+
headers,
|
|
2125
|
+
transformRequest: MultipartHttpClient.dataToFormData,
|
|
2126
|
+
}));
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
|
|
2130
|
+
let btoa;
|
|
2131
|
+
if (typeof window === "object") {
|
|
2132
|
+
btoa = window.btoa || nodeBtoa;
|
|
2133
|
+
}
|
|
2134
|
+
else if (typeof global === "object") {
|
|
2135
|
+
btoa = global.btoa || nodeBtoa;
|
|
2136
|
+
}
|
|
2137
|
+
else {
|
|
2138
|
+
btoa = nodeBtoa;
|
|
2139
|
+
}
|
|
2140
|
+
function _getAuthHeader(credentials) {
|
|
2141
|
+
if (credentials && credentials.credentials) {
|
|
2142
|
+
const btoaStr = `${credentials.credentials.uuid}:${credentials.hmac}`;
|
|
2143
|
+
return { Authorization: `Basic ${btoa(btoaStr)}` };
|
|
2144
|
+
}
|
|
2145
|
+
return {};
|
|
2146
|
+
}
|
|
2147
|
+
const noCredentials = () => Promise.resolve(null);
|
|
2148
|
+
class AuthenticatedHttpClient {
|
|
2149
|
+
constructor({ httpClient, fetchDeviceCredentials }) {
|
|
2150
|
+
this._httpClient = httpClient;
|
|
2151
|
+
this._fetchDeviceCredentials = fetchDeviceCredentials;
|
|
2152
|
+
}
|
|
2153
|
+
request(url, options) {
|
|
2154
|
+
return this._fetchDeviceCredentials().then((credentials) => {
|
|
2155
|
+
const headers = Object.assign({}, options.headers, _getAuthHeader(credentials), {
|
|
2156
|
+
"X-Appearin-Device-Platform": "web",
|
|
2157
|
+
});
|
|
2158
|
+
const httpClientOptions = Object.assign({}, options, { headers });
|
|
2159
|
+
return this._httpClient.request(url, httpClientOptions);
|
|
2160
|
+
});
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
class ApiClient {
|
|
2164
|
+
constructor({ baseUrl = "https://api.appearin.net", fetchDeviceCredentials = noCredentials, } = {}) {
|
|
2165
|
+
this.authenticatedHttpClient = new AuthenticatedHttpClient({
|
|
2166
|
+
httpClient: new HttpClient({
|
|
2167
|
+
baseUrl,
|
|
2168
|
+
}),
|
|
2169
|
+
fetchDeviceCredentials,
|
|
2170
|
+
});
|
|
2171
|
+
this.authenticatedFormDataHttpClient = new MultipartHttpClient({ httpClient: this.authenticatedHttpClient });
|
|
2172
|
+
}
|
|
2173
|
+
request(url, options) {
|
|
2174
|
+
assertString(url, "url");
|
|
2175
|
+
media.assert.ok(url[0] === "/", 'url<String> only accepts relative URLs beginning with "/".');
|
|
2176
|
+
media.assert.ok(options, "options are required");
|
|
2177
|
+
return this.authenticatedHttpClient.request(url, options);
|
|
2178
|
+
}
|
|
2179
|
+
requestMultipart(url, options) {
|
|
2180
|
+
assertString(url, "url");
|
|
2181
|
+
media.assert.ok(url[0] === "/", 'url<String> only accepts relative URLs beginning with "/".');
|
|
2182
|
+
media.assert.ok(options, "options are required");
|
|
2183
|
+
return this.authenticatedFormDataHttpClient.request(url, options);
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
function nullOrExtract(extract) {
|
|
2188
|
+
return (data, propertyName) => {
|
|
2189
|
+
const record = assertRecord(data, "data");
|
|
2190
|
+
const value = record[propertyName];
|
|
2191
|
+
return value === null || value === undefined ? null : extract(data, propertyName);
|
|
2192
|
+
};
|
|
2193
|
+
}
|
|
2194
|
+
function extractString(data, propertyName) {
|
|
2195
|
+
const record = assertRecord(data, "data");
|
|
2196
|
+
return assertString(record[propertyName], propertyName);
|
|
2197
|
+
}
|
|
2198
|
+
const extractNullOrString = nullOrExtract(extractString);
|
|
2199
|
+
function extractDate(data, propertyName) {
|
|
2200
|
+
const dateString = extractString(data, propertyName);
|
|
2201
|
+
const d = new Date(dateString);
|
|
2202
|
+
if (isNaN(d.getTime())) {
|
|
2203
|
+
throw new Error(`Invalid date for ${dateString}`);
|
|
2204
|
+
}
|
|
2205
|
+
return d;
|
|
2206
|
+
}
|
|
2207
|
+
function extractArrayOfJson(data, propertyName) {
|
|
2208
|
+
const record = assertRecord(data, "data");
|
|
2209
|
+
return assertArray(record[propertyName], propertyName);
|
|
2210
|
+
}
|
|
2211
|
+
function extractArray(data, propertyName, transformer) {
|
|
2212
|
+
return extractArrayOfJson(data, propertyName).map((value) => transformer(value));
|
|
2213
|
+
}
|
|
2214
|
+
function extractJson(data, propertyName) {
|
|
2215
|
+
const record = assertRecord(data, "data");
|
|
2216
|
+
const value = record[propertyName];
|
|
2217
|
+
return value === undefined ? null : value;
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
class Credentials {
|
|
2221
|
+
constructor(uuid, hmac, userId = undefined) {
|
|
2222
|
+
this.credentials = {
|
|
2223
|
+
uuid,
|
|
2224
|
+
};
|
|
2225
|
+
this.hmac = hmac;
|
|
2226
|
+
this.userId = userId;
|
|
2227
|
+
}
|
|
2228
|
+
toJson() {
|
|
2229
|
+
return Object.assign({ credentials: this.credentials, hmac: this.hmac }, (this.userId && { userId: this.userId }));
|
|
2230
|
+
}
|
|
2231
|
+
static fromJson(json) {
|
|
2232
|
+
return new Credentials(extractString(extractJson(json, "credentials"), "uuid"), extractString(json, "hmac"), extractNullOrString(json, "userId") || undefined);
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
class DeviceService {
|
|
2237
|
+
constructor({ apiClient }) {
|
|
2238
|
+
this._apiClient = apiClient;
|
|
2239
|
+
}
|
|
2240
|
+
getCredentials() {
|
|
2241
|
+
return this._apiClient
|
|
2242
|
+
.request("/devices", {
|
|
2243
|
+
method: "post",
|
|
2244
|
+
})
|
|
2245
|
+
.then(({ data }) => {
|
|
2246
|
+
return Credentials.fromJson(data);
|
|
2247
|
+
})
|
|
2248
|
+
.catch((error) => {
|
|
2249
|
+
if (error.response) {
|
|
2250
|
+
if (error.response.status === 404) {
|
|
2251
|
+
return null;
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
throw error;
|
|
2255
|
+
});
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
2258
|
+
|
|
2259
|
+
class ChromeStorageStore {
|
|
2260
|
+
constructor(key, chromeStorage) {
|
|
2261
|
+
this._key = key;
|
|
2262
|
+
this._chromeStorage = chromeStorage;
|
|
2263
|
+
}
|
|
2264
|
+
loadOrDefault(defaultValue) {
|
|
2265
|
+
return new Promise((resolve) => {
|
|
2266
|
+
this._chromeStorage.get(this._key, (result) => {
|
|
2267
|
+
const unknownResult = result;
|
|
2268
|
+
resolve(unknownResult[this._key] || defaultValue);
|
|
2269
|
+
});
|
|
2270
|
+
});
|
|
2271
|
+
}
|
|
2272
|
+
save(value) {
|
|
2273
|
+
return new Promise((resolve) => {
|
|
2274
|
+
this._chromeStorage.set({ [this._key]: value }, () => {
|
|
2275
|
+
resolve();
|
|
2276
|
+
});
|
|
2277
|
+
});
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
|
|
2281
|
+
class LocalStorageStore {
|
|
2282
|
+
constructor(key, localStorage) {
|
|
2283
|
+
assertTruthy(localStorage, "localStorage");
|
|
2284
|
+
this._key = assertString(key, "key");
|
|
2285
|
+
this._localStorage = localStorage;
|
|
2286
|
+
}
|
|
2287
|
+
loadOrDefault(defaultValue) {
|
|
2288
|
+
try {
|
|
2289
|
+
const value = this._localStorage.getItem(this._key);
|
|
2290
|
+
if (value) {
|
|
2291
|
+
try {
|
|
2292
|
+
return Promise.resolve(JSON.parse(value));
|
|
2293
|
+
}
|
|
2294
|
+
catch (e) {
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
return Promise.resolve(defaultValue);
|
|
2298
|
+
}
|
|
2299
|
+
catch (e) {
|
|
2300
|
+
console.warn("Error getting access to storage. Are cookies blocked?", e);
|
|
2301
|
+
return Promise.resolve(defaultValue);
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
save(value) {
|
|
2305
|
+
try {
|
|
2306
|
+
this._localStorage.setItem(this._key, JSON.stringify(value));
|
|
2307
|
+
return Promise.resolve();
|
|
2308
|
+
}
|
|
2309
|
+
catch (e) {
|
|
2310
|
+
console.warn("Error getting access to storage. Are cookies blocked?", e);
|
|
2311
|
+
return Promise.reject(e);
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
let localStorage;
|
|
2317
|
+
try {
|
|
2318
|
+
localStorage = self.localStorage;
|
|
2319
|
+
}
|
|
2320
|
+
catch (e) {
|
|
2321
|
+
localStorage = {
|
|
2322
|
+
getItem: () => undefined,
|
|
2323
|
+
key: () => undefined,
|
|
2324
|
+
setItem: () => undefined,
|
|
2325
|
+
removeItem: () => undefined,
|
|
2326
|
+
hasOwnProperty: () => undefined,
|
|
2327
|
+
length: 0,
|
|
2328
|
+
};
|
|
2329
|
+
}
|
|
2330
|
+
var localStorage$1 = localStorage;
|
|
2331
|
+
|
|
2332
|
+
const events = {
|
|
2333
|
+
CREDENTIALS_SAVED: "credentials_saved",
|
|
2334
|
+
};
|
|
2335
|
+
class CredentialsService extends EventEmitter {
|
|
2336
|
+
constructor({ deviceService, credentialsStore, }) {
|
|
2337
|
+
super();
|
|
2338
|
+
this._deviceService = deviceService;
|
|
2339
|
+
this._credentialsStore = credentialsStore;
|
|
2340
|
+
}
|
|
2341
|
+
static create({ baseUrl, storeName = "CredentialsStorage", storeType = "localStorage", }) {
|
|
2342
|
+
const deviceService = new DeviceService({
|
|
2343
|
+
apiClient: new ApiClient({ baseUrl }),
|
|
2344
|
+
});
|
|
2345
|
+
let credentialsStore = null;
|
|
2346
|
+
if (storeType === "localStorage") {
|
|
2347
|
+
credentialsStore = new LocalStorageStore(storeName, localStorage$1);
|
|
2348
|
+
}
|
|
2349
|
+
else if (storeType === "chromeStorage") {
|
|
2350
|
+
credentialsStore = new ChromeStorageStore(storeName, window["chrome"].storage.local);
|
|
2351
|
+
}
|
|
2352
|
+
else {
|
|
2353
|
+
throw new Error(`Unknown store type: ${storeType}`);
|
|
2354
|
+
}
|
|
2355
|
+
return new CredentialsService({
|
|
2356
|
+
deviceService,
|
|
2357
|
+
credentialsStore,
|
|
2358
|
+
});
|
|
2359
|
+
}
|
|
2360
|
+
_fetchNewCredentialsFromApi() {
|
|
2361
|
+
const credentialsStore = this._credentialsStore;
|
|
2362
|
+
return new Promise((resolve) => {
|
|
2363
|
+
const fetchCredentials = () => {
|
|
2364
|
+
this._deviceService
|
|
2365
|
+
.getCredentials()
|
|
2366
|
+
.then((credentials) => {
|
|
2367
|
+
return credentialsStore
|
|
2368
|
+
.save(credentials ? credentials.toJson() : null)
|
|
2369
|
+
.then(() => resolve(credentials));
|
|
2370
|
+
})
|
|
2371
|
+
.catch(() => {
|
|
2372
|
+
setTimeout(fetchCredentials, 2000);
|
|
2373
|
+
});
|
|
2374
|
+
};
|
|
2375
|
+
fetchCredentials();
|
|
2376
|
+
});
|
|
2377
|
+
}
|
|
2378
|
+
getCurrentCredentials() {
|
|
2379
|
+
return this._credentialsStore.loadOrDefault(null).then((json) => (json ? Credentials.fromJson(json) : null));
|
|
2380
|
+
}
|
|
2381
|
+
getCredentials() {
|
|
2382
|
+
if (!this.credentialsPromise) {
|
|
2383
|
+
this.credentialsPromise = this.getCurrentCredentials().then((storedCredentials) => {
|
|
2384
|
+
if (storedCredentials) {
|
|
2385
|
+
return storedCredentials;
|
|
2386
|
+
}
|
|
2387
|
+
return this._fetchNewCredentialsFromApi();
|
|
2388
|
+
});
|
|
2389
|
+
}
|
|
2390
|
+
return this.credentialsPromise;
|
|
2391
|
+
}
|
|
2392
|
+
saveCredentials(credentials) {
|
|
2393
|
+
this.credentialsPromise = undefined;
|
|
2394
|
+
return this._credentialsStore.save(credentials.toJson()).then(() => {
|
|
2395
|
+
this.emit(events.CREDENTIALS_SAVED, credentials);
|
|
2396
|
+
return credentials;
|
|
2397
|
+
});
|
|
2398
|
+
}
|
|
2399
|
+
setUserId(userId) {
|
|
2400
|
+
return this.getCurrentCredentials()
|
|
2401
|
+
.then((storedCredentials) => {
|
|
2402
|
+
if (!storedCredentials) {
|
|
2403
|
+
console.error("Illegal state: no credentials to set user id for.");
|
|
2404
|
+
}
|
|
2405
|
+
const userIdChangedFromLocalStorage = storedCredentials === null || storedCredentials.userId !== userId;
|
|
2406
|
+
if (!userIdChangedFromLocalStorage) {
|
|
2407
|
+
return undefined;
|
|
2408
|
+
}
|
|
2409
|
+
return this._credentialsStore.save(Object.assign({}, storedCredentials === null || storedCredentials === void 0 ? void 0 : storedCredentials.toJson(), { userId }));
|
|
2410
|
+
})
|
|
2411
|
+
.then(() => undefined);
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
|
|
2415
|
+
const noOrganization = () => Promise.resolve(undefined);
|
|
2416
|
+
class OrganizationApiClient {
|
|
2417
|
+
constructor({ apiClient, fetchOrganization = noOrganization, }) {
|
|
2418
|
+
this._apiClient = apiClient;
|
|
2419
|
+
this._fetchOrganization = fetchOrganization;
|
|
2420
|
+
this._apiClient = apiClient;
|
|
2421
|
+
}
|
|
2422
|
+
_callRequestMethod(method, url, options) {
|
|
2423
|
+
assertString(url, "url");
|
|
2424
|
+
media.assert.ok(url[0] === "/", 'url<String> only accepts relative URLs beginning with "/".');
|
|
2425
|
+
media.assert.ok(options, "options are required");
|
|
2426
|
+
return this._fetchOrganization().then((organization) => {
|
|
2427
|
+
if (!organization) {
|
|
2428
|
+
return this._apiClient[method](url, options);
|
|
2429
|
+
}
|
|
2430
|
+
const { organizationId } = organization;
|
|
2431
|
+
return this._apiClient[method](`/organizations/${encodeURIComponent(organizationId)}${url}`, options);
|
|
2432
|
+
});
|
|
2433
|
+
}
|
|
2434
|
+
request(url, options) {
|
|
2435
|
+
return this._callRequestMethod("request", url, options);
|
|
2436
|
+
}
|
|
2437
|
+
requestMultipart(url, options) {
|
|
2438
|
+
return this._callRequestMethod("requestMultipart", url, options);
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
class EmbeddedFreeTierStatus {
|
|
2443
|
+
constructor({ isExhausted, renewsAt, totalMinutesLimit, totalMinutesUsed, }) {
|
|
2444
|
+
this.isExhausted = isExhausted;
|
|
2445
|
+
this.renewsAt = renewsAt;
|
|
2446
|
+
this.totalMinutesLimit = totalMinutesLimit;
|
|
2447
|
+
this.totalMinutesUsed = totalMinutesUsed;
|
|
2448
|
+
}
|
|
2449
|
+
static fromJson(data) {
|
|
2450
|
+
return new EmbeddedFreeTierStatus({
|
|
2451
|
+
isExhausted: assertBoolean(data.isExhausted, "isExhausted"),
|
|
2452
|
+
renewsAt: new Date(assertString(data.renewsAt, "renewsAt")),
|
|
2453
|
+
totalMinutesLimit: assertNumber(data.totalMinutesLimit, "totalMinutesLimit"),
|
|
2454
|
+
totalMinutesUsed: assertNumber(data.totalMinutesUsed, "totalMinutesUsed"),
|
|
2455
|
+
});
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
|
|
2459
|
+
class Account {
|
|
2460
|
+
constructor({ basePlanId, embeddedFreeTierStatus, isDeactivated, isOnTrial, onTrialUntil, trialStatus, }) {
|
|
2461
|
+
this.basePlanId = basePlanId;
|
|
2462
|
+
this.isDeactivated = isDeactivated;
|
|
2463
|
+
this.isOnTrial = isOnTrial;
|
|
2464
|
+
this.onTrialUntil = onTrialUntil || null;
|
|
2465
|
+
this.trialStatus = trialStatus || null;
|
|
2466
|
+
this.embeddedFreeTierStatus = embeddedFreeTierStatus || null;
|
|
2467
|
+
}
|
|
2468
|
+
static fromJson(data) {
|
|
2469
|
+
return new Account({
|
|
2470
|
+
basePlanId: typeof data.basePlanId === "string" ? data.basePlanId : null,
|
|
2471
|
+
isDeactivated: assertBoolean(data.isDeactivated, "isDeactivated"),
|
|
2472
|
+
isOnTrial: assertBoolean(data.isOnTrial, "isOnTrial"),
|
|
2473
|
+
onTrialUntil: typeof data.onTrialUntil === "string" ? new Date(data.onTrialUntil) : null,
|
|
2474
|
+
trialStatus: typeof data.trialStatus === "string" ? data.trialStatus : null,
|
|
2475
|
+
embeddedFreeTierStatus: data.embeddedFreeTierStatus
|
|
2476
|
+
? EmbeddedFreeTierStatus.fromJson(data.embeddedFreeTierStatus)
|
|
2477
|
+
: null,
|
|
2478
|
+
});
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2482
|
+
function hasValue(value) {
|
|
2483
|
+
return value !== null && value !== undefined;
|
|
2484
|
+
}
|
|
2485
|
+
function createOrganizationLimits(limits = {}) {
|
|
2486
|
+
return {
|
|
2487
|
+
maxNumberOfInvitationsAndUsers: hasValue(limits === null || limits === void 0 ? void 0 : limits.maxNumberOfInvitationsAndUsers)
|
|
2488
|
+
? Number(limits === null || limits === void 0 ? void 0 : limits.maxNumberOfInvitationsAndUsers)
|
|
2489
|
+
: null,
|
|
2490
|
+
maxNumberOfClaimedRooms: hasValue(limits === null || limits === void 0 ? void 0 : limits.maxNumberOfClaimedRooms)
|
|
2491
|
+
? Number(limits === null || limits === void 0 ? void 0 : limits.maxNumberOfClaimedRooms)
|
|
2492
|
+
: null,
|
|
2493
|
+
maxRoomLimitPerOrganization: hasValue(limits === null || limits === void 0 ? void 0 : limits.maxRoomLimitPerOrganization)
|
|
2494
|
+
? Number(limits === null || limits === void 0 ? void 0 : limits.maxRoomLimitPerOrganization)
|
|
2495
|
+
: null,
|
|
2496
|
+
trialMinutesLimit: hasValue(limits === null || limits === void 0 ? void 0 : limits.trialMinutesLimit) ? Number(limits === null || limits === void 0 ? void 0 : limits.trialMinutesLimit) : null,
|
|
2497
|
+
includedUnits: hasValue(limits === null || limits === void 0 ? void 0 : limits.includedUnits) ? Number(limits === null || limits === void 0 ? void 0 : limits.includedUnits) : null,
|
|
2498
|
+
};
|
|
2499
|
+
}
|
|
2500
|
+
class Organization {
|
|
2501
|
+
constructor(properties) {
|
|
2502
|
+
this.logoImageUrl = null;
|
|
2503
|
+
this.roomBackgroundImageUrl = null;
|
|
2504
|
+
this.roomBackgroundThumbnailUrl = null;
|
|
2505
|
+
this.roomKnockPageBackgroundImageUrl = null;
|
|
2506
|
+
this.roomKnockPageBackgroundThumbnailUrl = null;
|
|
2507
|
+
this.preferences = null;
|
|
2508
|
+
this.onboardingSurvey = null;
|
|
2509
|
+
this.type = null;
|
|
2510
|
+
assertInstanceOf(properties, Object, "properties");
|
|
2511
|
+
assertString(properties.organizationId, "organizationId");
|
|
2512
|
+
assertString(properties.organizationName, "organizationName");
|
|
2513
|
+
assertString(properties.subdomain, "subdomain");
|
|
2514
|
+
assertInstanceOf(properties.permissions, Object, "permissions");
|
|
2515
|
+
assertInstanceOf(properties.limits, Object, "limits");
|
|
2516
|
+
this.organizationId = properties.organizationId;
|
|
2517
|
+
this.organizationName = properties.organizationName;
|
|
2518
|
+
this.subdomain = properties.subdomain;
|
|
2519
|
+
this.permissions = properties.permissions;
|
|
2520
|
+
this.limits = properties.limits;
|
|
2521
|
+
this.account = properties.account ? new Account(properties.account) : null;
|
|
2522
|
+
this.logoImageUrl = properties.logoImageUrl;
|
|
2523
|
+
this.roomBackgroundImageUrl = properties.roomBackgroundImageUrl;
|
|
2524
|
+
this.roomBackgroundThumbnailUrl = properties.roomBackgroundThumbnailUrl;
|
|
2525
|
+
this.roomKnockPageBackgroundImageUrl = properties.roomKnockPageBackgroundImageUrl;
|
|
2526
|
+
this.roomKnockPageBackgroundThumbnailUrl = properties.roomKnockPageBackgroundThumbnailUrl;
|
|
2527
|
+
this.preferences = properties.preferences;
|
|
2528
|
+
this.onboardingSurvey = properties.onboardingSurvey;
|
|
2529
|
+
this.type = properties.type;
|
|
2530
|
+
}
|
|
2531
|
+
static fromJson(data) {
|
|
2532
|
+
const parsedData = assertInstanceOf(data, Object, "data");
|
|
2533
|
+
const preferences = ((parsedData === null || parsedData === void 0 ? void 0 : parsedData.preferences) || {});
|
|
2534
|
+
const onboardingSurvey = ((parsedData === null || parsedData === void 0 ? void 0 : parsedData.onboardingSurvey) || null);
|
|
2535
|
+
const permissions = assertInstanceOf(parsedData.permissions, Object, "permissions");
|
|
2536
|
+
return new Organization({
|
|
2537
|
+
organizationId: assertString(parsedData.organizationId, "organizationId"),
|
|
2538
|
+
organizationName: assertString(parsedData.organizationName, "organizationName"),
|
|
2539
|
+
subdomain: assertString(parsedData.subdomain, "subdomain"),
|
|
2540
|
+
permissions,
|
|
2541
|
+
limits: createOrganizationLimits(assertInstanceOf(parsedData.limits, Object, "limits")),
|
|
2542
|
+
account: parsedData.account ? Account.fromJson(parsedData.account) : null,
|
|
2543
|
+
logoImageUrl: typeof parsedData.logoImageUrl === "string" ? parsedData.logoImageUrl : null,
|
|
2544
|
+
roomBackgroundImageUrl: typeof parsedData.roomBackgroundImageUrl === "string" ? parsedData.roomBackgroundImageUrl : null,
|
|
2545
|
+
roomBackgroundThumbnailUrl: typeof parsedData.roomBackgroundThumbnailUrl === "string"
|
|
2546
|
+
? parsedData.roomBackgroundThumbnailUrl
|
|
2547
|
+
: null,
|
|
2548
|
+
roomKnockPageBackgroundImageUrl: typeof parsedData.roomKnockPageBackgroundImageUrl === "string"
|
|
2549
|
+
? parsedData.roomKnockPageBackgroundImageUrl
|
|
2550
|
+
: null,
|
|
2551
|
+
roomKnockPageBackgroundThumbnailUrl: typeof parsedData.roomKnockPageBackgroundThumbnailUrl === "string"
|
|
2552
|
+
? parsedData.roomKnockPageBackgroundThumbnailUrl
|
|
2553
|
+
: null,
|
|
2554
|
+
preferences,
|
|
2555
|
+
onboardingSurvey,
|
|
2556
|
+
type: typeof parsedData.type === "string" ? parsedData.type : null,
|
|
2557
|
+
});
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
Organization.GLOBAL_ORGANIZATION_ID = "1";
|
|
2561
|
+
|
|
2562
|
+
class OrganizationService {
|
|
2563
|
+
constructor({ apiClient }) {
|
|
2564
|
+
this._apiClient = apiClient;
|
|
2565
|
+
}
|
|
2566
|
+
createOrganization({ organizationName, subdomain, owner, }) {
|
|
2567
|
+
const { displayName, consents } = owner || {};
|
|
2568
|
+
const email = "email" in owner
|
|
2569
|
+
? {
|
|
2570
|
+
value: owner.email,
|
|
2571
|
+
verificationCode: assertString(owner.verificationCode, "owner.verificationCode"),
|
|
2572
|
+
}
|
|
2573
|
+
: null;
|
|
2574
|
+
const idToken = "idToken" in owner ? owner.idToken : null;
|
|
2575
|
+
assertString(subdomain, "subdomain");
|
|
2576
|
+
assertString(organizationName, "organizationName");
|
|
2577
|
+
assertString(displayName, "owner.displayName");
|
|
2578
|
+
media.assert.ok(email || idToken, "owner.email or owner.idToken is required");
|
|
2579
|
+
if (consents) {
|
|
2580
|
+
assertArray(consents, "consents");
|
|
2581
|
+
for (const { consentRevisionId, action } of consents) {
|
|
2582
|
+
assertString(consentRevisionId, "consentRevisionId");
|
|
2583
|
+
assertNullOrString(action, "action");
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
return this._apiClient
|
|
2587
|
+
.request(`/organizations`, {
|
|
2588
|
+
method: "POST",
|
|
2589
|
+
data: {
|
|
2590
|
+
organizationName,
|
|
2591
|
+
type: "private",
|
|
2592
|
+
subdomain,
|
|
2593
|
+
owner: Object.assign(Object.assign(Object.assign(Object.assign({}, (email && { email })), (idToken && { idToken })), (consents && { consents })), { displayName }),
|
|
2594
|
+
},
|
|
2595
|
+
})
|
|
2596
|
+
.then(({ data }) => {
|
|
2597
|
+
return extractString(data, "organizationId");
|
|
2598
|
+
});
|
|
2599
|
+
}
|
|
2600
|
+
getOrganizationBySubdomain(subdomain) {
|
|
2601
|
+
assertString(subdomain, "subdomain");
|
|
2602
|
+
return this._apiClient
|
|
2603
|
+
.request(`/organization-subdomains/${encodeURIComponent(subdomain)}/?fields=permissions,account,onboardingSurvey`, {
|
|
2604
|
+
method: "GET",
|
|
2605
|
+
})
|
|
2606
|
+
.then(({ data }) => {
|
|
2607
|
+
return Organization.fromJson(data);
|
|
2608
|
+
})
|
|
2609
|
+
.catch((res) => {
|
|
2610
|
+
if (res instanceof Response) {
|
|
2611
|
+
if (res.status === 404) {
|
|
2612
|
+
return null;
|
|
2613
|
+
}
|
|
2614
|
+
throw new Error(res.statusText);
|
|
2615
|
+
}
|
|
2616
|
+
throw res;
|
|
2617
|
+
});
|
|
2618
|
+
}
|
|
2619
|
+
getOrganizationByOrganizationId(organizationId) {
|
|
2620
|
+
assertString(organizationId, "organizationId");
|
|
2621
|
+
return this._apiClient
|
|
2622
|
+
.request(`/organizations/${encodeURIComponent(organizationId)}?fields=permissions,account`, {
|
|
2623
|
+
method: "GET",
|
|
2624
|
+
})
|
|
2625
|
+
.then(({ data }) => {
|
|
2626
|
+
return Organization.fromJson(data);
|
|
2627
|
+
})
|
|
2628
|
+
.catch((res) => {
|
|
2629
|
+
if (res instanceof Response) {
|
|
2630
|
+
if (res.status === 404) {
|
|
2631
|
+
return null;
|
|
2632
|
+
}
|
|
2633
|
+
throw new Error(res.statusText);
|
|
2634
|
+
}
|
|
2635
|
+
throw res;
|
|
2636
|
+
});
|
|
2637
|
+
}
|
|
2638
|
+
getOrganizationsByContactPoint(options) {
|
|
2639
|
+
const { code } = options;
|
|
2640
|
+
const email = "email" in options ? options.email : null;
|
|
2641
|
+
const phoneNumber = "phoneNumber" in options ? options.phoneNumber : null;
|
|
2642
|
+
media.assert.ok((email || phoneNumber) && !(email && phoneNumber), "either email or phoneNumber is required");
|
|
2643
|
+
assertString(code, "code");
|
|
2644
|
+
const contactPoint = email ? { type: "email", value: email } : { type: "phoneNumber", value: phoneNumber };
|
|
2645
|
+
return this._apiClient
|
|
2646
|
+
.request("/organization-queries", {
|
|
2647
|
+
method: "POST",
|
|
2648
|
+
data: {
|
|
2649
|
+
contactPoint,
|
|
2650
|
+
code,
|
|
2651
|
+
},
|
|
2652
|
+
})
|
|
2653
|
+
.then(({ data }) => {
|
|
2654
|
+
return extractArray(data, "organizations", (organization) => Organization.fromJson(organization));
|
|
2655
|
+
});
|
|
2656
|
+
}
|
|
2657
|
+
getOrganizationsByIdToken({ idToken }) {
|
|
2658
|
+
assertString(idToken, "idToken");
|
|
2659
|
+
return this._apiClient
|
|
2660
|
+
.request("/organization-queries", {
|
|
2661
|
+
method: "POST",
|
|
2662
|
+
data: {
|
|
2663
|
+
idToken,
|
|
2664
|
+
},
|
|
2665
|
+
})
|
|
2666
|
+
.then(({ data }) => {
|
|
2667
|
+
return extractArray(data, "organizations", (organization) => {
|
|
2668
|
+
return Organization.fromJson(Object.assign({ permissions: {}, limits: {} }, assertRecord(organization, "organization")));
|
|
2669
|
+
});
|
|
2670
|
+
});
|
|
2671
|
+
}
|
|
2672
|
+
getOrganizationsByLoggedInUser() {
|
|
2673
|
+
return this._apiClient
|
|
2674
|
+
.request("/user/organizations", {
|
|
2675
|
+
method: "GET",
|
|
2676
|
+
})
|
|
2677
|
+
.then(({ data }) => {
|
|
2678
|
+
return extractArray(data, "organizations", (o) => {
|
|
2679
|
+
return Organization.fromJson(Object.assign({ permissions: {}, limits: {} }, assertRecord(o, "organization")));
|
|
2680
|
+
});
|
|
2681
|
+
});
|
|
2682
|
+
}
|
|
2683
|
+
getSubdomainAvailability(subdomain) {
|
|
2684
|
+
assertString(subdomain, "subdomain");
|
|
2685
|
+
return this._apiClient
|
|
2686
|
+
.request(`/organization-subdomains/${encodeURIComponent(subdomain)}/availability`, {
|
|
2687
|
+
method: "GET",
|
|
2688
|
+
})
|
|
2689
|
+
.then(({ data }) => {
|
|
2690
|
+
assertInstanceOf(data, Object, "data");
|
|
2691
|
+
return {
|
|
2692
|
+
status: extractString(data, "status"),
|
|
2693
|
+
};
|
|
2694
|
+
});
|
|
2695
|
+
}
|
|
2696
|
+
updatePreferences({ organizationId, preferences, }) {
|
|
2697
|
+
assertTruthy(organizationId, "organizationId");
|
|
2698
|
+
assertTruthy(preferences, "preferences");
|
|
2699
|
+
return this._apiClient
|
|
2700
|
+
.request(`/organizations/${encodeURIComponent(organizationId)}/preferences`, {
|
|
2701
|
+
method: "PATCH",
|
|
2702
|
+
data: preferences,
|
|
2703
|
+
})
|
|
2704
|
+
.then(() => undefined);
|
|
2705
|
+
}
|
|
2706
|
+
deleteOrganization({ organizationId }) {
|
|
2707
|
+
assertTruthy(organizationId, "organizationId");
|
|
2708
|
+
return this._apiClient
|
|
2709
|
+
.request(`/organizations/${encodeURIComponent(organizationId)}`, {
|
|
2710
|
+
method: "DELETE",
|
|
2711
|
+
})
|
|
2712
|
+
.then(() => undefined);
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
2715
|
+
|
|
2716
|
+
class OrganizationServiceCache {
|
|
2717
|
+
constructor({ organizationService, subdomain }) {
|
|
2718
|
+
this._organizationService = organizationService;
|
|
2719
|
+
this._subdomain = subdomain;
|
|
2720
|
+
this._organizationPromise = null;
|
|
2721
|
+
}
|
|
2722
|
+
initOrganization() {
|
|
2723
|
+
return this.fetchOrganization().then(() => undefined);
|
|
2724
|
+
}
|
|
2725
|
+
fetchOrganization() {
|
|
2726
|
+
if (!this._organizationPromise) {
|
|
2727
|
+
this._organizationPromise = this._organizationService.getOrganizationBySubdomain(this._subdomain);
|
|
2728
|
+
}
|
|
2729
|
+
return this._organizationPromise;
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
class Room {
|
|
2734
|
+
constructor(properties = {}) {
|
|
2735
|
+
media.assert.ok(properties instanceof Object, "properties<object> must be empty or an object");
|
|
2736
|
+
this.isClaimed = false;
|
|
2737
|
+
this.isBanned = false;
|
|
2738
|
+
this.isLocked = false;
|
|
2739
|
+
this.knockPage = {
|
|
2740
|
+
backgroundImageUrl: null,
|
|
2741
|
+
backgroundThumbnailUrl: null,
|
|
2742
|
+
};
|
|
2743
|
+
this.logoUrl = null;
|
|
2744
|
+
this.backgroundImageUrl = null;
|
|
2745
|
+
this.backgroundThumbnailUrl = null;
|
|
2746
|
+
this.type = null;
|
|
2747
|
+
this.legacyRoomType = null;
|
|
2748
|
+
this.mode = null;
|
|
2749
|
+
this.product = null;
|
|
2750
|
+
this.roomName = null;
|
|
2751
|
+
this.theme = null;
|
|
2752
|
+
this.preferences = {};
|
|
2753
|
+
this.protectedPreferences = {};
|
|
2754
|
+
this.publicProfile = null;
|
|
2755
|
+
const validProperties = {};
|
|
2756
|
+
Object.getOwnPropertyNames(properties).forEach((prop) => {
|
|
2757
|
+
if (Object.getOwnPropertyNames(this).indexOf(prop) !== -1) {
|
|
2758
|
+
validProperties[prop] = properties[prop];
|
|
2759
|
+
}
|
|
2760
|
+
});
|
|
2761
|
+
if (properties.ownerId !== undefined) {
|
|
2762
|
+
this.ownerId = properties.ownerId;
|
|
2763
|
+
}
|
|
2764
|
+
if (properties.meeting !== undefined) {
|
|
2765
|
+
this.meeting = properties.meeting;
|
|
2766
|
+
}
|
|
2767
|
+
Object.assign(this, validProperties);
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
class Meeting {
|
|
2772
|
+
constructor({ meetingId, roomName, roomUrl, startDate, endDate, hostRoomUrl, viewerRoomUrl }) {
|
|
2773
|
+
assertString(meetingId, "meetingId");
|
|
2774
|
+
assertString(roomName, "roomName");
|
|
2775
|
+
assertString(roomUrl, "roomUrl");
|
|
2776
|
+
assertInstanceOf(startDate, Date, "startDate");
|
|
2777
|
+
assertInstanceOf(endDate, Date, "endDate");
|
|
2778
|
+
this.meetingId = meetingId;
|
|
2779
|
+
this.roomName = roomName;
|
|
2780
|
+
this.roomUrl = roomUrl;
|
|
2781
|
+
this.startDate = startDate;
|
|
2782
|
+
this.endDate = endDate;
|
|
2783
|
+
this.hostRoomUrl = hostRoomUrl;
|
|
2784
|
+
this.viewerRoomUrl = viewerRoomUrl;
|
|
2785
|
+
}
|
|
2786
|
+
static fromJson(data) {
|
|
2787
|
+
return new Meeting({
|
|
2788
|
+
meetingId: extractString(data, "meetingId"),
|
|
2789
|
+
roomName: extractString(data, "roomName"),
|
|
2790
|
+
roomUrl: extractString(data, "roomUrl"),
|
|
2791
|
+
startDate: extractDate(data, "startDate"),
|
|
2792
|
+
endDate: extractDate(data, "endDate"),
|
|
2793
|
+
hostRoomUrl: extractNullOrString(data, "hostRoomUrl"),
|
|
2794
|
+
viewerRoomUrl: extractNullOrString(data, "viewerRoomUrl"),
|
|
2795
|
+
});
|
|
2796
|
+
}
|
|
2797
|
+
}
|
|
2798
|
+
|
|
2799
|
+
function createRoomUrl(roomName, path = "") {
|
|
2800
|
+
const encodedDisplayName = encodeURIComponent(roomName.substring(1));
|
|
2801
|
+
return `/room/${encodedDisplayName}${path}`;
|
|
2802
|
+
}
|
|
2803
|
+
class RoomService {
|
|
2804
|
+
constructor({ organizationApiClient }) {
|
|
2805
|
+
this._organizationApiClient = assertInstanceOf(organizationApiClient, OrganizationApiClient);
|
|
2806
|
+
}
|
|
2807
|
+
getRooms({ types, fields = [] } = {}) {
|
|
2808
|
+
assertArray(types, "types");
|
|
2809
|
+
assertArray(fields, "fields");
|
|
2810
|
+
return this._organizationApiClient
|
|
2811
|
+
.request("/room", {
|
|
2812
|
+
method: "GET",
|
|
2813
|
+
params: { types: types.join(","), fields: fields.join(","), includeOnlyLegacyRoomType: "false" },
|
|
2814
|
+
})
|
|
2815
|
+
.then(({ data }) => data.rooms.map((room) => new Room(room)));
|
|
2816
|
+
}
|
|
2817
|
+
getRoom({ roomName, fields }) {
|
|
2818
|
+
assertRoomName(roomName);
|
|
2819
|
+
const encodedDisplayName = encodeURIComponent(roomName.substring(1));
|
|
2820
|
+
return this._organizationApiClient
|
|
2821
|
+
.request(`/rooms/${encodedDisplayName}`, {
|
|
2822
|
+
method: "GET",
|
|
2823
|
+
params: Object.assign({ includeOnlyLegacyRoomType: "false" }, (fields && { fields: fields.join(",") })),
|
|
2824
|
+
})
|
|
2825
|
+
.then(({ data }) => new Room(Object.assign({}, data, Object.assign({ roomName }, (data.meeting && { meeting: Meeting.fromJson(data.meeting) })))))
|
|
2826
|
+
.catch((response) => {
|
|
2827
|
+
if (response.status === 404) {
|
|
2828
|
+
return new Room({
|
|
2829
|
+
roomName,
|
|
2830
|
+
isClaimed: false,
|
|
2831
|
+
mode: "normal",
|
|
2832
|
+
product: {
|
|
2833
|
+
categoryName: "personal_free",
|
|
2834
|
+
},
|
|
2835
|
+
type: "personal",
|
|
2836
|
+
legacyRoomType: "free",
|
|
2837
|
+
});
|
|
2838
|
+
}
|
|
2839
|
+
if (response.status === 400 && response.data.error === "Banned room") {
|
|
2840
|
+
return new Room({ roomName, isBanned: true });
|
|
2841
|
+
}
|
|
2842
|
+
throw new Error(response.data ? response.data.error : "Could not fetch room information");
|
|
2843
|
+
});
|
|
2844
|
+
}
|
|
2845
|
+
claimRoom({ roomName, type, mode, isLocked }) {
|
|
2846
|
+
assertRoomName(roomName);
|
|
2847
|
+
assertString(type, "type");
|
|
2848
|
+
return this._organizationApiClient
|
|
2849
|
+
.request("/room/claim", {
|
|
2850
|
+
method: "POST",
|
|
2851
|
+
data: Object.assign(Object.assign({ roomName,
|
|
2852
|
+
type }, (typeof mode === "string" && { mode })), (typeof isLocked === "boolean" && { isLocked })),
|
|
2853
|
+
})
|
|
2854
|
+
.then(() => undefined)
|
|
2855
|
+
.catch((response) => {
|
|
2856
|
+
throw new Error(response.data.error || "Failed to claim room");
|
|
2857
|
+
});
|
|
2858
|
+
}
|
|
2859
|
+
unclaimRoom(roomName) {
|
|
2860
|
+
assertRoomName(roomName);
|
|
2861
|
+
const encodedDisplayName = encodeURIComponent(roomName.substring(1));
|
|
2862
|
+
return this._organizationApiClient
|
|
2863
|
+
.request(`/room/${encodedDisplayName}`, {
|
|
2864
|
+
method: "DELETE",
|
|
2865
|
+
})
|
|
2866
|
+
.then(() => undefined);
|
|
2867
|
+
}
|
|
2868
|
+
renameRoom({ roomName, newRoomName }) {
|
|
2869
|
+
assertRoomName(roomName);
|
|
2870
|
+
assertString(newRoomName, "newRoomName");
|
|
2871
|
+
const encodedRoomName = encodeURIComponent(roomName.substring(1));
|
|
2872
|
+
return this._organizationApiClient
|
|
2873
|
+
.request(`/room/${encodedRoomName}/roomName`, {
|
|
2874
|
+
method: "PUT",
|
|
2875
|
+
data: { newRoomName },
|
|
2876
|
+
})
|
|
2877
|
+
.then(() => undefined);
|
|
2878
|
+
}
|
|
2879
|
+
changeMode({ roomName, mode }) {
|
|
2880
|
+
assertRoomName(roomName);
|
|
2881
|
+
assertString(mode, "mode");
|
|
2882
|
+
const encodedDisplayName = encodeURIComponent(roomName.substring(1));
|
|
2883
|
+
return this._organizationApiClient
|
|
2884
|
+
.request(`/room/${encodedDisplayName}/mode`, {
|
|
2885
|
+
method: "PUT",
|
|
2886
|
+
data: { mode },
|
|
2887
|
+
})
|
|
2888
|
+
.then(() => undefined);
|
|
2889
|
+
}
|
|
2890
|
+
updatePreferences({ roomName, preferences }) {
|
|
2891
|
+
assertRoomName(roomName);
|
|
2892
|
+
assertInstanceOf(preferences, Object, "preferences");
|
|
2893
|
+
const encodedDisplayName = encodeURIComponent(roomName.substring(1));
|
|
2894
|
+
return this._organizationApiClient
|
|
2895
|
+
.request(`/room/${encodedDisplayName}/preferences`, {
|
|
2896
|
+
method: "PATCH",
|
|
2897
|
+
data: preferences,
|
|
2898
|
+
})
|
|
2899
|
+
.then(() => undefined);
|
|
2900
|
+
}
|
|
2901
|
+
updateProtectedPreferences({ roomName, preferences }) {
|
|
2902
|
+
assertRoomName(roomName);
|
|
2903
|
+
assertInstanceOf(preferences, Object, "preferences");
|
|
2904
|
+
const encodedDisplayName = encodeURIComponent(roomName.substring(1));
|
|
2905
|
+
return this._organizationApiClient
|
|
2906
|
+
.request(`/room/${encodedDisplayName}/protected-preferences`, {
|
|
2907
|
+
method: "PATCH",
|
|
2908
|
+
data: preferences,
|
|
2909
|
+
})
|
|
2910
|
+
.then(() => undefined);
|
|
2911
|
+
}
|
|
2912
|
+
getRoomPermissions(roomName, { roomKey } = {}) {
|
|
2913
|
+
assertRoomName(roomName);
|
|
2914
|
+
return this._organizationApiClient
|
|
2915
|
+
.request(createRoomUrl(roomName, "/permissions"), Object.assign({ method: "GET" }, (roomKey && { headers: { "X-Whereby-Room-Key": roomKey } })))
|
|
2916
|
+
.then((response) => {
|
|
2917
|
+
const { permissions, limits } = response.data;
|
|
2918
|
+
return {
|
|
2919
|
+
permissions,
|
|
2920
|
+
limits,
|
|
2921
|
+
};
|
|
2922
|
+
});
|
|
2923
|
+
}
|
|
2924
|
+
getRoomMetrics({ roomName, metrics, from, to }) {
|
|
2925
|
+
assertRoomName(roomName);
|
|
2926
|
+
assertString(metrics, "metrics");
|
|
2927
|
+
return this._organizationApiClient
|
|
2928
|
+
.request(createRoomUrl(roomName, "/metrics"), {
|
|
2929
|
+
method: "GET",
|
|
2930
|
+
params: { metrics, from, to },
|
|
2931
|
+
})
|
|
2932
|
+
.then((response) => response.data);
|
|
2933
|
+
}
|
|
2934
|
+
changeType({ roomName, type }) {
|
|
2935
|
+
assertRoomName(roomName);
|
|
2936
|
+
assertOneOf(type, ["personal", "personal_xl"], "type");
|
|
2937
|
+
const encodedDisplayName = encodeURIComponent(roomName.substring(1));
|
|
2938
|
+
return this._organizationApiClient
|
|
2939
|
+
.request(`/room/${encodedDisplayName}/type`, {
|
|
2940
|
+
method: "PUT",
|
|
2941
|
+
data: { type },
|
|
2942
|
+
})
|
|
2943
|
+
.then(() => undefined);
|
|
2944
|
+
}
|
|
2945
|
+
getForestSocialImage({ roomName, count }) {
|
|
2946
|
+
assertRoomName(roomName);
|
|
2947
|
+
assertNumber(count, "count");
|
|
2948
|
+
return this._organizationApiClient
|
|
2949
|
+
.request(createRoomUrl(roomName, `/forest-social-image/${count}`), {
|
|
2950
|
+
method: "GET",
|
|
2951
|
+
})
|
|
2952
|
+
.then((response) => response.data.imageUrl);
|
|
2953
|
+
}
|
|
2954
|
+
}
|
|
2955
|
+
|
|
2956
|
+
class RoomParticipant {
|
|
2957
|
+
constructor({ displayName, id, stream, isAudioEnabled, isVideoEnabled }) {
|
|
2958
|
+
this.isLocalParticipant = false;
|
|
2959
|
+
this.displayName = displayName;
|
|
2960
|
+
this.id = id;
|
|
2961
|
+
this.stream = stream;
|
|
2962
|
+
this.isAudioEnabled = isAudioEnabled;
|
|
2963
|
+
this.isVideoEnabled = isVideoEnabled;
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2966
|
+
class LocalParticipant extends RoomParticipant {
|
|
2967
|
+
constructor({ displayName, id, stream, isAudioEnabled, isVideoEnabled }) {
|
|
2968
|
+
super({ displayName, id, stream, isAudioEnabled, isVideoEnabled });
|
|
2969
|
+
this.isLocalParticipant = true;
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
|
|
2973
|
+
const sdkVersion = "0.8.0";
|
|
2974
|
+
|
|
2975
|
+
const API_BASE_URL = "https://api.whereby.dev" ;
|
|
2976
|
+
function createServices() {
|
|
2977
|
+
const credentialsService = CredentialsService.create({ baseUrl: API_BASE_URL });
|
|
2978
|
+
const apiClient = new ApiClient({
|
|
2979
|
+
fetchDeviceCredentials: credentialsService.getCredentials.bind(credentialsService),
|
|
2980
|
+
baseUrl: API_BASE_URL,
|
|
2981
|
+
});
|
|
2982
|
+
const organizationService = new OrganizationService({ apiClient });
|
|
2983
|
+
const fetchOrganizationFromRoomUrl = (roomUrl) => {
|
|
2984
|
+
const roomUrlObj = new URL(roomUrl);
|
|
2985
|
+
const urls = media.fromLocation({ host: roomUrlObj.host });
|
|
2986
|
+
const organizationServiceCache = new OrganizationServiceCache({
|
|
2987
|
+
organizationService,
|
|
2988
|
+
subdomain: urls.subdomain,
|
|
2989
|
+
});
|
|
2990
|
+
return organizationServiceCache.fetchOrganization();
|
|
2991
|
+
};
|
|
2992
|
+
return {
|
|
2993
|
+
credentialsService,
|
|
2994
|
+
apiClient,
|
|
2995
|
+
organizationService,
|
|
2996
|
+
fetchOrganizationFromRoomUrl,
|
|
2997
|
+
};
|
|
2998
|
+
}
|
|
2999
|
+
|
|
3000
|
+
exports.ApiClient = ApiClient;
|
|
3001
|
+
exports.Credentials = Credentials;
|
|
3002
|
+
exports.CredentialsService = CredentialsService;
|
|
3003
|
+
exports.LocalParticipant = LocalParticipant;
|
|
3004
|
+
exports.OrganizationApiClient = OrganizationApiClient;
|
|
3005
|
+
exports.OrganizationService = OrganizationService;
|
|
3006
|
+
exports.OrganizationServiceCache = OrganizationServiceCache;
|
|
3007
|
+
exports.RoomService = RoomService;
|
|
3008
|
+
exports.addAppListener = addAppListener;
|
|
3009
|
+
exports.appLeft = appLeft;
|
|
3010
|
+
exports.appSlice = appSlice;
|
|
3011
|
+
exports.chatSlice = chatSlice;
|
|
3012
|
+
exports.cloudRecordingSlice = cloudRecordingSlice;
|
|
3013
|
+
exports.createAppAsyncThunk = createAppAsyncThunk;
|
|
3014
|
+
exports.createAppThunk = createAppThunk;
|
|
3015
|
+
exports.createReactor = createReactor;
|
|
3016
|
+
exports.createServices = createServices;
|
|
3017
|
+
exports.createStore = createStore;
|
|
3018
|
+
exports.createWebRtcEmitter = createWebRtcEmitter;
|
|
3019
|
+
exports.deviceBusy = deviceBusy;
|
|
3020
|
+
exports.deviceCredentialsSlice = deviceCredentialsSlice;
|
|
3021
|
+
exports.deviceIdentified = deviceIdentified;
|
|
3022
|
+
exports.deviceIdentifying = deviceIdentifying;
|
|
3023
|
+
exports.doAcceptWaitingParticipant = doAcceptWaitingParticipant;
|
|
3024
|
+
exports.doAppJoin = doAppJoin;
|
|
3025
|
+
exports.doConnectRoom = doConnectRoom;
|
|
3026
|
+
exports.doConnectRtc = doConnectRtc;
|
|
3027
|
+
exports.doDisconnectRtc = doDisconnectRtc;
|
|
3028
|
+
exports.doEnableAudio = doEnableAudio;
|
|
3029
|
+
exports.doEnableVideo = doEnableVideo;
|
|
3030
|
+
exports.doGetDeviceCredentials = doGetDeviceCredentials;
|
|
3031
|
+
exports.doHandleAcceptStreams = doHandleAcceptStreams;
|
|
3032
|
+
exports.doHandleStreamingStarted = doHandleStreamingStarted;
|
|
3033
|
+
exports.doHandleStreamingStopped = doHandleStreamingStopped;
|
|
3034
|
+
exports.doKnockRoom = doKnockRoom;
|
|
3035
|
+
exports.doOrganizationFetch = doOrganizationFetch;
|
|
3036
|
+
exports.doRejectWaitingParticipant = doRejectWaitingParticipant;
|
|
3037
|
+
exports.doRtcAnalyticsCustomEventsInitialize = doRtcAnalyticsCustomEventsInitialize;
|
|
3038
|
+
exports.doRtcManagerCreated = doRtcManagerCreated;
|
|
3039
|
+
exports.doRtcManagerInitialize = doRtcManagerInitialize;
|
|
3040
|
+
exports.doRtcReportStreamResolution = doRtcReportStreamResolution;
|
|
3041
|
+
exports.doSendChatMessage = doSendChatMessage;
|
|
3042
|
+
exports.doSetDevice = doSetDevice;
|
|
3043
|
+
exports.doSetDisplayName = doSetDisplayName;
|
|
3044
|
+
exports.doSetLocalParticipant = doSetLocalParticipant;
|
|
3045
|
+
exports.doSignalDisconnect = doSignalDisconnect;
|
|
3046
|
+
exports.doSignalIdentifyDevice = doSignalIdentifyDevice;
|
|
3047
|
+
exports.doSignalReconnect = doSignalReconnect;
|
|
3048
|
+
exports.doSignalSocketConnect = doSignalSocketConnect;
|
|
3049
|
+
exports.doStartCloudRecording = doStartCloudRecording;
|
|
3050
|
+
exports.doStartLocalMedia = doStartLocalMedia;
|
|
3051
|
+
exports.doStartScreenshare = doStartScreenshare;
|
|
3052
|
+
exports.doStopCloudRecording = doStopCloudRecording;
|
|
3053
|
+
exports.doStopLocalMedia = doStopLocalMedia;
|
|
3054
|
+
exports.doStopScreenshare = doStopScreenshare;
|
|
3055
|
+
exports.doSwitchLocalStream = doSwitchLocalStream;
|
|
3056
|
+
exports.doToggleCamera = doToggleCamera;
|
|
3057
|
+
exports.doUpdateDeviceList = doUpdateDeviceList;
|
|
3058
|
+
exports.initialCloudRecordingState = initialCloudRecordingState;
|
|
3059
|
+
exports.initialLocalMediaState = initialLocalMediaState;
|
|
3060
|
+
exports.isAcceptingStreams = isAcceptingStreams;
|
|
3061
|
+
exports.listenerMiddleware = listenerMiddleware;
|
|
3062
|
+
exports.localMediaSlice = localMediaSlice;
|
|
3063
|
+
exports.localMediaStopped = localMediaStopped;
|
|
3064
|
+
exports.localParticipantSlice = localParticipantSlice;
|
|
3065
|
+
exports.localScreenshareSlice = localScreenshareSlice;
|
|
3066
|
+
exports.localStreamMetadataUpdated = localStreamMetadataUpdated;
|
|
3067
|
+
exports.observeStore = observeStore;
|
|
3068
|
+
exports.organizationSlice = organizationSlice;
|
|
3069
|
+
exports.participantStreamAdded = participantStreamAdded;
|
|
3070
|
+
exports.participantStreamIdAdded = participantStreamIdAdded;
|
|
3071
|
+
exports.recordingRequestStarted = recordingRequestStarted;
|
|
3072
|
+
exports.remoteParticipantsSlice = remoteParticipantsSlice;
|
|
3073
|
+
exports.resolutionReported = resolutionReported;
|
|
3074
|
+
exports.roomConnectionSlice = roomConnectionSlice;
|
|
3075
|
+
exports.rootReducer = rootReducer;
|
|
3076
|
+
exports.rtcAnalyticsCustomEvents = rtcAnalyticsCustomEvents;
|
|
3077
|
+
exports.rtcAnalyticsSlice = rtcAnalyticsSlice;
|
|
3078
|
+
exports.rtcConnectionSlice = rtcConnectionSlice;
|
|
3079
|
+
exports.rtcDisconnected = rtcDisconnected;
|
|
3080
|
+
exports.rtcDispatcherCreated = rtcDispatcherCreated;
|
|
3081
|
+
exports.rtcManagerCreated = rtcManagerCreated;
|
|
3082
|
+
exports.rtcManagerDestroyed = rtcManagerDestroyed;
|
|
3083
|
+
exports.rtcManagerInitialized = rtcManagerInitialized;
|
|
3084
|
+
exports.sdkVersion = sdkVersion;
|
|
3085
|
+
exports.selectAppDisplayName = selectAppDisplayName;
|
|
3086
|
+
exports.selectAppExternalId = selectAppExternalId;
|
|
3087
|
+
exports.selectAppIsNodeSdk = selectAppIsNodeSdk;
|
|
3088
|
+
exports.selectAppRaw = selectAppRaw;
|
|
3089
|
+
exports.selectAppRoomKey = selectAppRoomKey;
|
|
3090
|
+
exports.selectAppRoomName = selectAppRoomName;
|
|
3091
|
+
exports.selectAppRoomUrl = selectAppRoomUrl;
|
|
3092
|
+
exports.selectAppSdkVersion = selectAppSdkVersion;
|
|
3093
|
+
exports.selectAppWantsToJoin = selectAppWantsToJoin;
|
|
3094
|
+
exports.selectBusyDeviceIds = selectBusyDeviceIds;
|
|
3095
|
+
exports.selectCameraDeviceError = selectCameraDeviceError;
|
|
3096
|
+
exports.selectCameraDevices = selectCameraDevices;
|
|
3097
|
+
exports.selectChatMessages = selectChatMessages;
|
|
3098
|
+
exports.selectChatRaw = selectChatRaw;
|
|
3099
|
+
exports.selectCloudRecordingError = selectCloudRecordingError;
|
|
3100
|
+
exports.selectCloudRecordingRaw = selectCloudRecordingRaw;
|
|
3101
|
+
exports.selectCloudRecordingStartedAt = selectCloudRecordingStartedAt;
|
|
3102
|
+
exports.selectCloudRecordingStatus = selectCloudRecordingStatus;
|
|
3103
|
+
exports.selectCurrentCameraDeviceId = selectCurrentCameraDeviceId;
|
|
3104
|
+
exports.selectCurrentMicrophoneDeviceId = selectCurrentMicrophoneDeviceId;
|
|
3105
|
+
exports.selectDeviceCredentialsRaw = selectDeviceCredentialsRaw;
|
|
3106
|
+
exports.selectDeviceId = selectDeviceId;
|
|
3107
|
+
exports.selectHasFetchedDeviceCredentials = selectHasFetchedDeviceCredentials;
|
|
3108
|
+
exports.selectIsAcceptingStreams = selectIsAcceptingStreams;
|
|
3109
|
+
exports.selectIsCameraEnabled = selectIsCameraEnabled;
|
|
3110
|
+
exports.selectIsCloudRecording = selectIsCloudRecording;
|
|
3111
|
+
exports.selectIsLocalMediaStarting = selectIsLocalMediaStarting;
|
|
3112
|
+
exports.selectIsMicrophoneEnabled = selectIsMicrophoneEnabled;
|
|
3113
|
+
exports.selectIsSettingCameraDevice = selectIsSettingCameraDevice;
|
|
3114
|
+
exports.selectIsSettingMicrophoneDevice = selectIsSettingMicrophoneDevice;
|
|
3115
|
+
exports.selectIsToggleCamera = selectIsToggleCamera;
|
|
3116
|
+
exports.selectLocalMediaConstraintsOptions = selectLocalMediaConstraintsOptions;
|
|
3117
|
+
exports.selectLocalMediaDevices = selectLocalMediaDevices;
|
|
3118
|
+
exports.selectLocalMediaIsSwitchingStream = selectLocalMediaIsSwitchingStream;
|
|
3119
|
+
exports.selectLocalMediaOptions = selectLocalMediaOptions;
|
|
3120
|
+
exports.selectLocalMediaOwnsStream = selectLocalMediaOwnsStream;
|
|
3121
|
+
exports.selectLocalMediaRaw = selectLocalMediaRaw;
|
|
3122
|
+
exports.selectLocalMediaShouldStartWithOptions = selectLocalMediaShouldStartWithOptions;
|
|
3123
|
+
exports.selectLocalMediaShouldStop = selectLocalMediaShouldStop;
|
|
3124
|
+
exports.selectLocalMediaStartError = selectLocalMediaStartError;
|
|
3125
|
+
exports.selectLocalMediaStatus = selectLocalMediaStatus;
|
|
3126
|
+
exports.selectLocalMediaStream = selectLocalMediaStream;
|
|
3127
|
+
exports.selectLocalParticipantClientClaim = selectLocalParticipantClientClaim;
|
|
3128
|
+
exports.selectLocalParticipantIsScreenSharing = selectLocalParticipantIsScreenSharing;
|
|
3129
|
+
exports.selectLocalParticipantRaw = selectLocalParticipantRaw;
|
|
3130
|
+
exports.selectLocalParticipantRole = selectLocalParticipantRole;
|
|
3131
|
+
exports.selectLocalScreenshareRaw = selectLocalScreenshareRaw;
|
|
3132
|
+
exports.selectLocalScreenshareStatus = selectLocalScreenshareStatus;
|
|
3133
|
+
exports.selectLocalScreenshareStream = selectLocalScreenshareStream;
|
|
3134
|
+
exports.selectMicrophoneDeviceError = selectMicrophoneDeviceError;
|
|
3135
|
+
exports.selectMicrophoneDevices = selectMicrophoneDevices;
|
|
3136
|
+
exports.selectOrganizationId = selectOrganizationId;
|
|
3137
|
+
exports.selectOrganizationRaw = selectOrganizationRaw;
|
|
3138
|
+
exports.selectRemoteParticipants = selectRemoteParticipants;
|
|
3139
|
+
exports.selectRemoteParticipantsRaw = selectRemoteParticipantsRaw;
|
|
3140
|
+
exports.selectRoomConnectionError = selectRoomConnectionError;
|
|
3141
|
+
exports.selectRoomConnectionRaw = selectRoomConnectionRaw;
|
|
3142
|
+
exports.selectRoomConnectionSession = selectRoomConnectionSession;
|
|
3143
|
+
exports.selectRoomConnectionSessionId = selectRoomConnectionSessionId;
|
|
3144
|
+
exports.selectRoomConnectionStatus = selectRoomConnectionStatus;
|
|
3145
|
+
exports.selectRtcConnectionRaw = selectRtcConnectionRaw;
|
|
3146
|
+
exports.selectRtcDispatcherCreated = selectRtcDispatcherCreated;
|
|
3147
|
+
exports.selectRtcIsCreatingDispatcher = selectRtcIsCreatingDispatcher;
|
|
3148
|
+
exports.selectRtcManager = selectRtcManager;
|
|
3149
|
+
exports.selectRtcManagerInitialized = selectRtcManagerInitialized;
|
|
3150
|
+
exports.selectRtcStatus = selectRtcStatus;
|
|
3151
|
+
exports.selectScreenshares = selectScreenshares;
|
|
3152
|
+
exports.selectSelfId = selectSelfId;
|
|
3153
|
+
exports.selectShouldConnectRoom = selectShouldConnectRoom;
|
|
3154
|
+
exports.selectShouldConnectRtc = selectShouldConnectRtc;
|
|
3155
|
+
exports.selectShouldConnectSignal = selectShouldConnectSignal;
|
|
3156
|
+
exports.selectShouldDisconnectRtc = selectShouldDisconnectRtc;
|
|
3157
|
+
exports.selectShouldFetchDeviceCredentials = selectShouldFetchDeviceCredentials;
|
|
3158
|
+
exports.selectShouldFetchOrganization = selectShouldFetchOrganization;
|
|
3159
|
+
exports.selectShouldIdentifyDevice = selectShouldIdentifyDevice;
|
|
3160
|
+
exports.selectShouldInitializeRtc = selectShouldInitializeRtc;
|
|
3161
|
+
exports.selectSignalConnectionDeviceIdentified = selectSignalConnectionDeviceIdentified;
|
|
3162
|
+
exports.selectSignalConnectionRaw = selectSignalConnectionRaw;
|
|
3163
|
+
exports.selectSignalConnectionSocket = selectSignalConnectionSocket;
|
|
3164
|
+
exports.selectSignalIsIdentifyingDevice = selectSignalIsIdentifyingDevice;
|
|
3165
|
+
exports.selectSignalStatus = selectSignalStatus;
|
|
3166
|
+
exports.selectSpeakerDevices = selectSpeakerDevices;
|
|
3167
|
+
exports.selectStreamingRaw = selectStreamingRaw;
|
|
3168
|
+
exports.selectStreamsToAccept = selectStreamsToAccept;
|
|
3169
|
+
exports.selectWaitingParticipants = selectWaitingParticipants;
|
|
3170
|
+
exports.selectWaitingParticipantsRaw = selectWaitingParticipantsRaw;
|
|
3171
|
+
exports.setCurrentCameraDeviceId = setCurrentCameraDeviceId;
|
|
3172
|
+
exports.setCurrentMicrophoneDeviceId = setCurrentMicrophoneDeviceId;
|
|
3173
|
+
exports.setLocalMediaOptions = setLocalMediaOptions;
|
|
3174
|
+
exports.setLocalMediaStream = setLocalMediaStream;
|
|
3175
|
+
exports.setRoomKey = setRoomKey;
|
|
3176
|
+
exports.signalConnectionSlice = signalConnectionSlice;
|
|
3177
|
+
exports.socketConnected = socketConnected;
|
|
3178
|
+
exports.socketConnecting = socketConnecting;
|
|
3179
|
+
exports.socketDisconnected = socketDisconnected;
|
|
3180
|
+
exports.socketReconnecting = socketReconnecting;
|
|
3181
|
+
exports.startAppListening = startAppListening;
|
|
3182
|
+
exports.stopScreenshare = stopScreenshare;
|
|
3183
|
+
exports.streamStatusUpdated = streamStatusUpdated;
|
|
3184
|
+
exports.streamingSlice = streamingSlice;
|
|
3185
|
+
exports.toggleCameraEnabled = toggleCameraEnabled;
|
|
3186
|
+
exports.toggleMicrophoneEnabled = toggleMicrophoneEnabled;
|
|
3187
|
+
exports.updateReportedValues = updateReportedValues;
|
|
3188
|
+
exports.waitingParticipantsSlice = waitingParticipantsSlice;
|