@whereby.com/browser-sdk 2.0.0-alpha2 → 2.0.0-alpha21
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/README.md +94 -20
- package/dist/{lib.cjs.js → lib.cjs} +1073 -351
- package/dist/lib.esm.js +1072 -352
- package/dist/types.d.ts +290 -12
- package/dist/v2-alpha21.js +43 -0
- package/package.json +82 -80
- package/dist/v2-alpha2.js +0 -105
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var heresy = require('heresy');
|
|
6
|
-
var React = require('react');
|
|
7
6
|
var tslib = require('tslib');
|
|
7
|
+
var React = require('react');
|
|
8
|
+
var assert = require('assert');
|
|
8
9
|
var adapter = require('webrtc-adapter');
|
|
9
10
|
var io = require('socket.io-client');
|
|
10
11
|
var SDPUtils = require('sdp');
|
|
11
|
-
var assert = require('assert');
|
|
12
12
|
var mediasoupClient = require('mediasoup-client');
|
|
13
13
|
var EventEmitter = require('events');
|
|
14
14
|
var uuid = require('uuid');
|
|
@@ -18,10 +18,10 @@ var axios = require('axios');
|
|
|
18
18
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
19
19
|
|
|
20
20
|
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
21
|
+
var assert__default = /*#__PURE__*/_interopDefaultLegacy(assert);
|
|
21
22
|
var adapter__default = /*#__PURE__*/_interopDefaultLegacy(adapter);
|
|
22
23
|
var io__default = /*#__PURE__*/_interopDefaultLegacy(io);
|
|
23
24
|
var SDPUtils__default = /*#__PURE__*/_interopDefaultLegacy(SDPUtils);
|
|
24
|
-
var assert__default = /*#__PURE__*/_interopDefaultLegacy(assert);
|
|
25
25
|
var EventEmitter__default = /*#__PURE__*/_interopDefaultLegacy(EventEmitter);
|
|
26
26
|
var nodeBtoa__default = /*#__PURE__*/_interopDefaultLegacy(nodeBtoa);
|
|
27
27
|
var axios__default = /*#__PURE__*/_interopDefaultLegacy(axios);
|
|
@@ -94,8 +94,7 @@ heresy.define("WherebyEmbed", {
|
|
|
94
94
|
// Commands
|
|
95
95
|
_postCommand(command, args = []) {
|
|
96
96
|
if (this.iframe.current) {
|
|
97
|
-
|
|
98
|
-
this.iframe.current.contentWindow.postMessage({ command, args }, url.origin);
|
|
97
|
+
this.iframe.current.contentWindow.postMessage({ command, args }, this.url.origin);
|
|
99
98
|
}
|
|
100
99
|
},
|
|
101
100
|
startRecording() {
|
|
@@ -114,8 +113,7 @@ heresy.define("WherebyEmbed", {
|
|
|
114
113
|
this._postCommand("toggle_screenshare", [enabled]);
|
|
115
114
|
},
|
|
116
115
|
onmessage({ origin, data }) {
|
|
117
|
-
|
|
118
|
-
if (origin !== url.origin)
|
|
116
|
+
if (origin !== this.url.origin)
|
|
119
117
|
return;
|
|
120
118
|
const { type, payload: detail } = data;
|
|
121
119
|
this.dispatchEvent(new CustomEvent(type, { detail }));
|
|
@@ -125,36 +123,354 @@ heresy.define("WherebyEmbed", {
|
|
|
125
123
|
if (!room)
|
|
126
124
|
return this.html `Whereby: Missing room attribute.`;
|
|
127
125
|
// Get subdomain from room URL, or use it specified
|
|
128
|
-
const m = /https:\/\/([^.]+)\.whereby.com\/.+/.exec(room);
|
|
126
|
+
const m = /https:\/\/([^.]+)(\.whereby.com|-ip-\d+-\d+-\d+-\d+.hereby.dev:4443)\/.+/.exec(room);
|
|
129
127
|
const subdomain = (m && m[1]) || this.subdomain;
|
|
130
128
|
if (!subdomain)
|
|
131
129
|
return this.html `Whereby: Missing subdomain attr.`;
|
|
132
|
-
|
|
133
|
-
|
|
130
|
+
if (!m) {
|
|
131
|
+
return this.html `could not parse URL.`;
|
|
132
|
+
}
|
|
133
|
+
const baseURL = m[2] || `.whereby.com`;
|
|
134
|
+
this.url = new URL(room, `https://${subdomain}${baseURL}`);
|
|
135
|
+
const roomUrl = new URL(room);
|
|
136
|
+
if (roomUrl.searchParams.get("roomKey")) {
|
|
137
|
+
this.url.searchParams.append("roomKey", roomUrl.searchParams.get("roomKey"));
|
|
138
|
+
}
|
|
139
|
+
Object.entries(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ jsApi: true, we: "2.0.0-alpha21", iframeSource: subdomain }, (displayName && { displayName })), (lang && { lang })), (metadata && { metadata })), (groups && { groups })), (virtualBackgroundUrl && { virtualBackgroundUrl })), (avatarUrl && { avatarUrl })), (minimal != null && { embed: minimal })), boolAttrs.reduce(
|
|
134
140
|
// add to URL if set in any way
|
|
135
141
|
(o, v) => (this[v.toLowerCase()] != null ? Object.assign(Object.assign({}, o), { [v]: this[v.toLowerCase()] }) : o), {}))).forEach(([k, v]) => {
|
|
136
|
-
if (!url.searchParams.has(k) && typeof v === "string") {
|
|
137
|
-
url.searchParams.set(k, v);
|
|
142
|
+
if (!this.url.searchParams.has(k) && typeof v === "string") {
|
|
143
|
+
this.url.searchParams.set(k, v);
|
|
138
144
|
}
|
|
139
145
|
});
|
|
140
146
|
return this.html `
|
|
141
147
|
<iframe
|
|
142
148
|
ref=${this.iframe}
|
|
143
|
-
src=${url}
|
|
149
|
+
src=${this.url}
|
|
144
150
|
allow="autoplay; camera; microphone; fullscreen; speaker; display-capture" />
|
|
145
151
|
`;
|
|
146
152
|
},
|
|
147
153
|
});
|
|
148
154
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
155
|
+
/**
|
|
156
|
+
* Debounce function.
|
|
157
|
+
*
|
|
158
|
+
* @param {Function} fn - Function to debounce.
|
|
159
|
+
* @param {Object} [options] - Options.
|
|
160
|
+
* @param {number} [options.delay=500] - Delay in milliseconds.
|
|
161
|
+
* @param {boolean} [options.edges=false] - Whether to call the function on the
|
|
162
|
+
* leading and trailing edges of the wait timeout.
|
|
163
|
+
* @returns {Function} Debounced function.
|
|
164
|
+
*/
|
|
165
|
+
function debounce(fn, { delay = 500, edges } = {}) {
|
|
166
|
+
assert__default["default"].ok(typeof fn === "function", "fn<function> is required");
|
|
167
|
+
let timeout;
|
|
168
|
+
let nCalls = 0;
|
|
169
|
+
return (...args) => {
|
|
170
|
+
nCalls += 1;
|
|
171
|
+
if (edges && nCalls === 1) {
|
|
172
|
+
fn(...args);
|
|
153
173
|
}
|
|
154
|
-
|
|
155
|
-
|
|
174
|
+
clearTimeout(timeout);
|
|
175
|
+
timeout = setTimeout(() => {
|
|
176
|
+
if (!edges || nCalls > 1) {
|
|
177
|
+
fn(...args);
|
|
178
|
+
}
|
|
179
|
+
timeout = undefined;
|
|
180
|
+
nCalls = 0;
|
|
181
|
+
}, delay);
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
var VideoView = (_a) => {
|
|
186
|
+
var { muted, stream, onResize } = _a, rest = tslib.__rest(_a, ["muted", "stream", "onResize"]);
|
|
187
|
+
const videoEl = React.useRef(null);
|
|
188
|
+
React.useEffect(() => {
|
|
189
|
+
if (!videoEl.current || !onResize) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const resizeObserver = new ResizeObserver(debounce(() => {
|
|
193
|
+
if (videoEl.current && (stream === null || stream === void 0 ? void 0 : stream.id)) {
|
|
194
|
+
onResize({
|
|
195
|
+
width: videoEl.current.clientWidth,
|
|
196
|
+
height: videoEl.current.clientHeight,
|
|
197
|
+
stream,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}, { delay: 1000, edges: true }));
|
|
201
|
+
resizeObserver.observe(videoEl.current);
|
|
202
|
+
return () => {
|
|
203
|
+
resizeObserver.disconnect();
|
|
204
|
+
};
|
|
205
|
+
}, [stream]);
|
|
206
|
+
React.useEffect(() => {
|
|
207
|
+
if (!videoEl.current) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (videoEl.current.srcObject !== stream) {
|
|
211
|
+
videoEl.current.srcObject = stream;
|
|
212
|
+
}
|
|
213
|
+
// Handle muting programatically, not as video attribute
|
|
214
|
+
// https://stackoverflow.com/questions/14111917/html5-video-muted-but-still-playing
|
|
215
|
+
if (videoEl.current.muted !== muted) {
|
|
216
|
+
videoEl.current.muted = Boolean(muted);
|
|
217
|
+
}
|
|
218
|
+
}, [muted, stream, videoEl]);
|
|
219
|
+
return React__default["default"].createElement("video", Object.assign({ ref: videoEl, autoPlay: true, playsInline: true }, rest));
|
|
156
220
|
};
|
|
157
221
|
|
|
222
|
+
const TypedLocalMediaEventTarget = EventTarget;
|
|
223
|
+
class LocalMedia extends TypedLocalMediaEventTarget {
|
|
224
|
+
constructor(constraints) {
|
|
225
|
+
super();
|
|
226
|
+
this._constraints = constraints;
|
|
227
|
+
this.stream = new MediaStream();
|
|
228
|
+
this._rtcManagers = [];
|
|
229
|
+
this.screenshareStream = undefined;
|
|
230
|
+
navigator.mediaDevices.addEventListener("devicechange", this._updateDeviceList.bind(this));
|
|
231
|
+
}
|
|
232
|
+
addRtcManager(rtcManager) {
|
|
233
|
+
this._rtcManagers.push(rtcManager);
|
|
234
|
+
}
|
|
235
|
+
removeRtcManager(rtcManager) {
|
|
236
|
+
this._rtcManagers = this._rtcManagers.filter((r) => r !== rtcManager);
|
|
237
|
+
}
|
|
238
|
+
getCameraDeviceId() {
|
|
239
|
+
var _a;
|
|
240
|
+
return (_a = this.stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
|
|
241
|
+
}
|
|
242
|
+
getMicrophoneDeviceId() {
|
|
243
|
+
var _a;
|
|
244
|
+
return (_a = this.stream.getAudioTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
|
|
245
|
+
}
|
|
246
|
+
isCameraEnabled() {
|
|
247
|
+
var _a;
|
|
248
|
+
return !!((_a = this.stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.enabled);
|
|
249
|
+
}
|
|
250
|
+
isMicrophoneEnabled() {
|
|
251
|
+
var _a;
|
|
252
|
+
return !!((_a = this.stream.getAudioTracks()[0]) === null || _a === void 0 ? void 0 : _a.enabled);
|
|
253
|
+
}
|
|
254
|
+
toggleCameraEnabled(enabled) {
|
|
255
|
+
const videoTrack = this.stream.getVideoTracks()[0];
|
|
256
|
+
if (!videoTrack) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const newValue = enabled !== null && enabled !== void 0 ? enabled : !videoTrack.enabled;
|
|
260
|
+
videoTrack.enabled = newValue;
|
|
261
|
+
this.dispatchEvent(new CustomEvent("camera_enabled", { detail: { enabled: newValue } }));
|
|
262
|
+
}
|
|
263
|
+
toggleMichrophoneEnabled(enabled) {
|
|
264
|
+
const audioTrack = this.stream.getAudioTracks()[0];
|
|
265
|
+
if (!audioTrack) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const newValue = enabled !== null && enabled !== void 0 ? enabled : !audioTrack.enabled;
|
|
269
|
+
audioTrack.enabled = newValue;
|
|
270
|
+
this.dispatchEvent(new CustomEvent("microphone_enabled", { detail: { enabled: newValue } }));
|
|
271
|
+
}
|
|
272
|
+
startScreenshare() {
|
|
273
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
274
|
+
if (this.screenshareStream) {
|
|
275
|
+
return this.screenshareStream;
|
|
276
|
+
}
|
|
277
|
+
const screenshareStream = yield navigator.mediaDevices.getDisplayMedia();
|
|
278
|
+
this.screenshareStream = screenshareStream;
|
|
279
|
+
return this.screenshareStream;
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
stopScreenshare() {
|
|
283
|
+
var _a;
|
|
284
|
+
(_a = this.screenshareStream) === null || _a === void 0 ? void 0 : _a.getTracks().forEach((track) => track.stop());
|
|
285
|
+
this.screenshareStream = undefined;
|
|
286
|
+
}
|
|
287
|
+
setCameraDevice(deviceId) {
|
|
288
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
289
|
+
const newStream = yield navigator.mediaDevices.getUserMedia({ video: { deviceId } });
|
|
290
|
+
const newVideoTrack = newStream.getVideoTracks()[0];
|
|
291
|
+
if (newVideoTrack) {
|
|
292
|
+
const oldVideoTrack = this.stream.getVideoTracks()[0];
|
|
293
|
+
newVideoTrack.enabled = oldVideoTrack.enabled;
|
|
294
|
+
oldVideoTrack === null || oldVideoTrack === void 0 ? void 0 : oldVideoTrack.stop();
|
|
295
|
+
this._rtcManagers.forEach((rtcManager) => {
|
|
296
|
+
rtcManager.replaceTrack(oldVideoTrack, newVideoTrack);
|
|
297
|
+
});
|
|
298
|
+
this.stream.removeTrack(oldVideoTrack);
|
|
299
|
+
this.stream.addTrack(newVideoTrack);
|
|
300
|
+
}
|
|
301
|
+
this.dispatchEvent(new CustomEvent("stream_updated", {
|
|
302
|
+
detail: { stream: this.stream },
|
|
303
|
+
}));
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
setMicrophoneDevice(deviceId) {
|
|
307
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
308
|
+
const newStream = yield navigator.mediaDevices.getUserMedia({ audio: { deviceId } });
|
|
309
|
+
const newAudioTrack = newStream.getAudioTracks()[0];
|
|
310
|
+
const oldAudioTrack = this.stream.getAudioTracks()[0];
|
|
311
|
+
if (oldAudioTrack) {
|
|
312
|
+
newAudioTrack.enabled = oldAudioTrack.enabled;
|
|
313
|
+
oldAudioTrack.stop();
|
|
314
|
+
this.stream.removeTrack(oldAudioTrack);
|
|
315
|
+
}
|
|
316
|
+
this._rtcManagers.forEach((rtcManager) => {
|
|
317
|
+
rtcManager.replaceTrack(oldAudioTrack, newAudioTrack);
|
|
318
|
+
});
|
|
319
|
+
this.stream.addTrack(newAudioTrack);
|
|
320
|
+
this.dispatchEvent(new CustomEvent("stream_updated", {
|
|
321
|
+
detail: { stream: this.stream },
|
|
322
|
+
}));
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
_updateDeviceList() {
|
|
326
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
327
|
+
try {
|
|
328
|
+
const devices = yield navigator.mediaDevices.enumerateDevices();
|
|
329
|
+
this.dispatchEvent(new CustomEvent("device_list_updated", {
|
|
330
|
+
detail: {
|
|
331
|
+
cameraDevices: devices.filter((d) => d.kind === "videoinput"),
|
|
332
|
+
microphoneDevices: devices.filter((d) => d.kind === "audioinput"),
|
|
333
|
+
speakerDevices: devices.filter((d) => d.kind === "audiooutput"),
|
|
334
|
+
},
|
|
335
|
+
}));
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
this.dispatchEvent(new CustomEvent("device_list_update_error", {
|
|
339
|
+
detail: {
|
|
340
|
+
error,
|
|
341
|
+
},
|
|
342
|
+
}));
|
|
343
|
+
throw error;
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
start() {
|
|
348
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
349
|
+
const newStream = yield navigator.mediaDevices.getUserMedia(this._constraints);
|
|
350
|
+
newStream.getTracks().forEach((t) => this.stream.addTrack(t));
|
|
351
|
+
this._updateDeviceList();
|
|
352
|
+
this.dispatchEvent(new CustomEvent("stream_updated", {
|
|
353
|
+
detail: { stream: this.stream },
|
|
354
|
+
}));
|
|
355
|
+
return this.stream;
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
stop() {
|
|
359
|
+
var _a;
|
|
360
|
+
(_a = this.stream) === null || _a === void 0 ? void 0 : _a.getTracks().forEach((t) => {
|
|
361
|
+
t.stop();
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const initialState$1 = {
|
|
367
|
+
cameraDeviceError: null,
|
|
368
|
+
cameraDevices: [],
|
|
369
|
+
isSettingCameraDevice: false,
|
|
370
|
+
isSettingMicrophoneDevice: false,
|
|
371
|
+
isStarting: false,
|
|
372
|
+
microphoneDeviceError: null,
|
|
373
|
+
microphoneDevices: [],
|
|
374
|
+
speakerDevices: [],
|
|
375
|
+
startError: null,
|
|
376
|
+
};
|
|
377
|
+
function reducer$1(state, action) {
|
|
378
|
+
switch (action.type) {
|
|
379
|
+
case "DEVICE_LIST_UPDATED":
|
|
380
|
+
return Object.assign(Object.assign({}, state), action.payload);
|
|
381
|
+
case "LOCAL_STREAM_UPDATED":
|
|
382
|
+
return Object.assign(Object.assign({}, state), { currentCameraDeviceId: action.payload.currentCameraDeviceId, currentMicrophoneDeviceId: action.payload.currentMicrophoneDeviceId, localStream: action.payload.stream });
|
|
383
|
+
case "SET_CAMERA_DEVICE":
|
|
384
|
+
return Object.assign(Object.assign({}, state), { cameraDeviceError: null, isSettingCameraDevice: true });
|
|
385
|
+
case "SET_CAMERA_DEVICE_COMPLETE":
|
|
386
|
+
return Object.assign(Object.assign({}, state), { isSettingCameraDevice: false });
|
|
387
|
+
case "SET_CAMERA_DEVICE_ERROR":
|
|
388
|
+
return Object.assign(Object.assign({}, state), { cameraDeviceError: action.payload, isSettingCameraDevice: false });
|
|
389
|
+
case "SET_MICROPHONE_DEVICE":
|
|
390
|
+
return Object.assign(Object.assign({}, state), { isSettingMicrophoneDevice: true, microphoneDeviceError: null });
|
|
391
|
+
case "SET_MICROPHONE_DEVICE_COMPLETE":
|
|
392
|
+
return Object.assign(Object.assign({}, state), { isSettingMicrophoneDevice: false });
|
|
393
|
+
case "SET_MICROPHONE_DEVICE_ERROR":
|
|
394
|
+
return Object.assign(Object.assign({}, state), { isSettingMicrophoneDevice: false, microphoneDeviceError: action.payload });
|
|
395
|
+
case "START":
|
|
396
|
+
return Object.assign(Object.assign({}, state), { isStarting: true, startError: null });
|
|
397
|
+
case "START_COMPLETE":
|
|
398
|
+
return Object.assign(Object.assign({}, state), { isStarting: false });
|
|
399
|
+
case "START_ERROR":
|
|
400
|
+
return Object.assign(Object.assign({}, state), { isStarting: false, startError: action.payload });
|
|
401
|
+
default:
|
|
402
|
+
return state;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
function useLocalMedia(constraints = { audio: true, video: true }) {
|
|
406
|
+
const [localMedia] = React.useState(() => new LocalMedia(constraints));
|
|
407
|
+
const [state, dispatch] = React.useReducer(reducer$1, initialState$1);
|
|
408
|
+
React.useEffect(() => {
|
|
409
|
+
localMedia.addEventListener("device_list_updated", (e) => {
|
|
410
|
+
const { cameraDevices, microphoneDevices, speakerDevices } = e.detail;
|
|
411
|
+
dispatch({ type: "DEVICE_LIST_UPDATED", payload: { cameraDevices, microphoneDevices, speakerDevices } });
|
|
412
|
+
});
|
|
413
|
+
localMedia.addEventListener("stream_updated", (e) => {
|
|
414
|
+
const { stream } = e.detail;
|
|
415
|
+
dispatch({
|
|
416
|
+
type: "LOCAL_STREAM_UPDATED",
|
|
417
|
+
payload: {
|
|
418
|
+
stream,
|
|
419
|
+
currentCameraDeviceId: localMedia.getCameraDeviceId(),
|
|
420
|
+
currentMicrophoneDeviceId: localMedia.getMicrophoneDeviceId(),
|
|
421
|
+
},
|
|
422
|
+
});
|
|
423
|
+
});
|
|
424
|
+
const start = () => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
425
|
+
dispatch({ type: "START" });
|
|
426
|
+
try {
|
|
427
|
+
yield localMedia.start();
|
|
428
|
+
dispatch({ type: "START_COMPLETE" });
|
|
429
|
+
}
|
|
430
|
+
catch (error) {
|
|
431
|
+
dispatch({ type: "START_ERROR", payload: error });
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
start();
|
|
435
|
+
// Perform cleanup on unmount
|
|
436
|
+
return () => {
|
|
437
|
+
localMedia.stop();
|
|
438
|
+
};
|
|
439
|
+
}, []);
|
|
440
|
+
return {
|
|
441
|
+
state,
|
|
442
|
+
actions: {
|
|
443
|
+
setCameraDevice: (...args) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
444
|
+
dispatch({ type: "SET_CAMERA_DEVICE" });
|
|
445
|
+
try {
|
|
446
|
+
yield localMedia.setCameraDevice(...args);
|
|
447
|
+
dispatch({ type: "SET_CAMERA_DEVICE_COMPLETE" });
|
|
448
|
+
}
|
|
449
|
+
catch (error) {
|
|
450
|
+
dispatch({ type: "SET_CAMERA_DEVICE_ERROR", payload: error });
|
|
451
|
+
}
|
|
452
|
+
}),
|
|
453
|
+
setMicrophoneDevice: (...args) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
454
|
+
dispatch({ type: "SET_MICROPHONE_DEVICE" });
|
|
455
|
+
try {
|
|
456
|
+
yield localMedia.setMicrophoneDevice(...args);
|
|
457
|
+
dispatch({ type: "SET_MICROPHONE_DEVICE_COMPLETE" });
|
|
458
|
+
}
|
|
459
|
+
catch (error) {
|
|
460
|
+
dispatch({ type: "SET_MICROPHONE_DEVICE_ERROR", payload: error });
|
|
461
|
+
}
|
|
462
|
+
}),
|
|
463
|
+
toggleCameraEnabled: (...args) => {
|
|
464
|
+
return localMedia.toggleCameraEnabled(...args);
|
|
465
|
+
},
|
|
466
|
+
toggleMicrophoneEnabled: (...args) => {
|
|
467
|
+
return localMedia.toggleMichrophoneEnabled(...args);
|
|
468
|
+
},
|
|
469
|
+
},
|
|
470
|
+
_ref: localMedia,
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
158
474
|
const EVENTS = {
|
|
159
475
|
CLIENT_CONNECTION_STATUS_CHANGED: "client_connection_status_changed",
|
|
160
476
|
STREAM_ADDED: "stream_added",
|
|
@@ -285,10 +601,10 @@ class ServerSocket {
|
|
|
285
601
|
}
|
|
286
602
|
|
|
287
603
|
this._socket = io__default["default"](hostName, options);
|
|
288
|
-
this._socket.on("reconnect", () => {
|
|
604
|
+
this._socket.io.on("reconnect", () => {
|
|
289
605
|
this._socket.sendBuffer = [];
|
|
290
606
|
});
|
|
291
|
-
this._socket.on("reconnect_attempt", () => {
|
|
607
|
+
this._socket.io.on("reconnect_attempt", () => {
|
|
292
608
|
if (this._wasConnectedUsingWebsocket) {
|
|
293
609
|
this._socket.io.opts.transports = ["websocket"];
|
|
294
610
|
// only fallback to polling if not safari
|
|
@@ -346,6 +662,10 @@ class ServerSocket {
|
|
|
346
662
|
);
|
|
347
663
|
}
|
|
348
664
|
|
|
665
|
+
getManager() {
|
|
666
|
+
return this._socket.io;
|
|
667
|
+
}
|
|
668
|
+
|
|
349
669
|
isConnecting() {
|
|
350
670
|
return this._socket && this._socket.connecting;
|
|
351
671
|
}
|
|
@@ -400,21 +720,21 @@ var rtcManagerEvents = {
|
|
|
400
720
|
DOMINANT_SPEAKER: "dominant_speaker",
|
|
401
721
|
};
|
|
402
722
|
|
|
403
|
-
const browserName$
|
|
723
|
+
const browserName$2 = adapter__default["default"].browserDetails.browser;
|
|
404
724
|
const browserVersion$1 = adapter__default["default"].browserDetails.version;
|
|
405
725
|
|
|
406
726
|
// SDP mangling for deprioritizing H264
|
|
407
727
|
function deprioritizeH264(sdp) {
|
|
408
728
|
return SDPUtils__default["default"].splitSections(sdp)
|
|
409
|
-
.map(
|
|
729
|
+
.map(section => {
|
|
410
730
|
// only modify video sections
|
|
411
731
|
if (SDPUtils__default["default"].getKind(section) !== "video") return section;
|
|
412
732
|
|
|
413
733
|
// list of payloadTypes used in this sdp/section
|
|
414
734
|
const h264payloadTypes = SDPUtils__default["default"].matchPrefix(section, "a=rtpmap:")
|
|
415
|
-
.map(
|
|
416
|
-
.filter(
|
|
417
|
-
.map(
|
|
735
|
+
.map(line => SDPUtils__default["default"].parseRtpMap(line))
|
|
736
|
+
.filter(codec => /h264/i.test(codec.name))
|
|
737
|
+
.map(codec => "" + codec.payloadType);
|
|
418
738
|
|
|
419
739
|
// return as is if no h264 found
|
|
420
740
|
if (!h264payloadTypes.length) return section;
|
|
@@ -424,7 +744,7 @@ function deprioritizeH264(sdp) {
|
|
|
424
744
|
const mlinePayloadsSection = /(\s\d+)+$/i.exec(mline)[0];
|
|
425
745
|
const mlinePayloadsNonH264 = mlinePayloadsSection
|
|
426
746
|
.split(" ")
|
|
427
|
-
.filter(
|
|
747
|
+
.filter(payloadType => payloadType && !h264payloadTypes.includes(payloadType));
|
|
428
748
|
const reorderedPayloads = [...mlinePayloadsNonH264, ...h264payloadTypes].join(" ");
|
|
429
749
|
const newmline = mline.replace(mlinePayloadsSection, " " + reorderedPayloads);
|
|
430
750
|
return section.replace(mline, newmline);
|
|
@@ -452,12 +772,12 @@ function replaceSSRCs(currentDescription, newDescription) {
|
|
|
452
772
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1478685
|
|
453
773
|
// filter out the mid rtp header extension
|
|
454
774
|
function filterMidExtension(sdp) {
|
|
455
|
-
if (browserName$
|
|
775
|
+
if (browserName$2 !== "safari" && (browserName$2 !== "firefox" || browserVersion$1 >= 63 || browserVersion$1 === 60)) {
|
|
456
776
|
return sdp;
|
|
457
777
|
}
|
|
458
778
|
return (
|
|
459
779
|
SDPUtils__default["default"].splitLines(sdp.trim())
|
|
460
|
-
.filter(
|
|
780
|
+
.filter(line => {
|
|
461
781
|
if (!line.startsWith("a=extmap:")) {
|
|
462
782
|
return true;
|
|
463
783
|
}
|
|
@@ -473,21 +793,21 @@ function filterMidExtension(sdp) {
|
|
|
473
793
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1534673
|
|
474
794
|
// Filter out a:msid-semantic header
|
|
475
795
|
function filterMsidSemantic(sdp) {
|
|
476
|
-
if (browserName$
|
|
796
|
+
if (browserName$2 !== "firefox") {
|
|
477
797
|
return sdp;
|
|
478
798
|
}
|
|
479
799
|
return (
|
|
480
800
|
SDPUtils__default["default"].splitLines(sdp.trim())
|
|
481
|
-
.map(
|
|
801
|
+
.map(line => (line.startsWith("a=msid-semantic:") ? "a=msid-semantic: WMS *" : line))
|
|
482
802
|
.join("\r\n") + "\r\n"
|
|
483
803
|
);
|
|
484
804
|
}
|
|
485
805
|
|
|
486
806
|
function isRelayed(pc) {
|
|
487
|
-
return pc.getStats(null).then(
|
|
807
|
+
return pc.getStats(null).then(result => {
|
|
488
808
|
let localCandidateType;
|
|
489
809
|
let remoteCandidateType;
|
|
490
|
-
result.forEach(
|
|
810
|
+
result.forEach(report => {
|
|
491
811
|
// Chrome 58+ / spec
|
|
492
812
|
if (report.type === "transport" && report.selectedCandidatePairId) {
|
|
493
813
|
const transport = result.get(report.selectedCandidatePairId);
|
|
@@ -517,7 +837,7 @@ const logger$4 = console;
|
|
|
517
837
|
|
|
518
838
|
// use https://w3c.github.io/webrtc-pc/#dom-rtcrtpsender-setparameters to change the video bandwidth.
|
|
519
839
|
function setVideoBandwidthUsingSetParameters(pc, bandwidth) {
|
|
520
|
-
const sender = pc.getSenders().find(
|
|
840
|
+
const sender = pc.getSenders().find(s => s.track && s.track.kind === "video");
|
|
521
841
|
if (!sender) {
|
|
522
842
|
return Promise.resolve();
|
|
523
843
|
}
|
|
@@ -538,7 +858,7 @@ function setVideoBandwidthUsingSetParameters(pc, bandwidth) {
|
|
|
538
858
|
parameters.encodings[0].maxBitrate = bandwidth * 1000; // convert to bps
|
|
539
859
|
}
|
|
540
860
|
|
|
541
|
-
return sender.setParameters(parameters).catch(
|
|
861
|
+
return sender.setParameters(parameters).catch(err => {
|
|
542
862
|
logger$4.error("setParameters err: ", err);
|
|
543
863
|
});
|
|
544
864
|
}
|
|
@@ -563,7 +883,7 @@ class Session {
|
|
|
563
883
|
this.streamIds = [];
|
|
564
884
|
this.streams = [];
|
|
565
885
|
this.earlyIceCandidates = [];
|
|
566
|
-
this.afterConnected = new Promise(
|
|
886
|
+
this.afterConnected = new Promise(resolve => {
|
|
567
887
|
this.registerConnected = resolve;
|
|
568
888
|
});
|
|
569
889
|
this.offerOptions = { offerToReceiveAudio: true, offerToReceiveVideo: true };
|
|
@@ -600,10 +920,10 @@ class Session {
|
|
|
600
920
|
this.streamIds.push(stream.id);
|
|
601
921
|
this.streams.push(stream);
|
|
602
922
|
if (RTCPeerConnection.prototype.addTrack) {
|
|
603
|
-
stream.getAudioTracks().forEach(
|
|
923
|
+
stream.getAudioTracks().forEach(track => {
|
|
604
924
|
this.pc.addTrack(track, stream);
|
|
605
925
|
});
|
|
606
|
-
stream.getVideoTracks().forEach(
|
|
926
|
+
stream.getVideoTracks().forEach(track => {
|
|
607
927
|
this.pc.addTrack(track, stream);
|
|
608
928
|
});
|
|
609
929
|
} else {
|
|
@@ -623,7 +943,7 @@ class Session {
|
|
|
623
943
|
removeTrack(track) {
|
|
624
944
|
const stream = this.streams[0];
|
|
625
945
|
stream.removeTrack(track);
|
|
626
|
-
const sender = this.pc.getSenders().find(
|
|
946
|
+
const sender = this.pc.getSenders().find(sender => sender.track === track);
|
|
627
947
|
if (sender) {
|
|
628
948
|
this.pc.removeTrack(sender);
|
|
629
949
|
}
|
|
@@ -639,8 +959,8 @@ class Session {
|
|
|
639
959
|
|
|
640
960
|
if (this.pc) {
|
|
641
961
|
if (this.pc.removeTrack) {
|
|
642
|
-
stream.getTracks().forEach(
|
|
643
|
-
const sender = this.pc.getSenders().find(
|
|
962
|
+
stream.getTracks().forEach(track => {
|
|
963
|
+
const sender = this.pc.getSenders().find(sender => sender.track === track);
|
|
644
964
|
if (sender) {
|
|
645
965
|
this.pc.removeTrack(sender);
|
|
646
966
|
}
|
|
@@ -658,14 +978,14 @@ class Session {
|
|
|
658
978
|
// wrapper around SRD which stores a promise
|
|
659
979
|
this.srdComplete = this.pc.setRemoteDescription(desc);
|
|
660
980
|
return this.srdComplete.then(() => {
|
|
661
|
-
this.earlyIceCandidates.forEach(
|
|
981
|
+
this.earlyIceCandidates.forEach(candidate => this.pc.addIceCandidate(candidate));
|
|
662
982
|
this.earlyIceCandidates = [];
|
|
663
983
|
});
|
|
664
984
|
}
|
|
665
985
|
|
|
666
986
|
handleOffer(message) {
|
|
667
987
|
if (!this.canModifyPeerConnection()) {
|
|
668
|
-
return new Promise(
|
|
988
|
+
return new Promise(resolve => {
|
|
669
989
|
this.pending.push(() => this.handleOffer(message).then(resolve));
|
|
670
990
|
});
|
|
671
991
|
}
|
|
@@ -683,7 +1003,7 @@ class Session {
|
|
|
683
1003
|
.then(() => {
|
|
684
1004
|
return this.pc.createAnswer();
|
|
685
1005
|
})
|
|
686
|
-
.then(
|
|
1006
|
+
.then(answer => {
|
|
687
1007
|
answerToSignal = answer;
|
|
688
1008
|
return this.pc.setLocalDescription(answer);
|
|
689
1009
|
})
|
|
@@ -711,7 +1031,7 @@ class Session {
|
|
|
711
1031
|
() => {
|
|
712
1032
|
return setVideoBandwidthUsingSetParameters(this.pc, this.bandwidth);
|
|
713
1033
|
},
|
|
714
|
-
|
|
1034
|
+
e => {
|
|
715
1035
|
logger$3.warn("Could not set remote description from remote answer: ", e);
|
|
716
1036
|
}
|
|
717
1037
|
);
|
|
@@ -732,7 +1052,7 @@ class Session {
|
|
|
732
1052
|
// filter due to https://github.com/webrtcHacks/adapter/issues/863
|
|
733
1053
|
return;
|
|
734
1054
|
}
|
|
735
|
-
this.pc.addIceCandidate(candidate).catch(
|
|
1055
|
+
this.pc.addIceCandidate(candidate).catch(e => {
|
|
736
1056
|
logger$3.warn("Failed to add ICE candidate ('%s'): %s", candidate ? candidate.candidate : null, e);
|
|
737
1057
|
});
|
|
738
1058
|
});
|
|
@@ -770,11 +1090,11 @@ class Session {
|
|
|
770
1090
|
if (!pc) return false;
|
|
771
1091
|
const senders = pc.getSenders();
|
|
772
1092
|
function dbg(msg) {
|
|
773
|
-
const tr =
|
|
1093
|
+
const tr = t => t && `id:${t.id},kind:${t.kind},state:${t.readyState}`;
|
|
774
1094
|
logger$3.warn(
|
|
775
1095
|
`${msg}. newTrack:${tr(newTrack)}, oldTrack:${tr(oldTrack)}, sender tracks: ${JSON.stringify(
|
|
776
|
-
senders.map(
|
|
777
|
-
)}, sender first codecs: ${JSON.stringify(senders.map(
|
|
1096
|
+
senders.map(s => `s ${tr(s.track)}`)
|
|
1097
|
+
)}, sender first codecs: ${JSON.stringify(senders.map(s => (s.getParameters().codecs || [])[0]))}`
|
|
778
1098
|
);
|
|
779
1099
|
}
|
|
780
1100
|
if (!senders.length) {
|
|
@@ -782,7 +1102,7 @@ class Session {
|
|
|
782
1102
|
}
|
|
783
1103
|
// If we didn't specify oldTrack, replace with first of its kind
|
|
784
1104
|
if (!oldTrack) {
|
|
785
|
-
oldTrack = (senders.find(
|
|
1105
|
+
oldTrack = (senders.find(s => s.track && s.track.kind === newTrack.kind) || {}).track;
|
|
786
1106
|
if (!oldTrack) {
|
|
787
1107
|
// odin: Temporary debug data, remove if you see after 2020-12-01
|
|
788
1108
|
dbg("No sender with same kind! Add new track then.");
|
|
@@ -839,7 +1159,7 @@ class Session {
|
|
|
839
1159
|
// we already know that the track has been added at least to the mediastream
|
|
840
1160
|
return result;
|
|
841
1161
|
}
|
|
842
|
-
const stream = this.streams.find(
|
|
1162
|
+
const stream = this.streams.find(s => s.getTracks().find(t => t.id === newTrack.id)) || this.streams[0];
|
|
843
1163
|
if (!stream) {
|
|
844
1164
|
dbg("No stream?");
|
|
845
1165
|
return Promise.reject(new Error("replaceTrack: No stream?"));
|
|
@@ -868,7 +1188,7 @@ class Session {
|
|
|
868
1188
|
if (pc.localDescription.type === "offer") {
|
|
869
1189
|
return pc
|
|
870
1190
|
.createOffer()
|
|
871
|
-
.then(
|
|
1191
|
+
.then(offer => {
|
|
872
1192
|
offer.sdp = replaceSSRCs(pc.localDescription.sdp, offer.sdp);
|
|
873
1193
|
return pc.setLocalDescription(offer);
|
|
874
1194
|
})
|
|
@@ -880,7 +1200,7 @@ class Session {
|
|
|
880
1200
|
.then(() => {
|
|
881
1201
|
return pc.createAnswer();
|
|
882
1202
|
})
|
|
883
|
-
.then(
|
|
1203
|
+
.then(answer => {
|
|
884
1204
|
answer.sdp = replaceSSRCs(pc.localDescription.sdp, answer.sdp);
|
|
885
1205
|
return pc.setLocalDescription(answer);
|
|
886
1206
|
});
|
|
@@ -895,7 +1215,7 @@ class Session {
|
|
|
895
1215
|
if (!this.pc.getStats) {
|
|
896
1216
|
return;
|
|
897
1217
|
}
|
|
898
|
-
isRelayed(this.pc).then(
|
|
1218
|
+
isRelayed(this.pc).then(isRelayed => {
|
|
899
1219
|
if (isRelayed && this.bandwidth === 0) {
|
|
900
1220
|
this.changeBandwidth(this.maximumTurnBandwidth);
|
|
901
1221
|
}
|
|
@@ -928,15 +1248,11 @@ const MAXIMUM_TURN_BANDWIDTH = 512; // kbps;
|
|
|
928
1248
|
const MAXIMUM_TURN_BANDWIDTH_PREMIUM = 768; // kbps;
|
|
929
1249
|
|
|
930
1250
|
/* globals process */
|
|
931
|
-
|
|
932
|
-
process.env.AWF_BASE_URL;
|
|
933
|
-
process.env.AWF_API_BASE_URL;
|
|
934
|
-
process.env.AP_ROOM_BASE_URL;
|
|
935
1251
|
const CAMERA_STREAM_ID = "0";
|
|
936
1252
|
|
|
937
1253
|
const logger$2 = console;
|
|
938
1254
|
|
|
939
|
-
const browserName$
|
|
1255
|
+
const browserName$1 = adapter__default["default"].browserDetails.browser;
|
|
940
1256
|
const browserVersion = adapter__default["default"].browserDetails.version;
|
|
941
1257
|
|
|
942
1258
|
class BaseRtcManager {
|
|
@@ -976,7 +1292,7 @@ class BaseRtcManager {
|
|
|
976
1292
|
}
|
|
977
1293
|
|
|
978
1294
|
numberOfRemotePeers() {
|
|
979
|
-
return Object.values(this.peerConnections).filter(
|
|
1295
|
+
return Object.values(this.peerConnections).filter(session => session.clientId !== this._selfId).length;
|
|
980
1296
|
}
|
|
981
1297
|
|
|
982
1298
|
_setConnectionStatus(session, newStatus, clientId) {
|
|
@@ -1050,7 +1366,7 @@ class BaseRtcManager {
|
|
|
1050
1366
|
// Some macs + ios devices have troubles using h264 encoder since safari 14
|
|
1051
1367
|
// this will make them encode VP8 instead if available
|
|
1052
1368
|
const deprioritizeH264Encoding =
|
|
1053
|
-
browserName$
|
|
1369
|
+
browserName$1 === "safari" && browserVersion >= 14 && this._features.deprioritizeH264OnSafari;
|
|
1054
1370
|
|
|
1055
1371
|
this.peerConnections[peerConnectionId] = session = new Session({
|
|
1056
1372
|
peerConnectionId,
|
|
@@ -1069,7 +1385,7 @@ class BaseRtcManager {
|
|
|
1069
1385
|
}
|
|
1070
1386
|
|
|
1071
1387
|
_getNonLocalCameraStreamIds() {
|
|
1072
|
-
return Object.keys(this.localStreams).filter(
|
|
1388
|
+
return Object.keys(this.localStreams).filter(streamId => streamId !== CAMERA_STREAM_ID);
|
|
1073
1389
|
}
|
|
1074
1390
|
|
|
1075
1391
|
_isScreensharingLocally() {
|
|
@@ -1098,7 +1414,7 @@ class BaseRtcManager {
|
|
|
1098
1414
|
}
|
|
1099
1415
|
const session = this._getOrCreateSession(peerConnectionId, initialBandwidth);
|
|
1100
1416
|
const constraints = { optional: [] };
|
|
1101
|
-
if (browserName$
|
|
1417
|
+
if (browserName$1 === "chrome") {
|
|
1102
1418
|
constraints.optional.push({
|
|
1103
1419
|
googCpuOveruseDetection: true,
|
|
1104
1420
|
});
|
|
@@ -1111,13 +1427,13 @@ class BaseRtcManager {
|
|
|
1111
1427
|
const host = this._features.turnServerOverrideHost;
|
|
1112
1428
|
const port = host.indexOf(":") > 0 ? "" : ":443";
|
|
1113
1429
|
const override = ":" + host + port;
|
|
1114
|
-
peerConnectionConfig.iceServers = peerConnectionConfig.iceServers.map(
|
|
1430
|
+
peerConnectionConfig.iceServers = peerConnectionConfig.iceServers.map(original => {
|
|
1115
1431
|
const entry = Object.assign({}, original);
|
|
1116
1432
|
if (entry.url) {
|
|
1117
1433
|
entry.url = entry.url.replace(/:[^?]*/, override);
|
|
1118
1434
|
}
|
|
1119
1435
|
if (entry.urls) {
|
|
1120
|
-
entry.urls = entry.urls.map(
|
|
1436
|
+
entry.urls = entry.urls.map(url => url.replace(/:[^?]*/, override));
|
|
1121
1437
|
}
|
|
1122
1438
|
return entry;
|
|
1123
1439
|
});
|
|
@@ -1131,12 +1447,12 @@ class BaseRtcManager {
|
|
|
1131
1447
|
}[this._features.useOnlyTURN];
|
|
1132
1448
|
if (filter) {
|
|
1133
1449
|
peerConnectionConfig.iceServers = peerConnectionConfig.iceServers.filter(
|
|
1134
|
-
|
|
1450
|
+
entry => entry.url && entry.url.match(filter)
|
|
1135
1451
|
);
|
|
1136
1452
|
}
|
|
1137
1453
|
}
|
|
1138
1454
|
|
|
1139
|
-
if (browserName$
|
|
1455
|
+
if (browserName$1 === "chrome") {
|
|
1140
1456
|
peerConnectionConfig.sdpSemantics = "unified-plan";
|
|
1141
1457
|
}
|
|
1142
1458
|
|
|
@@ -1147,7 +1463,7 @@ class BaseRtcManager {
|
|
|
1147
1463
|
clientId,
|
|
1148
1464
|
});
|
|
1149
1465
|
|
|
1150
|
-
pc.ontrack =
|
|
1466
|
+
pc.ontrack = event => {
|
|
1151
1467
|
const stream = event.streams[0];
|
|
1152
1468
|
if (stream.id === "default" && stream.getAudioTracks().length === 0) {
|
|
1153
1469
|
// due to our PlanB / UnifiedPlan conversion we can run into this:
|
|
@@ -1189,7 +1505,7 @@ class BaseRtcManager {
|
|
|
1189
1505
|
case "completed":
|
|
1190
1506
|
newStatus = TYPES.CONNECTION_SUCCESSFUL;
|
|
1191
1507
|
if (!session.wasEverConnected) {
|
|
1192
|
-
this._pendingActionsForConnectedPeerConnections.forEach(
|
|
1508
|
+
this._pendingActionsForConnectedPeerConnections.forEach(action => {
|
|
1193
1509
|
if (typeof action === "function") {
|
|
1194
1510
|
action();
|
|
1195
1511
|
}
|
|
@@ -1201,7 +1517,7 @@ class BaseRtcManager {
|
|
|
1201
1517
|
if (
|
|
1202
1518
|
!session.wasEverConnected &&
|
|
1203
1519
|
(pc.iceConnectionState.match(/connected|completed/) ||
|
|
1204
|
-
(browserName$
|
|
1520
|
+
(browserName$1 === "chrome" && pc.localDescription && pc.localDescription.type === "answer"))
|
|
1205
1521
|
) {
|
|
1206
1522
|
session.wasEverConnected = true;
|
|
1207
1523
|
if (this._features.bandwidth !== "false") {
|
|
@@ -1272,7 +1588,7 @@ class BaseRtcManager {
|
|
|
1272
1588
|
// Don't add existing screenshare-streams when using SFU as those will be
|
|
1273
1589
|
// added in a separate session/peerConnection
|
|
1274
1590
|
if (shouldAddLocalVideo) {
|
|
1275
|
-
Object.keys(this.localStreams).forEach(
|
|
1591
|
+
Object.keys(this.localStreams).forEach(id => {
|
|
1276
1592
|
if (id === CAMERA_STREAM_ID) {
|
|
1277
1593
|
return;
|
|
1278
1594
|
}
|
|
@@ -1309,27 +1625,27 @@ class BaseRtcManager {
|
|
|
1309
1625
|
}
|
|
1310
1626
|
|
|
1311
1627
|
_forEachPeerConnection(func) {
|
|
1312
|
-
Object.keys(this.peerConnections).forEach(
|
|
1628
|
+
Object.keys(this.peerConnections).forEach(peerConnectionId => {
|
|
1313
1629
|
const peerConnection = this.peerConnections[peerConnectionId];
|
|
1314
1630
|
func(peerConnection);
|
|
1315
1631
|
});
|
|
1316
1632
|
}
|
|
1317
1633
|
|
|
1318
1634
|
_addStreamToPeerConnections(stream) {
|
|
1319
|
-
this._forEachPeerConnection(
|
|
1635
|
+
this._forEachPeerConnection(session => {
|
|
1320
1636
|
this._withForcedRenegotiation(session, () => session.addStream(stream));
|
|
1321
1637
|
});
|
|
1322
1638
|
}
|
|
1323
1639
|
|
|
1324
1640
|
_addTrackToPeerConnections(track, stream) {
|
|
1325
|
-
this._forEachPeerConnection(
|
|
1641
|
+
this._forEachPeerConnection(session => {
|
|
1326
1642
|
this._withForcedRenegotiation(session, () => session.addTrack(track, stream));
|
|
1327
1643
|
});
|
|
1328
1644
|
}
|
|
1329
1645
|
|
|
1330
1646
|
_replaceTrackToPeerConnections(oldTrack, newTrack) {
|
|
1331
1647
|
const promises = [];
|
|
1332
|
-
this._forEachPeerConnection(
|
|
1648
|
+
this._forEachPeerConnection(session => {
|
|
1333
1649
|
if (!session.hasConnectedPeerConnection()) {
|
|
1334
1650
|
logger$2.log("Session doesn't have a connected PeerConnection, adding pending action!");
|
|
1335
1651
|
const pendingActions = this._pendingActionsForConnectedPeerConnections;
|
|
@@ -1347,7 +1663,7 @@ class BaseRtcManager {
|
|
|
1347
1663
|
reject(`ReplaceTrack returned false`);
|
|
1348
1664
|
return;
|
|
1349
1665
|
}
|
|
1350
|
-
replacedTrackPromise.then(
|
|
1666
|
+
replacedTrackPromise.then(track => resolve(track)).catch(error => reject(error));
|
|
1351
1667
|
};
|
|
1352
1668
|
pendingActions.push(action);
|
|
1353
1669
|
});
|
|
@@ -1365,13 +1681,13 @@ class BaseRtcManager {
|
|
|
1365
1681
|
}
|
|
1366
1682
|
|
|
1367
1683
|
_removeStreamFromPeerConnections(stream) {
|
|
1368
|
-
this._forEachPeerConnection(
|
|
1684
|
+
this._forEachPeerConnection(session => {
|
|
1369
1685
|
this._withForcedRenegotiation(session, () => session.removeStream(stream));
|
|
1370
1686
|
});
|
|
1371
1687
|
}
|
|
1372
1688
|
|
|
1373
1689
|
_removeTrackFromPeerConnections(track) {
|
|
1374
|
-
this._forEachPeerConnection(
|
|
1690
|
+
this._forEachPeerConnection(session => {
|
|
1375
1691
|
this._withForcedRenegotiation(session, () => session.removeTrack(track));
|
|
1376
1692
|
});
|
|
1377
1693
|
}
|
|
@@ -1424,11 +1740,11 @@ class BaseRtcManager {
|
|
|
1424
1740
|
}
|
|
1425
1741
|
|
|
1426
1742
|
disconnectAll() {
|
|
1427
|
-
Object.keys(this.peerConnections).forEach(
|
|
1743
|
+
Object.keys(this.peerConnections).forEach(peerConnectionId => {
|
|
1428
1744
|
this.disconnect(peerConnectionId);
|
|
1429
1745
|
});
|
|
1430
1746
|
this.peerConnections = {};
|
|
1431
|
-
this._socketListenerDeregisterFunctions.forEach(
|
|
1747
|
+
this._socketListenerDeregisterFunctions.forEach(func => {
|
|
1432
1748
|
func();
|
|
1433
1749
|
});
|
|
1434
1750
|
this._socketListenerDeregisterFunctions = [];
|
|
@@ -1445,7 +1761,7 @@ class BaseRtcManager {
|
|
|
1445
1761
|
* used in getUserMedia.
|
|
1446
1762
|
*/
|
|
1447
1763
|
fixChromeAudio(constraints) {
|
|
1448
|
-
if (browserName$
|
|
1764
|
+
if (browserName$1 !== "chrome") {
|
|
1449
1765
|
return;
|
|
1450
1766
|
}
|
|
1451
1767
|
const localStream = this._getLocalCameraStream();
|
|
@@ -1453,7 +1769,7 @@ class BaseRtcManager {
|
|
|
1453
1769
|
if (!audioTrack || audioTrack.readyState !== "ended") {
|
|
1454
1770
|
return;
|
|
1455
1771
|
}
|
|
1456
|
-
return navigator.mediaDevices.getUserMedia({ audio: constraints }).then(
|
|
1772
|
+
return navigator.mediaDevices.getUserMedia({ audio: constraints }).then(stream => {
|
|
1457
1773
|
const track = stream.getAudioTracks()[0];
|
|
1458
1774
|
track.enabled = audioTrack.enabled; // retain mute state and don't accidentally unmute.
|
|
1459
1775
|
localStream.removeTrack(audioTrack); // remove the old track.
|
|
@@ -1487,7 +1803,7 @@ class BaseRtcManager {
|
|
|
1487
1803
|
this._socketListenerDeregisterFunctions = [
|
|
1488
1804
|
() => this._clearMediaServersRefresh(),
|
|
1489
1805
|
|
|
1490
|
-
this._serverSocket.on(PROTOCOL_RESPONSES.MEDIASERVER_CONFIG,
|
|
1806
|
+
this._serverSocket.on(PROTOCOL_RESPONSES.MEDIASERVER_CONFIG, data => {
|
|
1491
1807
|
if (data.error) {
|
|
1492
1808
|
logger$2.warn("FETCH_MEDIASERVER_CONFIG failed:", data.error);
|
|
1493
1809
|
return;
|
|
@@ -1495,11 +1811,11 @@ class BaseRtcManager {
|
|
|
1495
1811
|
this._updateAndScheduleMediaServersRefresh(data);
|
|
1496
1812
|
}),
|
|
1497
1813
|
|
|
1498
|
-
this._serverSocket.on(RELAY_MESSAGES.READY_TO_RECEIVE_OFFER,
|
|
1814
|
+
this._serverSocket.on(RELAY_MESSAGES.READY_TO_RECEIVE_OFFER, data => {
|
|
1499
1815
|
this._connect(data.clientId);
|
|
1500
1816
|
}),
|
|
1501
1817
|
|
|
1502
|
-
this._serverSocket.on(RELAY_MESSAGES.ICE_CANDIDATE,
|
|
1818
|
+
this._serverSocket.on(RELAY_MESSAGES.ICE_CANDIDATE, data => {
|
|
1503
1819
|
const session = this._getSession(data.clientId);
|
|
1504
1820
|
if (!session) {
|
|
1505
1821
|
logger$2.warn("No RTCPeerConnection on ICE_CANDIDATE", data);
|
|
@@ -1508,7 +1824,7 @@ class BaseRtcManager {
|
|
|
1508
1824
|
session.addIceCandidate(data.message);
|
|
1509
1825
|
}),
|
|
1510
1826
|
|
|
1511
|
-
this._serverSocket.on(RELAY_MESSAGES.ICE_END_OF_CANDIDATES,
|
|
1827
|
+
this._serverSocket.on(RELAY_MESSAGES.ICE_END_OF_CANDIDATES, data => {
|
|
1512
1828
|
const session = this._getSession(data.clientId);
|
|
1513
1829
|
if (!session) {
|
|
1514
1830
|
logger$2.warn("No RTCPeerConnection on ICE_END_OF_CANDIDATES", data);
|
|
@@ -1518,14 +1834,14 @@ class BaseRtcManager {
|
|
|
1518
1834
|
}),
|
|
1519
1835
|
|
|
1520
1836
|
// when a new SDP offer is received from another client
|
|
1521
|
-
this._serverSocket.on(RELAY_MESSAGES.SDP_OFFER,
|
|
1837
|
+
this._serverSocket.on(RELAY_MESSAGES.SDP_OFFER, data => {
|
|
1522
1838
|
const session = this._getSession(data.clientId);
|
|
1523
1839
|
if (!session) {
|
|
1524
1840
|
logger$2.warn("No RTCPeerConnection on SDP_OFFER", data);
|
|
1525
1841
|
return;
|
|
1526
1842
|
}
|
|
1527
1843
|
const offer = this._transformIncomingSdp(data.message, session.pc);
|
|
1528
|
-
session.handleOffer(offer).then(
|
|
1844
|
+
session.handleOffer(offer).then(answer => {
|
|
1529
1845
|
this._emitServerEvent(RELAY_MESSAGES.SDP_ANSWER, {
|
|
1530
1846
|
receiverId: data.clientId,
|
|
1531
1847
|
message: this._transformOutgoingSdp(answer),
|
|
@@ -1534,7 +1850,7 @@ class BaseRtcManager {
|
|
|
1534
1850
|
}),
|
|
1535
1851
|
|
|
1536
1852
|
// when a new SDP answer is received from another client
|
|
1537
|
-
this._serverSocket.on(RELAY_MESSAGES.SDP_ANSWER,
|
|
1853
|
+
this._serverSocket.on(RELAY_MESSAGES.SDP_ANSWER, data => {
|
|
1538
1854
|
const session = this._getSession(data.clientId);
|
|
1539
1855
|
if (!session) {
|
|
1540
1856
|
logger$2.warn("No RTCPeerConnection on SDP_ANSWER", data);
|
|
@@ -1552,7 +1868,7 @@ class BaseRtcManager {
|
|
|
1552
1868
|
}
|
|
1553
1869
|
|
|
1554
1870
|
const logger$1 = console;
|
|
1555
|
-
const browserName
|
|
1871
|
+
const browserName = adapter__default["default"].browserDetails.browser;
|
|
1556
1872
|
class P2pRtcManager extends BaseRtcManager {
|
|
1557
1873
|
_connect(clientId) {
|
|
1558
1874
|
const shouldAddLocalVideo = true;
|
|
@@ -1604,7 +1920,7 @@ class P2pRtcManager extends BaseRtcManager {
|
|
|
1604
1920
|
session.isOperationPending = true;
|
|
1605
1921
|
|
|
1606
1922
|
pc.createOffer(constraints || this.offerOptions)
|
|
1607
|
-
.then(
|
|
1923
|
+
.then(offer => {
|
|
1608
1924
|
this._emitServerEvent(RELAY_MESSAGES.SDP_OFFER, {
|
|
1609
1925
|
receiverId: clientId,
|
|
1610
1926
|
message: this._transformOutgoingSdp(offer),
|
|
@@ -1613,17 +1929,17 @@ class P2pRtcManager extends BaseRtcManager {
|
|
|
1613
1929
|
// workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1394602
|
|
1614
1930
|
// make Chrome send media later when there are two (more more?) video tracks.
|
|
1615
1931
|
if (
|
|
1616
|
-
browserName
|
|
1617
|
-
pc.getSenders().filter(
|
|
1932
|
+
browserName === "chrome" &&
|
|
1933
|
+
pc.getSenders().filter(sender => sender.track && sender.track.kind === "video").length >= 2
|
|
1618
1934
|
) {
|
|
1619
1935
|
session.pendingOffer = offer;
|
|
1620
1936
|
return;
|
|
1621
1937
|
}
|
|
1622
|
-
pc.setLocalDescription(offer).catch(
|
|
1938
|
+
pc.setLocalDescription(offer).catch(e => {
|
|
1623
1939
|
logger$1.warn("RTCPeerConnection.setLocalDescription() failed with local offer", e);
|
|
1624
1940
|
});
|
|
1625
1941
|
})
|
|
1626
|
-
.catch(
|
|
1942
|
+
.catch(e => {
|
|
1627
1943
|
logger$1.warn("RTCPeerConnection.createOffer() failed to create local offer", e);
|
|
1628
1944
|
});
|
|
1629
1945
|
}
|
|
@@ -1673,7 +1989,7 @@ class P2pRtcManager extends BaseRtcManager {
|
|
|
1673
1989
|
return 0;
|
|
1674
1990
|
}
|
|
1675
1991
|
|
|
1676
|
-
this._forEachPeerConnection(
|
|
1992
|
+
this._forEachPeerConnection(session => {
|
|
1677
1993
|
session.changeBandwidth(bandwidth);
|
|
1678
1994
|
});
|
|
1679
1995
|
|
|
@@ -1704,7 +2020,7 @@ class P2pRtcManager extends BaseRtcManager {
|
|
|
1704
2020
|
pc.addTrack(this._stoppedVideoTrack, localCameraStream);
|
|
1705
2021
|
}
|
|
1706
2022
|
|
|
1707
|
-
pc.onicecandidate =
|
|
2023
|
+
pc.onicecandidate = event => {
|
|
1708
2024
|
if (event.candidate) {
|
|
1709
2025
|
session.relayCandidateSeen = session.relayCandidateSeen || event.candidate.type === "relay";
|
|
1710
2026
|
this._emitServerEvent(RELAY_MESSAGES.ICE_CANDIDATE, {
|
|
@@ -1761,7 +2077,7 @@ class P2pRtcManager extends BaseRtcManager {
|
|
|
1761
2077
|
const numPeers = this.numberOfPeerconnections();
|
|
1762
2078
|
if (numPeers === 0) {
|
|
1763
2079
|
setTimeout(() => {
|
|
1764
|
-
this.numberOfPeerconnections();
|
|
2080
|
+
//const numPeers = this.numberOfPeerconnections();
|
|
1765
2081
|
}, 60 * 1000);
|
|
1766
2082
|
}
|
|
1767
2083
|
}
|
|
@@ -1775,13 +2091,13 @@ class P2pRtcManager extends BaseRtcManager {
|
|
|
1775
2091
|
|
|
1776
2092
|
stopOrResumeVideo(localStream, enable) {
|
|
1777
2093
|
// actually turn off the camera. Chrome-only (Firefox has different plans)
|
|
1778
|
-
if (browserName
|
|
2094
|
+
if (browserName !== "chrome") {
|
|
1779
2095
|
return;
|
|
1780
2096
|
}
|
|
1781
2097
|
if (enable === false) {
|
|
1782
2098
|
// try to stop the local camera so the camera light goes off.
|
|
1783
2099
|
setTimeout(() => {
|
|
1784
|
-
localStream.getVideoTracks().forEach(
|
|
2100
|
+
localStream.getVideoTracks().forEach(track => {
|
|
1785
2101
|
if (track.enabled === false) {
|
|
1786
2102
|
track.stop();
|
|
1787
2103
|
localStream.removeTrack(track);
|
|
@@ -1820,7 +2136,7 @@ class P2pRtcManager extends BaseRtcManager {
|
|
|
1820
2136
|
// device has been plugged out or similar
|
|
1821
2137
|
return;
|
|
1822
2138
|
}
|
|
1823
|
-
navigator.mediaDevices.getUserMedia({ video: constraints }).then(
|
|
2139
|
+
navigator.mediaDevices.getUserMedia({ video: constraints }).then(stream => {
|
|
1824
2140
|
const track = stream.getVideoTracks()[0];
|
|
1825
2141
|
localStream.addTrack(track);
|
|
1826
2142
|
this._emit(EVENTS.LOCAL_STREAM_TRACK_ADDED, {
|
|
@@ -1979,10 +2295,11 @@ class VegaParser {
|
|
|
1979
2295
|
}
|
|
1980
2296
|
|
|
1981
2297
|
class VegaConnection extends EventEmitter.EventEmitter {
|
|
1982
|
-
constructor(wsUrl, logger) {
|
|
2298
|
+
constructor(wsUrl, logger, protocol = "whereby-sfu#v4") {
|
|
1983
2299
|
super();
|
|
1984
2300
|
|
|
1985
2301
|
this.wsUrl = wsUrl;
|
|
2302
|
+
this.protocol = protocol;
|
|
1986
2303
|
this.logger = logger;
|
|
1987
2304
|
|
|
1988
2305
|
// This is the map of sent requests that are waiting for a response
|
|
@@ -1991,7 +2308,7 @@ class VegaConnection extends EventEmitter.EventEmitter {
|
|
|
1991
2308
|
}
|
|
1992
2309
|
|
|
1993
2310
|
_setupSocket() {
|
|
1994
|
-
this.socket = new WebSocket(this.wsUrl,
|
|
2311
|
+
this.socket = new WebSocket(this.wsUrl, this.protocol);
|
|
1995
2312
|
this.socket.onopen = this._onOpen.bind(this);
|
|
1996
2313
|
this.socket.onmessage = this._onMessage.bind(this);
|
|
1997
2314
|
this.socket.onclose = this._onClose.bind(this);
|
|
@@ -2005,13 +2322,15 @@ class VegaConnection extends EventEmitter.EventEmitter {
|
|
|
2005
2322
|
this.socket.onerror = null;
|
|
2006
2323
|
this.socket = null;
|
|
2007
2324
|
|
|
2008
|
-
this.sents.forEach(
|
|
2325
|
+
this.sents.forEach(sent => sent.close());
|
|
2009
2326
|
|
|
2010
2327
|
this.emit("close");
|
|
2011
2328
|
}
|
|
2012
2329
|
|
|
2013
2330
|
close() {
|
|
2014
|
-
this.socket
|
|
2331
|
+
if (!this.socket) return;
|
|
2332
|
+
|
|
2333
|
+
this.socket.close();
|
|
2015
2334
|
}
|
|
2016
2335
|
|
|
2017
2336
|
_onOpen() {
|
|
@@ -2023,11 +2342,15 @@ class VegaConnection extends EventEmitter.EventEmitter {
|
|
|
2023
2342
|
_onMessage(event) {
|
|
2024
2343
|
const socketMessage = VegaParser.parse(event.data);
|
|
2025
2344
|
|
|
2345
|
+
if (!socketMessage) {
|
|
2346
|
+
return this.logger.log("VegaConnectionManager: Received invalid message", event.data);
|
|
2347
|
+
}
|
|
2348
|
+
|
|
2026
2349
|
this.logger.log("VegaConnectionManager: Received message", socketMessage);
|
|
2027
2350
|
|
|
2028
|
-
if (socketMessage
|
|
2351
|
+
if (socketMessage.response) {
|
|
2029
2352
|
this._handleResponse(socketMessage);
|
|
2030
|
-
} else if (socketMessage
|
|
2353
|
+
} else if (socketMessage.message) {
|
|
2031
2354
|
this.emit("message", socketMessage);
|
|
2032
2355
|
}
|
|
2033
2356
|
}
|
|
@@ -2073,13 +2396,13 @@ class VegaConnection extends EventEmitter.EventEmitter {
|
|
|
2073
2396
|
const sent = {
|
|
2074
2397
|
id: request.id,
|
|
2075
2398
|
method: request.method,
|
|
2076
|
-
resolve:
|
|
2399
|
+
resolve: data2 => {
|
|
2077
2400
|
if (!this.sents.delete(request.id)) return;
|
|
2078
2401
|
|
|
2079
2402
|
clearTimeout(sent.timer);
|
|
2080
2403
|
pResolve(data2);
|
|
2081
2404
|
},
|
|
2082
|
-
reject:
|
|
2405
|
+
reject: error => {
|
|
2083
2406
|
if (!this.sents.delete(request.id)) return;
|
|
2084
2407
|
|
|
2085
2408
|
clearTimeout(sent.timer);
|
|
@@ -2134,7 +2457,7 @@ const VIDEO_SETTINGS_VP9 = {
|
|
|
2134
2457
|
codecOptions: {
|
|
2135
2458
|
videoGoogleStartBitrate: 500,
|
|
2136
2459
|
},
|
|
2137
|
-
encodings: [{ scalabilityMode: "
|
|
2460
|
+
encodings: [{ scalabilityMode: "L3T2_KEY", networkPriority: "high" }],
|
|
2138
2461
|
};
|
|
2139
2462
|
|
|
2140
2463
|
const SCREEN_SHARE_SETTINGS = {
|
|
@@ -2143,13 +2466,13 @@ const SCREEN_SHARE_SETTINGS = {
|
|
|
2143
2466
|
|
|
2144
2467
|
const SCREEN_SHARE_SIMULCAST_SETTINGS = {
|
|
2145
2468
|
encodings: [
|
|
2146
|
-
{ dtx: true, maxBitrate: 500000 },
|
|
2147
|
-
{ dtx: true, maxBitrate: 1500000 },
|
|
2469
|
+
{ scaleResolutionDownBy: 2, dtx: true, maxBitrate: 500000 },
|
|
2470
|
+
{ scaleResolutionDownBy: 1, dtx: true, maxBitrate: 1500000 },
|
|
2148
2471
|
],
|
|
2149
2472
|
};
|
|
2150
2473
|
|
|
2151
2474
|
const SCREEN_SHARE_SETTINGS_VP9 = {
|
|
2152
|
-
encodings: [{ scalabilityMode: "
|
|
2475
|
+
encodings: [{ scalabilityMode: "L1T1", dtx: true, networkPriority: "high" }],
|
|
2153
2476
|
};
|
|
2154
2477
|
|
|
2155
2478
|
const getMediaSettings = (kind, isScreenShare, features) => {
|
|
@@ -2165,8 +2488,8 @@ const getMediaSettings = (kind, isScreenShare, features) => {
|
|
|
2165
2488
|
|
|
2166
2489
|
return SCREEN_SHARE_SETTINGS;
|
|
2167
2490
|
} else {
|
|
2168
|
-
if (lowDataModeEnabled) return VIDEO_SETTINGS_SD;
|
|
2169
2491
|
if (vp9On) return VIDEO_SETTINGS_VP9;
|
|
2492
|
+
if (lowDataModeEnabled) return VIDEO_SETTINGS_SD;
|
|
2170
2493
|
|
|
2171
2494
|
return VIDEO_SETTINGS_HD;
|
|
2172
2495
|
}
|
|
@@ -2177,30 +2500,30 @@ const modifyMediaCapabilities = (routerRtpCapabilities, features) => {
|
|
|
2177
2500
|
|
|
2178
2501
|
if (vp9On) {
|
|
2179
2502
|
const { preferredPayloadType } = routerRtpCapabilities.codecs.find(
|
|
2180
|
-
|
|
2503
|
+
codec => codec.mimeType.toLowerCase() === "video/vp9"
|
|
2181
2504
|
);
|
|
2182
2505
|
|
|
2183
2506
|
const { preferredPayloadType: aptPreferredPayloadType } = routerRtpCapabilities.codecs.find(
|
|
2184
|
-
|
|
2507
|
+
codec => codec.mimeType.toLowerCase() === "video/rtx" && codec.parameters.apt === preferredPayloadType
|
|
2185
2508
|
);
|
|
2186
2509
|
|
|
2187
2510
|
routerRtpCapabilities.codecs = routerRtpCapabilities.codecs.filter(
|
|
2188
|
-
|
|
2511
|
+
codec =>
|
|
2189
2512
|
codec.kind === "audio" ||
|
|
2190
2513
|
codec.preferredPayloadType === preferredPayloadType ||
|
|
2191
2514
|
codec.preferredPayloadType === aptPreferredPayloadType
|
|
2192
2515
|
);
|
|
2193
2516
|
} else if (h264On) {
|
|
2194
2517
|
const { preferredPayloadType } = routerRtpCapabilities.codecs.find(
|
|
2195
|
-
|
|
2518
|
+
codec => codec.mimeType.toLowerCase() === "video/h264"
|
|
2196
2519
|
);
|
|
2197
2520
|
|
|
2198
2521
|
const { preferredPayloadType: aptPreferredPayloadType } = routerRtpCapabilities.codecs.find(
|
|
2199
|
-
|
|
2522
|
+
codec => codec.mimeType.toLowerCase() === "video/rtx" && codec.parameters.apt === preferredPayloadType
|
|
2200
2523
|
);
|
|
2201
2524
|
|
|
2202
2525
|
routerRtpCapabilities.codecs = routerRtpCapabilities.codecs.filter(
|
|
2203
|
-
|
|
2526
|
+
codec =>
|
|
2204
2527
|
codec.kind === "audio" ||
|
|
2205
2528
|
codec.preferredPayloadType === preferredPayloadType ||
|
|
2206
2529
|
codec.preferredPayloadType === aptPreferredPayloadType
|
|
@@ -2234,7 +2557,7 @@ const maybeTurnOnly = (transportConfig, features) => {
|
|
|
2234
2557
|
}[features.useOnlyTURN];
|
|
2235
2558
|
|
|
2236
2559
|
if (filter) {
|
|
2237
|
-
transportConfig.iceServers = transportConfig.iceServers.filter(
|
|
2560
|
+
transportConfig.iceServers = transportConfig.iceServers.filter(entry => entry.url && entry.url.match(filter));
|
|
2238
2561
|
}
|
|
2239
2562
|
};
|
|
2240
2563
|
|
|
@@ -2338,7 +2661,7 @@ class VegaRtcManager {
|
|
|
2338
2661
|
this._socketListenerDeregisterFunctions.push(
|
|
2339
2662
|
() => this._clearMediaServersRefresh(),
|
|
2340
2663
|
|
|
2341
|
-
this._serverSocket.on(PROTOCOL_RESPONSES.MEDIASERVER_CONFIG,
|
|
2664
|
+
this._serverSocket.on(PROTOCOL_RESPONSES.MEDIASERVER_CONFIG, data => {
|
|
2342
2665
|
if (data.error) {
|
|
2343
2666
|
logger.warn("FETCH_MEDIASERVER_CONFIG failed:", data.error);
|
|
2344
2667
|
return;
|
|
@@ -2375,7 +2698,7 @@ class VegaRtcManager {
|
|
|
2375
2698
|
this._vegaConnection = new VegaConnection(wsUrl, logger);
|
|
2376
2699
|
this._vegaConnection.on("open", () => this._join());
|
|
2377
2700
|
this._vegaConnection.on("close", () => this._onClose());
|
|
2378
|
-
this._vegaConnection.on("message",
|
|
2701
|
+
this._vegaConnection.on("message", message => this._onMessage(message));
|
|
2379
2702
|
}
|
|
2380
2703
|
|
|
2381
2704
|
_onClose() {
|
|
@@ -2456,7 +2779,7 @@ class VegaRtcManager {
|
|
|
2456
2779
|
maybeTurnOnly(transportOptions, this._features);
|
|
2457
2780
|
|
|
2458
2781
|
const transport = this._mediasoupDevice[creator](transportOptions);
|
|
2459
|
-
const onConnectionStateListener = async
|
|
2782
|
+
const onConnectionStateListener = async connectionState => {
|
|
2460
2783
|
logger.debug(`Transport ConnectionStateChanged ${connectionState}`);
|
|
2461
2784
|
if (connectionState !== "disconnected" && connectionState !== "failed") {
|
|
2462
2785
|
return;
|
|
@@ -2568,7 +2891,7 @@ class VegaRtcManager {
|
|
|
2568
2891
|
const error = await transport
|
|
2569
2892
|
.restartIce({ iceParameters })
|
|
2570
2893
|
.then(() => null)
|
|
2571
|
-
.catch(
|
|
2894
|
+
.catch(err => err);
|
|
2572
2895
|
|
|
2573
2896
|
if (error) {
|
|
2574
2897
|
logger.error(`_restartIce: ICE restart failed: ${error}`);
|
|
@@ -2579,7 +2902,7 @@ class VegaRtcManager {
|
|
|
2579
2902
|
break;
|
|
2580
2903
|
default:
|
|
2581
2904
|
// exponential backoff
|
|
2582
|
-
await new Promise(
|
|
2905
|
+
await new Promise(resolve => {
|
|
2583
2906
|
setTimeout(() => {
|
|
2584
2907
|
resolve();
|
|
2585
2908
|
}, Math.min(RESTARTICE_ERROR_RETRY_THRESHOLD_IN_MS * 2 ** retried, 60000));
|
|
@@ -2589,7 +2912,7 @@ class VegaRtcManager {
|
|
|
2589
2912
|
}
|
|
2590
2913
|
return;
|
|
2591
2914
|
}
|
|
2592
|
-
await new Promise(
|
|
2915
|
+
await new Promise(resolve => {
|
|
2593
2916
|
setTimeout(() => {
|
|
2594
2917
|
resolve();
|
|
2595
2918
|
}, 60000 * Math.min(8, retried + 1));
|
|
@@ -3163,54 +3486,6 @@ class VegaRtcManager {
|
|
|
3163
3486
|
this._webcamPaused = !enable;
|
|
3164
3487
|
|
|
3165
3488
|
this._pauseResumeWebcam();
|
|
3166
|
-
|
|
3167
|
-
if (browserName === "chrome") {
|
|
3168
|
-
// actually turn off the camera. Chrome-only (Firefox etc. has different plans)
|
|
3169
|
-
|
|
3170
|
-
if (!enable) {
|
|
3171
|
-
clearTimeout(this._stopCameraTimeout);
|
|
3172
|
-
|
|
3173
|
-
// try to stop the local camera so the camera light goes off.
|
|
3174
|
-
this._stopCameraTimeout = setTimeout(() => {
|
|
3175
|
-
localStream.getVideoTracks().forEach((track) => {
|
|
3176
|
-
if (track.enabled === false) {
|
|
3177
|
-
track.stop();
|
|
3178
|
-
localStream.removeTrack(track);
|
|
3179
|
-
|
|
3180
|
-
this._emitToPWA(EVENTS.LOCAL_STREAM_TRACK_REMOVED, {
|
|
3181
|
-
stream: localStream,
|
|
3182
|
-
track,
|
|
3183
|
-
});
|
|
3184
|
-
|
|
3185
|
-
if (
|
|
3186
|
-
this._webcamProducer &&
|
|
3187
|
-
!this._webcamProducer.closed &&
|
|
3188
|
-
this._webcamProducer.track === track
|
|
3189
|
-
) {
|
|
3190
|
-
this._stopProducer(this._webcamProducer);
|
|
3191
|
-
this._webcamProducer = null;
|
|
3192
|
-
this._webcamTrack = null;
|
|
3193
|
-
}
|
|
3194
|
-
}
|
|
3195
|
-
});
|
|
3196
|
-
}, 5000);
|
|
3197
|
-
} else if (localStream.getVideoTracks().length === 0) {
|
|
3198
|
-
// re-enable the stream
|
|
3199
|
-
const constraints = this._webrtcProvider.getMediaConstraints().video;
|
|
3200
|
-
navigator.mediaDevices.getUserMedia({ video: constraints }).then((stream) => {
|
|
3201
|
-
const track = stream.getVideoTracks()[0];
|
|
3202
|
-
localStream.addTrack(track);
|
|
3203
|
-
|
|
3204
|
-
this._emitToPWA(EVENTS.LOCAL_STREAM_TRACK_ADDED, {
|
|
3205
|
-
streamId: localStream.id,
|
|
3206
|
-
tracks: [track],
|
|
3207
|
-
screenShare: false,
|
|
3208
|
-
});
|
|
3209
|
-
|
|
3210
|
-
this._sendWebcam(track);
|
|
3211
|
-
});
|
|
3212
|
-
}
|
|
3213
|
-
}
|
|
3214
3489
|
}
|
|
3215
3490
|
|
|
3216
3491
|
supportsScreenShareAudio() {
|
|
@@ -3277,7 +3552,7 @@ class VegaRtcManager {
|
|
|
3277
3552
|
}
|
|
3278
3553
|
|
|
3279
3554
|
disconnectAll() {
|
|
3280
|
-
this._socketListenerDeregisterFunctions.forEach(
|
|
3555
|
+
this._socketListenerDeregisterFunctions.forEach(func => {
|
|
3281
3556
|
func();
|
|
3282
3557
|
});
|
|
3283
3558
|
|
|
@@ -3320,7 +3595,7 @@ class VegaRtcManager {
|
|
|
3320
3595
|
return;
|
|
3321
3596
|
}
|
|
3322
3597
|
})
|
|
3323
|
-
.catch(
|
|
3598
|
+
.catch(error => {
|
|
3324
3599
|
console.error('"message" failed [error:%o]', error);
|
|
3325
3600
|
});
|
|
3326
3601
|
}
|
|
@@ -3455,7 +3730,7 @@ class VegaRtcManager {
|
|
|
3455
3730
|
const toPauseConsumers = [];
|
|
3456
3731
|
const toResumeConsumers = [];
|
|
3457
3732
|
|
|
3458
|
-
this._consumers.forEach(
|
|
3733
|
+
this._consumers.forEach(consumer => {
|
|
3459
3734
|
if (consumer.appData.sourceClientId !== clientId) return;
|
|
3460
3735
|
|
|
3461
3736
|
const hasAccepted = consumer.appData.screenShare ? hasAcceptedScreenStream : hasAcceptedWebcamStream;
|
|
@@ -3493,6 +3768,7 @@ class VegaRtcManager {
|
|
|
3493
3768
|
clientId,
|
|
3494
3769
|
stream: webcamStream,
|
|
3495
3770
|
streamId: camStreamId,
|
|
3771
|
+
streamType: "webcam",
|
|
3496
3772
|
});
|
|
3497
3773
|
|
|
3498
3774
|
clientState.hasEmittedWebcamStream = true;
|
|
@@ -3504,6 +3780,7 @@ class VegaRtcManager {
|
|
|
3504
3780
|
clientId,
|
|
3505
3781
|
stream: screenStream,
|
|
3506
3782
|
streamId: screenShareStreamId,
|
|
3783
|
+
streamType: "screenshare",
|
|
3507
3784
|
});
|
|
3508
3785
|
|
|
3509
3786
|
clientState.hasEmittedScreenStream = true;
|
|
@@ -5006,6 +5283,15 @@ class RemoteParticipant extends RoomParticipant {
|
|
|
5006
5283
|
this.newJoiner = newJoiner;
|
|
5007
5284
|
this.streams = streams.map((streamId) => ({ id: streamId, state: newJoiner ? "new_accept" : "to_accept" }));
|
|
5008
5285
|
}
|
|
5286
|
+
addStream(streamId, state) {
|
|
5287
|
+
this.streams.push({ id: streamId, state });
|
|
5288
|
+
}
|
|
5289
|
+
removeStream(streamId) {
|
|
5290
|
+
const index = this.streams.findIndex((s) => s.id === streamId);
|
|
5291
|
+
if (index !== -1) {
|
|
5292
|
+
this.streams.splice(index, 1);
|
|
5293
|
+
}
|
|
5294
|
+
}
|
|
5009
5295
|
updateStreamState(streamId, state) {
|
|
5010
5296
|
const stream = this.streams.find((s) => s.id === streamId);
|
|
5011
5297
|
if (stream) {
|
|
@@ -5020,19 +5306,23 @@ class LocalParticipant extends RoomParticipant {
|
|
|
5020
5306
|
}
|
|
5021
5307
|
}
|
|
5022
5308
|
|
|
5023
|
-
const API_BASE_URL = "https://api.
|
|
5024
|
-
const SIGNAL_BASE_URL = "wss://signal.appearin.net";
|
|
5309
|
+
const API_BASE_URL = process.env["REACT_APP_API_BASE_URL"] || "https://api.whereby.dev";
|
|
5310
|
+
const SIGNAL_BASE_URL = process.env["REACT_APP_SIGNAL_BASE_URL"] || "wss://signal.appearin.net";
|
|
5025
5311
|
const NON_PERSON_ROLES = ["recorder", "streamer"];
|
|
5312
|
+
// cache last reported stream resolutions
|
|
5313
|
+
const reportedStreamResolutions = new Map();
|
|
5026
5314
|
function createSocket() {
|
|
5027
5315
|
const parsedUrl = new URL(SIGNAL_BASE_URL);
|
|
5028
|
-
const path = `${parsedUrl.pathname.replace(/^\/$/, "")}/protocol/socket.io/
|
|
5316
|
+
const path = `${parsedUrl.pathname.replace(/^\/$/, "")}/protocol/socket.io/v4`;
|
|
5029
5317
|
const SOCKET_HOST = parsedUrl.origin;
|
|
5030
5318
|
const socketConf = {
|
|
5319
|
+
autoConnect: false,
|
|
5031
5320
|
host: SOCKET_HOST,
|
|
5032
5321
|
path,
|
|
5033
5322
|
reconnectionDelay: 5000,
|
|
5034
5323
|
reconnectionDelayMax: 30000,
|
|
5035
5324
|
timeout: 10000,
|
|
5325
|
+
withCredentials: true,
|
|
5036
5326
|
};
|
|
5037
5327
|
return new ServerSocket(SOCKET_HOST, socketConf);
|
|
5038
5328
|
}
|
|
@@ -5041,12 +5331,20 @@ const noop = () => {
|
|
|
5041
5331
|
};
|
|
5042
5332
|
const TypedEventTarget = EventTarget;
|
|
5043
5333
|
class RoomConnection extends TypedEventTarget {
|
|
5044
|
-
constructor(roomUrl, { displayName,
|
|
5334
|
+
constructor(roomUrl, { displayName, localMedia, localMediaConstraints, logger, roomKey }) {
|
|
5045
5335
|
super();
|
|
5046
5336
|
this.localParticipant = null;
|
|
5047
5337
|
this.remoteParticipants = [];
|
|
5048
|
-
this.
|
|
5338
|
+
this.screenshares = [];
|
|
5339
|
+
this._deviceCredentials = null;
|
|
5340
|
+
this._ownsLocalMedia = false;
|
|
5341
|
+
this.organizationId = "";
|
|
5342
|
+
this.roomConnectionStatus = "";
|
|
5343
|
+
this.selfId = null;
|
|
5049
5344
|
this.roomUrl = new URL(roomUrl); // Throw if invalid Whereby room url
|
|
5345
|
+
const searchParams = new URLSearchParams(this.roomUrl.search);
|
|
5346
|
+
this._roomKey = roomKey || searchParams.get("roomKey");
|
|
5347
|
+
this.roomName = this.roomUrl.pathname;
|
|
5050
5348
|
this.logger = logger || {
|
|
5051
5349
|
debug: noop,
|
|
5052
5350
|
error: noop,
|
|
@@ -5054,10 +5352,20 @@ class RoomConnection extends TypedEventTarget {
|
|
|
5054
5352
|
warn: noop,
|
|
5055
5353
|
};
|
|
5056
5354
|
this.displayName = displayName;
|
|
5057
|
-
this.localStream = localStream;
|
|
5058
5355
|
this.localMediaConstraints = localMediaConstraints;
|
|
5059
5356
|
const urls = fromLocation({ host: this.roomUrl.host });
|
|
5060
|
-
//
|
|
5357
|
+
// Set up local media
|
|
5358
|
+
if (localMedia) {
|
|
5359
|
+
this.localMedia = localMedia;
|
|
5360
|
+
}
|
|
5361
|
+
else if (localMediaConstraints) {
|
|
5362
|
+
this.localMedia = new LocalMedia(localMediaConstraints);
|
|
5363
|
+
this._ownsLocalMedia = true;
|
|
5364
|
+
}
|
|
5365
|
+
else {
|
|
5366
|
+
throw new Error("Missing constraints");
|
|
5367
|
+
}
|
|
5368
|
+
// Set up services
|
|
5061
5369
|
this.credentialsService = CredentialsService.create({ baseUrl: API_BASE_URL });
|
|
5062
5370
|
this.apiClient = new ApiClient({
|
|
5063
5371
|
fetchDeviceCredentials: this.credentialsService.getCredentials.bind(this.credentialsService),
|
|
@@ -5079,12 +5387,93 @@ class RoomConnection extends TypedEventTarget {
|
|
|
5079
5387
|
// Create signal socket and set up event listeners
|
|
5080
5388
|
this.signalSocket = createSocket();
|
|
5081
5389
|
this.signalSocket.on("new_client", this._handleNewClient.bind(this));
|
|
5390
|
+
this.signalSocket.on("chat_message", this._handleNewChatMessage.bind(this));
|
|
5082
5391
|
this.signalSocket.on("client_left", this._handleClientLeft.bind(this));
|
|
5083
5392
|
this.signalSocket.on("audio_enabled", this._handleClientAudioEnabled.bind(this));
|
|
5084
5393
|
this.signalSocket.on("video_enabled", this._handleClientVideoEnabled.bind(this));
|
|
5085
5394
|
this.signalSocket.on("client_metadata_received", this._handleClientMetadataReceived.bind(this));
|
|
5395
|
+
this.signalSocket.on("knock_handled", this._handleKnockHandled.bind(this));
|
|
5396
|
+
this.signalSocket.on("knocker_left", this._handleKnockerLeft.bind(this));
|
|
5397
|
+
this.signalSocket.on("room_joined", this._handleRoomJoined.bind(this));
|
|
5398
|
+
this.signalSocket.on("room_knocked", this._handleRoomKnocked.bind(this));
|
|
5399
|
+
this.signalSocket.on("cloud_recording_stopped", this._handleCloudRecordingStopped.bind(this));
|
|
5400
|
+
this.signalSocket.on("screenshare_started", this._handleScreenshareStarted.bind(this));
|
|
5401
|
+
this.signalSocket.on("screenshare_stopped", this._handleScreenshareStopped.bind(this));
|
|
5402
|
+
this.signalSocket.on("streaming_stopped", this._handleStreamingStopped.bind(this));
|
|
5403
|
+
this.signalSocket.on("disconnect", this._handleDisconnect.bind(this));
|
|
5404
|
+
this.signalSocket.on("connect_error", this._handleDisconnect.bind(this));
|
|
5405
|
+
this.signalSocketManager = this.signalSocket.getManager();
|
|
5406
|
+
this.signalSocketManager.on("reconnect", this._handleReconnect.bind(this));
|
|
5407
|
+
// Set up local media listeners
|
|
5408
|
+
this.localMedia.addEventListener("camera_enabled", (e) => {
|
|
5409
|
+
const { enabled } = e.detail;
|
|
5410
|
+
this.signalSocket.emit("enable_video", { enabled });
|
|
5411
|
+
});
|
|
5412
|
+
this.localMedia.addEventListener("microphone_enabled", (e) => {
|
|
5413
|
+
const { enabled } = e.detail;
|
|
5414
|
+
this.signalSocket.emit("enable_audio", { enabled });
|
|
5415
|
+
});
|
|
5416
|
+
const webrtcProvider = {
|
|
5417
|
+
getMediaConstraints: () => ({
|
|
5418
|
+
audio: this.localMedia.isMicrophoneEnabled(),
|
|
5419
|
+
video: this.localMedia.isCameraEnabled(),
|
|
5420
|
+
}),
|
|
5421
|
+
deferrable(clientId) {
|
|
5422
|
+
return !clientId;
|
|
5423
|
+
},
|
|
5424
|
+
};
|
|
5425
|
+
this.rtcManagerDispatcher = new RtcManagerDispatcher({
|
|
5426
|
+
emitter: {
|
|
5427
|
+
emit: this._handleRtcEvent.bind(this),
|
|
5428
|
+
},
|
|
5429
|
+
serverSocket: this.signalSocket,
|
|
5430
|
+
webrtcProvider,
|
|
5431
|
+
features: {
|
|
5432
|
+
lowDataModeEnabled: false,
|
|
5433
|
+
sfuServerOverrideHost: undefined,
|
|
5434
|
+
turnServerOverrideHost: undefined,
|
|
5435
|
+
useOnlyTURN: undefined,
|
|
5436
|
+
vp9On: false,
|
|
5437
|
+
h264On: false,
|
|
5438
|
+
simulcastScreenshareOn: false,
|
|
5439
|
+
},
|
|
5440
|
+
});
|
|
5441
|
+
}
|
|
5442
|
+
get roomKey() {
|
|
5443
|
+
return this._roomKey;
|
|
5444
|
+
}
|
|
5445
|
+
_handleNewChatMessage(message) {
|
|
5446
|
+
this.dispatchEvent(new CustomEvent("chat_message", { detail: message }));
|
|
5447
|
+
}
|
|
5448
|
+
_handleCloudRecordingStarted({ client }) {
|
|
5449
|
+
this.dispatchEvent(new CustomEvent("cloud_recording_started", {
|
|
5450
|
+
detail: {
|
|
5451
|
+
status: "recording",
|
|
5452
|
+
startedAt: client.startedCloudRecordingAt
|
|
5453
|
+
? new Date(client.startedCloudRecordingAt).getTime()
|
|
5454
|
+
: new Date().getTime(),
|
|
5455
|
+
},
|
|
5456
|
+
}));
|
|
5457
|
+
}
|
|
5458
|
+
_handleStreamingStarted() {
|
|
5459
|
+
this.dispatchEvent(new CustomEvent("streaming_started", {
|
|
5460
|
+
detail: {
|
|
5461
|
+
status: "streaming",
|
|
5462
|
+
// We don't have the streaming start time stored on the
|
|
5463
|
+
// server, so we use the current time instead. This gives
|
|
5464
|
+
// an invalid timestamp for "Client B" if "Client A" has
|
|
5465
|
+
// been streaming for a while before "Client B" joins.
|
|
5466
|
+
startedAt: new Date().getTime(),
|
|
5467
|
+
},
|
|
5468
|
+
}));
|
|
5086
5469
|
}
|
|
5087
5470
|
_handleNewClient({ client }) {
|
|
5471
|
+
if (client.role.roleName === "recorder") {
|
|
5472
|
+
this._handleCloudRecordingStarted({ client });
|
|
5473
|
+
}
|
|
5474
|
+
if (client.role.roleName === "streamer") {
|
|
5475
|
+
this._handleStreamingStarted();
|
|
5476
|
+
}
|
|
5088
5477
|
if (NON_PERSON_ROLES.includes(client.role.roleName)) {
|
|
5089
5478
|
return;
|
|
5090
5479
|
}
|
|
@@ -5128,6 +5517,135 @@ class RoomConnection extends TypedEventTarget {
|
|
|
5128
5517
|
detail: { participantId: remoteParticipant.id, displayName },
|
|
5129
5518
|
}));
|
|
5130
5519
|
}
|
|
5520
|
+
_handleKnockHandled(payload) {
|
|
5521
|
+
const { clientId, resolution } = payload;
|
|
5522
|
+
// If the knocker is not the local participant, ignore the event
|
|
5523
|
+
if (clientId !== this.selfId) {
|
|
5524
|
+
return;
|
|
5525
|
+
}
|
|
5526
|
+
if (resolution === "accepted") {
|
|
5527
|
+
this.roomConnectionStatus = "accepted";
|
|
5528
|
+
this._roomKey = payload.metadata.roomKey;
|
|
5529
|
+
this._joinRoom();
|
|
5530
|
+
}
|
|
5531
|
+
else if (resolution === "rejected") {
|
|
5532
|
+
this.roomConnectionStatus = "rejected";
|
|
5533
|
+
this.dispatchEvent(new CustomEvent("room_connection_status_changed", {
|
|
5534
|
+
detail: {
|
|
5535
|
+
roomConnectionStatus: this.roomConnectionStatus,
|
|
5536
|
+
},
|
|
5537
|
+
}));
|
|
5538
|
+
}
|
|
5539
|
+
}
|
|
5540
|
+
_handleKnockerLeft(payload) {
|
|
5541
|
+
const { clientId } = payload;
|
|
5542
|
+
this.dispatchEvent(new CustomEvent("waiting_participant_left", {
|
|
5543
|
+
detail: { participantId: clientId },
|
|
5544
|
+
}));
|
|
5545
|
+
}
|
|
5546
|
+
_handleRoomJoined(event) {
|
|
5547
|
+
const { error, isLocked, room, selfId } = event;
|
|
5548
|
+
this.selfId = selfId;
|
|
5549
|
+
if (error === "room_locked" && isLocked) {
|
|
5550
|
+
this.roomConnectionStatus = "room_locked";
|
|
5551
|
+
this.dispatchEvent(new CustomEvent("room_connection_status_changed", {
|
|
5552
|
+
detail: {
|
|
5553
|
+
roomConnectionStatus: this.roomConnectionStatus,
|
|
5554
|
+
},
|
|
5555
|
+
}));
|
|
5556
|
+
return;
|
|
5557
|
+
}
|
|
5558
|
+
// Check if we have an error
|
|
5559
|
+
// Check if it is a room joined error
|
|
5560
|
+
// Set state to connect_failed_locked
|
|
5561
|
+
// Set state to connect_failed_no_host
|
|
5562
|
+
if (room) {
|
|
5563
|
+
const { clients, knockers } = room;
|
|
5564
|
+
const localClient = clients.find((c) => c.id === selfId);
|
|
5565
|
+
if (!localClient)
|
|
5566
|
+
throw new Error("Missing local client");
|
|
5567
|
+
this.localParticipant = new LocalParticipant(Object.assign(Object.assign({}, localClient), { stream: this.localMedia.stream || undefined }));
|
|
5568
|
+
const recorderClient = clients.find((c) => c.role.roleName === "recorder");
|
|
5569
|
+
if (recorderClient) {
|
|
5570
|
+
this._handleCloudRecordingStarted({ client: recorderClient });
|
|
5571
|
+
}
|
|
5572
|
+
const streamerClient = clients.find((c) => c.role.roleName === "streamer");
|
|
5573
|
+
if (streamerClient) {
|
|
5574
|
+
this._handleStreamingStarted();
|
|
5575
|
+
}
|
|
5576
|
+
this.remoteParticipants = clients
|
|
5577
|
+
.filter((c) => c.id !== selfId)
|
|
5578
|
+
.filter((c) => !NON_PERSON_ROLES.includes(c.role.roleName))
|
|
5579
|
+
.map((c) => new RemoteParticipant(Object.assign(Object.assign({}, c), { newJoiner: false })));
|
|
5580
|
+
this.roomConnectionStatus = "connected";
|
|
5581
|
+
this.dispatchEvent(new CustomEvent("room_joined", {
|
|
5582
|
+
detail: {
|
|
5583
|
+
localParticipant: this.localParticipant,
|
|
5584
|
+
remoteParticipants: this.remoteParticipants,
|
|
5585
|
+
waitingParticipants: knockers.map((knocker) => {
|
|
5586
|
+
return { id: knocker.clientId, displayName: knocker.displayName };
|
|
5587
|
+
}),
|
|
5588
|
+
},
|
|
5589
|
+
}));
|
|
5590
|
+
}
|
|
5591
|
+
}
|
|
5592
|
+
_handleRoomKnocked(event) {
|
|
5593
|
+
const { clientId, displayName } = event;
|
|
5594
|
+
this.dispatchEvent(new CustomEvent("waiting_participant_joined", {
|
|
5595
|
+
detail: { participantId: clientId, displayName },
|
|
5596
|
+
}));
|
|
5597
|
+
}
|
|
5598
|
+
_handleReconnect() {
|
|
5599
|
+
this.logger.log("Reconnected to signal socket");
|
|
5600
|
+
this.signalSocket.emit("identify_device", { deviceCredentials: this._deviceCredentials });
|
|
5601
|
+
this.signalSocket.once("device_identified", () => {
|
|
5602
|
+
this._joinRoom();
|
|
5603
|
+
});
|
|
5604
|
+
}
|
|
5605
|
+
_handleDisconnect() {
|
|
5606
|
+
this.roomConnectionStatus = "disconnected";
|
|
5607
|
+
this.dispatchEvent(new CustomEvent("room_connection_status_changed", {
|
|
5608
|
+
detail: {
|
|
5609
|
+
roomConnectionStatus: this.roomConnectionStatus,
|
|
5610
|
+
},
|
|
5611
|
+
}));
|
|
5612
|
+
}
|
|
5613
|
+
_handleCloudRecordingStopped() {
|
|
5614
|
+
this.dispatchEvent(new CustomEvent("cloud_recording_stopped"));
|
|
5615
|
+
}
|
|
5616
|
+
_handleStreamingStopped() {
|
|
5617
|
+
this.dispatchEvent(new CustomEvent("streaming_stopped"));
|
|
5618
|
+
}
|
|
5619
|
+
_handleScreenshareStarted(screenshare) {
|
|
5620
|
+
const { clientId: participantId, streamId: id, hasAudioTrack } = screenshare;
|
|
5621
|
+
const remoteParticipant = this.remoteParticipants.find((p) => p.id === participantId);
|
|
5622
|
+
if (!remoteParticipant) {
|
|
5623
|
+
this.logger.log("WARN: Could not find participant for screenshare");
|
|
5624
|
+
return;
|
|
5625
|
+
}
|
|
5626
|
+
const foundScreenshare = this.screenshares.find((s) => s.id === id);
|
|
5627
|
+
if (foundScreenshare) {
|
|
5628
|
+
this.logger.log("WARN: Screenshare already exists");
|
|
5629
|
+
return;
|
|
5630
|
+
}
|
|
5631
|
+
remoteParticipant.addStream(id, "to_accept");
|
|
5632
|
+
this._handleAcceptStreams([remoteParticipant]);
|
|
5633
|
+
this.screenshares = [
|
|
5634
|
+
...this.screenshares,
|
|
5635
|
+
{ participantId, id, hasAudioTrack, stream: undefined, isLocal: false },
|
|
5636
|
+
];
|
|
5637
|
+
}
|
|
5638
|
+
_handleScreenshareStopped(screenshare) {
|
|
5639
|
+
const { clientId: participantId, streamId: id } = screenshare;
|
|
5640
|
+
const remoteParticipant = this.remoteParticipants.find((p) => p.id === participantId);
|
|
5641
|
+
if (!remoteParticipant) {
|
|
5642
|
+
this.logger.log("WARN: Could not find participant for screenshare");
|
|
5643
|
+
return;
|
|
5644
|
+
}
|
|
5645
|
+
remoteParticipant.removeStream(id);
|
|
5646
|
+
this.screenshares = this.screenshares.filter((s) => !(s.participantId === participantId && s.id === id));
|
|
5647
|
+
this.dispatchEvent(new CustomEvent("screenshare_stopped", { detail: { participantId, id } }));
|
|
5648
|
+
}
|
|
5131
5649
|
_handleRtcEvent(eventName, data) {
|
|
5132
5650
|
if (eventName === "rtc_manager_created") {
|
|
5133
5651
|
return this._handleRtcManagerCreated(data);
|
|
@@ -5135,16 +5653,26 @@ class RoomConnection extends TypedEventTarget {
|
|
|
5135
5653
|
else if (eventName === "stream_added") {
|
|
5136
5654
|
return this._handleStreamAdded(data);
|
|
5137
5655
|
}
|
|
5656
|
+
else if (eventName === "rtc_manager_destroyed") {
|
|
5657
|
+
return this._handleRtcManagerDestroyed();
|
|
5658
|
+
}
|
|
5138
5659
|
else {
|
|
5139
5660
|
this.logger.log(`Unhandled RTC event ${eventName}`);
|
|
5140
5661
|
}
|
|
5141
5662
|
}
|
|
5142
5663
|
_handleRtcManagerCreated({ rtcManager }) {
|
|
5143
|
-
var _a
|
|
5664
|
+
var _a;
|
|
5144
5665
|
this.rtcManager = rtcManager;
|
|
5145
|
-
|
|
5146
|
-
|
|
5666
|
+
this.localMedia.addRtcManager(rtcManager);
|
|
5667
|
+
if (this.localMedia.stream) {
|
|
5668
|
+
(_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.addNewStream("0", this.localMedia.stream, !this.localMedia.isMicrophoneEnabled(), !this.localMedia.isCameraEnabled());
|
|
5147
5669
|
}
|
|
5670
|
+
if (this.remoteParticipants.length) {
|
|
5671
|
+
this._handleAcceptStreams(this.remoteParticipants);
|
|
5672
|
+
}
|
|
5673
|
+
}
|
|
5674
|
+
_handleRtcManagerDestroyed() {
|
|
5675
|
+
this.rtcManager = undefined;
|
|
5148
5676
|
}
|
|
5149
5677
|
_handleAcceptStreams(remoteParticipants) {
|
|
5150
5678
|
var _a, _b;
|
|
@@ -5168,8 +5696,6 @@ class RoomConnection extends TypedEventTarget {
|
|
|
5168
5696
|
if (!newState) {
|
|
5169
5697
|
return;
|
|
5170
5698
|
}
|
|
5171
|
-
// #endregion
|
|
5172
|
-
// #region doAcceptStreams
|
|
5173
5699
|
if (newState === "to_accept" ||
|
|
5174
5700
|
(newState === "new_accept" && shouldAcceptNewClients) ||
|
|
5175
5701
|
(newState === "old_accept" && !shouldAcceptNewClients)) {
|
|
@@ -5193,155 +5719,118 @@ class RoomConnection extends TypedEventTarget {
|
|
|
5193
5719
|
else ;
|
|
5194
5720
|
// Update stream state
|
|
5195
5721
|
participant.updateStreamState(streamId, streamState.replace(/to_|new_|old_/, "done_"));
|
|
5196
|
-
// #endregion
|
|
5197
5722
|
});
|
|
5198
5723
|
});
|
|
5199
5724
|
}
|
|
5200
|
-
_handleStreamAdded({ clientId, stream, streamId }) {
|
|
5725
|
+
_handleStreamAdded({ clientId, stream, streamId, streamType }) {
|
|
5201
5726
|
const remoteParticipant = this.remoteParticipants.find((p) => p.id === clientId);
|
|
5202
5727
|
if (!remoteParticipant) {
|
|
5203
5728
|
this.logger.log("WARN: Could not find participant for incoming stream");
|
|
5204
5729
|
return;
|
|
5205
5730
|
}
|
|
5206
|
-
|
|
5731
|
+
const remoteParticipantStream = remoteParticipant.streams.find((s) => s.id === streamId);
|
|
5732
|
+
if ((remoteParticipant.stream && remoteParticipant.stream.id === streamId) ||
|
|
5733
|
+
(!remoteParticipant.stream && streamType === "webcam") ||
|
|
5734
|
+
(!remoteParticipant.stream &&
|
|
5735
|
+
!streamType &&
|
|
5736
|
+
remoteParticipantStream &&
|
|
5737
|
+
remoteParticipant.streams.indexOf(remoteParticipantStream) < 1)) {
|
|
5738
|
+
this.dispatchEvent(new CustomEvent("participant_stream_added", { detail: { participantId: clientId, stream, streamId } }));
|
|
5739
|
+
return;
|
|
5740
|
+
}
|
|
5741
|
+
// screenshare
|
|
5742
|
+
this.dispatchEvent(new CustomEvent("screenshare_started", {
|
|
5743
|
+
detail: { participantId: clientId, stream, id: streamId, isLocal: false },
|
|
5744
|
+
}));
|
|
5745
|
+
}
|
|
5746
|
+
_joinRoom() {
|
|
5747
|
+
this.signalSocket.emit("join_room", {
|
|
5748
|
+
avatarUrl: null,
|
|
5749
|
+
config: {
|
|
5750
|
+
isAudioEnabled: this.localMedia.isMicrophoneEnabled(),
|
|
5751
|
+
isVideoEnabled: this.localMedia.isCameraEnabled(),
|
|
5752
|
+
},
|
|
5753
|
+
deviceCapabilities: { canScreenshare: true },
|
|
5754
|
+
displayName: this.displayName,
|
|
5755
|
+
isCoLocated: false,
|
|
5756
|
+
isDevicePermissionDenied: false,
|
|
5757
|
+
kickFromOtherRooms: false,
|
|
5758
|
+
organizationId: this.organizationId,
|
|
5759
|
+
roomKey: this.roomKey,
|
|
5760
|
+
roomName: this.roomName,
|
|
5761
|
+
selfId: "",
|
|
5762
|
+
userAgent: `browser-sdk:${sdkVersion }`,
|
|
5763
|
+
});
|
|
5207
5764
|
}
|
|
5208
|
-
/**
|
|
5209
|
-
* Public API
|
|
5210
|
-
*/
|
|
5211
5765
|
join() {
|
|
5212
5766
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
5213
|
-
if (["connected", "connecting"].includes(this.
|
|
5214
|
-
console.warn(`Trying to join room state is ${this.
|
|
5767
|
+
if (["connected", "connecting"].includes(this.roomConnectionStatus)) {
|
|
5768
|
+
console.warn(`Trying to join when room state is already ${this.roomConnectionStatus}`);
|
|
5215
5769
|
return;
|
|
5216
5770
|
}
|
|
5217
5771
|
this.logger.log("Joining room");
|
|
5218
|
-
this.
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
|
|
5772
|
+
this.signalSocket.connect();
|
|
5773
|
+
this.roomConnectionStatus = "connecting";
|
|
5774
|
+
this.dispatchEvent(new CustomEvent("room_connection_status_changed", {
|
|
5775
|
+
detail: {
|
|
5776
|
+
roomConnectionStatus: this.roomConnectionStatus,
|
|
5777
|
+
},
|
|
5778
|
+
}));
|
|
5223
5779
|
const organization = yield this.organizationServiceCache.fetchOrganization();
|
|
5224
5780
|
if (!organization) {
|
|
5225
5781
|
throw new Error("Invalid room url");
|
|
5226
5782
|
}
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
var _a, _b;
|
|
5232
|
-
return ({
|
|
5233
|
-
audio: !!((_a = this.localStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().find((t) => t.enabled)),
|
|
5234
|
-
video: !!((_b = this.localStream) === null || _b === void 0 ? void 0 : _b.getVideoTracks().find((t) => t.enabled)),
|
|
5235
|
-
});
|
|
5236
|
-
},
|
|
5237
|
-
deferrable(clientId) {
|
|
5238
|
-
return !clientId;
|
|
5239
|
-
},
|
|
5240
|
-
};
|
|
5241
|
-
this.rtcManagerDispatcher = new RtcManagerDispatcher({
|
|
5242
|
-
emitter: {
|
|
5243
|
-
emit: this._handleRtcEvent.bind(this),
|
|
5244
|
-
},
|
|
5245
|
-
serverSocket: this.signalSocket,
|
|
5246
|
-
webrtcProvider,
|
|
5247
|
-
features: {
|
|
5248
|
-
lowDataModeEnabled: false,
|
|
5249
|
-
sfuServerOverrideHost: undefined,
|
|
5250
|
-
turnServerOverrideHost: undefined,
|
|
5251
|
-
useOnlyTURN: undefined,
|
|
5252
|
-
vp9On: false,
|
|
5253
|
-
h264On: false,
|
|
5254
|
-
simulcastScreenshareOn: false,
|
|
5255
|
-
},
|
|
5256
|
-
});
|
|
5783
|
+
this.organizationId = organization.organizationId;
|
|
5784
|
+
if (this._ownsLocalMedia) {
|
|
5785
|
+
yield this.localMedia.start();
|
|
5786
|
+
}
|
|
5257
5787
|
// Identify device on signal connection
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
this.logger.log("Connected to signal socket");
|
|
5262
|
-
this.signalSocket.emit("identify_device", { deviceCredentials });
|
|
5263
|
-
}, 2000);
|
|
5788
|
+
this._deviceCredentials = yield this.credentialsService.getCredentials();
|
|
5789
|
+
this.logger.log("Connected to signal socket");
|
|
5790
|
+
this.signalSocket.emit("identify_device", { deviceCredentials: this._deviceCredentials });
|
|
5264
5791
|
this.signalSocket.once("device_identified", () => {
|
|
5265
|
-
|
|
5266
|
-
this.signalSocket.emit("join_room", {
|
|
5267
|
-
avatarUrl: null,
|
|
5268
|
-
config: {
|
|
5269
|
-
isAudioEnabled: !!((_a = this.localStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().find((t) => t.enabled)),
|
|
5270
|
-
isVideoEnabled: !!((_b = this.localStream) === null || _b === void 0 ? void 0 : _b.getVideoTracks().find((t) => t.enabled)),
|
|
5271
|
-
},
|
|
5272
|
-
deviceCapabilities: { canScreenshare: true },
|
|
5273
|
-
displayName: this.displayName,
|
|
5274
|
-
isCoLocated: false,
|
|
5275
|
-
isDevicePermissionDenied: false,
|
|
5276
|
-
kickFromOtherRooms: false,
|
|
5277
|
-
organizationId: organization.organizationId,
|
|
5278
|
-
roomKey: null,
|
|
5279
|
-
roomName: this.roomUrl.pathname,
|
|
5280
|
-
selfId: "",
|
|
5281
|
-
});
|
|
5282
|
-
});
|
|
5283
|
-
this.signalSocket.once("room_joined", (res) => {
|
|
5284
|
-
const { selfId, room: { clients }, } = res;
|
|
5285
|
-
const localClient = clients.find((c) => c.id === selfId);
|
|
5286
|
-
if (!localClient)
|
|
5287
|
-
throw new Error("Missing local client");
|
|
5288
|
-
this.localParticipant = new LocalParticipant(Object.assign(Object.assign({}, localClient), { stream: this.localStream }));
|
|
5289
|
-
this.remoteParticipants = clients
|
|
5290
|
-
.filter((c) => c.id !== selfId)
|
|
5291
|
-
.map((c) => new RemoteParticipant(Object.assign(Object.assign({}, c), { newJoiner: false })));
|
|
5292
|
-
// Accept remote streams if RTC manager has been initialized
|
|
5293
|
-
if (this.rtcManager) {
|
|
5294
|
-
this._handleAcceptStreams(this.remoteParticipants);
|
|
5295
|
-
}
|
|
5296
|
-
this.roomConnectionState = "connected";
|
|
5297
|
-
this.dispatchEvent(new CustomEvent("room_joined", {
|
|
5298
|
-
detail: {
|
|
5299
|
-
localParticipant: this.localParticipant,
|
|
5300
|
-
remoteParticipants: this.remoteParticipants,
|
|
5301
|
-
},
|
|
5302
|
-
}));
|
|
5792
|
+
this._joinRoom();
|
|
5303
5793
|
});
|
|
5304
5794
|
});
|
|
5305
5795
|
}
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5796
|
+
knock() {
|
|
5797
|
+
this.roomConnectionStatus = "knocking";
|
|
5798
|
+
this.dispatchEvent(new CustomEvent("room_connection_status_changed", {
|
|
5799
|
+
detail: {
|
|
5800
|
+
roomConnectionStatus: this.roomConnectionStatus,
|
|
5801
|
+
},
|
|
5802
|
+
}));
|
|
5803
|
+
this.signalSocket.emit("knock_room", {
|
|
5804
|
+
displayName: this.displayName,
|
|
5805
|
+
imageUrl: null,
|
|
5806
|
+
kickFromOtherRooms: true,
|
|
5807
|
+
liveVideo: false,
|
|
5808
|
+
organizationId: this.organizationId,
|
|
5809
|
+
roomKey: this._roomKey,
|
|
5810
|
+
roomName: this.roomName,
|
|
5320
5811
|
});
|
|
5321
5812
|
}
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
this.logger.log("Tried toggling non-existing video track");
|
|
5327
|
-
return;
|
|
5813
|
+
leave() {
|
|
5814
|
+
this.roomConnectionStatus = "disconnecting";
|
|
5815
|
+
if (this._ownsLocalMedia) {
|
|
5816
|
+
this.localMedia.stop();
|
|
5328
5817
|
}
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
var _a;
|
|
5336
|
-
const localAudioTrack = (_a = this.localStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks()[0];
|
|
5337
|
-
if (!localAudioTrack) {
|
|
5338
|
-
this.logger.log("Tried toggling non-existing audio track");
|
|
5818
|
+
if (this.rtcManager) {
|
|
5819
|
+
this.localMedia.removeRtcManager(this.rtcManager);
|
|
5820
|
+
this.rtcManager.disconnectAll();
|
|
5821
|
+
this.rtcManager = undefined;
|
|
5822
|
+
}
|
|
5823
|
+
if (!this.signalSocket) {
|
|
5339
5824
|
return;
|
|
5340
5825
|
}
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5826
|
+
this.signalSocket.emit("leave_room");
|
|
5827
|
+
this.signalSocket.disconnect();
|
|
5828
|
+
this.roomConnectionStatus = "disconnected";
|
|
5829
|
+
}
|
|
5830
|
+
sendChatMessage(text) {
|
|
5831
|
+
this.signalSocket.emit("chat_message", {
|
|
5832
|
+
text,
|
|
5833
|
+
});
|
|
5345
5834
|
}
|
|
5346
5835
|
setDisplayName(displayName) {
|
|
5347
5836
|
this.signalSocket.emit("send_client_metadata", {
|
|
@@ -5351,8 +5840,93 @@ class RoomConnection extends TypedEventTarget {
|
|
|
5351
5840
|
},
|
|
5352
5841
|
});
|
|
5353
5842
|
}
|
|
5843
|
+
acceptWaitingParticipant(participantId) {
|
|
5844
|
+
this.signalSocket.emit("handle_knock", {
|
|
5845
|
+
action: "accept",
|
|
5846
|
+
clientId: participantId,
|
|
5847
|
+
response: {},
|
|
5848
|
+
});
|
|
5849
|
+
}
|
|
5850
|
+
rejectWaitingParticipant(participantId) {
|
|
5851
|
+
this.signalSocket.emit("handle_knock", {
|
|
5852
|
+
action: "reject",
|
|
5853
|
+
clientId: participantId,
|
|
5854
|
+
response: {},
|
|
5855
|
+
});
|
|
5856
|
+
}
|
|
5857
|
+
updateStreamResolution({ streamId, width, height }) {
|
|
5858
|
+
var _a, _b;
|
|
5859
|
+
if (!streamId || !this.rtcManager) {
|
|
5860
|
+
return;
|
|
5861
|
+
}
|
|
5862
|
+
// no need to report resolution for local participant
|
|
5863
|
+
if (((_b = (_a = this.localParticipant) === null || _a === void 0 ? void 0 : _a.stream) === null || _b === void 0 ? void 0 : _b.id) === streamId) {
|
|
5864
|
+
return;
|
|
5865
|
+
}
|
|
5866
|
+
const old = reportedStreamResolutions.get(streamId);
|
|
5867
|
+
if (!old || old.width !== width || old.height !== height) {
|
|
5868
|
+
this.rtcManager.updateStreamResolution(streamId, null, { width: width || 1, height: height || 1 });
|
|
5869
|
+
}
|
|
5870
|
+
reportedStreamResolutions.set(streamId, { width, height });
|
|
5871
|
+
}
|
|
5872
|
+
startScreenshare() {
|
|
5873
|
+
var _a;
|
|
5874
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
5875
|
+
const screenshareStream = this.localMedia.screenshareStream || (yield this.localMedia.startScreenshare());
|
|
5876
|
+
(_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.addNewStream(screenshareStream.id, screenshareStream, false, true);
|
|
5877
|
+
this.screenshares = [
|
|
5878
|
+
...this.screenshares,
|
|
5879
|
+
{
|
|
5880
|
+
participantId: this.selfId || "",
|
|
5881
|
+
id: screenshareStream.id,
|
|
5882
|
+
hasAudioTrack: false,
|
|
5883
|
+
stream: screenshareStream,
|
|
5884
|
+
isLocal: true,
|
|
5885
|
+
},
|
|
5886
|
+
];
|
|
5887
|
+
this.dispatchEvent(new CustomEvent("screenshare_started", {
|
|
5888
|
+
detail: {
|
|
5889
|
+
participantId: this.selfId || "",
|
|
5890
|
+
id: screenshareStream.id,
|
|
5891
|
+
hasAudioTrack: false,
|
|
5892
|
+
stream: screenshareStream,
|
|
5893
|
+
isLocal: true,
|
|
5894
|
+
},
|
|
5895
|
+
}));
|
|
5896
|
+
});
|
|
5897
|
+
}
|
|
5898
|
+
stopScreenshare() {
|
|
5899
|
+
var _a;
|
|
5900
|
+
if (this.localMedia.screenshareStream) {
|
|
5901
|
+
const { id } = this.localMedia.screenshareStream;
|
|
5902
|
+
(_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.removeStream(id, this.localMedia.screenshareStream, null);
|
|
5903
|
+
this.screenshares = this.screenshares.filter((s) => s.id !== id);
|
|
5904
|
+
this.dispatchEvent(new CustomEvent("screenshare_stopped", { detail: { participantId: this.selfId, id } }));
|
|
5905
|
+
this.localMedia.stopScreenshare();
|
|
5906
|
+
}
|
|
5907
|
+
}
|
|
5354
5908
|
}
|
|
5355
5909
|
|
|
5910
|
+
const initialState = {
|
|
5911
|
+
chatMessages: [],
|
|
5912
|
+
cloudRecording: {
|
|
5913
|
+
status: "",
|
|
5914
|
+
startedAt: null,
|
|
5915
|
+
},
|
|
5916
|
+
isJoining: false,
|
|
5917
|
+
isStartingScreenshare: false,
|
|
5918
|
+
joinError: null,
|
|
5919
|
+
startScreenshareError: null,
|
|
5920
|
+
mostRecentChatMessage: null,
|
|
5921
|
+
remoteParticipants: [],
|
|
5922
|
+
roomConnectionStatus: "",
|
|
5923
|
+
screenshares: [],
|
|
5924
|
+
streaming: {
|
|
5925
|
+
status: "",
|
|
5926
|
+
startedAt: null,
|
|
5927
|
+
},
|
|
5928
|
+
waitingParticipants: [],
|
|
5929
|
+
};
|
|
5356
5930
|
function updateParticipant(remoteParticipants, participantId, updates) {
|
|
5357
5931
|
const existingParticipant = remoteParticipants.find((p) => p.id === participantId);
|
|
5358
5932
|
if (!existingParticipant) {
|
|
@@ -5365,10 +5939,31 @@ function updateParticipant(remoteParticipants, participantId, updates) {
|
|
|
5365
5939
|
...remoteParticipants.slice(index + 1),
|
|
5366
5940
|
];
|
|
5367
5941
|
}
|
|
5942
|
+
function addScreenshare(screenshares, screenshare) {
|
|
5943
|
+
const existingScreenshare = screenshares.find((ss) => ss.id === screenshare.id);
|
|
5944
|
+
if (existingScreenshare) {
|
|
5945
|
+
return screenshares;
|
|
5946
|
+
}
|
|
5947
|
+
return [...screenshares, screenshare];
|
|
5948
|
+
}
|
|
5368
5949
|
function reducer(state, action) {
|
|
5369
5950
|
switch (action.type) {
|
|
5951
|
+
case "CHAT_MESSAGE":
|
|
5952
|
+
return Object.assign(Object.assign({}, state), { chatMessages: [...state.chatMessages, action.payload], mostRecentChatMessage: action.payload });
|
|
5953
|
+
case "CLOUD_RECORDING_STARTED":
|
|
5954
|
+
return Object.assign(Object.assign({}, state), { cloudRecording: {
|
|
5955
|
+
status: action.payload.status,
|
|
5956
|
+
startedAt: action.payload.startedAt,
|
|
5957
|
+
} });
|
|
5958
|
+
case "CLOUD_RECORDING_STOPPED":
|
|
5959
|
+
return Object.assign(Object.assign({}, state), { cloudRecording: {
|
|
5960
|
+
status: "",
|
|
5961
|
+
startedAt: null,
|
|
5962
|
+
} });
|
|
5370
5963
|
case "ROOM_JOINED":
|
|
5371
|
-
return Object.assign(Object.assign({}, state), { localParticipant: action.payload.localParticipant, remoteParticipants: action.payload.remoteParticipants, roomConnectionStatus: "connected" });
|
|
5964
|
+
return Object.assign(Object.assign({}, state), { localParticipant: action.payload.localParticipant, remoteParticipants: action.payload.remoteParticipants, waitingParticipants: action.payload.waitingParticipants, roomConnectionStatus: "connected" });
|
|
5965
|
+
case "ROOM_CONNECTION_STATUS_CHANGED":
|
|
5966
|
+
return Object.assign(Object.assign({}, state), { roomConnectionStatus: action.payload.roomConnectionStatus });
|
|
5372
5967
|
case "PARTICIPANT_AUDIO_ENABLED":
|
|
5373
5968
|
return Object.assign(Object.assign({}, state), { remoteParticipants: updateParticipant(state.remoteParticipants, action.payload.participantId, {
|
|
5374
5969
|
isAudioEnabled: action.payload.isAudioEnabled,
|
|
@@ -5393,75 +5988,202 @@ function reducer(state, action) {
|
|
|
5393
5988
|
if (!state.localParticipant)
|
|
5394
5989
|
return state;
|
|
5395
5990
|
return Object.assign(Object.assign({}, state), { localParticipant: Object.assign(Object.assign({}, state.localParticipant), { displayName: action.payload.displayName }) });
|
|
5991
|
+
case "SCREENSHARE_STARTED":
|
|
5992
|
+
return Object.assign(Object.assign({}, state), { screenshares: addScreenshare(state.screenshares, {
|
|
5993
|
+
participantId: action.payload.participantId,
|
|
5994
|
+
id: action.payload.id,
|
|
5995
|
+
hasAudioTrack: action.payload.hasAudioTrack,
|
|
5996
|
+
stream: action.payload.stream,
|
|
5997
|
+
isLocal: action.payload.isLocal,
|
|
5998
|
+
}) });
|
|
5999
|
+
case "SCREENSHARE_STOPPED":
|
|
6000
|
+
return Object.assign(Object.assign({}, state), { screenshares: state.screenshares.filter((ss) => ss.id !== action.payload.id) });
|
|
6001
|
+
case "LOCAL_SCREENSHARE_START_ERROR":
|
|
6002
|
+
return Object.assign(Object.assign({}, state), { isStartingScreenshare: false, startScreenshareError: action.payload });
|
|
6003
|
+
case "LOCAL_SCREENSHARE_STARTING":
|
|
6004
|
+
return Object.assign(Object.assign({}, state), { isStartingScreenshare: true });
|
|
6005
|
+
case "LOCAL_SCREENSHARE_STOPPED":
|
|
6006
|
+
return Object.assign(Object.assign({}, state), { screenshares: state.screenshares.filter((ss) => !ss.isLocal) });
|
|
6007
|
+
case "STREAMING_STARTED":
|
|
6008
|
+
return Object.assign(Object.assign({}, state), { streaming: {
|
|
6009
|
+
status: action.payload.status,
|
|
6010
|
+
startedAt: action.payload.startedAt,
|
|
6011
|
+
} });
|
|
6012
|
+
case "STREAMING_STOPPED":
|
|
6013
|
+
return Object.assign(Object.assign({}, state), { streaming: {
|
|
6014
|
+
status: "",
|
|
6015
|
+
startedAt: null,
|
|
6016
|
+
} });
|
|
6017
|
+
case "WAITING_PARTICIPANT_JOINED":
|
|
6018
|
+
return Object.assign(Object.assign({}, state), { waitingParticipants: [
|
|
6019
|
+
...state.waitingParticipants,
|
|
6020
|
+
{ id: action.payload.participantId, displayName: action.payload.displayName },
|
|
6021
|
+
] });
|
|
6022
|
+
case "WAITING_PARTICIPANT_LEFT":
|
|
6023
|
+
return Object.assign(Object.assign({}, state), { waitingParticipants: state.waitingParticipants.filter((wp) => wp.id !== action.payload.participantId) });
|
|
5396
6024
|
default:
|
|
5397
6025
|
throw state;
|
|
5398
6026
|
}
|
|
5399
|
-
}
|
|
5400
|
-
|
|
6027
|
+
}
|
|
5401
6028
|
function useRoomConnection(roomUrl, roomConnectionOptions) {
|
|
5402
|
-
const [roomConnection
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
6029
|
+
const [roomConnection] = React.useState(() => {
|
|
6030
|
+
var _a;
|
|
6031
|
+
return new RoomConnection(roomUrl, Object.assign(Object.assign({}, roomConnectionOptions), { localMedia: ((_a = roomConnectionOptions === null || roomConnectionOptions === void 0 ? void 0 : roomConnectionOptions.localMedia) === null || _a === void 0 ? void 0 : _a._ref) || undefined }));
|
|
6032
|
+
});
|
|
6033
|
+
const [state, dispatch] = React.useReducer(reducer, initialState);
|
|
6034
|
+
function createEventListener(eventName, listener, options) {
|
|
6035
|
+
return {
|
|
6036
|
+
eventName,
|
|
6037
|
+
listener,
|
|
6038
|
+
options,
|
|
6039
|
+
};
|
|
6040
|
+
}
|
|
6041
|
+
const eventListeners = React__default["default"].useMemo(() => [
|
|
6042
|
+
createEventListener("chat_message", (e) => {
|
|
6043
|
+
dispatch({ type: "CHAT_MESSAGE", payload: e.detail });
|
|
6044
|
+
}),
|
|
6045
|
+
createEventListener("cloud_recording_started", (e) => {
|
|
6046
|
+
const { status, startedAt } = e.detail;
|
|
6047
|
+
dispatch({ type: "CLOUD_RECORDING_STARTED", payload: { status, startedAt } });
|
|
6048
|
+
}),
|
|
6049
|
+
createEventListener("cloud_recording_stopped", () => {
|
|
6050
|
+
dispatch({ type: "CLOUD_RECORDING_STOPPED" });
|
|
6051
|
+
}),
|
|
6052
|
+
createEventListener("participant_audio_enabled", (e) => {
|
|
5412
6053
|
const { participantId, isAudioEnabled } = e.detail;
|
|
5413
6054
|
dispatch({ type: "PARTICIPANT_AUDIO_ENABLED", payload: { participantId, isAudioEnabled } });
|
|
5414
|
-
})
|
|
5415
|
-
|
|
6055
|
+
}),
|
|
6056
|
+
createEventListener("participant_joined", (e) => {
|
|
5416
6057
|
const { remoteParticipant } = e.detail;
|
|
5417
6058
|
dispatch({ type: "PARTICIPANT_JOINED", payload: { paritipant: remoteParticipant } });
|
|
5418
|
-
})
|
|
5419
|
-
|
|
6059
|
+
}),
|
|
6060
|
+
createEventListener("participant_left", (e) => {
|
|
5420
6061
|
const { participantId } = e.detail;
|
|
5421
6062
|
dispatch({ type: "PARTICIPANT_LEFT", payload: { participantId } });
|
|
5422
|
-
})
|
|
5423
|
-
|
|
6063
|
+
}),
|
|
6064
|
+
createEventListener("participant_metadata_changed", (e) => {
|
|
6065
|
+
const { participantId, displayName } = e.detail;
|
|
6066
|
+
dispatch({ type: "PARTICIPANT_METADATA_CHANGED", payload: { participantId, displayName } });
|
|
6067
|
+
}),
|
|
6068
|
+
createEventListener("participant_stream_added", (e) => {
|
|
5424
6069
|
const { participantId, stream } = e.detail;
|
|
5425
6070
|
dispatch({ type: "PARTICIPANT_STREAM_ADDED", payload: { participantId, stream } });
|
|
5426
|
-
})
|
|
5427
|
-
|
|
5428
|
-
const { localParticipant, remoteParticipants } = e.detail;
|
|
5429
|
-
dispatch({ type: "ROOM_JOINED", payload: { localParticipant, remoteParticipants } });
|
|
5430
|
-
});
|
|
5431
|
-
roomConnection.addEventListener("participant_video_enabled", (e) => {
|
|
6071
|
+
}),
|
|
6072
|
+
createEventListener("participant_video_enabled", (e) => {
|
|
5432
6073
|
const { participantId, isVideoEnabled } = e.detail;
|
|
5433
6074
|
dispatch({ type: "PARTICIPANT_VIDEO_ENABLED", payload: { participantId, isVideoEnabled } });
|
|
5434
|
-
})
|
|
5435
|
-
|
|
6075
|
+
}),
|
|
6076
|
+
createEventListener("room_connection_status_changed", (e) => {
|
|
6077
|
+
const { roomConnectionStatus } = e.detail;
|
|
6078
|
+
dispatch({
|
|
6079
|
+
type: "ROOM_CONNECTION_STATUS_CHANGED",
|
|
6080
|
+
payload: { roomConnectionStatus },
|
|
6081
|
+
});
|
|
6082
|
+
}),
|
|
6083
|
+
createEventListener("room_joined", (e) => {
|
|
6084
|
+
const { localParticipant, remoteParticipants, waitingParticipants } = e.detail;
|
|
6085
|
+
dispatch({
|
|
6086
|
+
type: "ROOM_JOINED",
|
|
6087
|
+
payload: { localParticipant, remoteParticipants, waitingParticipants },
|
|
6088
|
+
});
|
|
6089
|
+
}),
|
|
6090
|
+
createEventListener("screenshare_started", (e) => {
|
|
6091
|
+
const { participantId, stream, id, hasAudioTrack, isLocal } = e.detail;
|
|
6092
|
+
dispatch({
|
|
6093
|
+
type: "SCREENSHARE_STARTED",
|
|
6094
|
+
payload: { participantId, stream, id, hasAudioTrack, isLocal },
|
|
6095
|
+
});
|
|
6096
|
+
}),
|
|
6097
|
+
createEventListener("screenshare_stopped", (e) => {
|
|
6098
|
+
const { participantId, id } = e.detail;
|
|
6099
|
+
dispatch({
|
|
6100
|
+
type: "SCREENSHARE_STOPPED",
|
|
6101
|
+
payload: { participantId, id },
|
|
6102
|
+
});
|
|
6103
|
+
}),
|
|
6104
|
+
createEventListener("streaming_started", (e) => {
|
|
6105
|
+
const { status, startedAt } = e.detail;
|
|
6106
|
+
dispatch({ type: "STREAMING_STARTED", payload: { status, startedAt } });
|
|
6107
|
+
}),
|
|
6108
|
+
createEventListener("streaming_stopped", () => {
|
|
6109
|
+
dispatch({ type: "STREAMING_STOPPED" });
|
|
6110
|
+
}),
|
|
6111
|
+
createEventListener("waiting_participant_joined", (e) => {
|
|
5436
6112
|
const { participantId, displayName } = e.detail;
|
|
5437
|
-
dispatch({
|
|
6113
|
+
dispatch({
|
|
6114
|
+
type: "WAITING_PARTICIPANT_JOINED",
|
|
6115
|
+
payload: { participantId, displayName },
|
|
6116
|
+
});
|
|
6117
|
+
}),
|
|
6118
|
+
], []);
|
|
6119
|
+
React.useEffect(() => {
|
|
6120
|
+
eventListeners.forEach(({ eventName, listener }) => {
|
|
6121
|
+
roomConnection.addEventListener(eventName, listener);
|
|
5438
6122
|
});
|
|
5439
6123
|
roomConnection.join();
|
|
5440
6124
|
return () => {
|
|
6125
|
+
eventListeners.forEach(({ eventName, listener }) => {
|
|
6126
|
+
roomConnection.removeEventListener(eventName, listener);
|
|
6127
|
+
});
|
|
5441
6128
|
roomConnection.leave();
|
|
5442
6129
|
};
|
|
5443
|
-
}, [
|
|
5444
|
-
return
|
|
6130
|
+
}, []);
|
|
6131
|
+
return {
|
|
5445
6132
|
state,
|
|
5446
|
-
{
|
|
5447
|
-
|
|
5448
|
-
roomConnection
|
|
6133
|
+
actions: {
|
|
6134
|
+
knock: () => {
|
|
6135
|
+
roomConnection.knock();
|
|
5449
6136
|
},
|
|
5450
|
-
|
|
5451
|
-
roomConnection
|
|
6137
|
+
sendChatMessage: (text) => {
|
|
6138
|
+
roomConnection.sendChatMessage(text);
|
|
5452
6139
|
},
|
|
5453
6140
|
setDisplayName: (displayName) => {
|
|
5454
|
-
roomConnection
|
|
6141
|
+
roomConnection.setDisplayName(displayName);
|
|
5455
6142
|
dispatch({ type: "LOCAL_CLIENT_DISPLAY_NAME_CHANGED", payload: { displayName } });
|
|
5456
6143
|
},
|
|
6144
|
+
toggleCamera: (enabled) => {
|
|
6145
|
+
roomConnection.localMedia.toggleCameraEnabled(enabled);
|
|
6146
|
+
},
|
|
6147
|
+
toggleMicrophone: (enabled) => {
|
|
6148
|
+
roomConnection.localMedia.toggleMichrophoneEnabled(enabled);
|
|
6149
|
+
},
|
|
6150
|
+
acceptWaitingParticipant: (participantId) => {
|
|
6151
|
+
roomConnection.acceptWaitingParticipant(participantId);
|
|
6152
|
+
},
|
|
6153
|
+
rejectWaitingParticipant: (participantId) => {
|
|
6154
|
+
roomConnection.rejectWaitingParticipant(participantId);
|
|
6155
|
+
},
|
|
6156
|
+
startScreenshare: () => {
|
|
6157
|
+
dispatch({ type: "LOCAL_SCREENSHARE_STARTING" });
|
|
6158
|
+
try {
|
|
6159
|
+
roomConnection.startScreenshare();
|
|
6160
|
+
}
|
|
6161
|
+
catch (error) {
|
|
6162
|
+
dispatch({ type: "LOCAL_SCREENSHARE_START_ERROR", payload: error });
|
|
6163
|
+
}
|
|
6164
|
+
},
|
|
6165
|
+
stopScreenshare: () => {
|
|
6166
|
+
roomConnection.stopScreenshare();
|
|
6167
|
+
},
|
|
5457
6168
|
},
|
|
5458
|
-
{
|
|
5459
|
-
VideoView:
|
|
6169
|
+
components: {
|
|
6170
|
+
VideoView: (props) => React__default["default"].createElement(VideoView, Object.assign({}, props, {
|
|
6171
|
+
onResize: ({ stream, width, height, }) => {
|
|
6172
|
+
roomConnection.updateStreamResolution({
|
|
6173
|
+
streamId: stream.id,
|
|
6174
|
+
width,
|
|
6175
|
+
height,
|
|
6176
|
+
});
|
|
6177
|
+
},
|
|
6178
|
+
})),
|
|
5460
6179
|
},
|
|
5461
|
-
|
|
6180
|
+
_ref: roomConnection,
|
|
6181
|
+
};
|
|
5462
6182
|
}
|
|
5463
6183
|
|
|
5464
|
-
const sdkVersion = "2.0.0-
|
|
6184
|
+
const sdkVersion = "2.0.0-alpha21";
|
|
5465
6185
|
|
|
6186
|
+
exports.VideoView = VideoView;
|
|
5466
6187
|
exports.sdkVersion = sdkVersion;
|
|
6188
|
+
exports.useLocalMedia = useLocalMedia;
|
|
5467
6189
|
exports.useRoomConnection = useRoomConnection;
|