@whereby.com/media 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1880 -1870
- package/dist/index.d.cts +110 -80
- package/dist/index.d.mts +110 -80
- package/dist/index.d.ts +110 -80
- package/dist/index.mjs +1880 -1870
- package/dist/legacy-esm.js +1880 -1870
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,16 +1,173 @@
|
|
|
1
|
+
import { Device, detectDeviceAsync } from 'mediasoup-client';
|
|
1
2
|
import adapterRaw from 'webrtc-adapter';
|
|
3
|
+
import EventEmitter, { EventEmitter as EventEmitter$1 } from 'events';
|
|
2
4
|
import rtcstats from 'rtcstats';
|
|
3
5
|
import { v4 as v4$1 } from 'uuid';
|
|
6
|
+
import { io } from 'socket.io-client';
|
|
4
7
|
import SDPUtils from 'sdp';
|
|
5
8
|
import * as sdpTransform from 'sdp-transform';
|
|
6
9
|
import { Address6 } from 'ip-address';
|
|
7
10
|
import checkIp from 'check-ip';
|
|
8
11
|
import validate from 'uuid-validate';
|
|
9
|
-
import { Device, detectDeviceAsync } from 'mediasoup-client';
|
|
10
|
-
import EventEmitter, { EventEmitter as EventEmitter$1 } from 'events';
|
|
11
|
-
import { io } from 'socket.io-client';
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
class AssertionError extends Error {
|
|
14
|
+
constructor(options) {
|
|
15
|
+
super(options.message);
|
|
16
|
+
this.name = "AssertionError";
|
|
17
|
+
this.code = "ERR_ASSERTION";
|
|
18
|
+
this.actual = options.actual;
|
|
19
|
+
this.expected = options.expected;
|
|
20
|
+
this.operator = options.operator;
|
|
21
|
+
if (Error.captureStackTrace) {
|
|
22
|
+
Error.captureStackTrace(this, options.stackStartFn);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function innerOk(fn, argLen, value, message) {
|
|
27
|
+
if (!value) {
|
|
28
|
+
let generatedMessage = false;
|
|
29
|
+
if (argLen === 0) {
|
|
30
|
+
generatedMessage = true;
|
|
31
|
+
message = "No value argument passed to `assert.ok()`";
|
|
32
|
+
}
|
|
33
|
+
else if (message instanceof Error) {
|
|
34
|
+
throw message;
|
|
35
|
+
}
|
|
36
|
+
const err = new AssertionError({
|
|
37
|
+
actual: value,
|
|
38
|
+
expected: true,
|
|
39
|
+
message,
|
|
40
|
+
operator: "==",
|
|
41
|
+
stackStartFn: fn,
|
|
42
|
+
});
|
|
43
|
+
err.generatedMessage = generatedMessage;
|
|
44
|
+
throw err;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function innerFail(obj) {
|
|
48
|
+
if (obj.message instanceof Error)
|
|
49
|
+
throw obj.message;
|
|
50
|
+
throw new AssertionError(obj);
|
|
51
|
+
}
|
|
52
|
+
function ok(...args) {
|
|
53
|
+
innerOk(ok, args.length, ...args);
|
|
54
|
+
}
|
|
55
|
+
const assert = {
|
|
56
|
+
fail: (message) => {
|
|
57
|
+
innerFail({
|
|
58
|
+
actual: "fail()",
|
|
59
|
+
expected: "fail() should not be called",
|
|
60
|
+
message,
|
|
61
|
+
operator: "fail",
|
|
62
|
+
stackStartFn: assert.fail,
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
ok,
|
|
66
|
+
};
|
|
67
|
+
assert.notEqual = function notEqual(actual, expected, message) {
|
|
68
|
+
if (arguments.length < 2) {
|
|
69
|
+
throw new Error("'actual' and 'expected' arguments are required");
|
|
70
|
+
}
|
|
71
|
+
if (actual == expected) {
|
|
72
|
+
innerFail({
|
|
73
|
+
actual,
|
|
74
|
+
expected,
|
|
75
|
+
message,
|
|
76
|
+
operator: "!=",
|
|
77
|
+
stackStartFn: notEqual,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
assert.ok = ok;
|
|
82
|
+
|
|
83
|
+
const createWorker = (fn) => {
|
|
84
|
+
return new Worker(URL.createObjectURL(new Blob(["self.onmessage = ", fn.toString()], { type: "text/javascript" })));
|
|
85
|
+
};
|
|
86
|
+
const generateByteString = (count) => {
|
|
87
|
+
if (count === 0) {
|
|
88
|
+
return "";
|
|
89
|
+
}
|
|
90
|
+
const count2 = count / 2;
|
|
91
|
+
let result = "F";
|
|
92
|
+
while (result.length <= count2) {
|
|
93
|
+
result += result;
|
|
94
|
+
}
|
|
95
|
+
return result + result.substring(0, count - result.length);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/******************************************************************************
|
|
99
|
+
Copyright (c) Microsoft Corporation.
|
|
100
|
+
|
|
101
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
102
|
+
purpose with or without fee is hereby granted.
|
|
103
|
+
|
|
104
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
105
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
106
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
107
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
108
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
109
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
110
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
111
|
+
***************************************************************************** */
|
|
112
|
+
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
116
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
117
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
118
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
119
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
120
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
121
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
126
|
+
var e = new Error(message);
|
|
127
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const getMediasoupDeviceAsync = (features) => __awaiter(void 0, void 0, void 0, function* () {
|
|
131
|
+
if (features.isNodeSdk) {
|
|
132
|
+
return new Device({ handlerName: "Safari12" });
|
|
133
|
+
}
|
|
134
|
+
let handlerName = (yield detectDeviceAsync()) ||
|
|
135
|
+
(/applecoremedia|applewebkit|safari/i.test(navigator.userAgent) ? "Safari12" : undefined);
|
|
136
|
+
if (/iphone|ipad/i.test(navigator.userAgent)) {
|
|
137
|
+
handlerName = "Safari12";
|
|
138
|
+
}
|
|
139
|
+
return new Device({ handlerName });
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const word = "[a-fA-F\\d:]";
|
|
143
|
+
const boundry = (options) => options && options.includeBoundaries ? `(?:(?<=\\s|^)(?=${word})|(?<=${word})(?=\\s|$))` : "";
|
|
144
|
+
const v4 = "(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}";
|
|
145
|
+
const v6segment = "[a-fA-F\\d]{1,4}";
|
|
146
|
+
const v6 = `
|
|
147
|
+
(?:
|
|
148
|
+
(?:${v6segment}:){7}(?:${v6segment}|:)| // 1:2:3:4:5:6:7:: 1:2:3:4:5:6:7:8
|
|
149
|
+
(?:${v6segment}:){6}(?:${v4}|:${v6segment}|:)| // 1:2:3:4:5:6:: 1:2:3:4:5:6::8 1:2:3:4:5:6::8 1:2:3:4:5:6::1.2.3.4
|
|
150
|
+
(?:${v6segment}:){5}(?::${v4}|(?::${v6segment}){1,2}|:)| // 1:2:3:4:5:: 1:2:3:4:5::7:8 1:2:3:4:5::8 1:2:3:4:5::7:1.2.3.4
|
|
151
|
+
(?:${v6segment}:){4}(?:(?::${v6segment}){0,1}:${v4}|(?::${v6segment}){1,3}|:)| // 1:2:3:4:: 1:2:3:4::6:7:8 1:2:3:4::8 1:2:3:4::6:7:1.2.3.4
|
|
152
|
+
(?:${v6segment}:){3}(?:(?::${v6segment}){0,2}:${v4}|(?::${v6segment}){1,4}|:)| // 1:2:3:: 1:2:3::5:6:7:8 1:2:3::8 1:2:3::5:6:7:1.2.3.4
|
|
153
|
+
(?:${v6segment}:){2}(?:(?::${v6segment}){0,3}:${v4}|(?::${v6segment}){1,5}|:)| // 1:2:: 1:2::4:5:6:7:8 1:2::8 1:2::4:5:6:7:1.2.3.4
|
|
154
|
+
(?:${v6segment}:){1}(?:(?::${v6segment}){0,4}:${v4}|(?::${v6segment}){1,6}|:)| // 1:: 1::3:4:5:6:7:8 1::8 1::3:4:5:6:7:1.2.3.4
|
|
155
|
+
(?::(?:(?::${v6segment}){0,5}:${v4}|(?::${v6segment}){1,7}|:)) // ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 ::1.2.3.4
|
|
156
|
+
)(?:%[0-9a-zA-Z]{1,})? // %eth0 %1
|
|
157
|
+
`
|
|
158
|
+
.replace(/\s*\/\/.*$/gm, "")
|
|
159
|
+
.replace(/\n/g, "")
|
|
160
|
+
.trim();
|
|
161
|
+
const v46Exact = new RegExp(`(?:^${v4}$)|(?:^${v6}$)`);
|
|
162
|
+
const v4exact = new RegExp(`^${v4}$`);
|
|
163
|
+
const v6exact = new RegExp(`^${v6}$`);
|
|
164
|
+
const ipRegex = (options) => options && options.exact
|
|
165
|
+
? v46Exact
|
|
166
|
+
: new RegExp(`(?:${boundry(options)}${v4}${boundry(options)})|(?:${boundry(options)}${v6}${boundry(options)})`, "g");
|
|
167
|
+
ipRegex.v4 = (options) => options && options.exact ? v4exact : new RegExp(`${boundry(options)}${v4}${boundry(options)}`, "g");
|
|
168
|
+
ipRegex.v6 = (options) => options && options.exact ? v6exact : new RegExp(`${boundry(options)}${v6}${boundry(options)}`, "g");
|
|
169
|
+
|
|
170
|
+
const debugOn = new URLSearchParams(window.location.search).has("debug");
|
|
14
171
|
class Logger {
|
|
15
172
|
constructor() {
|
|
16
173
|
this._isEnabled = false;
|
|
@@ -65,209 +222,195 @@ class Logger {
|
|
|
65
222
|
}
|
|
66
223
|
}
|
|
67
224
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
75
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
76
|
-
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
77
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
78
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
79
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
80
|
-
PERFORMANCE OF THIS SOFTWARE.
|
|
81
|
-
***************************************************************************** */
|
|
82
|
-
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
function __awaiter(thisArg, _arguments, P, generator) {
|
|
86
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
87
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
88
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
89
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
90
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
91
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
96
|
-
var e = new Error(message);
|
|
97
|
-
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
225
|
+
const AUDIO_SETTINGS = {
|
|
226
|
+
codecOptions: {
|
|
227
|
+
opusDtx: true,
|
|
228
|
+
opusFec: true,
|
|
229
|
+
},
|
|
230
|
+
encodings: [{ dtx: true }],
|
|
98
231
|
};
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
232
|
+
const VIDEO_SETTINGS_HD = {
|
|
233
|
+
codecOptions: {
|
|
234
|
+
videoGoogleStartBitrate: 500,
|
|
235
|
+
},
|
|
236
|
+
encodings: [
|
|
237
|
+
{ scaleResolutionDownBy: 4, maxBitrate: 150000 },
|
|
238
|
+
{ scaleResolutionDownBy: 2, maxBitrate: 500000 },
|
|
239
|
+
{ scaleResolutionDownBy: 1, maxBitrate: 1000000 },
|
|
240
|
+
],
|
|
107
241
|
};
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const buffer = [];
|
|
112
|
-
let ws;
|
|
113
|
-
let organizationId;
|
|
114
|
-
let clientId;
|
|
115
|
-
let displayName;
|
|
116
|
-
let userRole;
|
|
117
|
-
let roomSessionId;
|
|
118
|
-
let connectionShouldBeOpen;
|
|
119
|
-
let connectionAttempt = 0;
|
|
120
|
-
let hasPassedOnRoomSessionId = false;
|
|
121
|
-
let getStatsBufferUsed = 0;
|
|
122
|
-
let deviceId;
|
|
123
|
-
let roomProduct;
|
|
124
|
-
let roomMode;
|
|
125
|
-
let sfuServer;
|
|
126
|
-
let featureFlags;
|
|
127
|
-
const connection = {
|
|
128
|
-
connected: false,
|
|
129
|
-
trace: (...args) => {
|
|
130
|
-
args.push(Date.now());
|
|
131
|
-
if (args[0] === "customEvent" && args[2].type === "roomSessionId") {
|
|
132
|
-
const oldRoomSessionIdValue = roomSessionId && roomSessionId[2].value.roomSessionId;
|
|
133
|
-
const newRoomSessionIdValue = args[2].value.roomSessionId;
|
|
134
|
-
roomSessionId = args;
|
|
135
|
-
if (hasPassedOnRoomSessionId &&
|
|
136
|
-
newRoomSessionIdValue &&
|
|
137
|
-
newRoomSessionIdValue !== oldRoomSessionIdValue) {
|
|
138
|
-
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
139
|
-
}
|
|
140
|
-
if (newRoomSessionIdValue)
|
|
141
|
-
hasPassedOnRoomSessionId = true;
|
|
142
|
-
}
|
|
143
|
-
else if (args[0] === "customEvent" && args[2].type === "clientId") {
|
|
144
|
-
clientId = args;
|
|
145
|
-
}
|
|
146
|
-
else if (args[0] === "customEvent" && args[2].type === "organizationId") {
|
|
147
|
-
organizationId = args;
|
|
148
|
-
}
|
|
149
|
-
else if (args[0] === "customEvent" && args[2].type === "displayName") {
|
|
150
|
-
displayName = args;
|
|
151
|
-
}
|
|
152
|
-
else if (args[0] === "customEvent" && args[2].type === "userRole") {
|
|
153
|
-
userRole = args;
|
|
154
|
-
}
|
|
155
|
-
else if (args[0] === "customEvent" && args[2].type === "deviceId") {
|
|
156
|
-
deviceId = args;
|
|
157
|
-
}
|
|
158
|
-
else if (args[0] === "customEvent" && args[2].type === "roomProduct") {
|
|
159
|
-
roomProduct = args;
|
|
160
|
-
}
|
|
161
|
-
else if (args[0] === "customEvent" && args[2].type === "roomMode") {
|
|
162
|
-
roomMode = args;
|
|
163
|
-
}
|
|
164
|
-
else if (args[0] === "customEvent" && args[2].type === "sfuServer") {
|
|
165
|
-
sfuServer = args;
|
|
166
|
-
}
|
|
167
|
-
else if (args[0] === "customEvent" && args[2].type === "featureFlags") {
|
|
168
|
-
featureFlags = args;
|
|
169
|
-
}
|
|
170
|
-
if ((ws === null || ws === void 0 ? void 0 : ws.readyState) === WebSocket.OPEN) {
|
|
171
|
-
connectionAttempt = 0;
|
|
172
|
-
ws.send(JSON.stringify(args));
|
|
173
|
-
}
|
|
174
|
-
else if (args[0] === "getstats") {
|
|
175
|
-
if (getStatsBufferUsed < GETSTATS_BUFFER_SIZE) {
|
|
176
|
-
getStatsBufferUsed++;
|
|
177
|
-
buffer.push(args);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
else if (args[0] === "customEvent" && args[2].type === "insightsStats") ;
|
|
181
|
-
else {
|
|
182
|
-
buffer.push(args);
|
|
183
|
-
}
|
|
184
|
-
if ((ws === null || ws === void 0 ? void 0 : ws.readyState) === WebSocket.CLOSED && connectionShouldBeOpen) {
|
|
185
|
-
setTimeout(() => {
|
|
186
|
-
if (ws.readyState === WebSocket.CLOSED && connectionShouldBeOpen) {
|
|
187
|
-
connection.connect();
|
|
188
|
-
}
|
|
189
|
-
}, 1000 * connectionAttempt);
|
|
190
|
-
}
|
|
191
|
-
},
|
|
192
|
-
close: () => {
|
|
193
|
-
connectionShouldBeOpen = false;
|
|
194
|
-
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
195
|
-
},
|
|
196
|
-
connect: () => {
|
|
197
|
-
connectionShouldBeOpen = true;
|
|
198
|
-
connectionAttempt += 1;
|
|
199
|
-
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
200
|
-
connection.connected = true;
|
|
201
|
-
ws = new WebSocket(wsURL + window.location.pathname, RTCSTATS_PROTOCOL_VERSION);
|
|
202
|
-
ws.onerror = (e) => {
|
|
203
|
-
connection.connected = false;
|
|
204
|
-
logger.warn(`[RTCSTATS] WebSocket error`, e);
|
|
205
|
-
};
|
|
206
|
-
ws.onclose = (e) => {
|
|
207
|
-
connection.connected = false;
|
|
208
|
-
logger.info(`[RTCSTATS] Closed ${e.code}`);
|
|
209
|
-
resetDelta();
|
|
210
|
-
};
|
|
211
|
-
ws.onopen = () => {
|
|
212
|
-
clientInfo.connectionNumber++;
|
|
213
|
-
ws.send(JSON.stringify(["clientInfo", null, clientInfo]));
|
|
214
|
-
if (organizationId) {
|
|
215
|
-
ws.send(JSON.stringify(organizationId));
|
|
216
|
-
}
|
|
217
|
-
if (clientId) {
|
|
218
|
-
ws.send(JSON.stringify(clientId));
|
|
219
|
-
}
|
|
220
|
-
if (roomSessionId) {
|
|
221
|
-
ws.send(JSON.stringify(roomSessionId));
|
|
222
|
-
}
|
|
223
|
-
if (displayName) {
|
|
224
|
-
ws.send(JSON.stringify(displayName));
|
|
225
|
-
}
|
|
226
|
-
if (userRole) {
|
|
227
|
-
ws.send(JSON.stringify(userRole));
|
|
228
|
-
}
|
|
229
|
-
if (deviceId) {
|
|
230
|
-
ws.send(JSON.stringify(deviceId));
|
|
231
|
-
}
|
|
232
|
-
if (roomMode) {
|
|
233
|
-
ws.send(JSON.stringify(roomMode));
|
|
234
|
-
}
|
|
235
|
-
if (roomProduct) {
|
|
236
|
-
ws.send(JSON.stringify(roomProduct));
|
|
237
|
-
}
|
|
238
|
-
if (sfuServer) {
|
|
239
|
-
ws.send(JSON.stringify(sfuServer));
|
|
240
|
-
}
|
|
241
|
-
if (featureFlags) {
|
|
242
|
-
ws.send(JSON.stringify(featureFlags));
|
|
243
|
-
}
|
|
244
|
-
while (buffer.length) {
|
|
245
|
-
ws.send(JSON.stringify(buffer.shift()));
|
|
246
|
-
}
|
|
247
|
-
getStatsBufferUsed = 0;
|
|
248
|
-
};
|
|
249
|
-
},
|
|
250
|
-
};
|
|
251
|
-
return connection;
|
|
252
|
-
}
|
|
253
|
-
const server = rtcStatsConnection(process.env.RTCSTATS_URL || "wss://rtcstats.srv.whereby.com");
|
|
254
|
-
const stats = rtcstats(server.trace, 10000, [""]);
|
|
255
|
-
resetDelta = (stats === null || stats === void 0 ? void 0 : stats.resetDelta) || noop;
|
|
256
|
-
const rtcStats = {
|
|
257
|
-
sendEvent: (type, value) => {
|
|
258
|
-
server.trace("customEvent", null, {
|
|
259
|
-
type,
|
|
260
|
-
value,
|
|
261
|
-
});
|
|
242
|
+
const VIDEO_SETTINGS_SD = {
|
|
243
|
+
codecOptions: {
|
|
244
|
+
videoGoogleStartBitrate: 500,
|
|
262
245
|
},
|
|
263
|
-
|
|
264
|
-
|
|
246
|
+
encodings: [
|
|
247
|
+
{ scaleResolutionDownBy: 2, maxBitrate: 150000 },
|
|
248
|
+
{ scaleResolutionDownBy: 1, maxBitrate: 500000 },
|
|
249
|
+
],
|
|
250
|
+
};
|
|
251
|
+
const VIDEO_SETTINGS_VP9 = {
|
|
252
|
+
codecOptions: {
|
|
253
|
+
videoGoogleStartBitrate: 500,
|
|
265
254
|
},
|
|
266
|
-
|
|
267
|
-
|
|
255
|
+
encodings: [{ scalabilityMode: "L3T2", maxBitrate: 1000000 }],
|
|
256
|
+
};
|
|
257
|
+
const VIDEO_SETTINGS_VP9_LOW_BANDWIDTH = {
|
|
258
|
+
codecOptions: {
|
|
259
|
+
videoGoogleStartBitrate: 500,
|
|
268
260
|
},
|
|
269
|
-
|
|
261
|
+
encodings: [{ scalabilityMode: "L2T2", maxBitrate: 500000 }],
|
|
262
|
+
};
|
|
263
|
+
const SCREEN_SHARE_SETTINGS = {
|
|
264
|
+
encodings: [{}],
|
|
265
|
+
};
|
|
266
|
+
const SCREEN_SHARE_SIMULCAST_SETTINGS = {
|
|
267
|
+
encodings: [
|
|
268
|
+
{ scaleResolutionDownBy: 2, dtx: true, maxBitrate: 500000 },
|
|
269
|
+
{ scaleResolutionDownBy: 1, dtx: true, maxBitrate: 1500000 },
|
|
270
|
+
],
|
|
271
|
+
};
|
|
272
|
+
const ADDITIONAL_SCREEN_SHARE_SETTINGS = {
|
|
273
|
+
encodings: [
|
|
274
|
+
{ scaleResolutionDownBy: 4, dtx: true, maxBitrate: 150000 },
|
|
275
|
+
{ scaleResolutionDownBy: 2, dtx: true, maxBitrate: 500000 },
|
|
276
|
+
{ scaleResolutionDownBy: 1, dtx: true, maxBitrate: 1500000 },
|
|
277
|
+
],
|
|
278
|
+
};
|
|
279
|
+
const getMediaSettings = (kind, isScreenShare, features, isSomeoneAlreadyPresenting = false) => {
|
|
280
|
+
const { lowDataModeEnabled, simulcastScreenshareOn, vp9On } = features;
|
|
281
|
+
if (kind === "audio") {
|
|
282
|
+
return AUDIO_SETTINGS;
|
|
283
|
+
}
|
|
284
|
+
const isChrome = adapterRaw.browserDetails.browser === "chrome";
|
|
285
|
+
const isVp9Available = isChrome && vp9On;
|
|
286
|
+
if (isScreenShare) {
|
|
287
|
+
return getScreenShareMediaSettings({
|
|
288
|
+
isSomeoneAlreadyPresenting,
|
|
289
|
+
simulcastScreenshareOn,
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
return getCameraMediaSettings({
|
|
294
|
+
lowBandwidth: lowDataModeEnabled,
|
|
295
|
+
isVp9Available,
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
const getCameraMediaSettings = ({ lowBandwidth, isVp9Available, }) => {
|
|
300
|
+
if (lowBandwidth) {
|
|
301
|
+
if (isVp9Available) {
|
|
302
|
+
return VIDEO_SETTINGS_VP9_LOW_BANDWIDTH;
|
|
303
|
+
}
|
|
304
|
+
return VIDEO_SETTINGS_SD;
|
|
305
|
+
}
|
|
306
|
+
if (isVp9Available) {
|
|
307
|
+
return VIDEO_SETTINGS_VP9;
|
|
308
|
+
}
|
|
309
|
+
return VIDEO_SETTINGS_HD;
|
|
310
|
+
};
|
|
311
|
+
const getScreenShareMediaSettings = ({ isSomeoneAlreadyPresenting, simulcastScreenshareOn, }) => {
|
|
312
|
+
if (isSomeoneAlreadyPresenting) {
|
|
313
|
+
return ADDITIONAL_SCREEN_SHARE_SETTINGS;
|
|
314
|
+
}
|
|
315
|
+
if (simulcastScreenshareOn)
|
|
316
|
+
return SCREEN_SHARE_SIMULCAST_SETTINGS;
|
|
317
|
+
return SCREEN_SHARE_SETTINGS;
|
|
318
|
+
};
|
|
319
|
+
var PrioritizableCodec;
|
|
320
|
+
(function (PrioritizableCodec) {
|
|
321
|
+
PrioritizableCodec["H264"] = "video/h264";
|
|
322
|
+
PrioritizableCodec["VP9"] = "video/vp9";
|
|
323
|
+
})(PrioritizableCodec || (PrioritizableCodec = {}));
|
|
324
|
+
const modifyMediaCapabilities = (routerRtpCapabilities, features) => {
|
|
325
|
+
const { vp9On, h264On } = features;
|
|
326
|
+
const isChrome = adapterRaw.browserDetails.browser === "chrome";
|
|
327
|
+
if (!(routerRtpCapabilities === null || routerRtpCapabilities === void 0 ? void 0 : routerRtpCapabilities.codecs)) {
|
|
328
|
+
return routerRtpCapabilities;
|
|
329
|
+
}
|
|
330
|
+
if (vp9On && isChrome) {
|
|
331
|
+
const sorted = prioritizeRouterRtpCapabilitiesCodecs(routerRtpCapabilities.codecs, PrioritizableCodec.VP9);
|
|
332
|
+
return Object.assign(Object.assign({}, routerRtpCapabilities), { codecs: sorted });
|
|
333
|
+
}
|
|
334
|
+
else if (h264On) {
|
|
335
|
+
const sorted = prioritizeRouterRtpCapabilitiesCodecs(routerRtpCapabilities.codecs, PrioritizableCodec.H264);
|
|
336
|
+
return Object.assign(Object.assign({}, routerRtpCapabilities), { codecs: sorted });
|
|
337
|
+
}
|
|
338
|
+
return routerRtpCapabilities;
|
|
270
339
|
};
|
|
340
|
+
function prioritizeRouterRtpCapabilitiesCodecs(codecs, preferredCodec) {
|
|
341
|
+
const preferredCodecEntry = codecs.find(({ mimeType }) => mimeType.toLowerCase() === preferredCodec);
|
|
342
|
+
if (!preferredCodecEntry) {
|
|
343
|
+
return codecs;
|
|
344
|
+
}
|
|
345
|
+
return [...codecs].sort((left, right) => {
|
|
346
|
+
var _a;
|
|
347
|
+
if (left.mimeType.toLowerCase() === preferredCodec) {
|
|
348
|
+
return -1;
|
|
349
|
+
}
|
|
350
|
+
if (left.mimeType.toLowerCase() === "video/rtx" &&
|
|
351
|
+
((_a = left.parameters) === null || _a === void 0 ? void 0 : _a.apt) === preferredCodecEntry.preferredPayloadType) {
|
|
352
|
+
if (right.mimeType.toLowerCase() === preferredCodec) {
|
|
353
|
+
return 1;
|
|
354
|
+
}
|
|
355
|
+
return -1;
|
|
356
|
+
}
|
|
357
|
+
return 0;
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
function getPreferredOrder(availableCodecs, { av1On }) {
|
|
361
|
+
availableCodecs.unshift("video/vp9");
|
|
362
|
+
if (av1On) {
|
|
363
|
+
availableCodecs.unshift("video/av1");
|
|
364
|
+
}
|
|
365
|
+
return availableCodecs;
|
|
366
|
+
}
|
|
367
|
+
function sortCodecsByMimeType(codecs, features) {
|
|
368
|
+
const availableCodecs = codecs
|
|
369
|
+
.map(({ mimeType }) => mimeType)
|
|
370
|
+
.filter((value, index, array) => array.indexOf(value) === index);
|
|
371
|
+
const preferredOrder = getPreferredOrder(availableCodecs, features);
|
|
372
|
+
return codecs.sort((a, b) => {
|
|
373
|
+
const indexA = preferredOrder.indexOf(a.mimeType.toLowerCase());
|
|
374
|
+
const indexB = preferredOrder.indexOf(b.mimeType.toLowerCase());
|
|
375
|
+
const orderA = indexA >= 0 ? indexA : Number.MAX_VALUE;
|
|
376
|
+
const orderB = indexB >= 0 ? indexB : Number.MAX_VALUE;
|
|
377
|
+
return orderA - orderB;
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
function getIsCodecDecodingPowerEfficient(codec) {
|
|
381
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
382
|
+
const { powerEfficient } = yield navigator.mediaCapabilities.decodingInfo({
|
|
383
|
+
type: "webrtc",
|
|
384
|
+
video: {
|
|
385
|
+
width: 1280,
|
|
386
|
+
height: 720,
|
|
387
|
+
bitrate: 2580,
|
|
388
|
+
framerate: 24,
|
|
389
|
+
contentType: codec,
|
|
390
|
+
},
|
|
391
|
+
});
|
|
392
|
+
return powerEfficient;
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
function sortCodecsByPowerEfficiency(codecs) {
|
|
396
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
397
|
+
const codecPowerEfficiencyEntries = yield Promise.all(codecs.map(({ mimeType }) => getIsCodecDecodingPowerEfficient(mimeType).then((val) => [mimeType, val])));
|
|
398
|
+
const codecPowerEfficiencies = Object.fromEntries(codecPowerEfficiencyEntries);
|
|
399
|
+
const sorted = codecs.sort((a, b) => {
|
|
400
|
+
const aPowerEfficient = codecPowerEfficiencies[a.mimeType];
|
|
401
|
+
const bPowerEfficient = codecPowerEfficiencies[b.mimeType];
|
|
402
|
+
return aPowerEfficient === bPowerEfficient ? 0 : aPowerEfficient ? -1 : 1;
|
|
403
|
+
});
|
|
404
|
+
return sorted;
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
function sortCodecs(codecs, features) {
|
|
408
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
409
|
+
let sortedCodecs = sortCodecsByMimeType(codecs, features);
|
|
410
|
+
sortedCodecs = yield sortCodecsByPowerEfficiency(codecs);
|
|
411
|
+
return sortedCodecs;
|
|
412
|
+
});
|
|
413
|
+
}
|
|
271
414
|
|
|
272
415
|
function captureCandidatePairInfoMetrics(cpMetrics, currentCptats, prevCptats, timeDiff, report) {
|
|
273
416
|
const bytesReceivedDiff = currentCptats.bytesReceived - ((prevCptats === null || prevCptats === void 0 ? void 0 : prevCptats.bytesReceived) || 0);
|
|
@@ -286,7 +429,7 @@ function captureCandidatePairInfoMetrics(cpMetrics, currentCptats, prevCptats, t
|
|
|
286
429
|
const local = report.get(currentCptats.localCandidateId);
|
|
287
430
|
cpMetrics.usingTurn = false;
|
|
288
431
|
if (local) {
|
|
289
|
-
if (/relay/i.test(local.candidateType ||
|
|
432
|
+
if (/relay/i.test(local.candidateType || "")) {
|
|
290
433
|
cpMetrics.usingTurn = true;
|
|
291
434
|
cpMetrics.turnProtocol = local.relayProtocol;
|
|
292
435
|
}
|
|
@@ -443,6 +586,179 @@ function captureVideoSsrcMetrics(ssrcMetrics, currentSsrcStats, prevSsrcStats, t
|
|
|
443
586
|
}
|
|
444
587
|
}
|
|
445
588
|
|
|
589
|
+
var _a$7;
|
|
590
|
+
(_a$7 = adapterRaw.default) !== null && _a$7 !== void 0 ? _a$7 : adapterRaw;
|
|
591
|
+
const RTCSTATS_PROTOCOL_VERSION = "1.0";
|
|
592
|
+
const GETSTATS_BUFFER_SIZE = 20;
|
|
593
|
+
const clientInfo = {
|
|
594
|
+
id: v4$1(),
|
|
595
|
+
connectionNumber: 0,
|
|
596
|
+
};
|
|
597
|
+
const noop = () => { };
|
|
598
|
+
let resetDelta = noop;
|
|
599
|
+
function rtcStatsConnection(wsURL, logger = console) {
|
|
600
|
+
const buffer = [];
|
|
601
|
+
let ws;
|
|
602
|
+
let organizationId;
|
|
603
|
+
let clientId;
|
|
604
|
+
let displayName;
|
|
605
|
+
let userRole;
|
|
606
|
+
let roomSessionId;
|
|
607
|
+
let connectionShouldBeOpen;
|
|
608
|
+
let connectionAttempt = 0;
|
|
609
|
+
let hasPassedOnRoomSessionId = false;
|
|
610
|
+
let getStatsBufferUsed = 0;
|
|
611
|
+
let deviceId;
|
|
612
|
+
let roomProduct;
|
|
613
|
+
let roomMode;
|
|
614
|
+
let sfuServer;
|
|
615
|
+
let featureFlags;
|
|
616
|
+
const connection = {
|
|
617
|
+
connected: false,
|
|
618
|
+
trace: (...args) => {
|
|
619
|
+
args.push(Date.now());
|
|
620
|
+
if (args[0] === "customEvent" && args[2].type === "roomSessionId") {
|
|
621
|
+
const oldRoomSessionIdValue = roomSessionId && roomSessionId[2].value.roomSessionId;
|
|
622
|
+
const newRoomSessionIdValue = args[2].value.roomSessionId;
|
|
623
|
+
roomSessionId = args;
|
|
624
|
+
if (hasPassedOnRoomSessionId &&
|
|
625
|
+
newRoomSessionIdValue &&
|
|
626
|
+
newRoomSessionIdValue !== oldRoomSessionIdValue) {
|
|
627
|
+
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
628
|
+
}
|
|
629
|
+
if (newRoomSessionIdValue)
|
|
630
|
+
hasPassedOnRoomSessionId = true;
|
|
631
|
+
}
|
|
632
|
+
else if (args[0] === "customEvent" && args[2].type === "clientId") {
|
|
633
|
+
clientId = args;
|
|
634
|
+
}
|
|
635
|
+
else if (args[0] === "customEvent" && args[2].type === "organizationId") {
|
|
636
|
+
organizationId = args;
|
|
637
|
+
}
|
|
638
|
+
else if (args[0] === "customEvent" && args[2].type === "displayName") {
|
|
639
|
+
displayName = args;
|
|
640
|
+
}
|
|
641
|
+
else if (args[0] === "customEvent" && args[2].type === "userRole") {
|
|
642
|
+
userRole = args;
|
|
643
|
+
}
|
|
644
|
+
else if (args[0] === "customEvent" && args[2].type === "deviceId") {
|
|
645
|
+
deviceId = args;
|
|
646
|
+
}
|
|
647
|
+
else if (args[0] === "customEvent" && args[2].type === "roomProduct") {
|
|
648
|
+
roomProduct = args;
|
|
649
|
+
}
|
|
650
|
+
else if (args[0] === "customEvent" && args[2].type === "roomMode") {
|
|
651
|
+
roomMode = args;
|
|
652
|
+
}
|
|
653
|
+
else if (args[0] === "customEvent" && args[2].type === "sfuServer") {
|
|
654
|
+
sfuServer = args;
|
|
655
|
+
}
|
|
656
|
+
else if (args[0] === "customEvent" && args[2].type === "featureFlags") {
|
|
657
|
+
featureFlags = args;
|
|
658
|
+
}
|
|
659
|
+
if ((ws === null || ws === void 0 ? void 0 : ws.readyState) === WebSocket.OPEN) {
|
|
660
|
+
connectionAttempt = 0;
|
|
661
|
+
ws.send(JSON.stringify(args));
|
|
662
|
+
}
|
|
663
|
+
else if (args[0] === "getstats") {
|
|
664
|
+
if (getStatsBufferUsed < GETSTATS_BUFFER_SIZE) {
|
|
665
|
+
getStatsBufferUsed++;
|
|
666
|
+
buffer.push(args);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
else if (args[0] === "customEvent" && args[2].type === "insightsStats") ;
|
|
670
|
+
else {
|
|
671
|
+
buffer.push(args);
|
|
672
|
+
}
|
|
673
|
+
if ((ws === null || ws === void 0 ? void 0 : ws.readyState) === WebSocket.CLOSED && connectionShouldBeOpen) {
|
|
674
|
+
setTimeout(() => {
|
|
675
|
+
if (ws.readyState === WebSocket.CLOSED && connectionShouldBeOpen) {
|
|
676
|
+
connection.connect();
|
|
677
|
+
}
|
|
678
|
+
}, 1000 * connectionAttempt);
|
|
679
|
+
}
|
|
680
|
+
},
|
|
681
|
+
close: () => {
|
|
682
|
+
connectionShouldBeOpen = false;
|
|
683
|
+
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
684
|
+
},
|
|
685
|
+
connect: () => {
|
|
686
|
+
connectionShouldBeOpen = true;
|
|
687
|
+
connectionAttempt += 1;
|
|
688
|
+
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
689
|
+
connection.connected = true;
|
|
690
|
+
ws = new WebSocket(wsURL + window.location.pathname, RTCSTATS_PROTOCOL_VERSION);
|
|
691
|
+
ws.onerror = (e) => {
|
|
692
|
+
connection.connected = false;
|
|
693
|
+
logger.warn(`[RTCSTATS] WebSocket error`, e);
|
|
694
|
+
};
|
|
695
|
+
ws.onclose = (e) => {
|
|
696
|
+
connection.connected = false;
|
|
697
|
+
logger.info(`[RTCSTATS] Closed ${e.code}`);
|
|
698
|
+
resetDelta();
|
|
699
|
+
};
|
|
700
|
+
ws.onopen = () => {
|
|
701
|
+
clientInfo.connectionNumber++;
|
|
702
|
+
ws.send(JSON.stringify(["clientInfo", null, clientInfo]));
|
|
703
|
+
if (organizationId) {
|
|
704
|
+
ws.send(JSON.stringify(organizationId));
|
|
705
|
+
}
|
|
706
|
+
if (clientId) {
|
|
707
|
+
ws.send(JSON.stringify(clientId));
|
|
708
|
+
}
|
|
709
|
+
if (roomSessionId) {
|
|
710
|
+
ws.send(JSON.stringify(roomSessionId));
|
|
711
|
+
}
|
|
712
|
+
if (displayName) {
|
|
713
|
+
ws.send(JSON.stringify(displayName));
|
|
714
|
+
}
|
|
715
|
+
if (userRole) {
|
|
716
|
+
ws.send(JSON.stringify(userRole));
|
|
717
|
+
}
|
|
718
|
+
if (deviceId) {
|
|
719
|
+
ws.send(JSON.stringify(deviceId));
|
|
720
|
+
}
|
|
721
|
+
if (roomMode) {
|
|
722
|
+
ws.send(JSON.stringify(roomMode));
|
|
723
|
+
}
|
|
724
|
+
if (roomProduct) {
|
|
725
|
+
ws.send(JSON.stringify(roomProduct));
|
|
726
|
+
}
|
|
727
|
+
if (sfuServer) {
|
|
728
|
+
ws.send(JSON.stringify(sfuServer));
|
|
729
|
+
}
|
|
730
|
+
if (featureFlags) {
|
|
731
|
+
ws.send(JSON.stringify(featureFlags));
|
|
732
|
+
}
|
|
733
|
+
while (buffer.length) {
|
|
734
|
+
ws.send(JSON.stringify(buffer.shift()));
|
|
735
|
+
}
|
|
736
|
+
getStatsBufferUsed = 0;
|
|
737
|
+
};
|
|
738
|
+
},
|
|
739
|
+
};
|
|
740
|
+
return connection;
|
|
741
|
+
}
|
|
742
|
+
const RTCSTATS_URL = "wss://rtcstats.srv.whereby.com";
|
|
743
|
+
const server = rtcStatsConnection(RTCSTATS_URL);
|
|
744
|
+
const stats = rtcstats(server.trace, 10000, [""]);
|
|
745
|
+
resetDelta = (stats === null || stats === void 0 ? void 0 : stats.resetDelta) || noop;
|
|
746
|
+
const rtcStats = {
|
|
747
|
+
sendEvent: (type, value) => {
|
|
748
|
+
server.trace("customEvent", null, {
|
|
749
|
+
type,
|
|
750
|
+
value,
|
|
751
|
+
});
|
|
752
|
+
},
|
|
753
|
+
sendAudioMuted: (muted) => {
|
|
754
|
+
rtcStats.sendEvent("audio_muted", { muted });
|
|
755
|
+
},
|
|
756
|
+
sendVideoMuted: (muted) => {
|
|
757
|
+
rtcStats.sendEvent("video_muted", { muted });
|
|
758
|
+
},
|
|
759
|
+
server,
|
|
760
|
+
};
|
|
761
|
+
|
|
446
762
|
let peerConnections = [];
|
|
447
763
|
let peerConnectionCounter = 0;
|
|
448
764
|
const peerConnectionData = new WeakMap();
|
|
@@ -471,10 +787,10 @@ const getCurrentPeerConnections = () => peerConnections;
|
|
|
471
787
|
const getPeerConnectionIndex = (pc) => { var _a; return (_a = peerConnectionData.get(pc)) === null || _a === void 0 ? void 0 : _a.index; };
|
|
472
788
|
const setPeerConnectionsForTests = (pcs) => (peerConnections = pcs);
|
|
473
789
|
|
|
474
|
-
const
|
|
790
|
+
const PC_DATA_BY_PC = new WeakMap();
|
|
475
791
|
let numMissingTrackSsrcLookups = 0;
|
|
476
792
|
let numFailedTrackSsrcLookups = 0;
|
|
477
|
-
const getPeerConnectionsWithStatsReports = () => Promise.all(getCurrentPeerConnections().map((pc) => __awaiter(void 0, void 0, void 0, function* () {
|
|
793
|
+
const getPeerConnectionsWithStatsReports = (pcDataByPc = PC_DATA_BY_PC) => Promise.all(getCurrentPeerConnections().map((pc) => __awaiter(void 0, void 0, void 0, function* () {
|
|
478
794
|
let pcData = pcDataByPc.get(pc);
|
|
479
795
|
if (!pcData) {
|
|
480
796
|
pcData = { ssrcToTrackId: {} };
|
|
@@ -543,7 +859,7 @@ const getPeerConnectionsWithStatsReports = () => Promise.all(getCurrentPeerConne
|
|
|
543
859
|
const getOrCreateSsrcMetricsContainer = (statsByView, time, pcIndex, clientId, trackId, ssrc) => {
|
|
544
860
|
let viewStats = statsByView[clientId];
|
|
545
861
|
if (!viewStats) {
|
|
546
|
-
viewStats = { tracks: {}, startTime: time, updated: time };
|
|
862
|
+
viewStats = { candidatePairs: {}, tracks: {}, startTime: time, updated: time };
|
|
547
863
|
statsByView[clientId] = viewStats;
|
|
548
864
|
}
|
|
549
865
|
viewStats.updated = time;
|
|
@@ -567,7 +883,7 @@ const getOrCreateSsrcMetricsContainer = (statsByView, time, pcIndex, clientId, t
|
|
|
567
883
|
};
|
|
568
884
|
const removeNonUpdatedStats = (statsByView, time) => {
|
|
569
885
|
Object.entries(statsByView).forEach(([viewId, viewStats]) => {
|
|
570
|
-
if (viewStats.updated < time) {
|
|
886
|
+
if (viewStats.updated !== undefined && viewStats.updated < time) {
|
|
571
887
|
delete statsByView[viewId];
|
|
572
888
|
}
|
|
573
889
|
else {
|
|
@@ -586,12 +902,21 @@ const removeNonUpdatedStats = (statsByView, time) => {
|
|
|
586
902
|
}
|
|
587
903
|
});
|
|
588
904
|
};
|
|
905
|
+
const DEFAULT_CLIENT = {
|
|
906
|
+
id: "unknown",
|
|
907
|
+
clientId: "unknown",
|
|
908
|
+
audio: { enabled: false, track: undefined },
|
|
909
|
+
video: { enabled: false, track: undefined },
|
|
910
|
+
isAudioOnlyModeEnabled: false,
|
|
911
|
+
isLocalClient: true,
|
|
912
|
+
isPresentation: false,
|
|
913
|
+
};
|
|
589
914
|
function collectStats(state_1, _a, immediate_1) {
|
|
590
915
|
return __awaiter(this, arguments, void 0, function* (state, { logger, interval }, immediate) {
|
|
591
916
|
const collectStatsBound = collectStats.bind(null, state, { interval, logger });
|
|
592
917
|
try {
|
|
593
918
|
const clients = state.getClients();
|
|
594
|
-
const defaultClient = clients.find((c) => c.isLocalClient && !c.isPresentation) ||
|
|
919
|
+
const defaultClient = clients.find((c) => c.isLocalClient && !c.isPresentation) || DEFAULT_CLIENT;
|
|
595
920
|
let defaultViewStats = state.statsByView[defaultClient.id];
|
|
596
921
|
if (!defaultViewStats) {
|
|
597
922
|
defaultViewStats = { tracks: {}, candidatePairs: {}, pressure: null };
|
|
@@ -609,6 +934,9 @@ function collectStats(state_1, _a, immediate_1) {
|
|
|
609
934
|
state.lastUpdateTime = Date.now();
|
|
610
935
|
(yield getPeerConnectionsWithStatsReports()).forEach(([pc, report, pcData]) => {
|
|
611
936
|
const pcIndex = getPeerConnectionIndex(pc);
|
|
937
|
+
if (pcIndex === undefined) {
|
|
938
|
+
logger.warn("Could not find index for PeerConnection");
|
|
939
|
+
}
|
|
612
940
|
if (pc.connectionState === "closed") {
|
|
613
941
|
report = new Map();
|
|
614
942
|
removePeerConnection(pc);
|
|
@@ -616,7 +944,7 @@ function collectStats(state_1, _a, immediate_1) {
|
|
|
616
944
|
pcData.previousSSRCs = pcData.currentSSRCs || {};
|
|
617
945
|
pcData.currentSSRCs = {};
|
|
618
946
|
report.forEach((currentRtcStats) => {
|
|
619
|
-
var _a, _b
|
|
947
|
+
var _a, _b;
|
|
620
948
|
if (currentRtcStats.type === "candidate-pair" && /inprogress|succeeded/.test(currentRtcStats.state)) {
|
|
621
949
|
const prevRtcStats = (_a = pcData._oldReport) === null || _a === void 0 ? void 0 : _a.get(currentRtcStats.id);
|
|
622
950
|
const timeDiff = prevRtcStats ? currentRtcStats.timestamp - prevRtcStats.timestamp : interval;
|
|
@@ -630,7 +958,7 @@ function collectStats(state_1, _a, immediate_1) {
|
|
|
630
958
|
cpMetrics.lastRtcStatsTime = state.lastUpdateTime;
|
|
631
959
|
}
|
|
632
960
|
if (currentRtcStats.type === "inbound-rtp" || currentRtcStats.type === "outbound-rtp") {
|
|
633
|
-
const kind = currentRtcStats.mediaType || currentRtcStats.kind;
|
|
961
|
+
const kind = (currentRtcStats.mediaType || currentRtcStats.kind);
|
|
634
962
|
const ssrc = currentRtcStats.ssrc;
|
|
635
963
|
let trackId = currentRtcStats.trackIdentifier || pcData.ssrcToTrackId[ssrc];
|
|
636
964
|
let prevRtcStats = (_b = pcData._oldReport) === null || _b === void 0 ? void 0 : _b.get(currentRtcStats.id);
|
|
@@ -642,12 +970,13 @@ function collectStats(state_1, _a, immediate_1) {
|
|
|
642
970
|
}
|
|
643
971
|
}
|
|
644
972
|
const client = clients.find((c) => { var _a; return ((_a = c[kind].track) === null || _a === void 0 ? void 0 : _a.id) === trackId; }) || defaultClient;
|
|
973
|
+
const clientTrack = client[kind].track;
|
|
645
974
|
if (!currentRtcStats.trackIdentifier &&
|
|
646
975
|
pcData.ssrcToTrackId[ssrc] &&
|
|
647
|
-
(
|
|
648
|
-
|
|
649
|
-
trackId =
|
|
650
|
-
pcData.ssrcToTrackId[ssrc] =
|
|
976
|
+
(clientTrack === null || clientTrack === void 0 ? void 0 : clientTrack.id) &&
|
|
977
|
+
clientTrack.id !== pcData.ssrcToTrackId[ssrc]) {
|
|
978
|
+
trackId = clientTrack.id;
|
|
979
|
+
pcData.ssrcToTrackId[ssrc] = clientTrack.id;
|
|
651
980
|
}
|
|
652
981
|
pcData.currentSSRCs[ssrc] = client.id;
|
|
653
982
|
if (prevRtcStats) {
|
|
@@ -808,8 +1137,7 @@ function startStatsMonitor(state, { interval, logger }) {
|
|
|
808
1137
|
},
|
|
809
1138
|
stop: () => {
|
|
810
1139
|
clearTimeout(state.nextTimeout);
|
|
811
|
-
|
|
812
|
-
cpuObserver.stop();
|
|
1140
|
+
cpuObserver === null || cpuObserver === void 0 ? void 0 : cpuObserver.stop();
|
|
813
1141
|
},
|
|
814
1142
|
};
|
|
815
1143
|
}
|
|
@@ -829,1598 +1157,1391 @@ function subscribeStats(subscription, options = OPTIONS, state = STATE) {
|
|
|
829
1157
|
};
|
|
830
1158
|
}
|
|
831
1159
|
|
|
832
|
-
|
|
833
|
-
|
|
1160
|
+
const PROTOCOL_REQUESTS = {
|
|
1161
|
+
BLOCK_CLIENT: "block_client",
|
|
1162
|
+
CLAIM_ROOM: "claim_room",
|
|
1163
|
+
CLEAR_CHAT_HISTORY: "clear_chat_history",
|
|
1164
|
+
ENABLE_AUDIO: "enable_audio",
|
|
1165
|
+
ENABLE_VIDEO: "enable_video",
|
|
1166
|
+
END_STREAM: "end_stream",
|
|
1167
|
+
FETCH_MEDIASERVER_CONFIG: "fetch_mediaserver_config",
|
|
1168
|
+
HANDLE_KNOCK: "handle_knock",
|
|
1169
|
+
IDENTIFY_DEVICE: "identify_device",
|
|
1170
|
+
INVITE_CLIENT_AS_MEMBER: "invite_client_as_member",
|
|
1171
|
+
JOIN_ROOM: "join_room",
|
|
1172
|
+
KICK_CLIENT: "kick_client",
|
|
1173
|
+
KNOCK_ROOM: "knock_room",
|
|
1174
|
+
LEAVE_ROOM: "leave_room",
|
|
1175
|
+
SEND_CLIENT_METADATA: "send_client_metadata",
|
|
1176
|
+
SET_LOCK: "set_lock",
|
|
1177
|
+
SHARE_MEDIA: "share_media",
|
|
1178
|
+
START_NEW_STREAM: "start_new_stream",
|
|
1179
|
+
START_SCREENSHARE: "start_screenshare",
|
|
1180
|
+
STOP_SCREENSHARE: "stop_screenshare",
|
|
1181
|
+
START_URL_EMBED: "start_url_embed",
|
|
1182
|
+
STOP_URL_EMBED: "stop_url_embed",
|
|
1183
|
+
START_RECORDING: "start_recording",
|
|
1184
|
+
STOP_RECORDING: "stop_recording",
|
|
1185
|
+
};
|
|
1186
|
+
const PROTOCOL_RESPONSES = {
|
|
1187
|
+
AUDIO_ENABLED: "audio_enabled",
|
|
1188
|
+
BACKGROUND_IMAGE_CHANGED: "background_image_changed",
|
|
1189
|
+
BLOCK_ADDED: "block_added",
|
|
1190
|
+
BLOCK_REMOVED: "block_removed",
|
|
1191
|
+
CHAT_HISTORY_CLEARED: "chat_history_cleared",
|
|
1192
|
+
CLIENT_BLOCKED: "client_blocked",
|
|
1193
|
+
CLIENT_INVITED_AS_MEMBER: "client_invited_as_member",
|
|
1194
|
+
CLIENT_KICKED: "client_kicked",
|
|
1195
|
+
CLIENT_LEFT: "client_left",
|
|
1196
|
+
CLIENT_METADATA_RECEIVED: "client_metadata_received",
|
|
1197
|
+
CLIENT_READY: "client_ready",
|
|
1198
|
+
CLIENT_ROLE_CHANGED: "client_role_changed",
|
|
1199
|
+
CLIENT_USER_ID_CHANGED: "client_user_id_changed",
|
|
1200
|
+
CONTACTS_UPDATED: "contacts_updated",
|
|
1201
|
+
DEVICE_IDENTIFIED: "device_identified",
|
|
1202
|
+
ROOM_ROLES_UPDATED: "room_roles_updated",
|
|
1203
|
+
KNOCK_HANDLED: "knock_handled",
|
|
1204
|
+
KNOCK_PAGE_BACKGROUND_CHANGED: "knock_page_background_changed",
|
|
1205
|
+
KNOCKER_LEFT: "knocker_left",
|
|
1206
|
+
MEDIASERVER_CONFIG: "mediaserver_config",
|
|
1207
|
+
MEDIA_SHARED: "media_shared",
|
|
1208
|
+
MEMBER_INVITE: "member_invite",
|
|
1209
|
+
NEW_CLIENT: "new_client",
|
|
1210
|
+
NEW_STREAM_STARTED: "new_stream_started",
|
|
1211
|
+
SCREENSHARE_STARTED: "screenshare_started",
|
|
1212
|
+
SCREENSHARE_STOPPED: "screenshare_stopped",
|
|
1213
|
+
OWNER_NOTIFIED: "owner_notified",
|
|
1214
|
+
OWNERS_CHANGED: "owners_changed",
|
|
1215
|
+
PLAY_CLIENT_STICKER: "play_client_sticker",
|
|
1216
|
+
ROOM_INTEGRATION_ENABLED: "room_integration_enabled",
|
|
1217
|
+
ROOM_INTEGRATION_DISABLED: "room_integration_disabled",
|
|
1218
|
+
ROOM_JOINED: "room_joined",
|
|
1219
|
+
ROOM_KNOCKED: "room_knocked",
|
|
1220
|
+
ROOM_LEFT: "room_left",
|
|
1221
|
+
ROOM_LOCKED: "room_locked",
|
|
1222
|
+
ROOM_PERMISSIONS_CHANGED: "room_permissions_changed",
|
|
1223
|
+
ROOM_LOGO_CHANGED: "room_logo_changed",
|
|
1224
|
+
ROOM_TYPE_CHANGED: "room_type_changed",
|
|
1225
|
+
ROOM_MODE_CHANGED: "room_mode_changed",
|
|
1226
|
+
SOCKET_USER_ID_CHANGED: "socket_user_id_changed",
|
|
1227
|
+
STICKERS_UNLOCKED: "stickers_unlocked",
|
|
1228
|
+
STREAM_ENDED: "stream_ended",
|
|
1229
|
+
URL_EMBED_STARTED: "url_embed_started",
|
|
1230
|
+
URL_EMBED_STOPPED: "url_embed_stopped",
|
|
1231
|
+
RECORDING_STARTED: "recording_started",
|
|
1232
|
+
RECORDING_STOPPED: "recording_stopped",
|
|
1233
|
+
USER_NOTIFIED: "user_notified",
|
|
1234
|
+
VIDEO_ENABLED: "video_enabled",
|
|
1235
|
+
CLIENT_UNABLE_TO_JOIN: "client_unable_to_join",
|
|
1236
|
+
LIVE_TRANSCRIPTION_STARTED: "live_transcription_started",
|
|
1237
|
+
LIVE_TRANSCRIPTION_STOPPED: "live_transcription_stopped",
|
|
1238
|
+
};
|
|
1239
|
+
const PROTOCOL_ERRORS = {
|
|
1240
|
+
CANNOT_INVITE_YOURSELF: "cannot_invite_yourself",
|
|
1241
|
+
CLIENT_MISSING_DEVICE_ID: "client_missing_device_id",
|
|
1242
|
+
FORBIDDEN: "forbidden",
|
|
1243
|
+
INTERNAL_SERVER_ERROR: "internal_server_error",
|
|
1244
|
+
INVALID_AVATAR: "invalid_avatar",
|
|
1245
|
+
INVALID_PARAMETERS: "invalid_parameters",
|
|
1246
|
+
INVALID_ROOM_NAME: "invalid_room_name",
|
|
1247
|
+
MISSING_PARAMETERS: "missing_parameters",
|
|
1248
|
+
MISSING_ROOM_NAME: "missing_room_name",
|
|
1249
|
+
NOT_AN_OWNER: "not_an_owner",
|
|
1250
|
+
NOT_IN_A_ROOM: "not_in_a_room",
|
|
1251
|
+
ROOM_ALREADY_CLAIMED: "room_already_claimed",
|
|
1252
|
+
ROOM_EMAIL_MISSING: "room_email_missing",
|
|
1253
|
+
ROOM_FULL: "room_full",
|
|
1254
|
+
ROOM_UNCLAIMED: "room_unclaimed",
|
|
1255
|
+
CLIENT_BLOCKED: "client_blocked",
|
|
1256
|
+
ROOM_LOCKED: "room_locked",
|
|
1257
|
+
TOO_LONG_TEXT: "too_long_text",
|
|
1258
|
+
VIDEO_STICKER_DOES_NOT_EXIST: "video_sticker_does_not_exist",
|
|
1259
|
+
VIDEO_STICKER_FORMAT_ERROR: "video_sticker_format_error",
|
|
1260
|
+
UNSUPPORTED_VIDEO_ENCODING: "unsupported_video_encoding",
|
|
1261
|
+
};
|
|
1262
|
+
const RELAY_MESSAGES = {
|
|
1263
|
+
CHAT_MESSAGE: "chat_message",
|
|
1264
|
+
CHAT_READ_STATE: "chat_read_state",
|
|
1265
|
+
CHAT_STATE: "chat_state",
|
|
1266
|
+
ICE_CANDIDATE: "ice_candidate",
|
|
1267
|
+
ICE_END_OF_CANDIDATES: "ice_endofcandidates",
|
|
1268
|
+
READY_TO_RECEIVE_OFFER: "ready_to_receive_offer",
|
|
1269
|
+
REMOTE_CLIENT_MEDIA_REQUEST: "remote_client_media_request",
|
|
1270
|
+
SDP_ANSWER: "sdp_answer",
|
|
1271
|
+
SDP_OFFER: "sdp_offer",
|
|
1272
|
+
VIDEO_STICKER: "video_sticker",
|
|
1273
|
+
};
|
|
1274
|
+
const KNOCK_MESSAGES = {
|
|
1275
|
+
actions: {
|
|
1276
|
+
ACCEPT: "accept",
|
|
1277
|
+
HOLD: "hold",
|
|
1278
|
+
REJECT: "reject",
|
|
1279
|
+
},
|
|
1280
|
+
resolutions: {
|
|
1281
|
+
ACCEPTED: "accepted",
|
|
1282
|
+
ON_HOLD: "on_hold",
|
|
1283
|
+
REJECTED: "rejected",
|
|
1284
|
+
},
|
|
1285
|
+
};
|
|
1286
|
+
const PROTOCOL_EVENTS = {
|
|
1287
|
+
PENDING_CLIENT_LEFT: "pending_client_left",
|
|
1288
|
+
MEDIA_QUALITY_CHANGED: "media_quality_changed",
|
|
1289
|
+
};
|
|
1290
|
+
|
|
834
1291
|
const logger$a = new Logger();
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
1292
|
+
class ReconnectManager extends EventEmitter {
|
|
1293
|
+
constructor(socket) {
|
|
1294
|
+
super();
|
|
1295
|
+
this.reconnectThresholdInMs = 0;
|
|
1296
|
+
this._socket = socket;
|
|
1297
|
+
this._clients = {};
|
|
1298
|
+
this._signalDisconnectTime = undefined;
|
|
1299
|
+
this.rtcManager = undefined;
|
|
1300
|
+
this.metrics = {
|
|
1301
|
+
roomJoinedLate: 0,
|
|
1302
|
+
pendingClientCanceled: 0,
|
|
1303
|
+
evaluationFailed: 0,
|
|
1304
|
+
roomJoined: 0,
|
|
1305
|
+
};
|
|
1306
|
+
socket.on("disconnect", () => {
|
|
1307
|
+
this._signalDisconnectTime = Date.now();
|
|
1308
|
+
});
|
|
1309
|
+
socket.on(PROTOCOL_RESPONSES.ROOM_JOINED, (payload) => this._onRoomJoined(payload));
|
|
1310
|
+
socket.on(PROTOCOL_RESPONSES.NEW_CLIENT, (payload) => this._onNewClient(payload));
|
|
1311
|
+
socket.on(PROTOCOL_RESPONSES.CLIENT_LEFT, (payload) => this._onClientLeft(payload));
|
|
1312
|
+
socket.on(PROTOCOL_EVENTS.PENDING_CLIENT_LEFT, (payload) => this._onPendingClientLeft(payload));
|
|
1313
|
+
socket.on(PROTOCOL_RESPONSES.AUDIO_ENABLED, (payload) => this._onAudioEnabled(payload));
|
|
1314
|
+
socket.on(PROTOCOL_RESPONSES.VIDEO_ENABLED, (payload) => this._onVideoEnabled(payload));
|
|
1315
|
+
socket.on(PROTOCOL_RESPONSES.SCREENSHARE_STARTED, (payload) => this._onScreenshareChanged(payload, true));
|
|
1316
|
+
socket.on(PROTOCOL_RESPONSES.SCREENSHARE_STOPPED, (payload) => this._onScreenshareChanged(payload, false));
|
|
1317
|
+
}
|
|
1318
|
+
_onRoomJoined(payload) {
|
|
1319
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1320
|
+
var _a;
|
|
1321
|
+
this.reconnectThresholdInMs = (payload.disconnectTimeout || 0) * 0.8;
|
|
1322
|
+
if (payload === null || payload === void 0 ? void 0 : payload.error) {
|
|
1323
|
+
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1324
|
+
return;
|
|
1325
|
+
}
|
|
1326
|
+
if (!payload.selfId) {
|
|
1327
|
+
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
const myDeviceId = (_a = payload.room.clients.find((c) => payload.selfId === c.id)) === null || _a === void 0 ? void 0 : _a.deviceId;
|
|
1331
|
+
if (!myDeviceId) {
|
|
1332
|
+
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1333
|
+
return;
|
|
1334
|
+
}
|
|
1335
|
+
if (!this._signalDisconnectTime) {
|
|
1336
|
+
this._resetClientState(payload);
|
|
1337
|
+
payload.room.clients = payload.room.clients.filter((c) => !(c.deviceId === myDeviceId && c.isPendingToLeave));
|
|
1338
|
+
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1341
|
+
const RECONNECT_THRESHOLD = payload.disconnectTimeout * 0.8;
|
|
1342
|
+
const timeSinceDisconnect = Date.now() - this._signalDisconnectTime;
|
|
1343
|
+
if (timeSinceDisconnect > RECONNECT_THRESHOLD) {
|
|
1344
|
+
this._resetClientState(payload);
|
|
1345
|
+
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1346
|
+
this.metrics.roomJoinedLate++;
|
|
1347
|
+
return;
|
|
855
1348
|
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
1349
|
+
payload.room.clients = payload.room.clients.filter((c) => !(c.deviceId === myDeviceId && c.isPendingToLeave));
|
|
1350
|
+
const allStats = yield getUpdatedStats();
|
|
1351
|
+
payload.room.clients.forEach((client) => {
|
|
1352
|
+
var _a;
|
|
1353
|
+
try {
|
|
1354
|
+
if (client.id === payload.selfId)
|
|
1355
|
+
return;
|
|
1356
|
+
if (!this._clients[client.id]) {
|
|
1357
|
+
this._addClientToState(client);
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
if (!((_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.hasClient(client.id))) {
|
|
1361
|
+
return;
|
|
1362
|
+
}
|
|
1363
|
+
if (this._hasClientStateChanged({
|
|
1364
|
+
clientId: client.id,
|
|
1365
|
+
webcam: client.isVideoEnabled,
|
|
1366
|
+
mic: client.isAudioEnabled,
|
|
1367
|
+
screenShare: client.streams.length > 1,
|
|
1368
|
+
})) {
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
if (this._wasClientSendingMedia(client.id)) {
|
|
1372
|
+
if (!this._isClientMediaActive(allStats, client.id)) {
|
|
1373
|
+
return;
|
|
866
1374
|
}
|
|
867
1375
|
}
|
|
1376
|
+
client.mergeWithOldClientState = true;
|
|
868
1377
|
}
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
sdpObject.media.forEach((mediaObject) => {
|
|
882
|
-
const usedPayloads = {};
|
|
883
|
-
if (mediaObject.payloads)
|
|
884
|
-
mediaObject.payloads = ("" + mediaObject.payloads)
|
|
885
|
-
.split(" ")
|
|
886
|
-
.filter((p) => !usedPayloads[p] && (usedPayloads[p] = true))
|
|
887
|
-
.join(" ");
|
|
888
|
-
const usedRtps = {};
|
|
889
|
-
mediaObject.rtp = mediaObject.rtp.filter((p) => !p.payload || (usedPayloads[p.payload] && !usedRtps[p.payload] && (usedRtps[p.payload] = true)));
|
|
890
|
-
const usedFmtps = {};
|
|
891
|
-
if (mediaObject.fmtp)
|
|
892
|
-
mediaObject.fmtp = mediaObject.fmtp.filter((p) => !p.payload ||
|
|
893
|
-
(usedPayloads[p.payload] && !usedFmtps[p.payload] && (usedFmtps[p.payload] = true)));
|
|
894
|
-
const usedRtcpFb = {};
|
|
895
|
-
if (mediaObject.rtcpFb)
|
|
896
|
-
mediaObject.rtcpFb = mediaObject.rtcpFb.filter((p) => !p.payload ||
|
|
897
|
-
(usedPayloads[p.payload] &&
|
|
898
|
-
!usedRtcpFb[p.payload + p.type + p.subtype] &&
|
|
899
|
-
(usedRtcpFb[p.payload + p.type + p.subtype] = true)));
|
|
1378
|
+
catch (error) {
|
|
1379
|
+
logger$a.error("Failed to evaluate if we should merge client state %o", error);
|
|
1380
|
+
this.metrics.evaluationFailed++;
|
|
1381
|
+
}
|
|
1382
|
+
});
|
|
1383
|
+
payload.room.clients.forEach((c) => {
|
|
1384
|
+
if (c.isPendingToLeave) {
|
|
1385
|
+
this._onPendingClientLeft({ clientId: c.id });
|
|
1386
|
+
}
|
|
1387
|
+
});
|
|
1388
|
+
this.metrics.roomJoined++;
|
|
1389
|
+
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
900
1390
|
});
|
|
901
|
-
return sdpTransform.write(sdpObject);
|
|
902
1391
|
}
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
1392
|
+
_onClientLeft(payload) {
|
|
1393
|
+
var _a;
|
|
1394
|
+
const { clientId } = payload;
|
|
1395
|
+
const client = this._clients[clientId];
|
|
1396
|
+
if (client) {
|
|
1397
|
+
clearTimeout(client.timeout);
|
|
1398
|
+
delete this._clients[clientId];
|
|
1399
|
+
}
|
|
1400
|
+
(_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.disconnect(clientId, null, payload.eventClaim);
|
|
1401
|
+
this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, payload);
|
|
909
1402
|
}
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
1403
|
+
_onPendingClientLeft(payload) {
|
|
1404
|
+
const { clientId } = payload;
|
|
1405
|
+
const client = this._clients[clientId];
|
|
1406
|
+
if (!client) {
|
|
1407
|
+
logger$a.warn(`client ${clientId} not found`);
|
|
1408
|
+
return;
|
|
914
1409
|
}
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
return SDPUtils.parseRtpMap(line);
|
|
918
|
-
})
|
|
919
|
-
.map((codec) => {
|
|
920
|
-
return codec.name.toUpperCase();
|
|
921
|
-
});
|
|
922
|
-
if (codecs.indexOf("H264") === -1 &&
|
|
923
|
-
sections[i][8] === "9") {
|
|
924
|
-
sections[i] = sections[i].replace("m=video 9 ", "m=video 0 ");
|
|
1410
|
+
if (client.isPendingToLeave) {
|
|
1411
|
+
return;
|
|
925
1412
|
}
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
return SDPUtils.splitSections(sdp)
|
|
931
|
-
.map((section) => {
|
|
932
|
-
if (SDPUtils.getKind(section) !== "video")
|
|
933
|
-
return section;
|
|
934
|
-
const h264payloadTypes = SDPUtils.matchPrefix(section, "a=rtpmap:")
|
|
935
|
-
.map((line) => SDPUtils.parseRtpMap(line))
|
|
936
|
-
.filter((codec) => /h264/i.test(codec.name))
|
|
937
|
-
.map((codec) => "" + codec.payloadType);
|
|
938
|
-
if (!h264payloadTypes.length)
|
|
939
|
-
return section;
|
|
940
|
-
const mline = SDPUtils.matchPrefix(section, "m=video")[0];
|
|
941
|
-
const mlinePayloadsSectionExec = /(\s\d+)+$/i.exec(mline);
|
|
942
|
-
const mlinePayloadsSection = mlinePayloadsSectionExec ? mlinePayloadsSectionExec[0] : "";
|
|
943
|
-
const mlinePayloadsNonH264 = mlinePayloadsSection
|
|
944
|
-
.split(" ")
|
|
945
|
-
.filter((payloadType) => payloadType && !h264payloadTypes.includes(payloadType));
|
|
946
|
-
const reorderedPayloads = [...mlinePayloadsNonH264, ...h264payloadTypes].join(" ");
|
|
947
|
-
const newmline = mline.replace(mlinePayloadsSection, " " + reorderedPayloads);
|
|
948
|
-
return section.replace(mline, newmline);
|
|
949
|
-
})
|
|
950
|
-
.join("");
|
|
951
|
-
}
|
|
952
|
-
function replaceSSRCs(currentDescription, newDescription) {
|
|
953
|
-
let ssrcs = currentDescription.match(/a=ssrc-group:FID (\d+) (\d+)\r\n/);
|
|
954
|
-
let newssrcs = newDescription.match(/a=ssrc-group:FID (\d+) (\d+)\r\n/);
|
|
955
|
-
if (!ssrcs) {
|
|
956
|
-
ssrcs = currentDescription.match(/a=ssrc:(\d+) cname:(.*)\r\n/g)[1].match(/a=ssrc:(\d+)/);
|
|
957
|
-
newssrcs = newDescription.match(/a=ssrc:(\d+) cname:(.*)\r\n/g)[1].match(/a=ssrc:(\d+)/);
|
|
958
|
-
}
|
|
959
|
-
for (let i = 1; i < ssrcs.length; i++) {
|
|
960
|
-
newDescription = newDescription.replace(new RegExp(newssrcs[i], "g"), ssrcs[i]);
|
|
961
|
-
}
|
|
962
|
-
return newDescription;
|
|
963
|
-
}
|
|
964
|
-
function filterMidExtension(sdp) {
|
|
965
|
-
if (browserName$2 !== "safari" &&
|
|
966
|
-
(browserName$2 !== "firefox" || (browserVersion$1 && browserVersion$1 >= 63) || browserVersion$1 === 60)) {
|
|
967
|
-
return sdp;
|
|
968
|
-
}
|
|
969
|
-
return (SDPUtils.splitLines(sdp.trim())
|
|
970
|
-
.filter((line) => {
|
|
971
|
-
if (!line.startsWith("a=extmap:")) {
|
|
972
|
-
return true;
|
|
1413
|
+
client.isPendingToLeave = true;
|
|
1414
|
+
if (this._wasClientSendingMedia(clientId)) {
|
|
1415
|
+
client.checkActiveMediaAttempts = 0;
|
|
1416
|
+
this._abortIfNotActive(payload);
|
|
973
1417
|
}
|
|
974
|
-
const extmap = SDPUtils.parseExtmap(line);
|
|
975
|
-
return extmap.uri !== "urn:ietf:params:rtp-hdrext:sdes:mid";
|
|
976
|
-
})
|
|
977
|
-
.join("\r\n") + "\r\n");
|
|
978
|
-
}
|
|
979
|
-
function filterMsidSemantic(sdp) {
|
|
980
|
-
if (browserName$2 !== "firefox") {
|
|
981
|
-
return sdp;
|
|
982
1418
|
}
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
.map((section) => {
|
|
992
|
-
const currentDirection = SDPUtils.getDirection(section, SDPUtils.getKind(section));
|
|
993
|
-
return section.replace("a=" + currentDirection, "a=" + (active ? "recvonly" : "inactive"));
|
|
994
|
-
})
|
|
995
|
-
.join(""));
|
|
996
|
-
}
|
|
997
|
-
function addExtMap(sdp, extmapUri, modifyAudio = false, modifyVideo = false) {
|
|
998
|
-
var _a, _b;
|
|
999
|
-
try {
|
|
1000
|
-
const sdpObj = sdpTransform.parse(sdp);
|
|
1001
|
-
if (((_a = sdpObj === null || sdpObj === void 0 ? void 0 : sdpObj.ext) === null || _a === void 0 ? void 0 : _a.length) && sdpObj.ext.length > 0) {
|
|
1002
|
-
return sdp;
|
|
1419
|
+
_onNewClient(payload) {
|
|
1420
|
+
const { client: { id: clientId, deviceId }, } = payload;
|
|
1421
|
+
const client = this._clients[clientId];
|
|
1422
|
+
if (client && client.isPendingToLeave) {
|
|
1423
|
+
clearTimeout(client.timeoutHandler);
|
|
1424
|
+
client.isPendingToLeave = false;
|
|
1425
|
+
this.metrics.pendingClientCanceled++;
|
|
1426
|
+
return;
|
|
1003
1427
|
}
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1428
|
+
this._getPendingClientsByDeviceId(deviceId).forEach((client) => {
|
|
1429
|
+
clearTimeout(client.timeoutHandler);
|
|
1430
|
+
client.isPendingToLeave = undefined;
|
|
1431
|
+
this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, { clientId: client.clientId });
|
|
1432
|
+
});
|
|
1433
|
+
this._addClientToState(payload.client);
|
|
1434
|
+
this.emit(PROTOCOL_RESPONSES.NEW_CLIENT, payload);
|
|
1435
|
+
}
|
|
1436
|
+
_abortIfNotActive(payload) {
|
|
1437
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1438
|
+
const { clientId } = payload;
|
|
1439
|
+
let client = this._clients[clientId];
|
|
1440
|
+
if (!(client === null || client === void 0 ? void 0 : client.isPendingToLeave))
|
|
1441
|
+
return;
|
|
1442
|
+
client.checkActiveMediaAttempts++;
|
|
1443
|
+
if (client.checkActiveMediaAttempts > 3) {
|
|
1444
|
+
return;
|
|
1445
|
+
}
|
|
1446
|
+
const stillActive = yield this._checkIsActive(clientId);
|
|
1447
|
+
if (stillActive) {
|
|
1448
|
+
client.timeoutHandler = setTimeout(() => this._abortIfNotActive(payload), 500);
|
|
1449
|
+
return;
|
|
1022
1450
|
}
|
|
1451
|
+
client = this._clients[clientId];
|
|
1452
|
+
if (client === null || client === void 0 ? void 0 : client.isPendingToLeave) {
|
|
1453
|
+
clearTimeout(client.timeoutHandler);
|
|
1454
|
+
delete this._clients[clientId];
|
|
1455
|
+
this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, payload);
|
|
1456
|
+
}
|
|
1457
|
+
});
|
|
1458
|
+
}
|
|
1459
|
+
_checkIsActive(clientId) {
|
|
1460
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1461
|
+
const allStats = yield getUpdatedStats();
|
|
1462
|
+
return this._isClientMediaActive(allStats, clientId);
|
|
1023
1463
|
});
|
|
1024
|
-
return sdpTransform.write(sdpObj);
|
|
1025
1464
|
}
|
|
1026
|
-
|
|
1027
|
-
|
|
1465
|
+
_isClientMediaActive(stats, clientId) {
|
|
1466
|
+
const clientStats = stats === null || stats === void 0 ? void 0 : stats[clientId];
|
|
1467
|
+
let isActive = false;
|
|
1468
|
+
if (clientStats) {
|
|
1469
|
+
Object.entries(clientStats.tracks).forEach(([trackId, trackStats]) => {
|
|
1470
|
+
if (trackId !== "probator")
|
|
1471
|
+
Object.values(trackStats.ssrcs).forEach((ssrcStats) => {
|
|
1472
|
+
if ((ssrcStats.bitrate || 0) > 0)
|
|
1473
|
+
isActive = true;
|
|
1474
|
+
});
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
return isActive;
|
|
1028
1478
|
}
|
|
1029
|
-
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
const absCaptureTimeUri = "http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time";
|
|
1033
|
-
return addExtMap(sdp, absCaptureTimeUri, true, true);
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
function setVideoBandwidthUsingSetParameters(pc, bandwidth, logger = console) {
|
|
1037
|
-
const sender = pc.getSenders().find((s) => s.track && s.track.kind === "video");
|
|
1038
|
-
if (!sender) {
|
|
1039
|
-
return Promise.resolve();
|
|
1479
|
+
_onAudioEnabled(payload) {
|
|
1480
|
+
const { clientId, isAudioEnabled } = payload;
|
|
1481
|
+
this._clients[clientId] = Object.assign(Object.assign({}, (this._clients[clientId] || {})), { isAudioEnabled });
|
|
1040
1482
|
}
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1483
|
+
_onVideoEnabled(payload) {
|
|
1484
|
+
const { clientId, isVideoEnabled } = payload;
|
|
1485
|
+
this._clients[clientId] = Object.assign(Object.assign({}, (this._clients[clientId] || {})), { isVideoEnabled });
|
|
1044
1486
|
}
|
|
1045
|
-
|
|
1046
|
-
|
|
1487
|
+
_onScreenshareChanged(payload, action) {
|
|
1488
|
+
const { clientId } = payload;
|
|
1489
|
+
this._clients[clientId] = Object.assign(Object.assign({}, (this._clients[clientId] || {})), { isScreenshareEnabled: action });
|
|
1047
1490
|
}
|
|
1048
|
-
|
|
1049
|
-
|
|
1491
|
+
_hasClientStateChanged({ clientId, webcam, mic, screenShare, }) {
|
|
1492
|
+
const state = this._clients[clientId];
|
|
1493
|
+
if (!state) {
|
|
1494
|
+
throw new Error(`Client ${clientId} not found in ReconnectManager state`);
|
|
1495
|
+
}
|
|
1496
|
+
if (webcam !== state.isVideoEnabled) {
|
|
1497
|
+
return true;
|
|
1498
|
+
}
|
|
1499
|
+
if (mic !== state.isAudioEnabled) {
|
|
1500
|
+
return true;
|
|
1501
|
+
}
|
|
1502
|
+
if (screenShare !== state.isScreenshareEnabled) {
|
|
1503
|
+
return true;
|
|
1504
|
+
}
|
|
1505
|
+
return false;
|
|
1050
1506
|
}
|
|
1051
|
-
|
|
1052
|
-
|
|
1507
|
+
_addClientToState(newClient) {
|
|
1508
|
+
this._clients[newClient.id] = Object.assign(Object.assign({}, (this._clients[newClient.id] || {})), { isAudioEnabled: newClient.isAudioEnabled, isVideoEnabled: newClient.isVideoEnabled, isScreenshareEnabled: newClient.streams.length > 1, deviceId: newClient.deviceId, isPendingToLeave: newClient.isPendingToLeave, clientId: newClient.id });
|
|
1053
1509
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
this.peerConnectionId = peerConnectionId;
|
|
1065
|
-
this.relayCandidateSeen = false;
|
|
1066
|
-
this.serverReflexiveCandidateSeen = false;
|
|
1067
|
-
this.publicHostCandidateSeen = false;
|
|
1068
|
-
this.ipv6HostCandidateSeen = false;
|
|
1069
|
-
this.ipv6HostCandidateTeredoSeen = false;
|
|
1070
|
-
this.ipv6HostCandidate6to4Seen = false;
|
|
1071
|
-
this.mdnsHostCandidateSeen = false;
|
|
1072
|
-
this.pc = null;
|
|
1073
|
-
this.wasEverConnected = false;
|
|
1074
|
-
this.connectionStatus = null;
|
|
1075
|
-
this.stats = {
|
|
1076
|
-
totalSent: 0,
|
|
1077
|
-
totalRecv: 0,
|
|
1078
|
-
};
|
|
1079
|
-
this.bandwidth = bandwidth || 0;
|
|
1080
|
-
this.pending = [];
|
|
1081
|
-
this.isOperationPending = false;
|
|
1082
|
-
this.streamIds = [];
|
|
1083
|
-
this.streams = [];
|
|
1084
|
-
this.earlyIceCandidates = [];
|
|
1085
|
-
this.afterConnected = new Promise((resolve) => {
|
|
1086
|
-
this.registerConnected = resolve;
|
|
1510
|
+
_wasClientSendingMedia(clientId) {
|
|
1511
|
+
const client = this._clients[clientId];
|
|
1512
|
+
if (!client) {
|
|
1513
|
+
throw new Error(`Client ${clientId} not found in ReconnectManager state`);
|
|
1514
|
+
}
|
|
1515
|
+
return client.isAudioEnabled || client.isVideoEnabled || client.isScreenshareEnabled;
|
|
1516
|
+
}
|
|
1517
|
+
_getPendingClientsByDeviceId(deviceId) {
|
|
1518
|
+
return Object.values(this._clients).filter((clientState) => {
|
|
1519
|
+
return clientState.deviceId === deviceId && clientState.isPendingToLeave;
|
|
1087
1520
|
});
|
|
1088
|
-
this.offerOptions = { offerToReceiveAudio: true, offerToReceiveVideo: true };
|
|
1089
|
-
this._deprioritizeH264Encoding = deprioritizeH264Encoding;
|
|
1090
1521
|
}
|
|
1091
|
-
|
|
1092
|
-
this.
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
this.pc = new RTCPeerConnection(peerConnectionConfig);
|
|
1096
|
-
this.signalingState = this.pc.signalingState;
|
|
1097
|
-
this.pc.addEventListener("signalingstatechange", () => {
|
|
1098
|
-
if (this.signalingState === this.pc.signalingState) {
|
|
1522
|
+
_resetClientState(payload) {
|
|
1523
|
+
this._clients = {};
|
|
1524
|
+
payload.room.clients.forEach((client) => {
|
|
1525
|
+
if (client.id === payload.selfId) {
|
|
1099
1526
|
return;
|
|
1100
1527
|
}
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
this.isOperationPending = false;
|
|
1104
|
-
const action = this.pending.shift();
|
|
1105
|
-
if (action) {
|
|
1106
|
-
action.apply();
|
|
1107
|
-
}
|
|
1528
|
+
else {
|
|
1529
|
+
this._addClientToState(client);
|
|
1108
1530
|
}
|
|
1109
1531
|
});
|
|
1110
|
-
return this.pc;
|
|
1111
|
-
}
|
|
1112
|
-
addStream(stream) {
|
|
1113
|
-
this.streamIds.push(stream.id);
|
|
1114
|
-
this.streams.push(stream);
|
|
1115
|
-
if (RTCPeerConnection.prototype.addTrack) {
|
|
1116
|
-
stream.getAudioTracks().forEach((track) => {
|
|
1117
|
-
this.pc.addTrack(track, stream);
|
|
1118
|
-
});
|
|
1119
|
-
stream.getVideoTracks().forEach((track) => {
|
|
1120
|
-
this.pc.addTrack(track, stream);
|
|
1121
|
-
});
|
|
1122
|
-
}
|
|
1123
|
-
else {
|
|
1124
|
-
this.pc.addStream(stream);
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
addTrack(track, stream) {
|
|
1128
|
-
if (!stream) {
|
|
1129
|
-
stream = this.streams[0];
|
|
1130
|
-
}
|
|
1131
|
-
stream === null || stream === void 0 ? void 0 : stream.addTrack(track);
|
|
1132
|
-
this.pc.addTrack(track, stream);
|
|
1133
|
-
}
|
|
1134
|
-
removeTrack(track) {
|
|
1135
|
-
const stream = this.streams[0];
|
|
1136
|
-
stream.removeTrack(track);
|
|
1137
|
-
const sender = this.pc.getSenders().find((sender) => sender.track === track);
|
|
1138
|
-
if (sender) {
|
|
1139
|
-
this.pc.removeTrack(sender);
|
|
1140
|
-
}
|
|
1141
1532
|
}
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
var _a$6;
|
|
1536
|
+
const adapter$6 = (_a$6 = adapterRaw.default) !== null && _a$6 !== void 0 ? _a$6 : adapterRaw;
|
|
1537
|
+
const DEFAULT_SOCKET_PATH = "/protocol/socket.io/v4";
|
|
1538
|
+
const NOOP_KEEPALIVE_INTERVAL = 2000;
|
|
1539
|
+
class ServerSocket {
|
|
1540
|
+
constructor(hostName, optionsOverrides, glitchFree = false) {
|
|
1541
|
+
this._wasConnectedUsingWebsocket = false;
|
|
1542
|
+
this._reconnectManager = null;
|
|
1543
|
+
this._socket = io(hostName, Object.assign({ path: DEFAULT_SOCKET_PATH, randomizationFactor: 0.5, reconnectionDelay: 250, reconnectionDelayMax: 5000, timeout: 5000, transports: ["websocket"], withCredentials: true }, optionsOverrides));
|
|
1544
|
+
this._socket.io.on("reconnect", () => {
|
|
1545
|
+
this._socket.sendBuffer = [];
|
|
1546
|
+
});
|
|
1547
|
+
this._socket.io.on("reconnect_attempt", () => {
|
|
1548
|
+
if (this._wasConnectedUsingWebsocket) {
|
|
1549
|
+
this._socket.io.opts.transports = ["websocket"];
|
|
1550
|
+
if (adapter$6.browserDetails.browser !== "safari")
|
|
1551
|
+
delete this._wasConnectedUsingWebsocket;
|
|
1147
1552
|
}
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
if (this.pc.removeTrack) {
|
|
1151
|
-
stream.getTracks().forEach((track) => {
|
|
1152
|
-
const sender = this.pc.getSenders().find((sender) => sender.track === track);
|
|
1153
|
-
if (sender) {
|
|
1154
|
-
this.pc.removeTrack(sender);
|
|
1155
|
-
}
|
|
1156
|
-
});
|
|
1553
|
+
else {
|
|
1554
|
+
this._socket.io.opts.transports = ["websocket", "polling"];
|
|
1157
1555
|
}
|
|
1158
|
-
|
|
1159
|
-
|
|
1556
|
+
});
|
|
1557
|
+
if (glitchFree)
|
|
1558
|
+
this._reconnectManager = new ReconnectManager(this._socket);
|
|
1559
|
+
this._socket.on("connect", () => {
|
|
1560
|
+
const transport = this.getTransport();
|
|
1561
|
+
if (transport === "websocket") {
|
|
1562
|
+
this._wasConnectedUsingWebsocket = true;
|
|
1563
|
+
if (!this.noopKeepaliveInterval)
|
|
1564
|
+
this.noopKeepaliveInterval = setInterval(() => {
|
|
1565
|
+
try {
|
|
1566
|
+
if (this._socket.connected) {
|
|
1567
|
+
this._socket.io.engine.sendPacket("noop");
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
catch (ex) { }
|
|
1571
|
+
}, NOOP_KEEPALIVE_INTERVAL);
|
|
1160
1572
|
}
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
_setRemoteDescription(desc) {
|
|
1164
|
-
if (this._deprioritizeH264Encoding)
|
|
1165
|
-
desc.sdp = deprioritizeH264(desc.sdp);
|
|
1166
|
-
this.srdComplete = this.pc.setRemoteDescription(desc);
|
|
1167
|
-
return this.srdComplete.then(() => {
|
|
1168
|
-
this.earlyIceCandidates.forEach((candidate) => this.pc.addIceCandidate(candidate));
|
|
1169
|
-
this.earlyIceCandidates = [];
|
|
1170
1573
|
});
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
this.
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
this.isOperationPending = true;
|
|
1179
|
-
let sdp = message.sdp;
|
|
1180
|
-
sdp = filterMidExtension(sdp);
|
|
1181
|
-
sdp = filterMsidSemantic(sdp);
|
|
1182
|
-
const desc = { type: message.type, sdp };
|
|
1183
|
-
let answerToSignal;
|
|
1184
|
-
return this._setRemoteDescription(desc)
|
|
1185
|
-
.then(() => {
|
|
1186
|
-
return this.pc.createAnswer();
|
|
1187
|
-
})
|
|
1188
|
-
.then((answer) => {
|
|
1189
|
-
answerToSignal = answer;
|
|
1190
|
-
return this.pc.setLocalDescription(answer);
|
|
1191
|
-
})
|
|
1192
|
-
.then(() => {
|
|
1193
|
-
return setVideoBandwidthUsingSetParameters(this.pc, this.bandwidth);
|
|
1194
|
-
})
|
|
1195
|
-
.then(() => {
|
|
1196
|
-
return answerToSignal;
|
|
1574
|
+
this._socket.on("disconnect", () => {
|
|
1575
|
+
this.disconnectTimestamp = Date.now();
|
|
1576
|
+
if (this.noopKeepaliveInterval) {
|
|
1577
|
+
clearInterval(this.noopKeepaliveInterval);
|
|
1578
|
+
this.noopKeepaliveInterval = null;
|
|
1579
|
+
}
|
|
1197
1580
|
});
|
|
1198
1581
|
}
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
return setVideoBandwidthUsingSetParameters(this.pc, this.bandwidth);
|
|
1204
|
-
}, (e) => {
|
|
1205
|
-
logger$9.warn("Could not set remote description from remote answer: ", e);
|
|
1206
|
-
});
|
|
1582
|
+
setRtcManager(rtcManager) {
|
|
1583
|
+
if (this._reconnectManager) {
|
|
1584
|
+
this._reconnectManager.rtcManager = rtcManager;
|
|
1585
|
+
}
|
|
1207
1586
|
}
|
|
1208
|
-
|
|
1209
|
-
if (
|
|
1210
|
-
this.earlyIceCandidates.push(candidate);
|
|
1587
|
+
connect() {
|
|
1588
|
+
if (this.isConnected() || this.isConnecting()) {
|
|
1211
1589
|
return;
|
|
1212
1590
|
}
|
|
1213
|
-
this.
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
this.
|
|
1221
|
-
logger$9.warn("Failed to add ICE candidate ('%s'): %s", candidate ? candidate.candidate : null, e);
|
|
1222
|
-
});
|
|
1591
|
+
this._socket.open();
|
|
1592
|
+
}
|
|
1593
|
+
disconnect() {
|
|
1594
|
+
this._socket.disconnect();
|
|
1595
|
+
}
|
|
1596
|
+
disconnectOnConnect() {
|
|
1597
|
+
this._socket.once("connect", () => {
|
|
1598
|
+
this._socket.disconnect();
|
|
1223
1599
|
});
|
|
1224
1600
|
}
|
|
1225
|
-
|
|
1226
|
-
|
|
1601
|
+
emit(eventName, ...args) {
|
|
1602
|
+
this._socket.emit.apply(this._socket, arguments);
|
|
1227
1603
|
}
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
if (!pc) {
|
|
1604
|
+
emitIfConnected(eventName, data) {
|
|
1605
|
+
if (!this.isConnected()) {
|
|
1231
1606
|
return;
|
|
1232
1607
|
}
|
|
1233
|
-
|
|
1234
|
-
pc.onicecandidate = null;
|
|
1235
|
-
pc.ontrack = null;
|
|
1236
|
-
try {
|
|
1237
|
-
pc.close();
|
|
1238
|
-
}
|
|
1239
|
-
catch (e) {
|
|
1240
|
-
logger$9.warn("failures during close of session", e);
|
|
1241
|
-
}
|
|
1608
|
+
this.emit(eventName, data);
|
|
1242
1609
|
}
|
|
1243
|
-
|
|
1244
|
-
return this.
|
|
1610
|
+
getTransport() {
|
|
1611
|
+
return (this._socket &&
|
|
1612
|
+
this._socket.io &&
|
|
1613
|
+
this._socket.io.engine &&
|
|
1614
|
+
this._socket.io.engine.transport &&
|
|
1615
|
+
this._socket.io.engine.transport.name);
|
|
1245
1616
|
}
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
if (!pc)
|
|
1249
|
-
return false;
|
|
1250
|
-
const senders = pc.getSenders();
|
|
1251
|
-
if (!oldTrack) {
|
|
1252
|
-
oldTrack = (senders.find((s) => s.track && s.track.kind === newTrack.kind) || {}).track;
|
|
1253
|
-
}
|
|
1254
|
-
if (window.RTCRtpSender && window.RTCRtpSender.prototype.replaceTrack) {
|
|
1255
|
-
if (oldTrack) {
|
|
1256
|
-
const process = () => {
|
|
1257
|
-
for (let i = 0; i < senders.length; i++) {
|
|
1258
|
-
const sender = senders[i];
|
|
1259
|
-
const track = sender.track;
|
|
1260
|
-
if ((track === null || track === void 0 ? void 0 : track.id) === newTrack.id) {
|
|
1261
|
-
return Promise.resolve(newTrack);
|
|
1262
|
-
}
|
|
1263
|
-
if ((track === null || track === void 0 ? void 0 : track.id) === oldTrack.id) {
|
|
1264
|
-
return senders[i].replaceTrack(newTrack);
|
|
1265
|
-
}
|
|
1266
|
-
}
|
|
1267
|
-
return null;
|
|
1268
|
-
};
|
|
1269
|
-
let result = process();
|
|
1270
|
-
if (result) {
|
|
1271
|
-
return result;
|
|
1272
|
-
}
|
|
1273
|
-
let resolve = null;
|
|
1274
|
-
let reject = null;
|
|
1275
|
-
result = new Promise((_resolve, _reject) => {
|
|
1276
|
-
resolve = _resolve;
|
|
1277
|
-
reject = _reject;
|
|
1278
|
-
});
|
|
1279
|
-
let retried = 0;
|
|
1280
|
-
let timer = setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
1281
|
-
const trackReplacedPromise = process();
|
|
1282
|
-
if (!trackReplacedPromise) {
|
|
1283
|
-
if (3 < ++retried) {
|
|
1284
|
-
clearInterval(timer);
|
|
1285
|
-
timer = null;
|
|
1286
|
-
reject("No sender track to replace");
|
|
1287
|
-
}
|
|
1288
|
-
return;
|
|
1289
|
-
}
|
|
1290
|
-
clearInterval(timer);
|
|
1291
|
-
timer = null;
|
|
1292
|
-
const trackReplaced = yield trackReplacedPromise;
|
|
1293
|
-
resolve(trackReplaced);
|
|
1294
|
-
}), 1000);
|
|
1295
|
-
return result;
|
|
1296
|
-
}
|
|
1297
|
-
const stream = this.streams.find((s) => s.getTracks().find((t) => t.id === newTrack.id)) || this.streams[0];
|
|
1298
|
-
if (!stream) {
|
|
1299
|
-
return Promise.reject(new Error("replaceTrack: No stream?"));
|
|
1300
|
-
}
|
|
1301
|
-
return pc.addTrack(newTrack, stream);
|
|
1302
|
-
}
|
|
1303
|
-
if (!this.canModifyPeerConnection()) {
|
|
1304
|
-
this.pending.push(() => {
|
|
1305
|
-
this.replaceTrack(oldTrack, newTrack);
|
|
1306
|
-
});
|
|
1307
|
-
return;
|
|
1308
|
-
}
|
|
1309
|
-
this.isOperationPending = true;
|
|
1310
|
-
const onn = pc.onnegotiationneeded;
|
|
1311
|
-
pc.onnegotiationneeded = null;
|
|
1312
|
-
this.removeTrack(oldTrack);
|
|
1313
|
-
this.addTrack(newTrack);
|
|
1314
|
-
setTimeout(() => {
|
|
1315
|
-
pc.onnegotiationneeded = onn;
|
|
1316
|
-
}, 0);
|
|
1317
|
-
if (pc.localDescription.type === "offer") {
|
|
1318
|
-
return pc
|
|
1319
|
-
.createOffer()
|
|
1320
|
-
.then((offer) => {
|
|
1321
|
-
offer.sdp = replaceSSRCs(pc.localDescription.sdp, offer.sdp);
|
|
1322
|
-
return pc.setLocalDescription(offer);
|
|
1323
|
-
})
|
|
1324
|
-
.then(() => {
|
|
1325
|
-
return this._setRemoteDescription(pc.remoteDescription);
|
|
1326
|
-
});
|
|
1327
|
-
}
|
|
1328
|
-
else {
|
|
1329
|
-
return this._setRemoteDescription(pc.remoteDescription)
|
|
1330
|
-
.then(() => {
|
|
1331
|
-
return pc.createAnswer();
|
|
1332
|
-
})
|
|
1333
|
-
.then((answer) => {
|
|
1334
|
-
answer.sdp = replaceSSRCs(pc.localDescription.sdp, answer.sdp);
|
|
1335
|
-
return pc.setLocalDescription(answer);
|
|
1336
|
-
});
|
|
1337
|
-
}
|
|
1617
|
+
getManager() {
|
|
1618
|
+
return this._socket.io;
|
|
1338
1619
|
}
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1620
|
+
isConnecting() {
|
|
1621
|
+
return this._socket && this._socket.connecting;
|
|
1622
|
+
}
|
|
1623
|
+
isConnected() {
|
|
1624
|
+
return this._socket && this._socket.connected;
|
|
1625
|
+
}
|
|
1626
|
+
on(eventName, handler) {
|
|
1627
|
+
const relayableEvents = [
|
|
1628
|
+
PROTOCOL_RESPONSES.ROOM_JOINED,
|
|
1629
|
+
PROTOCOL_RESPONSES.CLIENT_LEFT,
|
|
1630
|
+
PROTOCOL_RESPONSES.NEW_CLIENT,
|
|
1631
|
+
];
|
|
1632
|
+
if (this._reconnectManager && relayableEvents.includes(eventName)) {
|
|
1633
|
+
return this._interceptEvent(eventName, handler);
|
|
1346
1634
|
}
|
|
1347
|
-
this.
|
|
1348
|
-
|
|
1349
|
-
|
|
1635
|
+
this._socket.on(eventName, handler);
|
|
1636
|
+
return () => {
|
|
1637
|
+
this._socket.off(eventName, handler);
|
|
1638
|
+
};
|
|
1639
|
+
}
|
|
1640
|
+
onEngineEvent(eventName, handler) {
|
|
1641
|
+
var _a;
|
|
1642
|
+
(_a = this._socket.io) === null || _a === void 0 ? void 0 : _a.on(eventName, handler);
|
|
1643
|
+
return () => {
|
|
1644
|
+
var _a;
|
|
1645
|
+
(_a = this._socket.io) === null || _a === void 0 ? void 0 : _a.off(eventName, handler);
|
|
1646
|
+
};
|
|
1647
|
+
}
|
|
1648
|
+
once(eventName, handler) {
|
|
1649
|
+
this._socket.once(eventName, handler);
|
|
1650
|
+
}
|
|
1651
|
+
off(eventName, handler) {
|
|
1652
|
+
this._socket.off(eventName, handler);
|
|
1653
|
+
}
|
|
1654
|
+
_interceptEvent(eventName, handler) {
|
|
1655
|
+
if (this._reconnectManager) {
|
|
1656
|
+
this._reconnectManager.on(eventName, handler);
|
|
1350
1657
|
}
|
|
1351
|
-
|
|
1658
|
+
return () => {
|
|
1659
|
+
if (this._reconnectManager)
|
|
1660
|
+
this._reconnectManager.removeListener(eventName, handler);
|
|
1661
|
+
};
|
|
1352
1662
|
}
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
!excludedTrackIds.includes((_d = (_c = videoTransceiver === null || videoTransceiver === void 0 ? void 0 : videoTransceiver.receiver) === null || _c === void 0 ? void 0 : _c.track) === null || _d === void 0 ? void 0 : _d.id) &&
|
|
1361
|
-
!excludedTrackIds.includes((_f = (_e = videoTransceiver === null || videoTransceiver === void 0 ? void 0 : videoTransceiver.sender) === null || _e === void 0 ? void 0 : _e.track) === null || _f === void 0 ? void 0 : _f.id);
|
|
1362
|
-
})
|
|
1363
|
-
.forEach((videoTransceiver) => {
|
|
1364
|
-
videoTransceiver.direction = enable ? "sendonly" : "sendrecv";
|
|
1365
|
-
});
|
|
1663
|
+
getGlitchFreeMetrics() {
|
|
1664
|
+
var _a;
|
|
1665
|
+
return (_a = this._reconnectManager) === null || _a === void 0 ? void 0 : _a.metrics;
|
|
1666
|
+
}
|
|
1667
|
+
getReconnectThreshold() {
|
|
1668
|
+
var _a;
|
|
1669
|
+
return (_a = this._reconnectManager) === null || _a === void 0 ? void 0 : _a.reconnectThresholdInMs;
|
|
1366
1670
|
}
|
|
1367
1671
|
}
|
|
1368
1672
|
|
|
1369
|
-
const
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
const adapter$4 = (_a$4 = adapterRaw.default) !== null && _a$4 !== void 0 ? _a$4 : adapterRaw;
|
|
1373
|
-
function detectMicrophoneNotWorking(pc) {
|
|
1374
|
-
if (adapter$4.browserDetails.browser !== "chrome" ||
|
|
1375
|
-
adapter$4.browserDetails.browser < 58 ||
|
|
1376
|
-
pc.signalingState === "closed") {
|
|
1377
|
-
return Promise.resolve(false);
|
|
1673
|
+
const maybeTurnOnly = (iceConfig, features) => {
|
|
1674
|
+
if (!features.useOnlyTURN) {
|
|
1675
|
+
return;
|
|
1378
1676
|
}
|
|
1379
|
-
|
|
1380
|
-
const
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
receivingAudio) {
|
|
1394
|
-
if (report.bytesReceived === 0) {
|
|
1395
|
-
microphoneFailed = "inbound";
|
|
1396
|
-
}
|
|
1677
|
+
iceConfig.iceTransportPolicy = "relay";
|
|
1678
|
+
const filter = {
|
|
1679
|
+
onlyudp: /^turn:.*transport=udp$/,
|
|
1680
|
+
onlytcp: /^turn:.*transport=tcp$/,
|
|
1681
|
+
onlytls: /^turns:.*transport=tcp$/,
|
|
1682
|
+
}[features.useOnlyTURN];
|
|
1683
|
+
if (filter) {
|
|
1684
|
+
iceConfig.iceServers = iceConfig.iceServers.filter((entry) => {
|
|
1685
|
+
if (entry.url && entry.url.match(filter))
|
|
1686
|
+
return entry;
|
|
1687
|
+
if (entry.urls) {
|
|
1688
|
+
entry.urls = (entry.urls.some ? entry.urls : [entry.urls]).filter((url) => url.match(filter));
|
|
1689
|
+
if (entry.urls.length > 0)
|
|
1690
|
+
return entry;
|
|
1397
1691
|
}
|
|
1398
1692
|
});
|
|
1399
|
-
|
|
1400
|
-
});
|
|
1401
|
-
}
|
|
1402
|
-
|
|
1403
|
-
const PROTOCOL_REQUESTS = {
|
|
1404
|
-
BLOCK_CLIENT: "block_client",
|
|
1405
|
-
CLAIM_ROOM: "claim_room",
|
|
1406
|
-
CLEAR_CHAT_HISTORY: "clear_chat_history",
|
|
1407
|
-
ENABLE_AUDIO: "enable_audio",
|
|
1408
|
-
ENABLE_VIDEO: "enable_video",
|
|
1409
|
-
END_STREAM: "end_stream",
|
|
1410
|
-
FETCH_MEDIASERVER_CONFIG: "fetch_mediaserver_config",
|
|
1411
|
-
HANDLE_KNOCK: "handle_knock",
|
|
1412
|
-
IDENTIFY_DEVICE: "identify_device",
|
|
1413
|
-
INVITE_CLIENT_AS_MEMBER: "invite_client_as_member",
|
|
1414
|
-
JOIN_ROOM: "join_room",
|
|
1415
|
-
KICK_CLIENT: "kick_client",
|
|
1416
|
-
KNOCK_ROOM: "knock_room",
|
|
1417
|
-
LEAVE_ROOM: "leave_room",
|
|
1418
|
-
SEND_CLIENT_METADATA: "send_client_metadata",
|
|
1419
|
-
SET_LOCK: "set_lock",
|
|
1420
|
-
SHARE_MEDIA: "share_media",
|
|
1421
|
-
START_NEW_STREAM: "start_new_stream",
|
|
1422
|
-
START_SCREENSHARE: "start_screenshare",
|
|
1423
|
-
STOP_SCREENSHARE: "stop_screenshare",
|
|
1424
|
-
START_URL_EMBED: "start_url_embed",
|
|
1425
|
-
STOP_URL_EMBED: "stop_url_embed",
|
|
1426
|
-
START_RECORDING: "start_recording",
|
|
1427
|
-
STOP_RECORDING: "stop_recording",
|
|
1428
|
-
};
|
|
1429
|
-
const PROTOCOL_RESPONSES = {
|
|
1430
|
-
AUDIO_ENABLED: "audio_enabled",
|
|
1431
|
-
BACKGROUND_IMAGE_CHANGED: "background_image_changed",
|
|
1432
|
-
BLOCK_ADDED: "block_added",
|
|
1433
|
-
BLOCK_REMOVED: "block_removed",
|
|
1434
|
-
CHAT_HISTORY_CLEARED: "chat_history_cleared",
|
|
1435
|
-
CLIENT_BLOCKED: "client_blocked",
|
|
1436
|
-
CLIENT_INVITED_AS_MEMBER: "client_invited_as_member",
|
|
1437
|
-
CLIENT_KICKED: "client_kicked",
|
|
1438
|
-
CLIENT_LEFT: "client_left",
|
|
1439
|
-
CLIENT_METADATA_RECEIVED: "client_metadata_received",
|
|
1440
|
-
CLIENT_READY: "client_ready",
|
|
1441
|
-
CLIENT_ROLE_CHANGED: "client_role_changed",
|
|
1442
|
-
CLIENT_USER_ID_CHANGED: "client_user_id_changed",
|
|
1443
|
-
CONTACTS_UPDATED: "contacts_updated",
|
|
1444
|
-
DEVICE_IDENTIFIED: "device_identified",
|
|
1445
|
-
ROOM_ROLES_UPDATED: "room_roles_updated",
|
|
1446
|
-
KNOCK_HANDLED: "knock_handled",
|
|
1447
|
-
KNOCK_PAGE_BACKGROUND_CHANGED: "knock_page_background_changed",
|
|
1448
|
-
KNOCKER_LEFT: "knocker_left",
|
|
1449
|
-
MEDIASERVER_CONFIG: "mediaserver_config",
|
|
1450
|
-
MEDIA_SHARED: "media_shared",
|
|
1451
|
-
MEMBER_INVITE: "member_invite",
|
|
1452
|
-
NEW_CLIENT: "new_client",
|
|
1453
|
-
NEW_STREAM_STARTED: "new_stream_started",
|
|
1454
|
-
SCREENSHARE_STARTED: "screenshare_started",
|
|
1455
|
-
SCREENSHARE_STOPPED: "screenshare_stopped",
|
|
1456
|
-
OWNER_NOTIFIED: "owner_notified",
|
|
1457
|
-
OWNERS_CHANGED: "owners_changed",
|
|
1458
|
-
PLAY_CLIENT_STICKER: "play_client_sticker",
|
|
1459
|
-
ROOM_INTEGRATION_ENABLED: "room_integration_enabled",
|
|
1460
|
-
ROOM_INTEGRATION_DISABLED: "room_integration_disabled",
|
|
1461
|
-
ROOM_JOINED: "room_joined",
|
|
1462
|
-
ROOM_KNOCKED: "room_knocked",
|
|
1463
|
-
ROOM_LEFT: "room_left",
|
|
1464
|
-
ROOM_LOCKED: "room_locked",
|
|
1465
|
-
ROOM_PERMISSIONS_CHANGED: "room_permissions_changed",
|
|
1466
|
-
ROOM_LOGO_CHANGED: "room_logo_changed",
|
|
1467
|
-
ROOM_TYPE_CHANGED: "room_type_changed",
|
|
1468
|
-
ROOM_MODE_CHANGED: "room_mode_changed",
|
|
1469
|
-
SOCKET_USER_ID_CHANGED: "socket_user_id_changed",
|
|
1470
|
-
STICKERS_UNLOCKED: "stickers_unlocked",
|
|
1471
|
-
STREAM_ENDED: "stream_ended",
|
|
1472
|
-
URL_EMBED_STARTED: "url_embed_started",
|
|
1473
|
-
URL_EMBED_STOPPED: "url_embed_stopped",
|
|
1474
|
-
RECORDING_STARTED: "recording_started",
|
|
1475
|
-
RECORDING_STOPPED: "recording_stopped",
|
|
1476
|
-
USER_NOTIFIED: "user_notified",
|
|
1477
|
-
VIDEO_ENABLED: "video_enabled",
|
|
1478
|
-
CLIENT_UNABLE_TO_JOIN: "client_unable_to_join",
|
|
1479
|
-
LIVE_TRANSCRIPTION_STARTED: "live_transcription_started",
|
|
1480
|
-
LIVE_TRANSCRIPTION_STOPPED: "live_transcription_stopped",
|
|
1481
|
-
};
|
|
1482
|
-
const PROTOCOL_ERRORS = {
|
|
1483
|
-
CANNOT_INVITE_YOURSELF: "cannot_invite_yourself",
|
|
1484
|
-
CLIENT_MISSING_DEVICE_ID: "client_missing_device_id",
|
|
1485
|
-
FORBIDDEN: "forbidden",
|
|
1486
|
-
INTERNAL_SERVER_ERROR: "internal_server_error",
|
|
1487
|
-
INVALID_AVATAR: "invalid_avatar",
|
|
1488
|
-
INVALID_PARAMETERS: "invalid_parameters",
|
|
1489
|
-
INVALID_ROOM_NAME: "invalid_room_name",
|
|
1490
|
-
MISSING_PARAMETERS: "missing_parameters",
|
|
1491
|
-
MISSING_ROOM_NAME: "missing_room_name",
|
|
1492
|
-
NOT_AN_OWNER: "not_an_owner",
|
|
1493
|
-
NOT_IN_A_ROOM: "not_in_a_room",
|
|
1494
|
-
ROOM_ALREADY_CLAIMED: "room_already_claimed",
|
|
1495
|
-
ROOM_EMAIL_MISSING: "room_email_missing",
|
|
1496
|
-
ROOM_FULL: "room_full",
|
|
1497
|
-
ROOM_UNCLAIMED: "room_unclaimed",
|
|
1498
|
-
CLIENT_BLOCKED: "client_blocked",
|
|
1499
|
-
ROOM_LOCKED: "room_locked",
|
|
1500
|
-
TOO_LONG_TEXT: "too_long_text",
|
|
1501
|
-
VIDEO_STICKER_DOES_NOT_EXIST: "video_sticker_does_not_exist",
|
|
1502
|
-
VIDEO_STICKER_FORMAT_ERROR: "video_sticker_format_error",
|
|
1503
|
-
UNSUPPORTED_VIDEO_ENCODING: "unsupported_video_encoding",
|
|
1504
|
-
};
|
|
1505
|
-
const RELAY_MESSAGES = {
|
|
1506
|
-
CHAT_MESSAGE: "chat_message",
|
|
1507
|
-
CHAT_READ_STATE: "chat_read_state",
|
|
1508
|
-
CHAT_STATE: "chat_state",
|
|
1509
|
-
ICE_CANDIDATE: "ice_candidate",
|
|
1510
|
-
ICE_END_OF_CANDIDATES: "ice_endofcandidates",
|
|
1511
|
-
READY_TO_RECEIVE_OFFER: "ready_to_receive_offer",
|
|
1512
|
-
REMOTE_CLIENT_MEDIA_REQUEST: "remote_client_media_request",
|
|
1513
|
-
SDP_ANSWER: "sdp_answer",
|
|
1514
|
-
SDP_OFFER: "sdp_offer",
|
|
1515
|
-
VIDEO_STICKER: "video_sticker",
|
|
1693
|
+
}
|
|
1516
1694
|
};
|
|
1517
|
-
const
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1695
|
+
const external_stun_servers = (iceConfig, features) => {
|
|
1696
|
+
if (features.addGoogleStunServers) {
|
|
1697
|
+
iceConfig.iceServers = [
|
|
1698
|
+
{ urls: "stun:stun.l.google.com:19302" },
|
|
1699
|
+
{ urls: "stun:stun2.l.google.com:19302" },
|
|
1700
|
+
...iceConfig.iceServers,
|
|
1701
|
+
];
|
|
1702
|
+
}
|
|
1703
|
+
if (features.addCloudflareStunServers) {
|
|
1704
|
+
iceConfig.iceServers = [
|
|
1705
|
+
{ urls: "stun:stun.cloudflare.com:3478" },
|
|
1706
|
+
{ urls: "stun:stun.cloudflare.com:53" },
|
|
1707
|
+
...iceConfig.iceServers,
|
|
1708
|
+
];
|
|
1709
|
+
}
|
|
1528
1710
|
};
|
|
1529
|
-
const
|
|
1530
|
-
|
|
1531
|
-
|
|
1711
|
+
const turnServerOverride = (iceServers, overrideHost) => {
|
|
1712
|
+
if (overrideHost && iceServers) {
|
|
1713
|
+
const host = overrideHost;
|
|
1714
|
+
const port = host.indexOf(":") > 0 ? "" : ":443";
|
|
1715
|
+
const override = ":" + host + port;
|
|
1716
|
+
return iceServers.map((original) => {
|
|
1717
|
+
const entry = Object.assign({}, original);
|
|
1718
|
+
if (entry.url) {
|
|
1719
|
+
entry.url = entry.url.replace(/:[^?]*/, override);
|
|
1720
|
+
}
|
|
1721
|
+
if (entry.urls) {
|
|
1722
|
+
entry.urls = entry.urls.map((url) => url.replace(/:[^?]*/, override));
|
|
1723
|
+
}
|
|
1724
|
+
return entry;
|
|
1725
|
+
});
|
|
1726
|
+
}
|
|
1727
|
+
else {
|
|
1728
|
+
return iceServers;
|
|
1729
|
+
}
|
|
1532
1730
|
};
|
|
1533
1731
|
|
|
1534
|
-
const
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
}
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1732
|
+
const defaultSubdomainPattern = /^(?:([^.]+)[.])?((:?[^.]+[.]){1,}[^.]+)$/;
|
|
1733
|
+
const localstackPattern = /^(?:([^.]+)-)?(ip-[^.]*[.](?:hereby[.]dev|rfc1918[.]disappear[.]at)(?::\d+|))$/;
|
|
1734
|
+
const localhostPattern = /^(?:([^.]+)[.])?(localhost:?\d*)/;
|
|
1735
|
+
const serverPattern = /^(?:([^.]+)[.])?(server:?\d*)/;
|
|
1736
|
+
const ipv4Pattern = /^(?:([^.]+)[.])?((\d+[.]){3}:?\d*)$/;
|
|
1737
|
+
const subdomainPatterns = [
|
|
1738
|
+
{ pattern: serverPattern, separator: "." },
|
|
1739
|
+
{ pattern: localhostPattern, separator: "." },
|
|
1740
|
+
{ pattern: ipv4Pattern, separator: "." },
|
|
1741
|
+
{ pattern: localstackPattern, separator: "-" },
|
|
1742
|
+
{ pattern: defaultSubdomainPattern, separator: "." },
|
|
1743
|
+
];
|
|
1744
|
+
function fromLocation({ host = "whereby.com", protocol = "https:" } = {}) {
|
|
1745
|
+
let subdomain = "";
|
|
1746
|
+
let domain = host;
|
|
1747
|
+
let subdomainSeparator = ".";
|
|
1748
|
+
for (const { separator, pattern } of subdomainPatterns) {
|
|
1749
|
+
const match = pattern.exec(host);
|
|
1750
|
+
if (match) {
|
|
1751
|
+
subdomain = match[1] || "";
|
|
1752
|
+
domain = match[2];
|
|
1753
|
+
subdomainSeparator = separator;
|
|
1754
|
+
break;
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
const organizationDomain = !subdomain ? domain : `${subdomain}${subdomainSeparator}${domain}`;
|
|
1758
|
+
return {
|
|
1759
|
+
domain,
|
|
1760
|
+
domainWithSeparator: `${subdomainSeparator}${domain}`,
|
|
1761
|
+
organizationDomain,
|
|
1762
|
+
organization: `${protocol}//${organizationDomain}`,
|
|
1763
|
+
service: `${protocol}//${domain}`,
|
|
1764
|
+
subdomain,
|
|
1765
|
+
};
|
|
1766
|
+
}
|
|
1767
|
+
fromLocation(window && window.location);
|
|
1550
1768
|
|
|
1551
|
-
const
|
|
1552
|
-
const
|
|
1553
|
-
|
|
1554
|
-
SCREEN_SHARE: "screen_share",
|
|
1769
|
+
const logger$9 = new Logger();
|
|
1770
|
+
const debugLogger = {
|
|
1771
|
+
print: (...args) => console.debug(args[0], ...args.slice(1)),
|
|
1555
1772
|
};
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
this.
|
|
1560
|
-
this.
|
|
1561
|
-
this.
|
|
1562
|
-
this.
|
|
1563
|
-
this.
|
|
1564
|
-
this.
|
|
1565
|
-
this.
|
|
1566
|
-
|
|
1773
|
+
logger$9.withDebugLogger(debugLogger);
|
|
1774
|
+
class PacketLossAnalyser {
|
|
1775
|
+
constructor() {
|
|
1776
|
+
this.BEGIN_PACKET_LOSS_PERIOD_THRESHOLD = 0.04;
|
|
1777
|
+
this.END_PACKET_LOSS_PERIOD_THRESHOLD = 0.005;
|
|
1778
|
+
this.INTERVAL_DIFF_THRESHOLD_MS = 4000;
|
|
1779
|
+
this.STALE_MEASUREMENT_TIMEOUT_MS = 10000;
|
|
1780
|
+
this.MINIMUM_INTERVAL_MS = 30000;
|
|
1781
|
+
this.ssrcsHistory = new Map();
|
|
1782
|
+
this.staleMeasurementTimeouts = new Map();
|
|
1783
|
+
}
|
|
1784
|
+
addPacketLossMeasurement(id, packetLoss, timestamp) {
|
|
1785
|
+
this.handleStaleMeasurements(id);
|
|
1786
|
+
const beginNewPacketLossPeriod = packetLoss > this.BEGIN_PACKET_LOSS_PERIOD_THRESHOLD;
|
|
1787
|
+
let history = this.ssrcsHistory.get(id);
|
|
1788
|
+
if (!history) {
|
|
1789
|
+
history = {
|
|
1790
|
+
id,
|
|
1791
|
+
hasActivePacketLoss: beginNewPacketLossPeriod,
|
|
1792
|
+
currPeriod: beginNewPacketLossPeriod ? { begin: timestamp } : undefined,
|
|
1793
|
+
hasPeriodicPacketLoss: false,
|
|
1794
|
+
};
|
|
1795
|
+
this.ssrcsHistory.set(id, history);
|
|
1796
|
+
return;
|
|
1797
|
+
}
|
|
1798
|
+
if (history.hasActivePacketLoss) {
|
|
1799
|
+
if (packetLoss < this.END_PACKET_LOSS_PERIOD_THRESHOLD) {
|
|
1800
|
+
this.endPacketLossPeriod(history, timestamp);
|
|
1801
|
+
if (history.prevIntervalInMs && history.prevIntervalInMs < this.MINIMUM_INTERVAL_MS) {
|
|
1802
|
+
this.ssrcsHistory.delete(id);
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
return;
|
|
1806
|
+
}
|
|
1807
|
+
if (beginNewPacketLossPeriod) {
|
|
1808
|
+
history.hasActivePacketLoss = true;
|
|
1809
|
+
history.currPeriod = {
|
|
1810
|
+
begin: timestamp,
|
|
1811
|
+
};
|
|
1812
|
+
}
|
|
1567
1813
|
}
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
this.
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1814
|
+
hasPeriodicPacketLoss(id, timestamp) {
|
|
1815
|
+
const history = this.ssrcsHistory.get(id);
|
|
1816
|
+
if (history && this.prevIntervalExceeded(history, timestamp)) {
|
|
1817
|
+
this.ssrcsHistory.delete(history.id);
|
|
1818
|
+
return false;
|
|
1819
|
+
}
|
|
1820
|
+
return (history === null || history === void 0 ? void 0 : history.hasPeriodicPacketLoss) || false;
|
|
1574
1821
|
}
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1822
|
+
prevIntervalExceeded(history, timestamp) {
|
|
1823
|
+
if (history.prevPeriod && history.prevIntervalInMs) {
|
|
1824
|
+
const intervalLimitTimestamp = this.calculatePeriodCenterTimestamp(history.prevPeriod) +
|
|
1825
|
+
history.prevIntervalInMs +
|
|
1826
|
+
this.INTERVAL_DIFF_THRESHOLD_MS;
|
|
1827
|
+
return timestamp > intervalLimitTimestamp;
|
|
1828
|
+
}
|
|
1829
|
+
return false;
|
|
1578
1830
|
}
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
if (
|
|
1582
|
-
|
|
1831
|
+
handleStaleMeasurements(id) {
|
|
1832
|
+
const staleMeasurementTimeout = this.staleMeasurementTimeouts.get(id);
|
|
1833
|
+
if (staleMeasurementTimeout) {
|
|
1834
|
+
clearTimeout(staleMeasurementTimeout);
|
|
1583
1835
|
}
|
|
1584
|
-
this.
|
|
1585
|
-
|
|
1586
|
-
|
|
1836
|
+
this.staleMeasurementTimeouts.set(id, setTimeout(() => {
|
|
1837
|
+
logger$9.debug("handleStaleMeasurements() [measurements invalid for ssrc: %s]", id);
|
|
1838
|
+
this.ssrcsHistory.delete(id);
|
|
1839
|
+
}, this.STALE_MEASUREMENT_TIMEOUT_MS));
|
|
1587
1840
|
}
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
if (!
|
|
1591
|
-
|
|
1841
|
+
endPacketLossPeriod(history, timestamp) {
|
|
1842
|
+
logger$9.debug("endPacketLossPeriod() [ssrcId: %s, timestamp: %s]", history.id, timestamp);
|
|
1843
|
+
if (!history.currPeriod)
|
|
1844
|
+
throw new Error("No packet loss period for " + history.id);
|
|
1845
|
+
if (!history.prevPeriod) {
|
|
1846
|
+
history.prevPeriod = Object.assign(Object.assign({}, history.currPeriod), { end: timestamp });
|
|
1592
1847
|
}
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1848
|
+
else {
|
|
1849
|
+
history.currPeriod.end = timestamp;
|
|
1850
|
+
this.addNewPacketLossInterval(history);
|
|
1851
|
+
}
|
|
1852
|
+
delete history.currPeriod;
|
|
1853
|
+
history.hasActivePacketLoss = false;
|
|
1596
1854
|
}
|
|
1597
|
-
|
|
1598
|
-
|
|
1855
|
+
addNewPacketLossInterval(history) {
|
|
1856
|
+
logger$9.debug("addNewPacketLossInterval() [ssrcId: %s, prevIntervalInMs: %s]", history.id, history.prevIntervalInMs);
|
|
1857
|
+
if (!history.currPeriod || !history.prevPeriod)
|
|
1858
|
+
throw new Error("missing period timestamps");
|
|
1859
|
+
const prevPeriodCenter = this.calculatePeriodCenterTimestamp(history.prevPeriod);
|
|
1860
|
+
const currPeriodCenter = this.calculatePeriodCenterTimestamp(history.currPeriod);
|
|
1861
|
+
const currIntervalInMs = currPeriodCenter - prevPeriodCenter;
|
|
1862
|
+
if (history.prevIntervalInMs) {
|
|
1863
|
+
const intervalDiffInMs = Math.abs(history.prevIntervalInMs - currIntervalInMs);
|
|
1864
|
+
history.hasPeriodicPacketLoss = intervalDiffInMs < this.INTERVAL_DIFF_THRESHOLD_MS;
|
|
1865
|
+
logger$9.debug("addNewPacketLossInterval() [hasPeriodicPacketLoss: %s, intervalDiffInMs: %s]", intervalDiffInMs < this.INTERVAL_DIFF_THRESHOLD_MS, intervalDiffInMs);
|
|
1866
|
+
}
|
|
1867
|
+
history.prevIntervalInMs = currIntervalInMs;
|
|
1868
|
+
history.prevPeriod = history.currPeriod;
|
|
1599
1869
|
}
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1870
|
+
calculatePeriodCenterTimestamp(period) {
|
|
1871
|
+
if (!period.end)
|
|
1872
|
+
throw new Error("Missing period end timestamp");
|
|
1873
|
+
return period.begin + (period.end - period.begin) / 2;
|
|
1603
1874
|
}
|
|
1604
1875
|
}
|
|
1605
1876
|
|
|
1606
|
-
|
|
1607
|
-
const
|
|
1608
|
-
const
|
|
1609
|
-
const
|
|
1610
|
-
const
|
|
1611
|
-
(
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
(
|
|
1615
|
-
(
|
|
1616
|
-
(
|
|
1617
|
-
(
|
|
1618
|
-
|
|
1619
|
-
(
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1877
|
+
var _a$5;
|
|
1878
|
+
const adapter$5 = (_a$5 = adapterRaw.default) !== null && _a$5 !== void 0 ? _a$5 : adapterRaw;
|
|
1879
|
+
const logger$8 = new Logger();
|
|
1880
|
+
const browserName$2 = adapter$5.browserDetails.browser;
|
|
1881
|
+
const browserVersion$1 = adapter$5.browserDetails.version;
|
|
1882
|
+
function setCodecPreferenceSDP(sdp, redOn) {
|
|
1883
|
+
var _a, _b;
|
|
1884
|
+
try {
|
|
1885
|
+
const sdpObject = sdpTransform.parse(sdp);
|
|
1886
|
+
if (Array.isArray(sdpObject === null || sdpObject === void 0 ? void 0 : sdpObject.media)) {
|
|
1887
|
+
const mediaAudio = sdpObject.media.find((m) => m.type === "audio");
|
|
1888
|
+
if (Array.isArray(mediaAudio === null || mediaAudio === void 0 ? void 0 : mediaAudio.rtp)) {
|
|
1889
|
+
const rtp = mediaAudio.rtp;
|
|
1890
|
+
for (let i = 0; i < rtp.length; i++) {
|
|
1891
|
+
if (redOn && rtp[i].codec === "red") {
|
|
1892
|
+
const payloads = (_a = mediaAudio.payloads) === null || _a === void 0 ? void 0 : _a.split(" ");
|
|
1893
|
+
const pt = payloads === null || payloads === void 0 ? void 0 : payloads.indexOf("" + rtp[i].payload);
|
|
1894
|
+
if (pt && pt !== -1 && pt >= 0) {
|
|
1895
|
+
payloads === null || payloads === void 0 ? void 0 : payloads.unshift(payloads.splice(pt, 1)[0]);
|
|
1896
|
+
mediaAudio.payloads = payloads === null || payloads === void 0 ? void 0 : payloads.join(" ");
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
const mediaVideo = sdpObject.media.find((m) => m.type === "video");
|
|
1902
|
+
if (Array.isArray(mediaVideo === null || mediaVideo === void 0 ? void 0 : mediaVideo.rtp)) {
|
|
1903
|
+
const rtp = mediaVideo.rtp;
|
|
1904
|
+
for (let i = 0; i < rtp.length; i++) {
|
|
1905
|
+
if (rtp[i].codec === "VP9") {
|
|
1906
|
+
const payloads = (_b = mediaVideo.payloads) === null || _b === void 0 ? void 0 : _b.split(" ");
|
|
1907
|
+
const pt = payloads === null || payloads === void 0 ? void 0 : payloads.indexOf("" + rtp[i].payload);
|
|
1908
|
+
if (pt && pt !== -1 && pt >= 0) {
|
|
1909
|
+
payloads === null || payloads === void 0 ? void 0 : payloads.unshift(payloads.splice(pt, 1)[0]);
|
|
1910
|
+
mediaVideo.payloads = payloads === null || payloads === void 0 ? void 0 : payloads.join(" ");
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
const newSdp = sdpTransform.write(sdpObject);
|
|
1917
|
+
return newSdp;
|
|
1918
|
+
}
|
|
1919
|
+
catch (error) {
|
|
1920
|
+
logger$8.error("setCodecPreferenceSDP error:", error);
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
function cleanSdp(sdp) {
|
|
1924
|
+
try {
|
|
1925
|
+
const sdpObject = sdpTransform.parse(sdp);
|
|
1926
|
+
sdpObject.media.forEach((mediaObject) => {
|
|
1927
|
+
const usedPayloads = {};
|
|
1928
|
+
if (mediaObject.payloads)
|
|
1929
|
+
mediaObject.payloads = ("" + mediaObject.payloads)
|
|
1930
|
+
.split(" ")
|
|
1931
|
+
.filter((p) => !usedPayloads[p] && (usedPayloads[p] = true))
|
|
1932
|
+
.join(" ");
|
|
1933
|
+
const usedRtps = {};
|
|
1934
|
+
mediaObject.rtp = mediaObject.rtp.filter((p) => !p.payload || (usedPayloads[p.payload] && !usedRtps[p.payload] && (usedRtps[p.payload] = true)));
|
|
1935
|
+
const usedFmtps = {};
|
|
1936
|
+
if (mediaObject.fmtp)
|
|
1937
|
+
mediaObject.fmtp = mediaObject.fmtp.filter((p) => !p.payload ||
|
|
1938
|
+
(usedPayloads[p.payload] && !usedFmtps[p.payload] && (usedFmtps[p.payload] = true)));
|
|
1939
|
+
const usedRtcpFb = {};
|
|
1940
|
+
if (mediaObject.rtcpFb)
|
|
1941
|
+
mediaObject.rtcpFb = mediaObject.rtcpFb.filter((p) => !p.payload ||
|
|
1942
|
+
(usedPayloads[p.payload] &&
|
|
1943
|
+
!usedRtcpFb[p.payload + p.type + p.subtype] &&
|
|
1944
|
+
(usedRtcpFb[p.payload + p.type + p.subtype] = true)));
|
|
1945
|
+
});
|
|
1946
|
+
return sdpTransform.write(sdpObject);
|
|
1947
|
+
}
|
|
1948
|
+
catch (_) { }
|
|
1949
|
+
return sdp;
|
|
1950
|
+
}
|
|
1951
|
+
function maybeRejectNoH264(sdp) {
|
|
1952
|
+
if (browserName$2 !== "safari") {
|
|
1953
|
+
return sdp;
|
|
1954
|
+
}
|
|
1955
|
+
const sections = SDPUtils.splitSections(sdp);
|
|
1956
|
+
for (let i = 1; i < sections.length; i++) {
|
|
1957
|
+
if (SDPUtils.getKind(sections[i]) !== "video") {
|
|
1958
|
+
continue;
|
|
1959
|
+
}
|
|
1960
|
+
const codecs = SDPUtils.matchPrefix(sections[i], "a=rtpmap:")
|
|
1961
|
+
.map((line) => {
|
|
1962
|
+
return SDPUtils.parseRtpMap(line);
|
|
1963
|
+
})
|
|
1964
|
+
.map((codec) => {
|
|
1965
|
+
return codec.name.toUpperCase();
|
|
1966
|
+
});
|
|
1967
|
+
if (codecs.indexOf("H264") === -1 &&
|
|
1968
|
+
sections[i][8] === "9") {
|
|
1969
|
+
sections[i] = sections[i].replace("m=video 9 ", "m=video 0 ");
|
|
1666
1970
|
}
|
|
1667
1971
|
}
|
|
1972
|
+
return sections.join("");
|
|
1973
|
+
}
|
|
1974
|
+
function deprioritizeH264(sdp) {
|
|
1975
|
+
return SDPUtils.splitSections(sdp)
|
|
1976
|
+
.map((section) => {
|
|
1977
|
+
if (SDPUtils.getKind(section) !== "video")
|
|
1978
|
+
return section;
|
|
1979
|
+
const h264payloadTypes = SDPUtils.matchPrefix(section, "a=rtpmap:")
|
|
1980
|
+
.map((line) => SDPUtils.parseRtpMap(line))
|
|
1981
|
+
.filter((codec) => /h264/i.test(codec.name))
|
|
1982
|
+
.map((codec) => "" + codec.payloadType);
|
|
1983
|
+
if (!h264payloadTypes.length)
|
|
1984
|
+
return section;
|
|
1985
|
+
const mline = SDPUtils.matchPrefix(section, "m=video")[0];
|
|
1986
|
+
const mlinePayloadsSectionExec = /(\s\d+)+$/i.exec(mline);
|
|
1987
|
+
const mlinePayloadsSection = mlinePayloadsSectionExec ? mlinePayloadsSectionExec[0] : "";
|
|
1988
|
+
const mlinePayloadsNonH264 = mlinePayloadsSection
|
|
1989
|
+
.split(" ")
|
|
1990
|
+
.filter((payloadType) => payloadType && !h264payloadTypes.includes(payloadType));
|
|
1991
|
+
const reorderedPayloads = [...mlinePayloadsNonH264, ...h264payloadTypes].join(" ");
|
|
1992
|
+
const newmline = mline.replace(mlinePayloadsSection, " " + reorderedPayloads);
|
|
1993
|
+
return section.replace(mline, newmline);
|
|
1994
|
+
})
|
|
1995
|
+
.join("");
|
|
1996
|
+
}
|
|
1997
|
+
function replaceSSRCs(currentDescription, newDescription) {
|
|
1998
|
+
let ssrcs = currentDescription.match(/a=ssrc-group:FID (\d+) (\d+)\r\n/);
|
|
1999
|
+
let newssrcs = newDescription.match(/a=ssrc-group:FID (\d+) (\d+)\r\n/);
|
|
2000
|
+
if (!ssrcs) {
|
|
2001
|
+
ssrcs = currentDescription.match(/a=ssrc:(\d+) cname:(.*)\r\n/g)[1].match(/a=ssrc:(\d+)/);
|
|
2002
|
+
newssrcs = newDescription.match(/a=ssrc:(\d+) cname:(.*)\r\n/g)[1].match(/a=ssrc:(\d+)/);
|
|
2003
|
+
}
|
|
2004
|
+
for (let i = 1; i < ssrcs.length; i++) {
|
|
2005
|
+
newDescription = newDescription.replace(new RegExp(newssrcs[i], "g"), ssrcs[i]);
|
|
2006
|
+
}
|
|
2007
|
+
return newDescription;
|
|
1668
2008
|
}
|
|
1669
|
-
function
|
|
1670
|
-
if (
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
generatedMessage = true;
|
|
1674
|
-
message = "No value argument passed to `assert.ok()`";
|
|
1675
|
-
}
|
|
1676
|
-
else if (message instanceof Error) {
|
|
1677
|
-
throw message;
|
|
1678
|
-
}
|
|
1679
|
-
const err = new AssertionError({
|
|
1680
|
-
actual: value,
|
|
1681
|
-
expected: true,
|
|
1682
|
-
message,
|
|
1683
|
-
operator: "==",
|
|
1684
|
-
stackStartFn: fn,
|
|
1685
|
-
});
|
|
1686
|
-
err.generatedMessage = generatedMessage;
|
|
1687
|
-
throw err;
|
|
2009
|
+
function filterMidExtension(sdp) {
|
|
2010
|
+
if (browserName$2 !== "safari" &&
|
|
2011
|
+
(browserName$2 !== "firefox" || (browserVersion$1 && browserVersion$1 >= 63) || browserVersion$1 === 60)) {
|
|
2012
|
+
return sdp;
|
|
1688
2013
|
}
|
|
2014
|
+
return (SDPUtils.splitLines(sdp.trim())
|
|
2015
|
+
.filter((line) => {
|
|
2016
|
+
if (!line.startsWith("a=extmap:")) {
|
|
2017
|
+
return true;
|
|
2018
|
+
}
|
|
2019
|
+
const extmap = SDPUtils.parseExtmap(line);
|
|
2020
|
+
return extmap.uri !== "urn:ietf:params:rtp-hdrext:sdes:mid";
|
|
2021
|
+
})
|
|
2022
|
+
.join("\r\n") + "\r\n");
|
|
1689
2023
|
}
|
|
1690
|
-
function
|
|
1691
|
-
if (
|
|
1692
|
-
|
|
1693
|
-
|
|
2024
|
+
function filterMsidSemantic(sdp) {
|
|
2025
|
+
if (browserName$2 !== "firefox") {
|
|
2026
|
+
return sdp;
|
|
2027
|
+
}
|
|
2028
|
+
return (SDPUtils.splitLines(sdp.trim())
|
|
2029
|
+
.map((line) => (line.startsWith("a=msid-semantic:") ? "a=msid-semantic: WMS *" : line))
|
|
2030
|
+
.join("\r\n") + "\r\n");
|
|
1694
2031
|
}
|
|
1695
|
-
function
|
|
1696
|
-
|
|
2032
|
+
function changeMediaDirection(sdp, active) {
|
|
2033
|
+
const sections = SDPUtils.splitSections(sdp);
|
|
2034
|
+
return (sections.shift() +
|
|
2035
|
+
sections
|
|
2036
|
+
.map((section) => {
|
|
2037
|
+
const currentDirection = SDPUtils.getDirection(section, SDPUtils.getKind(section));
|
|
2038
|
+
return section.replace("a=" + currentDirection, "a=" + (active ? "recvonly" : "inactive"));
|
|
2039
|
+
})
|
|
2040
|
+
.join(""));
|
|
1697
2041
|
}
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
2042
|
+
function addExtMap(sdp, extmapUri, modifyAudio = false, modifyVideo = false) {
|
|
2043
|
+
var _a, _b;
|
|
2044
|
+
try {
|
|
2045
|
+
const sdpObj = sdpTransform.parse(sdp);
|
|
2046
|
+
if (((_a = sdpObj === null || sdpObj === void 0 ? void 0 : sdpObj.ext) === null || _a === void 0 ? void 0 : _a.length) && sdpObj.ext.length > 0) {
|
|
2047
|
+
return sdp;
|
|
2048
|
+
}
|
|
2049
|
+
if ((sdpObj === null || sdpObj === void 0 ? void 0 : sdpObj.media.length) < 1)
|
|
2050
|
+
return sdp;
|
|
2051
|
+
const allHeaderExtensions = sdpObj === null || sdpObj === void 0 ? void 0 : sdpObj.media.flatMap((section) => section.ext || []);
|
|
2052
|
+
const extmapId = ((_b = allHeaderExtensions.find((ext) => ext.uri === extmapUri)) === null || _b === void 0 ? void 0 : _b.value) ||
|
|
2053
|
+
[...new Set([0, 15, ...allHeaderExtensions.map((ext) => ext.value)])]
|
|
2054
|
+
.sort((a, b) => a - b)
|
|
2055
|
+
.find((n, i, arr) => n + 1 !== arr[i + 1]) + 1;
|
|
2056
|
+
sdpObj.media.forEach((mediaSection) => {
|
|
2057
|
+
var _a;
|
|
2058
|
+
if ((modifyAudio && mediaSection.type === "audio") || (modifyVideo && mediaSection.type === "video")) {
|
|
2059
|
+
if (!((_a = mediaSection.ext) === null || _a === void 0 ? void 0 : _a.find((e) => e.uri === extmapUri))) {
|
|
2060
|
+
if (Array.isArray(mediaSection.ext)) {
|
|
2061
|
+
mediaSection["ext"].push({ value: extmapId, uri: extmapUri });
|
|
2062
|
+
}
|
|
2063
|
+
else {
|
|
2064
|
+
mediaSection["ext"] = [{ value: extmapId, uri: extmapUri }];
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
1706
2068
|
});
|
|
1707
|
-
|
|
1708
|
-
ok,
|
|
1709
|
-
};
|
|
1710
|
-
assert.notEqual = function notEqual(actual, expected, message) {
|
|
1711
|
-
if (arguments.length < 2) {
|
|
1712
|
-
throw new Error("'actual' and 'expected' arguments are required");
|
|
2069
|
+
return sdpTransform.write(sdpObj);
|
|
1713
2070
|
}
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
actual,
|
|
1717
|
-
expected,
|
|
1718
|
-
message,
|
|
1719
|
-
operator: "!=",
|
|
1720
|
-
stackStartFn: notEqual,
|
|
1721
|
-
});
|
|
2071
|
+
catch (error) {
|
|
2072
|
+
console.error("Error during addAbsCaptureTimeExtMap: ", error);
|
|
1722
2073
|
}
|
|
1723
|
-
|
|
1724
|
-
|
|
2074
|
+
return sdp;
|
|
2075
|
+
}
|
|
2076
|
+
function addAbsCaptureTimeExtMap(sdp) {
|
|
2077
|
+
const absCaptureTimeUri = "http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time";
|
|
2078
|
+
return addExtMap(sdp, absCaptureTimeUri, true, true);
|
|
2079
|
+
}
|
|
1725
2080
|
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
if (count === 0) {
|
|
1731
|
-
return "";
|
|
2081
|
+
function setVideoBandwidthUsingSetParameters(pc, bandwidth, logger = console) {
|
|
2082
|
+
const sender = pc.getSenders().find((s) => s.track && s.track.kind === "video");
|
|
2083
|
+
if (!sender) {
|
|
2084
|
+
return Promise.resolve();
|
|
1732
2085
|
}
|
|
1733
|
-
const
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
result += result;
|
|
2086
|
+
const parameters = sender.getParameters();
|
|
2087
|
+
if (parameters.encodings && parameters.encodings.length === 0) {
|
|
2088
|
+
return Promise.resolve();
|
|
1737
2089
|
}
|
|
1738
|
-
|
|
1739
|
-
};
|
|
1740
|
-
|
|
1741
|
-
const getMediasoupDeviceAsync = (features) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1742
|
-
if (features.isNodeSdk) {
|
|
1743
|
-
return new Device({ handlerName: "Safari12" });
|
|
2090
|
+
if (!parameters.encodings) {
|
|
2091
|
+
parameters.encodings = [{}];
|
|
1744
2092
|
}
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
if (/iphone|ipad/i.test(navigator.userAgent)) {
|
|
1748
|
-
handlerName = "Safari12";
|
|
2093
|
+
if (bandwidth === 0) {
|
|
2094
|
+
delete parameters.encodings[0].maxBitrate;
|
|
1749
2095
|
}
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
const AUDIO_SETTINGS = {
|
|
1754
|
-
codecOptions: {
|
|
1755
|
-
opusDtx: true,
|
|
1756
|
-
opusFec: true,
|
|
1757
|
-
},
|
|
1758
|
-
encodings: [{ dtx: true }],
|
|
1759
|
-
};
|
|
1760
|
-
const VIDEO_SETTINGS_HD = {
|
|
1761
|
-
codecOptions: {
|
|
1762
|
-
videoGoogleStartBitrate: 500,
|
|
1763
|
-
},
|
|
1764
|
-
encodings: [
|
|
1765
|
-
{ scaleResolutionDownBy: 4, maxBitrate: 150000 },
|
|
1766
|
-
{ scaleResolutionDownBy: 2, maxBitrate: 500000 },
|
|
1767
|
-
{ scaleResolutionDownBy: 1, maxBitrate: 1000000 },
|
|
1768
|
-
],
|
|
1769
|
-
};
|
|
1770
|
-
const VIDEO_SETTINGS_SD = {
|
|
1771
|
-
codecOptions: {
|
|
1772
|
-
videoGoogleStartBitrate: 500,
|
|
1773
|
-
},
|
|
1774
|
-
encodings: [
|
|
1775
|
-
{ scaleResolutionDownBy: 2, maxBitrate: 150000 },
|
|
1776
|
-
{ scaleResolutionDownBy: 1, maxBitrate: 500000 },
|
|
1777
|
-
],
|
|
1778
|
-
};
|
|
1779
|
-
const VIDEO_SETTINGS_VP9 = {
|
|
1780
|
-
codecOptions: {
|
|
1781
|
-
videoGoogleStartBitrate: 500,
|
|
1782
|
-
},
|
|
1783
|
-
encodings: [{ scalabilityMode: "L3T2", maxBitrate: 1000000 }],
|
|
1784
|
-
};
|
|
1785
|
-
const VIDEO_SETTINGS_VP9_LOW_BANDWIDTH = {
|
|
1786
|
-
codecOptions: {
|
|
1787
|
-
videoGoogleStartBitrate: 500,
|
|
1788
|
-
},
|
|
1789
|
-
encodings: [{ scalabilityMode: "L2T2", maxBitrate: 500000 }],
|
|
1790
|
-
};
|
|
1791
|
-
const SCREEN_SHARE_SETTINGS = {
|
|
1792
|
-
encodings: [{}],
|
|
1793
|
-
};
|
|
1794
|
-
const SCREEN_SHARE_SIMULCAST_SETTINGS = {
|
|
1795
|
-
encodings: [
|
|
1796
|
-
{ scaleResolutionDownBy: 2, dtx: true, maxBitrate: 500000 },
|
|
1797
|
-
{ scaleResolutionDownBy: 1, dtx: true, maxBitrate: 1500000 },
|
|
1798
|
-
],
|
|
1799
|
-
};
|
|
1800
|
-
const ADDITIONAL_SCREEN_SHARE_SETTINGS = {
|
|
1801
|
-
encodings: [
|
|
1802
|
-
{ scaleResolutionDownBy: 4, dtx: true, maxBitrate: 150000 },
|
|
1803
|
-
{ scaleResolutionDownBy: 2, dtx: true, maxBitrate: 500000 },
|
|
1804
|
-
{ scaleResolutionDownBy: 1, dtx: true, maxBitrate: 1500000 },
|
|
1805
|
-
],
|
|
1806
|
-
};
|
|
1807
|
-
const getMediaSettings = (kind, isScreenShare, features, isSomeoneAlreadyPresenting = false) => {
|
|
1808
|
-
const { lowDataModeEnabled, simulcastScreenshareOn, vp9On } = features;
|
|
1809
|
-
if (kind === "audio") {
|
|
1810
|
-
return AUDIO_SETTINGS;
|
|
2096
|
+
else {
|
|
2097
|
+
parameters.encodings[0].maxBitrate = bandwidth * 1000;
|
|
1811
2098
|
}
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
2099
|
+
return sender.setParameters(parameters).catch((err) => {
|
|
2100
|
+
logger.error("setParameters err: ", err);
|
|
2101
|
+
});
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2104
|
+
var _a$4;
|
|
2105
|
+
const adapter$4 = (_a$4 = adapterRaw.default) !== null && _a$4 !== void 0 ? _a$4 : adapterRaw;
|
|
2106
|
+
const logger$7 = new Logger();
|
|
2107
|
+
class Session {
|
|
2108
|
+
constructor({ peerConnectionId, bandwidth, deprioritizeH264Encoding, }) {
|
|
2109
|
+
this.peerConnectionId = peerConnectionId;
|
|
2110
|
+
this.relayCandidateSeen = false;
|
|
2111
|
+
this.serverReflexiveCandidateSeen = false;
|
|
2112
|
+
this.publicHostCandidateSeen = false;
|
|
2113
|
+
this.ipv6HostCandidateSeen = false;
|
|
2114
|
+
this.ipv6HostCandidateTeredoSeen = false;
|
|
2115
|
+
this.ipv6HostCandidate6to4Seen = false;
|
|
2116
|
+
this.mdnsHostCandidateSeen = false;
|
|
2117
|
+
this.pc = null;
|
|
2118
|
+
this.wasEverConnected = false;
|
|
2119
|
+
this.connectionStatus = null;
|
|
2120
|
+
this.stats = {
|
|
2121
|
+
totalSent: 0,
|
|
2122
|
+
totalRecv: 0,
|
|
2123
|
+
};
|
|
2124
|
+
this.bandwidth = bandwidth || 0;
|
|
2125
|
+
this.pending = [];
|
|
2126
|
+
this.isOperationPending = false;
|
|
2127
|
+
this.streamIds = [];
|
|
2128
|
+
this.streams = [];
|
|
2129
|
+
this.earlyIceCandidates = [];
|
|
2130
|
+
this.afterConnected = new Promise((resolve) => {
|
|
2131
|
+
this.registerConnected = resolve;
|
|
1818
2132
|
});
|
|
2133
|
+
this.offerOptions = { offerToReceiveAudio: true, offerToReceiveVideo: true };
|
|
2134
|
+
this._deprioritizeH264Encoding = deprioritizeH264Encoding;
|
|
1819
2135
|
}
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
2136
|
+
setAndGetPeerConnection({ clientId, constraints, peerConnectionConfig, shouldAddLocalVideo, }) {
|
|
2137
|
+
this.peerConnectionConfig = peerConnectionConfig;
|
|
2138
|
+
this.shouldAddLocalVideo = shouldAddLocalVideo;
|
|
2139
|
+
this.clientId = clientId;
|
|
2140
|
+
this.pc = new RTCPeerConnection(peerConnectionConfig);
|
|
2141
|
+
this.signalingState = this.pc.signalingState;
|
|
2142
|
+
this.pc.addEventListener("signalingstatechange", () => {
|
|
2143
|
+
if (this.signalingState === this.pc.signalingState) {
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
2146
|
+
this.signalingState = this.pc.signalingState;
|
|
2147
|
+
if (this.pc.signalingState === "stable") {
|
|
2148
|
+
this.isOperationPending = false;
|
|
2149
|
+
const action = this.pending.shift();
|
|
2150
|
+
if (action) {
|
|
2151
|
+
action.apply();
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
1824
2154
|
});
|
|
2155
|
+
return this.pc;
|
|
1825
2156
|
}
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
if (
|
|
1830
|
-
|
|
2157
|
+
addStream(stream) {
|
|
2158
|
+
this.streamIds.push(stream.id);
|
|
2159
|
+
this.streams.push(stream);
|
|
2160
|
+
if (RTCPeerConnection.prototype.addTrack) {
|
|
2161
|
+
stream.getAudioTracks().forEach((track) => {
|
|
2162
|
+
this.pc.addTrack(track, stream);
|
|
2163
|
+
});
|
|
2164
|
+
stream.getVideoTracks().forEach((track) => {
|
|
2165
|
+
this.pc.addTrack(track, stream);
|
|
2166
|
+
});
|
|
2167
|
+
}
|
|
2168
|
+
else {
|
|
2169
|
+
this.pc.addStream(stream);
|
|
1831
2170
|
}
|
|
1832
|
-
return VIDEO_SETTINGS_SD;
|
|
1833
|
-
}
|
|
1834
|
-
if (isVp9Available) {
|
|
1835
|
-
return VIDEO_SETTINGS_VP9;
|
|
1836
|
-
}
|
|
1837
|
-
return VIDEO_SETTINGS_HD;
|
|
1838
|
-
};
|
|
1839
|
-
const getScreenShareMediaSettings = ({ isSomeoneAlreadyPresenting, simulcastScreenshareOn, }) => {
|
|
1840
|
-
if (isSomeoneAlreadyPresenting) {
|
|
1841
|
-
return ADDITIONAL_SCREEN_SHARE_SETTINGS;
|
|
1842
|
-
}
|
|
1843
|
-
if (simulcastScreenshareOn)
|
|
1844
|
-
return SCREEN_SHARE_SIMULCAST_SETTINGS;
|
|
1845
|
-
return SCREEN_SHARE_SETTINGS;
|
|
1846
|
-
};
|
|
1847
|
-
var PrioritizableCodec;
|
|
1848
|
-
(function (PrioritizableCodec) {
|
|
1849
|
-
PrioritizableCodec["H264"] = "video/h264";
|
|
1850
|
-
PrioritizableCodec["VP9"] = "video/vp9";
|
|
1851
|
-
})(PrioritizableCodec || (PrioritizableCodec = {}));
|
|
1852
|
-
const modifyMediaCapabilities = (routerRtpCapabilities, features) => {
|
|
1853
|
-
const { vp9On, h264On } = features;
|
|
1854
|
-
const isChrome = adapterRaw.browserDetails.browser === "chrome";
|
|
1855
|
-
if (!(routerRtpCapabilities === null || routerRtpCapabilities === void 0 ? void 0 : routerRtpCapabilities.codecs)) {
|
|
1856
|
-
return routerRtpCapabilities;
|
|
1857
|
-
}
|
|
1858
|
-
if (vp9On && isChrome) {
|
|
1859
|
-
const sorted = prioritizeRouterRtpCapabilitiesCodecs(routerRtpCapabilities.codecs, PrioritizableCodec.VP9);
|
|
1860
|
-
return Object.assign(Object.assign({}, routerRtpCapabilities), { codecs: sorted });
|
|
1861
2171
|
}
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
2172
|
+
addTrack(track, stream) {
|
|
2173
|
+
if (!stream) {
|
|
2174
|
+
stream = this.streams[0];
|
|
2175
|
+
}
|
|
2176
|
+
stream === null || stream === void 0 ? void 0 : stream.addTrack(track);
|
|
2177
|
+
this.pc.addTrack(track, stream);
|
|
1865
2178
|
}
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
2179
|
+
removeTrack(track) {
|
|
2180
|
+
const stream = this.streams[0];
|
|
2181
|
+
stream.removeTrack(track);
|
|
2182
|
+
const sender = this.pc.getSenders().find((sender) => sender.track === track);
|
|
2183
|
+
if (sender) {
|
|
2184
|
+
this.pc.removeTrack(sender);
|
|
2185
|
+
}
|
|
1872
2186
|
}
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
2187
|
+
removeStream(stream) {
|
|
2188
|
+
for (let i = 0; i < this.streamIds.length; i++) {
|
|
2189
|
+
if (this.streamIds[i] === stream.id) {
|
|
2190
|
+
this.streamIds.splice(i, 1);
|
|
2191
|
+
this.streams.splice(i, 1);
|
|
2192
|
+
}
|
|
1877
2193
|
}
|
|
1878
|
-
if (
|
|
1879
|
-
(
|
|
1880
|
-
|
|
1881
|
-
|
|
2194
|
+
if (this.pc) {
|
|
2195
|
+
if (this.pc.removeTrack) {
|
|
2196
|
+
stream.getTracks().forEach((track) => {
|
|
2197
|
+
const sender = this.pc.getSenders().find((sender) => sender.track === track);
|
|
2198
|
+
if (sender) {
|
|
2199
|
+
this.pc.removeTrack(sender);
|
|
2200
|
+
}
|
|
2201
|
+
});
|
|
2202
|
+
}
|
|
2203
|
+
else if (this.pc.removeStream) {
|
|
2204
|
+
this.pc.removeStream(stream);
|
|
1882
2205
|
}
|
|
1883
|
-
return -1;
|
|
1884
2206
|
}
|
|
1885
|
-
return 0;
|
|
1886
|
-
});
|
|
1887
|
-
}
|
|
1888
|
-
function getPreferredOrder(availableCodecs, { av1On }) {
|
|
1889
|
-
availableCodecs.unshift("video/vp9");
|
|
1890
|
-
if (av1On) {
|
|
1891
|
-
availableCodecs.unshift("video/av1");
|
|
1892
2207
|
}
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
.
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
return codecs.sort((a, b) => {
|
|
1901
|
-
const indexA = preferredOrder.indexOf(a.mimeType.toLowerCase());
|
|
1902
|
-
const indexB = preferredOrder.indexOf(b.mimeType.toLowerCase());
|
|
1903
|
-
const orderA = indexA >= 0 ? indexA : Number.MAX_VALUE;
|
|
1904
|
-
const orderB = indexB >= 0 ? indexB : Number.MAX_VALUE;
|
|
1905
|
-
return orderA - orderB;
|
|
1906
|
-
});
|
|
1907
|
-
}
|
|
1908
|
-
function getIsCodecDecodingPowerEfficient(codec) {
|
|
1909
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
1910
|
-
const { powerEfficient } = yield navigator.mediaCapabilities.decodingInfo({
|
|
1911
|
-
type: "webrtc",
|
|
1912
|
-
video: {
|
|
1913
|
-
width: 1280,
|
|
1914
|
-
height: 720,
|
|
1915
|
-
bitrate: 2580,
|
|
1916
|
-
framerate: 24,
|
|
1917
|
-
contentType: codec,
|
|
1918
|
-
},
|
|
2208
|
+
_setRemoteDescription(desc) {
|
|
2209
|
+
if (this._deprioritizeH264Encoding)
|
|
2210
|
+
desc.sdp = deprioritizeH264(desc.sdp);
|
|
2211
|
+
this.srdComplete = this.pc.setRemoteDescription(desc);
|
|
2212
|
+
return this.srdComplete.then(() => {
|
|
2213
|
+
this.earlyIceCandidates.forEach((candidate) => this.pc.addIceCandidate(candidate));
|
|
2214
|
+
this.earlyIceCandidates = [];
|
|
1919
2215
|
});
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
2216
|
+
}
|
|
2217
|
+
handleOffer(message) {
|
|
2218
|
+
if (!this.canModifyPeerConnection()) {
|
|
2219
|
+
return new Promise((resolve) => {
|
|
2220
|
+
this.pending.push(() => this.handleOffer(message).then(resolve));
|
|
2221
|
+
});
|
|
2222
|
+
}
|
|
2223
|
+
this.isOperationPending = true;
|
|
2224
|
+
let sdp = message.sdp;
|
|
2225
|
+
sdp = filterMidExtension(sdp);
|
|
2226
|
+
sdp = filterMsidSemantic(sdp);
|
|
2227
|
+
const desc = { type: message.type, sdp };
|
|
2228
|
+
let answerToSignal;
|
|
2229
|
+
return this._setRemoteDescription(desc)
|
|
2230
|
+
.then(() => {
|
|
2231
|
+
return this.pc.createAnswer();
|
|
2232
|
+
})
|
|
2233
|
+
.then((answer) => {
|
|
2234
|
+
answerToSignal = answer;
|
|
2235
|
+
return this.pc.setLocalDescription(answer);
|
|
2236
|
+
})
|
|
2237
|
+
.then(() => {
|
|
2238
|
+
return setVideoBandwidthUsingSetParameters(this.pc, this.bandwidth);
|
|
2239
|
+
})
|
|
2240
|
+
.then(() => {
|
|
2241
|
+
return answerToSignal;
|
|
1931
2242
|
});
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
});
|
|
1941
|
-
}
|
|
1942
|
-
|
|
1943
|
-
const logger$8 = new Logger();
|
|
1944
|
-
class ReconnectManager extends EventEmitter {
|
|
1945
|
-
constructor(socket) {
|
|
1946
|
-
super();
|
|
1947
|
-
this.reconnectThresholdInMs = 0;
|
|
1948
|
-
this._socket = socket;
|
|
1949
|
-
this._clients = {};
|
|
1950
|
-
this._signalDisconnectTime = undefined;
|
|
1951
|
-
this.rtcManager = undefined;
|
|
1952
|
-
this.metrics = {
|
|
1953
|
-
roomJoinedLate: 0,
|
|
1954
|
-
pendingClientCanceled: 0,
|
|
1955
|
-
evaluationFailed: 0,
|
|
1956
|
-
roomJoined: 0,
|
|
1957
|
-
};
|
|
1958
|
-
socket.on("disconnect", () => {
|
|
1959
|
-
this._signalDisconnectTime = Date.now();
|
|
2243
|
+
}
|
|
2244
|
+
handleAnswer(message) {
|
|
2245
|
+
const sdp = filterMsidSemantic(message.sdp);
|
|
2246
|
+
const desc = { type: message.type, sdp };
|
|
2247
|
+
return this._setRemoteDescription(desc).then(() => {
|
|
2248
|
+
return setVideoBandwidthUsingSetParameters(this.pc, this.bandwidth);
|
|
2249
|
+
}, (e) => {
|
|
2250
|
+
logger$7.warn("Could not set remote description from remote answer: ", e);
|
|
1960
2251
|
});
|
|
1961
|
-
socket.on(PROTOCOL_RESPONSES.ROOM_JOINED, (payload) => this._onRoomJoined(payload));
|
|
1962
|
-
socket.on(PROTOCOL_RESPONSES.NEW_CLIENT, (payload) => this._onNewClient(payload));
|
|
1963
|
-
socket.on(PROTOCOL_RESPONSES.CLIENT_LEFT, (payload) => this._onClientLeft(payload));
|
|
1964
|
-
socket.on(PROTOCOL_EVENTS.PENDING_CLIENT_LEFT, (payload) => this._onPendingClientLeft(payload));
|
|
1965
|
-
socket.on(PROTOCOL_RESPONSES.AUDIO_ENABLED, (payload) => this._onAudioEnabled(payload));
|
|
1966
|
-
socket.on(PROTOCOL_RESPONSES.VIDEO_ENABLED, (payload) => this._onVideoEnabled(payload));
|
|
1967
|
-
socket.on(PROTOCOL_RESPONSES.SCREENSHARE_STARTED, (payload) => this._onScreenshareChanged(payload, true));
|
|
1968
|
-
socket.on(PROTOCOL_RESPONSES.SCREENSHARE_STOPPED, (payload) => this._onScreenshareChanged(payload, false));
|
|
1969
2252
|
}
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
}
|
|
1978
|
-
if (!payload.selfId) {
|
|
1979
|
-
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1980
|
-
return;
|
|
1981
|
-
}
|
|
1982
|
-
const myDeviceId = (_a = payload.room.clients.find((c) => payload.selfId === c.id)) === null || _a === void 0 ? void 0 : _a.deviceId;
|
|
1983
|
-
if (!myDeviceId) {
|
|
1984
|
-
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1985
|
-
return;
|
|
1986
|
-
}
|
|
1987
|
-
if (!this._signalDisconnectTime) {
|
|
1988
|
-
this._resetClientState(payload);
|
|
1989
|
-
payload.room.clients = payload.room.clients.filter((c) => !(c.deviceId === myDeviceId && c.isPendingToLeave));
|
|
1990
|
-
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
2253
|
+
addIceCandidate(candidate) {
|
|
2254
|
+
if (!this.srdComplete) {
|
|
2255
|
+
this.earlyIceCandidates.push(candidate);
|
|
2256
|
+
return;
|
|
2257
|
+
}
|
|
2258
|
+
this.srdComplete.then(() => {
|
|
2259
|
+
if (this.pc.signalingState === "closed") {
|
|
1991
2260
|
return;
|
|
1992
2261
|
}
|
|
1993
|
-
|
|
1994
|
-
const timeSinceDisconnect = Date.now() - this._signalDisconnectTime;
|
|
1995
|
-
if (timeSinceDisconnect > RECONNECT_THRESHOLD) {
|
|
1996
|
-
this._resetClientState(payload);
|
|
1997
|
-
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1998
|
-
this.metrics.roomJoinedLate++;
|
|
2262
|
+
if (adapter$4.browserDetails.browser === "safari" && candidate && candidate.candidate === "") {
|
|
1999
2263
|
return;
|
|
2000
2264
|
}
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
payload.room.clients.forEach((client) => {
|
|
2004
|
-
var _a;
|
|
2005
|
-
try {
|
|
2006
|
-
if (client.id === payload.selfId)
|
|
2007
|
-
return;
|
|
2008
|
-
if (!this._clients[client.id]) {
|
|
2009
|
-
this._addClientToState(client);
|
|
2010
|
-
return;
|
|
2011
|
-
}
|
|
2012
|
-
if (!((_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.hasClient(client.id))) {
|
|
2013
|
-
return;
|
|
2014
|
-
}
|
|
2015
|
-
if (this._hasClientStateChanged({
|
|
2016
|
-
clientId: client.id,
|
|
2017
|
-
webcam: client.isVideoEnabled,
|
|
2018
|
-
mic: client.isAudioEnabled,
|
|
2019
|
-
screenShare: client.streams.length > 1,
|
|
2020
|
-
})) {
|
|
2021
|
-
return;
|
|
2022
|
-
}
|
|
2023
|
-
if (this._wasClientSendingMedia(client.id)) {
|
|
2024
|
-
if (!this._isClientMediaActive(allStats, client.id)) {
|
|
2025
|
-
return;
|
|
2026
|
-
}
|
|
2027
|
-
}
|
|
2028
|
-
client.mergeWithOldClientState = true;
|
|
2029
|
-
}
|
|
2030
|
-
catch (error) {
|
|
2031
|
-
logger$8.error("Failed to evaluate if we should merge client state %o", error);
|
|
2032
|
-
this.metrics.evaluationFailed++;
|
|
2033
|
-
}
|
|
2034
|
-
});
|
|
2035
|
-
payload.room.clients.forEach((c) => {
|
|
2036
|
-
if (c.isPendingToLeave) {
|
|
2037
|
-
this._onPendingClientLeft({ clientId: c.id });
|
|
2038
|
-
}
|
|
2265
|
+
this.pc.addIceCandidate(candidate).catch((e) => {
|
|
2266
|
+
logger$7.warn("Failed to add ICE candidate ('%s'): %s", candidate ? candidate.candidate : null, e);
|
|
2039
2267
|
});
|
|
2040
|
-
this.metrics.roomJoined++;
|
|
2041
|
-
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
2042
2268
|
});
|
|
2043
2269
|
}
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
const { clientId } = payload;
|
|
2047
|
-
const client = this._clients[clientId];
|
|
2048
|
-
if (client) {
|
|
2049
|
-
clearTimeout(client.timeout);
|
|
2050
|
-
delete this._clients[clientId];
|
|
2051
|
-
}
|
|
2052
|
-
(_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.disconnect(clientId, null, payload.eventClaim);
|
|
2053
|
-
this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, payload);
|
|
2270
|
+
canModifyPeerConnection() {
|
|
2271
|
+
return this.pc.signalingState === "stable" && !this.isOperationPending;
|
|
2054
2272
|
}
|
|
2055
|
-
|
|
2056
|
-
const
|
|
2057
|
-
|
|
2058
|
-
if (!client) {
|
|
2059
|
-
logger$8.warn(`client ${clientId} not found`);
|
|
2273
|
+
close() {
|
|
2274
|
+
const pc = this.pc;
|
|
2275
|
+
if (!pc) {
|
|
2060
2276
|
return;
|
|
2061
2277
|
}
|
|
2062
|
-
|
|
2063
|
-
|
|
2278
|
+
pc.oniceconnectionstatechange = null;
|
|
2279
|
+
pc.onicecandidate = null;
|
|
2280
|
+
pc.ontrack = null;
|
|
2281
|
+
try {
|
|
2282
|
+
pc.close();
|
|
2064
2283
|
}
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
client.checkActiveMediaAttempts = 0;
|
|
2068
|
-
this._abortIfNotActive(payload);
|
|
2284
|
+
catch (e) {
|
|
2285
|
+
logger$7.warn("failures during close of session", e);
|
|
2069
2286
|
}
|
|
2070
2287
|
}
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
const client = this._clients[clientId];
|
|
2074
|
-
if (client && client.isPendingToLeave) {
|
|
2075
|
-
clearTimeout(client.timeoutHandler);
|
|
2076
|
-
client.isPendingToLeave = false;
|
|
2077
|
-
this.metrics.pendingClientCanceled++;
|
|
2078
|
-
return;
|
|
2079
|
-
}
|
|
2080
|
-
this._getPendingClientsByDeviceId(deviceId).forEach((client) => {
|
|
2081
|
-
clearTimeout(client.timeoutHandler);
|
|
2082
|
-
client.isPendingToLeave = undefined;
|
|
2083
|
-
this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, { clientId: client.clientId });
|
|
2084
|
-
});
|
|
2085
|
-
this._addClientToState(payload.client);
|
|
2086
|
-
this.emit(PROTOCOL_RESPONSES.NEW_CLIENT, payload);
|
|
2288
|
+
hasConnectedPeerConnection() {
|
|
2289
|
+
return this.pc && this.pc.connectionState === "connected";
|
|
2087
2290
|
}
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2291
|
+
replaceTrack(oldTrack, newTrack) {
|
|
2292
|
+
const pc = this.pc;
|
|
2293
|
+
if (!pc)
|
|
2294
|
+
return false;
|
|
2295
|
+
const senders = pc.getSenders();
|
|
2296
|
+
if (!oldTrack) {
|
|
2297
|
+
oldTrack = (senders.find((s) => s.track && s.track.kind === newTrack.kind) || {}).track;
|
|
2298
|
+
}
|
|
2299
|
+
if (window.RTCRtpSender && window.RTCRtpSender.prototype.replaceTrack) {
|
|
2300
|
+
if (oldTrack) {
|
|
2301
|
+
const process = () => {
|
|
2302
|
+
for (let i = 0; i < senders.length; i++) {
|
|
2303
|
+
const sender = senders[i];
|
|
2304
|
+
const track = sender.track;
|
|
2305
|
+
if ((track === null || track === void 0 ? void 0 : track.id) === newTrack.id) {
|
|
2306
|
+
return Promise.resolve(newTrack);
|
|
2307
|
+
}
|
|
2308
|
+
if ((track === null || track === void 0 ? void 0 : track.id) === oldTrack.id) {
|
|
2309
|
+
return senders[i].replaceTrack(newTrack);
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
return null;
|
|
2313
|
+
};
|
|
2314
|
+
let result = process();
|
|
2315
|
+
if (result) {
|
|
2316
|
+
return result;
|
|
2317
|
+
}
|
|
2318
|
+
let resolve = null;
|
|
2319
|
+
let reject = null;
|
|
2320
|
+
result = new Promise((_resolve, _reject) => {
|
|
2321
|
+
resolve = _resolve;
|
|
2322
|
+
reject = _reject;
|
|
2323
|
+
});
|
|
2324
|
+
let retried = 0;
|
|
2325
|
+
let timer = setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
2326
|
+
const trackReplacedPromise = process();
|
|
2327
|
+
if (!trackReplacedPromise) {
|
|
2328
|
+
if (3 < ++retried) {
|
|
2329
|
+
clearInterval(timer);
|
|
2330
|
+
timer = null;
|
|
2331
|
+
reject("No sender track to replace");
|
|
2332
|
+
}
|
|
2333
|
+
return;
|
|
2334
|
+
}
|
|
2335
|
+
clearInterval(timer);
|
|
2336
|
+
timer = null;
|
|
2337
|
+
const trackReplaced = yield trackReplacedPromise;
|
|
2338
|
+
resolve(trackReplaced);
|
|
2339
|
+
}), 1000);
|
|
2340
|
+
return result;
|
|
2102
2341
|
}
|
|
2103
|
-
|
|
2104
|
-
if (
|
|
2105
|
-
|
|
2106
|
-
delete this._clients[clientId];
|
|
2107
|
-
this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, payload);
|
|
2342
|
+
const stream = this.streams.find((s) => s.getTracks().find((t) => t.id === newTrack.id)) || this.streams[0];
|
|
2343
|
+
if (!stream) {
|
|
2344
|
+
return Promise.reject(new Error("replaceTrack: No stream?"));
|
|
2108
2345
|
}
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
const
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2346
|
+
return pc.addTrack(newTrack, stream);
|
|
2347
|
+
}
|
|
2348
|
+
if (!this.canModifyPeerConnection()) {
|
|
2349
|
+
this.pending.push(() => {
|
|
2350
|
+
this.replaceTrack(oldTrack, newTrack);
|
|
2351
|
+
});
|
|
2352
|
+
return;
|
|
2353
|
+
}
|
|
2354
|
+
this.isOperationPending = true;
|
|
2355
|
+
const onn = pc.onnegotiationneeded;
|
|
2356
|
+
pc.onnegotiationneeded = null;
|
|
2357
|
+
this.removeTrack(oldTrack);
|
|
2358
|
+
this.addTrack(newTrack);
|
|
2359
|
+
setTimeout(() => {
|
|
2360
|
+
pc.onnegotiationneeded = onn;
|
|
2361
|
+
}, 0);
|
|
2362
|
+
if (pc.localDescription.type === "offer") {
|
|
2363
|
+
return pc
|
|
2364
|
+
.createOffer()
|
|
2365
|
+
.then((offer) => {
|
|
2366
|
+
offer.sdp = replaceSSRCs(pc.localDescription.sdp, offer.sdp);
|
|
2367
|
+
return pc.setLocalDescription(offer);
|
|
2368
|
+
})
|
|
2369
|
+
.then(() => {
|
|
2370
|
+
return this._setRemoteDescription(pc.remoteDescription);
|
|
2371
|
+
});
|
|
2372
|
+
}
|
|
2373
|
+
else {
|
|
2374
|
+
return this._setRemoteDescription(pc.remoteDescription)
|
|
2375
|
+
.then(() => {
|
|
2376
|
+
return pc.createAnswer();
|
|
2377
|
+
})
|
|
2378
|
+
.then((answer) => {
|
|
2379
|
+
answer.sdp = replaceSSRCs(pc.localDescription.sdp, answer.sdp);
|
|
2380
|
+
return pc.setLocalDescription(answer);
|
|
2127
2381
|
});
|
|
2128
2382
|
}
|
|
2129
|
-
return isActive;
|
|
2130
|
-
}
|
|
2131
|
-
_onAudioEnabled(payload) {
|
|
2132
|
-
const { clientId, isAudioEnabled } = payload;
|
|
2133
|
-
this._clients[clientId] = Object.assign(Object.assign({}, (this._clients[clientId] || {})), { isAudioEnabled });
|
|
2134
|
-
}
|
|
2135
|
-
_onVideoEnabled(payload) {
|
|
2136
|
-
const { clientId, isVideoEnabled } = payload;
|
|
2137
|
-
this._clients[clientId] = Object.assign(Object.assign({}, (this._clients[clientId] || {})), { isVideoEnabled });
|
|
2138
|
-
}
|
|
2139
|
-
_onScreenshareChanged(payload, action) {
|
|
2140
|
-
const { clientId } = payload;
|
|
2141
|
-
this._clients[clientId] = Object.assign(Object.assign({}, (this._clients[clientId] || {})), { isScreenshareEnabled: action });
|
|
2142
2383
|
}
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
throw new Error(`Client ${clientId} not found in ReconnectManager state`);
|
|
2147
|
-
}
|
|
2148
|
-
if (webcam !== state.isVideoEnabled) {
|
|
2149
|
-
return true;
|
|
2150
|
-
}
|
|
2151
|
-
if (mic !== state.isAudioEnabled) {
|
|
2152
|
-
return true;
|
|
2384
|
+
changeBandwidth(bandwidth) {
|
|
2385
|
+
if (bandwidth === this.bandwidth) {
|
|
2386
|
+
return;
|
|
2153
2387
|
}
|
|
2154
|
-
if (
|
|
2155
|
-
|
|
2388
|
+
if (!this.canModifyPeerConnection()) {
|
|
2389
|
+
this.pending.push(() => this.changeBandwidth(bandwidth));
|
|
2390
|
+
return;
|
|
2156
2391
|
}
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
this._clients[newClient.id] = Object.assign(Object.assign({}, (this._clients[newClient.id] || {})), { isAudioEnabled: newClient.isAudioEnabled, isVideoEnabled: newClient.isVideoEnabled, isScreenshareEnabled: newClient.streams.length > 1, deviceId: newClient.deviceId, isPendingToLeave: newClient.isPendingToLeave, clientId: newClient.id });
|
|
2161
|
-
}
|
|
2162
|
-
_wasClientSendingMedia(clientId) {
|
|
2163
|
-
const client = this._clients[clientId];
|
|
2164
|
-
if (!client) {
|
|
2165
|
-
throw new Error(`Client ${clientId} not found in ReconnectManager state`);
|
|
2392
|
+
this.bandwidth = bandwidth;
|
|
2393
|
+
if (!this.pc.localDescription || this.pc.localDescription.type === "") {
|
|
2394
|
+
return;
|
|
2166
2395
|
}
|
|
2167
|
-
|
|
2168
|
-
}
|
|
2169
|
-
_getPendingClientsByDeviceId(deviceId) {
|
|
2170
|
-
return Object.values(this._clients).filter((clientState) => {
|
|
2171
|
-
return clientState.deviceId === deviceId && clientState.isPendingToLeave;
|
|
2172
|
-
});
|
|
2396
|
+
setVideoBandwidthUsingSetParameters(this.pc, this.bandwidth);
|
|
2173
2397
|
}
|
|
2174
|
-
|
|
2175
|
-
this.
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2398
|
+
setAudioOnly(enable, excludedTrackIds = []) {
|
|
2399
|
+
this.pc
|
|
2400
|
+
.getTransceivers()
|
|
2401
|
+
.filter((videoTransceiver) => {
|
|
2402
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2403
|
+
return (videoTransceiver === null || videoTransceiver === void 0 ? void 0 : videoTransceiver.direction) !== "recvonly" &&
|
|
2404
|
+
((_b = (_a = videoTransceiver === null || videoTransceiver === void 0 ? void 0 : videoTransceiver.receiver) === null || _a === void 0 ? void 0 : _a.track) === null || _b === void 0 ? void 0 : _b.kind) === "video" &&
|
|
2405
|
+
!excludedTrackIds.includes((_d = (_c = videoTransceiver === null || videoTransceiver === void 0 ? void 0 : videoTransceiver.receiver) === null || _c === void 0 ? void 0 : _c.track) === null || _d === void 0 ? void 0 : _d.id) &&
|
|
2406
|
+
!excludedTrackIds.includes((_f = (_e = videoTransceiver === null || videoTransceiver === void 0 ? void 0 : videoTransceiver.sender) === null || _e === void 0 ? void 0 : _e.track) === null || _f === void 0 ? void 0 : _f.id);
|
|
2407
|
+
})
|
|
2408
|
+
.forEach((videoTransceiver) => {
|
|
2409
|
+
videoTransceiver.direction = enable ? "sendonly" : "sendrecv";
|
|
2183
2410
|
});
|
|
2184
2411
|
}
|
|
2185
2412
|
}
|
|
2186
2413
|
|
|
2414
|
+
const MEDIA_JITTER_BUFFER_TARGET = 400;
|
|
2415
|
+
|
|
2187
2416
|
var _a$3;
|
|
2188
2417
|
const adapter$3 = (_a$3 = adapterRaw.default) !== null && _a$3 !== void 0 ? _a$3 : adapterRaw;
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
if (
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
this._socket.io.opts.transports = ["websocket", "polling"];
|
|
2207
|
-
}
|
|
2208
|
-
});
|
|
2209
|
-
if (glitchFree)
|
|
2210
|
-
this._reconnectManager = new ReconnectManager(this._socket);
|
|
2211
|
-
this._socket.on("connect", () => {
|
|
2212
|
-
const transport = this.getTransport();
|
|
2213
|
-
if (transport === "websocket") {
|
|
2214
|
-
this._wasConnectedUsingWebsocket = true;
|
|
2215
|
-
if (!this.noopKeepaliveInterval)
|
|
2216
|
-
this.noopKeepaliveInterval = setInterval(() => {
|
|
2217
|
-
try {
|
|
2218
|
-
if (this._socket.connected) {
|
|
2219
|
-
this._socket.io.engine.sendPacket("noop");
|
|
2220
|
-
}
|
|
2221
|
-
}
|
|
2222
|
-
catch (ex) { }
|
|
2223
|
-
}, NOOP_KEEPALIVE_INTERVAL);
|
|
2418
|
+
function detectMicrophoneNotWorking(pc) {
|
|
2419
|
+
if (adapter$3.browserDetails.browser !== "chrome" ||
|
|
2420
|
+
adapter$3.browserDetails.browser < 58 ||
|
|
2421
|
+
pc.signalingState === "closed") {
|
|
2422
|
+
return Promise.resolve(false);
|
|
2423
|
+
}
|
|
2424
|
+
const sendingAudio = pc.getSenders().some((sender) => sender.track && sender.track.kind === "audio");
|
|
2425
|
+
const receivingAudio = pc.getReceivers().some((receiver) => receiver.track && receiver.track.kind === "audio");
|
|
2426
|
+
return pc.getStats(null).then((result) => {
|
|
2427
|
+
let microphoneFailed = false;
|
|
2428
|
+
result.forEach((report) => {
|
|
2429
|
+
if (report.type === "outbound-rtp" &&
|
|
2430
|
+
(report.kind === "audio" || report.mediaType === "audio") &&
|
|
2431
|
+
sendingAudio) {
|
|
2432
|
+
if (report.bytesSent === 0) {
|
|
2433
|
+
microphoneFailed = "outbound";
|
|
2434
|
+
}
|
|
2224
2435
|
}
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2436
|
+
else if (report.type === "inbound-rtp" &&
|
|
2437
|
+
(report.kind === "audio" || report.mediaType === "audio") &&
|
|
2438
|
+
receivingAudio) {
|
|
2439
|
+
if (report.bytesReceived === 0) {
|
|
2440
|
+
microphoneFailed = "inbound";
|
|
2441
|
+
}
|
|
2231
2442
|
}
|
|
2232
2443
|
});
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
if (this._reconnectManager) {
|
|
2236
|
-
this._reconnectManager.rtcManager = rtcManager;
|
|
2237
|
-
}
|
|
2238
|
-
}
|
|
2239
|
-
connect() {
|
|
2240
|
-
if (this.isConnected() || this.isConnecting()) {
|
|
2241
|
-
return;
|
|
2242
|
-
}
|
|
2243
|
-
this._socket.open();
|
|
2244
|
-
}
|
|
2245
|
-
disconnect() {
|
|
2246
|
-
this._socket.disconnect();
|
|
2247
|
-
}
|
|
2248
|
-
disconnectOnConnect() {
|
|
2249
|
-
this._socket.once("connect", () => {
|
|
2250
|
-
this._socket.disconnect();
|
|
2251
|
-
});
|
|
2252
|
-
}
|
|
2253
|
-
emit(eventName, ...args) {
|
|
2254
|
-
this._socket.emit.apply(this._socket, arguments);
|
|
2255
|
-
}
|
|
2256
|
-
emitIfConnected(eventName, data) {
|
|
2257
|
-
if (!this.isConnected()) {
|
|
2258
|
-
return;
|
|
2259
|
-
}
|
|
2260
|
-
this.emit(eventName, data);
|
|
2261
|
-
}
|
|
2262
|
-
getTransport() {
|
|
2263
|
-
return (this._socket &&
|
|
2264
|
-
this._socket.io &&
|
|
2265
|
-
this._socket.io.engine &&
|
|
2266
|
-
this._socket.io.engine.transport &&
|
|
2267
|
-
this._socket.io.engine.transport.name);
|
|
2268
|
-
}
|
|
2269
|
-
getManager() {
|
|
2270
|
-
return this._socket.io;
|
|
2271
|
-
}
|
|
2272
|
-
isConnecting() {
|
|
2273
|
-
return this._socket && this._socket.connecting;
|
|
2274
|
-
}
|
|
2275
|
-
isConnected() {
|
|
2276
|
-
return this._socket && this._socket.connected;
|
|
2277
|
-
}
|
|
2278
|
-
on(eventName, handler) {
|
|
2279
|
-
const relayableEvents = [
|
|
2280
|
-
PROTOCOL_RESPONSES.ROOM_JOINED,
|
|
2281
|
-
PROTOCOL_RESPONSES.CLIENT_LEFT,
|
|
2282
|
-
PROTOCOL_RESPONSES.NEW_CLIENT,
|
|
2283
|
-
];
|
|
2284
|
-
if (this._reconnectManager && relayableEvents.includes(eventName)) {
|
|
2285
|
-
return this._interceptEvent(eventName, handler);
|
|
2286
|
-
}
|
|
2287
|
-
this._socket.on(eventName, handler);
|
|
2288
|
-
return () => {
|
|
2289
|
-
this._socket.off(eventName, handler);
|
|
2290
|
-
};
|
|
2291
|
-
}
|
|
2292
|
-
onEngineEvent(eventName, handler) {
|
|
2293
|
-
var _a;
|
|
2294
|
-
(_a = this._socket.io) === null || _a === void 0 ? void 0 : _a.on(eventName, handler);
|
|
2295
|
-
return () => {
|
|
2296
|
-
var _a;
|
|
2297
|
-
(_a = this._socket.io) === null || _a === void 0 ? void 0 : _a.off(eventName, handler);
|
|
2298
|
-
};
|
|
2299
|
-
}
|
|
2300
|
-
once(eventName, handler) {
|
|
2301
|
-
this._socket.once(eventName, handler);
|
|
2302
|
-
}
|
|
2303
|
-
off(eventName, handler) {
|
|
2304
|
-
this._socket.off(eventName, handler);
|
|
2305
|
-
}
|
|
2306
|
-
_interceptEvent(eventName, handler) {
|
|
2307
|
-
if (this._reconnectManager) {
|
|
2308
|
-
this._reconnectManager.on(eventName, handler);
|
|
2309
|
-
}
|
|
2310
|
-
return () => {
|
|
2311
|
-
if (this._reconnectManager)
|
|
2312
|
-
this._reconnectManager.removeListener(eventName, handler);
|
|
2313
|
-
};
|
|
2314
|
-
}
|
|
2315
|
-
getGlitchFreeMetrics() {
|
|
2316
|
-
var _a;
|
|
2317
|
-
return (_a = this._reconnectManager) === null || _a === void 0 ? void 0 : _a.metrics;
|
|
2318
|
-
}
|
|
2319
|
-
getReconnectThreshold() {
|
|
2320
|
-
var _a;
|
|
2321
|
-
return (_a = this._reconnectManager) === null || _a === void 0 ? void 0 : _a.reconnectThresholdInMs;
|
|
2322
|
-
}
|
|
2444
|
+
return microphoneFailed;
|
|
2445
|
+
});
|
|
2323
2446
|
}
|
|
2324
2447
|
|
|
2325
|
-
const
|
|
2326
|
-
|
|
2327
|
-
|
|
2448
|
+
const EVENTS = {
|
|
2449
|
+
CLIENT_CONNECTION_STATUS_CHANGED: "client_connection_status_changed",
|
|
2450
|
+
STREAM_ADDED: "stream_added",
|
|
2451
|
+
RTC_MANAGER_CREATED: "rtc_manager_created",
|
|
2452
|
+
RTC_MANAGER_DESTROYED: "rtc_manager_destroyed",
|
|
2453
|
+
LOCAL_STREAM_TRACK_ADDED: "local_stream_track_added",
|
|
2454
|
+
LOCAL_STREAM_TRACK_REMOVED: "local_stream_track_removed",
|
|
2455
|
+
REMOTE_STREAM_TRACK_ADDED: "remote_stream_track_added",
|
|
2456
|
+
REMOTE_STREAM_TRACK_REMOVED: "remote_stream_track_removed",
|
|
2457
|
+
};
|
|
2458
|
+
const TYPES = {
|
|
2459
|
+
CONNECTING: "connecting",
|
|
2460
|
+
CONNECTION_FAILED: "connection_failed",
|
|
2461
|
+
CONNECTION_SUCCESSFUL: "connection_successful",
|
|
2462
|
+
CONNECTION_DISCONNECTED: "connection_disconnected",
|
|
2463
|
+
};
|
|
2464
|
+
|
|
2465
|
+
const CAMERA_STREAM_ID$1 = "0";
|
|
2466
|
+
const STREAM_TYPES = {
|
|
2467
|
+
CAMERA: "camera",
|
|
2468
|
+
SCREEN_SHARE: "screen_share",
|
|
2469
|
+
};
|
|
2470
|
+
class RtcStream {
|
|
2471
|
+
constructor(id, type) {
|
|
2472
|
+
this.id = "" + id;
|
|
2473
|
+
this.type = type;
|
|
2474
|
+
this.isEnabled = true;
|
|
2475
|
+
this.hasSupportForAutoSuperSize = false;
|
|
2476
|
+
this.isAudioEnabled = true;
|
|
2477
|
+
this.isVideoEnabled = true;
|
|
2478
|
+
this.status = TYPES.CONNECTING;
|
|
2479
|
+
this.stream = null;
|
|
2480
|
+
this.streamId = null;
|
|
2328
2481
|
}
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
if (filter) {
|
|
2336
|
-
iceConfig.iceServers = iceConfig.iceServers.filter((entry) => {
|
|
2337
|
-
if (entry.url && entry.url.match(filter))
|
|
2338
|
-
return entry;
|
|
2339
|
-
if (entry.urls) {
|
|
2340
|
-
entry.urls = (entry.urls.some ? entry.urls : [entry.urls]).filter((url) => url.match(filter));
|
|
2341
|
-
if (entry.urls.length > 0)
|
|
2342
|
-
return entry;
|
|
2343
|
-
}
|
|
2344
|
-
});
|
|
2482
|
+
setup(stream) {
|
|
2483
|
+
this.stream = stream;
|
|
2484
|
+
this.streamId = stream.id;
|
|
2485
|
+
this.setVideoEnabled(this.isVideoEnabled && stream.getVideoTracks().length > 0);
|
|
2486
|
+
this.setAudioEnabled(this.isAudioEnabled && stream.getAudioTracks().length > 0);
|
|
2487
|
+
return this;
|
|
2345
2488
|
}
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
iceConfig.iceServers = [
|
|
2350
|
-
{ urls: "stun:stun.l.google.com:19302" },
|
|
2351
|
-
{ urls: "stun:stun2.l.google.com:19302" },
|
|
2352
|
-
...iceConfig.iceServers,
|
|
2353
|
-
];
|
|
2489
|
+
setStatus(status) {
|
|
2490
|
+
this.status = status;
|
|
2491
|
+
return this;
|
|
2354
2492
|
}
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2493
|
+
setVideoEnabled(isEnabled) {
|
|
2494
|
+
this.isVideoEnabled = isEnabled;
|
|
2495
|
+
if (!this.stream) {
|
|
2496
|
+
return;
|
|
2497
|
+
}
|
|
2498
|
+
this.stream.getVideoTracks().forEach((track) => {
|
|
2499
|
+
track.enabled = isEnabled;
|
|
2500
|
+
});
|
|
2361
2501
|
}
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
const entry = Object.assign({}, original);
|
|
2370
|
-
if (entry.url) {
|
|
2371
|
-
entry.url = entry.url.replace(/:[^?]*/, override);
|
|
2372
|
-
}
|
|
2373
|
-
if (entry.urls) {
|
|
2374
|
-
entry.urls = entry.urls.map((url) => url.replace(/:[^?]*/, override));
|
|
2375
|
-
}
|
|
2376
|
-
return entry;
|
|
2502
|
+
setAudioEnabled(isEnabled) {
|
|
2503
|
+
this.isAudioEnabled = isEnabled;
|
|
2504
|
+
if (!this.stream) {
|
|
2505
|
+
return;
|
|
2506
|
+
}
|
|
2507
|
+
this.stream.getAudioTracks().forEach((track) => {
|
|
2508
|
+
track.enabled = isEnabled;
|
|
2377
2509
|
});
|
|
2378
2510
|
}
|
|
2379
|
-
|
|
2380
|
-
return
|
|
2511
|
+
static getCameraId() {
|
|
2512
|
+
return CAMERA_STREAM_ID$1;
|
|
2381
2513
|
}
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
const localstackPattern = /^(?:([^.]+)-)?(ip-[^.]*[.](?:hereby[.]dev|rfc1918[.]disappear[.]at)(?::\d+|))$/;
|
|
2386
|
-
const localhostPattern = /^(?:([^.]+)[.])?(localhost:?\d*)/;
|
|
2387
|
-
const serverPattern = /^(?:([^.]+)[.])?(server:?\d*)/;
|
|
2388
|
-
const ipv4Pattern = /^(?:([^.]+)[.])?((\d+[.]){3}:?\d*)$/;
|
|
2389
|
-
const subdomainPatterns = [
|
|
2390
|
-
{ pattern: serverPattern, separator: "." },
|
|
2391
|
-
{ pattern: localhostPattern, separator: "." },
|
|
2392
|
-
{ pattern: ipv4Pattern, separator: "." },
|
|
2393
|
-
{ pattern: localstackPattern, separator: "-" },
|
|
2394
|
-
{ pattern: defaultSubdomainPattern, separator: "." },
|
|
2395
|
-
];
|
|
2396
|
-
function fromLocation({ host = "whereby.com", protocol = "https:" } = {}) {
|
|
2397
|
-
let subdomain = "";
|
|
2398
|
-
let domain = host;
|
|
2399
|
-
let subdomainSeparator = ".";
|
|
2400
|
-
for (const { separator, pattern } of subdomainPatterns) {
|
|
2401
|
-
const match = pattern.exec(host);
|
|
2402
|
-
if (match) {
|
|
2403
|
-
subdomain = match[1] || "";
|
|
2404
|
-
domain = match[2];
|
|
2405
|
-
subdomainSeparator = separator;
|
|
2406
|
-
break;
|
|
2407
|
-
}
|
|
2514
|
+
static getTypeFromId(id) {
|
|
2515
|
+
const streamId = "" + id;
|
|
2516
|
+
return streamId === CAMERA_STREAM_ID$1 ? STREAM_TYPES.CAMERA : STREAM_TYPES.SCREEN_SHARE;
|
|
2408
2517
|
}
|
|
2409
|
-
const organizationDomain = !subdomain ? domain : `${subdomain}${subdomainSeparator}${domain}`;
|
|
2410
|
-
return {
|
|
2411
|
-
domain,
|
|
2412
|
-
domainWithSeparator: `${subdomainSeparator}${domain}`,
|
|
2413
|
-
organizationDomain,
|
|
2414
|
-
organization: `${protocol}//${organizationDomain}`,
|
|
2415
|
-
service: `${protocol}//${domain}`,
|
|
2416
|
-
subdomain,
|
|
2417
|
-
};
|
|
2418
2518
|
}
|
|
2419
|
-
|
|
2519
|
+
|
|
2520
|
+
var rtcManagerEvents = {
|
|
2521
|
+
CAMERA_NOT_WORKING: "camera_not_working",
|
|
2522
|
+
CONNECTION_BLOCKED_BY_NETWORK: "connection_blocked_by_network",
|
|
2523
|
+
ICE_IPV6_SEEN: "ice_ipv6_seen",
|
|
2524
|
+
ICE_MDNS_SEEN: "ice_mdns_seen",
|
|
2525
|
+
ICE_NO_PUBLIC_IP_GATHERED: "ice_no_public_ip_gathered",
|
|
2526
|
+
ICE_NO_PUBLIC_IP_GATHERED_3SEC: "ice_no_public_ip_gathered_3sec",
|
|
2527
|
+
ICE_RESTART: "ice_restart",
|
|
2528
|
+
MICROPHONE_NOT_WORKING: "microphone_not_working",
|
|
2529
|
+
MICROPHONE_STOPPED_WORKING: "microphone_stopped_working",
|
|
2530
|
+
CAMERA_STOPPED_WORKING: "camera_stopped_working",
|
|
2531
|
+
NEW_PC: "new_pc",
|
|
2532
|
+
SFU_CONNECTION_OPEN: "sfu_connection_open",
|
|
2533
|
+
SFU_CONNECTION_CLOSED: "sfu_connection_closed",
|
|
2534
|
+
SFU_CONNECTION_INFO: "sfu_connection_info",
|
|
2535
|
+
COLOCATION_SPEAKER: "colocation_speaker",
|
|
2536
|
+
DOMINANT_SPEAKER: "dominant_speaker",
|
|
2537
|
+
PC_SLD_FAILURE: "pc_sld_failure",
|
|
2538
|
+
PC_ON_ANSWER_FAILURE: "pc_on_answer_failure",
|
|
2539
|
+
PC_ON_OFFER_FAILURE: "pc_on_offer_failure",
|
|
2540
|
+
};
|
|
2420
2541
|
|
|
2421
2542
|
var _a$2, _b;
|
|
2422
2543
|
const adapter$2 = (_a$2 = adapterRaw.default) !== null && _a$2 !== void 0 ? _a$2 : adapterRaw;
|
|
2423
|
-
const logger$
|
|
2544
|
+
const logger$6 = new Logger();
|
|
2424
2545
|
const ICE_PUBLIC_IP_GATHERING_TIMEOUT = 3 * 1000;
|
|
2425
2546
|
const CAMERA_STREAM_ID = RtcStream.getCameraId();
|
|
2426
2547
|
const browserName$1 = adapter$2.browserDetails.browser;
|
|
@@ -2568,7 +2689,7 @@ class P2pRtcManager {
|
|
|
2568
2689
|
() => this._clearMediaServersRefresh(),
|
|
2569
2690
|
this._serverSocket.on(PROTOCOL_RESPONSES.MEDIASERVER_CONFIG, (data) => {
|
|
2570
2691
|
if (data.error) {
|
|
2571
|
-
logger$
|
|
2692
|
+
logger$6.warn("FETCH_MEDIASERVER_CONFIG failed:", data.error);
|
|
2572
2693
|
return;
|
|
2573
2694
|
}
|
|
2574
2695
|
this._updateAndScheduleMediaServersRefresh(data);
|
|
@@ -2579,7 +2700,7 @@ class P2pRtcManager {
|
|
|
2579
2700
|
this._serverSocket.on(RELAY_MESSAGES.ICE_CANDIDATE, (data) => {
|
|
2580
2701
|
const session = this._getSession(data.clientId);
|
|
2581
2702
|
if (!session) {
|
|
2582
|
-
logger$
|
|
2703
|
+
logger$6.warn("No RTCPeerConnection on ICE_CANDIDATE", data);
|
|
2583
2704
|
return;
|
|
2584
2705
|
}
|
|
2585
2706
|
session.addIceCandidate(data.message);
|
|
@@ -2587,7 +2708,7 @@ class P2pRtcManager {
|
|
|
2587
2708
|
this._serverSocket.on(RELAY_MESSAGES.ICE_END_OF_CANDIDATES, (data) => {
|
|
2588
2709
|
const session = this._getSession(data.clientId);
|
|
2589
2710
|
if (!session) {
|
|
2590
|
-
logger$
|
|
2711
|
+
logger$6.warn("No RTCPeerConnection on ICE_END_OF_CANDIDATES", data);
|
|
2591
2712
|
return;
|
|
2592
2713
|
}
|
|
2593
2714
|
session.addIceCandidate(null);
|
|
@@ -2596,7 +2717,7 @@ class P2pRtcManager {
|
|
|
2596
2717
|
var _a, _b;
|
|
2597
2718
|
const session = this._getSession(data.clientId);
|
|
2598
2719
|
if (!session) {
|
|
2599
|
-
logger$
|
|
2720
|
+
logger$6.warn("No RTCPeerConnection on SDP_OFFER", data);
|
|
2600
2721
|
return;
|
|
2601
2722
|
}
|
|
2602
2723
|
const offer = this._transformIncomingSdp(data.message, session.pc);
|
|
@@ -2615,7 +2736,7 @@ class P2pRtcManager {
|
|
|
2615
2736
|
var _a, _b;
|
|
2616
2737
|
const session = this._getSession(data.clientId);
|
|
2617
2738
|
if (!session) {
|
|
2618
|
-
logger$
|
|
2739
|
+
logger$6.warn("No RTCPeerConnection on SDP_ANSWER", data);
|
|
2619
2740
|
return;
|
|
2620
2741
|
}
|
|
2621
2742
|
const answer = this._transformIncomingSdp(data.message, session.pc);
|
|
@@ -2637,7 +2758,7 @@ class P2pRtcManager {
|
|
|
2637
2758
|
}
|
|
2638
2759
|
const screenshareStream = this.localStreams[screenShareStreamId];
|
|
2639
2760
|
if (!screenshareStream) {
|
|
2640
|
-
logger$
|
|
2761
|
+
logger$6.warn("screenshare stream %s not found", screenShareStreamId);
|
|
2641
2762
|
return;
|
|
2642
2763
|
}
|
|
2643
2764
|
const hasAudioTrack = screenshareStream.getAudioTracks().length > 0;
|
|
@@ -2714,7 +2835,7 @@ class P2pRtcManager {
|
|
|
2714
2835
|
});
|
|
2715
2836
|
}
|
|
2716
2837
|
catch (error) {
|
|
2717
|
-
logger$
|
|
2838
|
+
logger$6.error("Error during setting jitter buffer target:", error);
|
|
2718
2839
|
}
|
|
2719
2840
|
}
|
|
2720
2841
|
_emitServerEvent(eventName, data, callback) {
|
|
@@ -2934,7 +3055,7 @@ class P2pRtcManager {
|
|
|
2934
3055
|
_cleanup(peerConnectionId) {
|
|
2935
3056
|
const session = this._getSession(peerConnectionId);
|
|
2936
3057
|
if (!session) {
|
|
2937
|
-
logger$
|
|
3058
|
+
logger$6.warn("No RTCPeerConnection in RTCManager.disconnect()", peerConnectionId);
|
|
2938
3059
|
return;
|
|
2939
3060
|
}
|
|
2940
3061
|
session.close();
|
|
@@ -2959,17 +3080,17 @@ class P2pRtcManager {
|
|
|
2959
3080
|
const promises = [];
|
|
2960
3081
|
this._forEachPeerConnection((session) => {
|
|
2961
3082
|
if (!session.hasConnectedPeerConnection()) {
|
|
2962
|
-
logger$
|
|
3083
|
+
logger$6.info("Session doesn't have a connected PeerConnection, adding pending action!");
|
|
2963
3084
|
const pendingActions = this._pendingActionsForConnectedPeerConnections;
|
|
2964
3085
|
if (!pendingActions) {
|
|
2965
|
-
logger$
|
|
3086
|
+
logger$6.warn(`No pending action is created to replace track, because the pending actions array is null`);
|
|
2966
3087
|
return;
|
|
2967
3088
|
}
|
|
2968
3089
|
const promise = new Promise((resolve, reject) => {
|
|
2969
3090
|
const action = () => {
|
|
2970
3091
|
const replacedTrackPromise = session.replaceTrack(oldTrack, newTrack);
|
|
2971
3092
|
if (!replacedTrackPromise) {
|
|
2972
|
-
logger$
|
|
3093
|
+
logger$6.error("replaceTrack returned false!");
|
|
2973
3094
|
reject(`ReplaceTrack returned false`);
|
|
2974
3095
|
return;
|
|
2975
3096
|
}
|
|
@@ -2982,7 +3103,7 @@ class P2pRtcManager {
|
|
|
2982
3103
|
}
|
|
2983
3104
|
const replacedTrackResult = session.replaceTrack(oldTrack, newTrack);
|
|
2984
3105
|
if (!replacedTrackResult) {
|
|
2985
|
-
logger$
|
|
3106
|
+
logger$6.error("replaceTrack returned false!");
|
|
2986
3107
|
return;
|
|
2987
3108
|
}
|
|
2988
3109
|
promises.push(replacedTrackResult);
|
|
@@ -3044,7 +3165,7 @@ class P2pRtcManager {
|
|
|
3044
3165
|
let session = this._getSession(clientId);
|
|
3045
3166
|
let initialBandwidth = (session && session.bandwidth) || 0;
|
|
3046
3167
|
if (session) {
|
|
3047
|
-
logger$
|
|
3168
|
+
logger$6.warn("Replacing peer session", clientId);
|
|
3048
3169
|
this._cleanup(clientId);
|
|
3049
3170
|
}
|
|
3050
3171
|
else {
|
|
@@ -3114,13 +3235,13 @@ class P2pRtcManager {
|
|
|
3114
3235
|
})));
|
|
3115
3236
|
}
|
|
3116
3237
|
catch (error) {
|
|
3117
|
-
logger$
|
|
3238
|
+
logger$6.error("Error during setting setCodecPreferences:", error);
|
|
3118
3239
|
}
|
|
3119
3240
|
});
|
|
3120
3241
|
}
|
|
3121
3242
|
_negotiatePeerConnection(clientId, session, constraints) {
|
|
3122
3243
|
if (!session) {
|
|
3123
|
-
logger$
|
|
3244
|
+
logger$6.warn("No RTCPeerConnection in negotiatePeerConnection()", clientId);
|
|
3124
3245
|
return;
|
|
3125
3246
|
}
|
|
3126
3247
|
const pc = session.pc;
|
|
@@ -3144,7 +3265,7 @@ class P2pRtcManager {
|
|
|
3144
3265
|
offer.sdp = cleanSdp(offer.sdp);
|
|
3145
3266
|
pc.setLocalDescription(offer)
|
|
3146
3267
|
.catch((e) => {
|
|
3147
|
-
logger$
|
|
3268
|
+
logger$6.warn("RTCPeerConnection.setLocalDescription() failed with local offer", e);
|
|
3148
3269
|
this._emit(rtcManagerEvents.PC_SLD_FAILURE, e);
|
|
3149
3270
|
throw e;
|
|
3150
3271
|
})
|
|
@@ -3156,7 +3277,7 @@ class P2pRtcManager {
|
|
|
3156
3277
|
});
|
|
3157
3278
|
})
|
|
3158
3279
|
.catch((e) => {
|
|
3159
|
-
logger$
|
|
3280
|
+
logger$6.warn("RTCPeerConnection.createOffer() failed to create local offer", e);
|
|
3160
3281
|
}));
|
|
3161
3282
|
}
|
|
3162
3283
|
_withForcedRenegotiation(session, action) {
|
|
@@ -3271,7 +3392,7 @@ class P2pRtcManager {
|
|
|
3271
3392
|
}
|
|
3272
3393
|
}
|
|
3273
3394
|
catch (error) {
|
|
3274
|
-
logger$
|
|
3395
|
+
logger$6.info("Error during parsing candidates! Error: ", { error });
|
|
3275
3396
|
}
|
|
3276
3397
|
break;
|
|
3277
3398
|
case "srflx":
|
|
@@ -3327,7 +3448,7 @@ class P2pRtcManager {
|
|
|
3327
3448
|
}
|
|
3328
3449
|
let initialBandwidth = (session && session.bandwidth) || 0;
|
|
3329
3450
|
if (session) {
|
|
3330
|
-
logger$
|
|
3451
|
+
logger$6.warn("Replacing peer session", clientId);
|
|
3331
3452
|
this._cleanup(clientId);
|
|
3332
3453
|
}
|
|
3333
3454
|
else {
|
|
@@ -3544,7 +3665,7 @@ const defaultParams = {
|
|
|
3544
3665
|
scoreFormula: "300 * bands[1].avg / Math.max(bands[1].avg + bands[0].avg, 0.01)",
|
|
3545
3666
|
outFormula: "score",
|
|
3546
3667
|
};
|
|
3547
|
-
const logger$
|
|
3668
|
+
const logger$5 = new Logger();
|
|
3548
3669
|
function createMicAnalyser({ micTrack, params, onScoreUpdated, }) {
|
|
3549
3670
|
const audioCtx = new AudioContext();
|
|
3550
3671
|
let analyser = null;
|
|
@@ -3566,7 +3687,7 @@ function createMicAnalyser({ micTrack, params, onScoreUpdated, }) {
|
|
|
3566
3687
|
lastTrackWasOurs = true;
|
|
3567
3688
|
}
|
|
3568
3689
|
catch (ex) {
|
|
3569
|
-
logger$
|
|
3690
|
+
logger$5.warn("unable to fetch new track for colocation speaker analysis, using current", ex);
|
|
3570
3691
|
}
|
|
3571
3692
|
}
|
|
3572
3693
|
lastTrack = track;
|
|
@@ -3653,7 +3774,7 @@ function createMicAnalyser({ micTrack, params, onScoreUpdated, }) {
|
|
|
3653
3774
|
};
|
|
3654
3775
|
}
|
|
3655
3776
|
|
|
3656
|
-
const logger$
|
|
3777
|
+
const logger$4 = new Logger();
|
|
3657
3778
|
const MEDIA_QUALITY = Object.freeze({
|
|
3658
3779
|
ok: "ok",
|
|
3659
3780
|
warning: "warning",
|
|
@@ -3723,7 +3844,7 @@ class VegaMediaQualityMonitor extends EventEmitter {
|
|
|
3723
3844
|
}
|
|
3724
3845
|
addProducer(clientId, producerId) {
|
|
3725
3846
|
if (!clientId || !producerId || !(typeof clientId === "string" && typeof producerId === "string")) {
|
|
3726
|
-
logger$
|
|
3847
|
+
logger$4.warn("Missing clientId or producerId");
|
|
3727
3848
|
return;
|
|
3728
3849
|
}
|
|
3729
3850
|
if (!this._producers[clientId]) {
|
|
@@ -3739,7 +3860,7 @@ class VegaMediaQualityMonitor extends EventEmitter {
|
|
|
3739
3860
|
}
|
|
3740
3861
|
addConsumer(clientId, consumerId) {
|
|
3741
3862
|
if (!clientId || !consumerId) {
|
|
3742
|
-
logger$
|
|
3863
|
+
logger$4.warn("Missing clientId or consumerId");
|
|
3743
3864
|
return;
|
|
3744
3865
|
}
|
|
3745
3866
|
if (!this._producers[clientId]) {
|
|
@@ -3757,14 +3878,14 @@ class VegaMediaQualityMonitor extends EventEmitter {
|
|
|
3757
3878
|
if (!Array.isArray(score) ||
|
|
3758
3879
|
score.length === 0 ||
|
|
3759
3880
|
score.some((s) => !s || !s.hasOwnProperty("score") || typeof s.score !== "number" || isNaN(s.score))) {
|
|
3760
|
-
logger$
|
|
3881
|
+
logger$4.warn("Unexpected producer score format");
|
|
3761
3882
|
return;
|
|
3762
3883
|
}
|
|
3763
3884
|
this._producers[clientId][producerId] = { kind, score: this._calcAvgProducerScore(score.map((s) => s.score)) };
|
|
3764
3885
|
}
|
|
3765
3886
|
addConsumerScore(clientId, consumerId, kind, score) {
|
|
3766
3887
|
if (!score || !score.hasOwnProperty("producerScores") || !Array.isArray(score.producerScores)) {
|
|
3767
|
-
logger$
|
|
3888
|
+
logger$4.warn("Unexpected consumer score format");
|
|
3768
3889
|
return;
|
|
3769
3890
|
}
|
|
3770
3891
|
this._producers[clientId][consumerId] = { kind, score: this._calcAvgProducerScore(score.producerScores) };
|
|
@@ -3801,7 +3922,7 @@ class VegaMediaQualityMonitor extends EventEmitter {
|
|
|
3801
3922
|
}
|
|
3802
3923
|
}
|
|
3803
3924
|
catch (error) {
|
|
3804
|
-
logger$
|
|
3925
|
+
logger$4.error(error);
|
|
3805
3926
|
return 0;
|
|
3806
3927
|
}
|
|
3807
3928
|
}
|
|
@@ -3942,7 +4063,7 @@ class SfuV2Parser {
|
|
|
3942
4063
|
}
|
|
3943
4064
|
}
|
|
3944
4065
|
|
|
3945
|
-
const logger$
|
|
4066
|
+
const logger$3 = new Logger();
|
|
3946
4067
|
class VegaConnection extends EventEmitter$1 {
|
|
3947
4068
|
constructor(wsUrl, protocol = "whereby-sfu#v4") {
|
|
3948
4069
|
super();
|
|
@@ -3975,12 +4096,12 @@ class VegaConnection extends EventEmitter$1 {
|
|
|
3975
4096
|
(_a = this.socket) === null || _a === void 0 ? void 0 : _a.close();
|
|
3976
4097
|
}
|
|
3977
4098
|
_onOpen() {
|
|
3978
|
-
logger$
|
|
4099
|
+
logger$3.info("Connected");
|
|
3979
4100
|
this.emit("open");
|
|
3980
4101
|
}
|
|
3981
4102
|
_onMessage(event) {
|
|
3982
4103
|
const socketMessage = SfuV2Parser.parse(event.data);
|
|
3983
|
-
logger$
|
|
4104
|
+
logger$3.info("Received message", socketMessage);
|
|
3984
4105
|
if (socketMessage === null || socketMessage === void 0 ? void 0 : socketMessage.response) {
|
|
3985
4106
|
this._handleResponse(socketMessage);
|
|
3986
4107
|
}
|
|
@@ -3989,11 +4110,11 @@ class VegaConnection extends EventEmitter$1 {
|
|
|
3989
4110
|
}
|
|
3990
4111
|
}
|
|
3991
4112
|
_onClose() {
|
|
3992
|
-
logger$
|
|
4113
|
+
logger$3.info("Disconnected");
|
|
3993
4114
|
this._tearDown();
|
|
3994
4115
|
}
|
|
3995
4116
|
_onError(error) {
|
|
3996
|
-
logger$
|
|
4117
|
+
logger$3.info("Error", error);
|
|
3997
4118
|
}
|
|
3998
4119
|
_handleResponse(socketMessage) {
|
|
3999
4120
|
const sent = this.sents.get(socketMessage.id);
|
|
@@ -4229,7 +4350,7 @@ function createVegaConnectionManager(config) {
|
|
|
4229
4350
|
|
|
4230
4351
|
var _a$1;
|
|
4231
4352
|
const adapter$1 = (_a$1 = adapterRaw.default) !== null && _a$1 !== void 0 ? _a$1 : adapterRaw;
|
|
4232
|
-
const logger$
|
|
4353
|
+
const logger$2 = new Logger();
|
|
4233
4354
|
const browserName = adapter$1.browserDetails.browser;
|
|
4234
4355
|
let unloading = false;
|
|
4235
4356
|
const RESTARTICE_ERROR_RETRY_THRESHOLD_IN_MS = 3500;
|
|
@@ -4359,7 +4480,7 @@ class VegaRtcManager {
|
|
|
4359
4480
|
setupSocketListeners() {
|
|
4360
4481
|
this._socketListenerDeregisterFunctions.push(() => this._clearMediaServersRefresh(), this._serverSocket.on(PROTOCOL_RESPONSES.MEDIASERVER_CONFIG, (data) => {
|
|
4361
4482
|
if (data.error) {
|
|
4362
|
-
logger$
|
|
4483
|
+
logger$2.warn("FETCH_MEDIASERVER_CONFIG failed:", data.error);
|
|
4363
4484
|
return;
|
|
4364
4485
|
}
|
|
4365
4486
|
this._updateAndScheduleMediaServersRefresh(data);
|
|
@@ -4431,7 +4552,7 @@ class VegaRtcManager {
|
|
|
4431
4552
|
}
|
|
4432
4553
|
_onClose() {
|
|
4433
4554
|
var _a, _b;
|
|
4434
|
-
logger$
|
|
4555
|
+
logger$2.info("_onClose()");
|
|
4435
4556
|
(_a = this._sendTransport) === null || _a === void 0 ? void 0 : _a.close();
|
|
4436
4557
|
(_b = this._receiveTransport) === null || _b === void 0 ? void 0 : _b.close();
|
|
4437
4558
|
this._sendTransport = null;
|
|
@@ -4447,7 +4568,7 @@ class VegaRtcManager {
|
|
|
4447
4568
|
_join() {
|
|
4448
4569
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4449
4570
|
var _a, _b;
|
|
4450
|
-
logger$
|
|
4571
|
+
logger$2.info("join()");
|
|
4451
4572
|
this._emitToPWA(rtcManagerEvents.SFU_CONNECTION_OPEN);
|
|
4452
4573
|
try {
|
|
4453
4574
|
const { routerRtpCapabilities } = yield this._vegaConnection.request("getCapabilities");
|
|
@@ -4474,7 +4595,7 @@ class VegaRtcManager {
|
|
|
4474
4595
|
yield Promise.all(mediaPromises);
|
|
4475
4596
|
}
|
|
4476
4597
|
catch (error) {
|
|
4477
|
-
logger$
|
|
4598
|
+
logger$2.error("_join() [error:%o]", error);
|
|
4478
4599
|
}
|
|
4479
4600
|
});
|
|
4480
4601
|
}
|
|
@@ -4502,7 +4623,7 @@ class VegaRtcManager {
|
|
|
4502
4623
|
maybeTurnOnly(transportOptions, this._features);
|
|
4503
4624
|
const transport = (_a = (yield this._mediasoupDeviceInitializedAsync)) === null || _a === void 0 ? void 0 : _a[creator](transportOptions);
|
|
4504
4625
|
const onConnectionStateListener = (connectionState) => __awaiter(this, void 0, void 0, function* () {
|
|
4505
|
-
logger$
|
|
4626
|
+
logger$2.info(`Transport ConnectionStateChanged ${connectionState}`);
|
|
4506
4627
|
if (connectionState !== "disconnected" && connectionState !== "failed") {
|
|
4507
4628
|
return;
|
|
4508
4629
|
}
|
|
@@ -4576,15 +4697,15 @@ class VegaRtcManager {
|
|
|
4576
4697
|
_restartIce(transport_1) {
|
|
4577
4698
|
return __awaiter(this, arguments, void 0, function* (transport, retried = 0) {
|
|
4578
4699
|
if (!transport || !("closed" in transport) || !("connectionState" in transport)) {
|
|
4579
|
-
logger$
|
|
4700
|
+
logger$2.info("_restartIce: No transport or property closed or connectionState!");
|
|
4580
4701
|
return;
|
|
4581
4702
|
}
|
|
4582
4703
|
if (transport.closed) {
|
|
4583
|
-
logger$
|
|
4704
|
+
logger$2.info("_restartIce: Transport is closed!");
|
|
4584
4705
|
return;
|
|
4585
4706
|
}
|
|
4586
4707
|
if (transport.connectionState !== "disconnected" && transport.connectionState !== "failed") {
|
|
4587
|
-
logger$
|
|
4708
|
+
logger$2.info("_restartIce: Connection is healthy ICE restart no loneger needed!");
|
|
4588
4709
|
return;
|
|
4589
4710
|
}
|
|
4590
4711
|
const { iceRestartStarted } = transport.appData;
|
|
@@ -4594,21 +4715,21 @@ class VegaRtcManager {
|
|
|
4594
4715
|
}
|
|
4595
4716
|
transport.appData.iceRestartStarted = now;
|
|
4596
4717
|
if (RESTARTICE_ERROR_MAX_RETRY_COUNT <= retried) {
|
|
4597
|
-
logger$
|
|
4718
|
+
logger$2.info("_restartIce: Reached restart ICE maximum retry count!");
|
|
4598
4719
|
return;
|
|
4599
4720
|
}
|
|
4600
4721
|
if (!this._vegaConnection) {
|
|
4601
|
-
logger$
|
|
4722
|
+
logger$2.info(`_restartIce: Connection is undefined`);
|
|
4602
4723
|
return;
|
|
4603
4724
|
}
|
|
4604
4725
|
const { iceParameters } = yield this._vegaConnection.request("restartIce", { transportId: transport.id });
|
|
4605
|
-
logger$
|
|
4726
|
+
logger$2.info("_restartIce: ICE restart iceParameters received from SFU: ", iceParameters);
|
|
4606
4727
|
const error = yield transport
|
|
4607
4728
|
.restartIce({ iceParameters })
|
|
4608
4729
|
.then(() => null)
|
|
4609
4730
|
.catch((err) => err);
|
|
4610
4731
|
if (error) {
|
|
4611
|
-
logger$
|
|
4732
|
+
logger$2.error(`_restartIce: ICE restart failed: ${error}`);
|
|
4612
4733
|
switch (error.message) {
|
|
4613
4734
|
case "missing transportId":
|
|
4614
4735
|
case "no such transport":
|
|
@@ -4637,7 +4758,7 @@ class VegaRtcManager {
|
|
|
4637
4758
|
}
|
|
4638
4759
|
_internalSendMic() {
|
|
4639
4760
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4640
|
-
logger$
|
|
4761
|
+
logger$2.info("_internalSendMic()");
|
|
4641
4762
|
this._micProducerPromise = (() => __awaiter(this, void 0, void 0, function* () {
|
|
4642
4763
|
try {
|
|
4643
4764
|
if (!this._micTrack || !this._sendTransport || this._micProducer) {
|
|
@@ -4657,7 +4778,7 @@ class VegaRtcManager {
|
|
|
4657
4778
|
this._qualityMonitor.addProducer(this._selfId, producer.id);
|
|
4658
4779
|
producer.observer.once("close", () => {
|
|
4659
4780
|
var _a;
|
|
4660
|
-
logger$
|
|
4781
|
+
logger$2.info('micProducer "close" event');
|
|
4661
4782
|
if (producer.appData.localClosed)
|
|
4662
4783
|
(_a = this._vegaConnection) === null || _a === void 0 ? void 0 : _a.message("closeProducers", { producerIds: [producer.id] });
|
|
4663
4784
|
this._micProducer = null;
|
|
@@ -4670,7 +4791,7 @@ class VegaRtcManager {
|
|
|
4670
4791
|
this._pauseResumeMic();
|
|
4671
4792
|
}
|
|
4672
4793
|
catch (error) {
|
|
4673
|
-
logger$
|
|
4794
|
+
logger$2.error("micProducer failed:%o", error);
|
|
4674
4795
|
}
|
|
4675
4796
|
finally {
|
|
4676
4797
|
this._micProducerPromise = null;
|
|
@@ -4684,7 +4805,7 @@ class VegaRtcManager {
|
|
|
4684
4805
|
}
|
|
4685
4806
|
_internalSetupMicScore() {
|
|
4686
4807
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4687
|
-
logger$
|
|
4808
|
+
logger$2.info("_internalSetupMicScore()");
|
|
4688
4809
|
this._micScoreProducerPromise = (() => __awaiter(this, void 0, void 0, function* () {
|
|
4689
4810
|
try {
|
|
4690
4811
|
if (!this._micProducer || !this._colocation || this._micScoreProducer) {
|
|
@@ -4703,7 +4824,7 @@ class VegaRtcManager {
|
|
|
4703
4824
|
this._micScoreProducer = producer;
|
|
4704
4825
|
producer.observer.once("close", () => {
|
|
4705
4826
|
var _a;
|
|
4706
|
-
logger$
|
|
4827
|
+
logger$2.info('micScoreProducer "close" event');
|
|
4707
4828
|
if (producer.appData.localClosed) {
|
|
4708
4829
|
(_a = this._vegaConnection) === null || _a === void 0 ? void 0 : _a.message("closeDataProducers", { dataProducerIds: [producer.id] });
|
|
4709
4830
|
}
|
|
@@ -4712,7 +4833,7 @@ class VegaRtcManager {
|
|
|
4712
4833
|
});
|
|
4713
4834
|
}
|
|
4714
4835
|
catch (error) {
|
|
4715
|
-
logger$
|
|
4836
|
+
logger$2.error("micScoreProducer failed:%o", error);
|
|
4716
4837
|
}
|
|
4717
4838
|
finally {
|
|
4718
4839
|
this._micScoreProducerPromise = null;
|
|
@@ -4730,7 +4851,7 @@ class VegaRtcManager {
|
|
|
4730
4851
|
_replaceMicTrack() {
|
|
4731
4852
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4732
4853
|
var _a;
|
|
4733
|
-
logger$
|
|
4854
|
+
logger$2.info("_replaceMicTrack()");
|
|
4734
4855
|
if (!this._micTrack || !this._micProducer || this._micProducer.closed)
|
|
4735
4856
|
return;
|
|
4736
4857
|
if (this._micProducer.track !== this._micTrack) {
|
|
@@ -4742,7 +4863,7 @@ class VegaRtcManager {
|
|
|
4742
4863
|
}
|
|
4743
4864
|
_pauseResumeMic() {
|
|
4744
4865
|
var _a, _b;
|
|
4745
|
-
logger$
|
|
4866
|
+
logger$2.info("_pauseResumeMic()");
|
|
4746
4867
|
if (!this._micProducer || this._micProducer.closed)
|
|
4747
4868
|
return;
|
|
4748
4869
|
if (this._micPaused !== this._micProducer.paused) {
|
|
@@ -4763,7 +4884,7 @@ class VegaRtcManager {
|
|
|
4763
4884
|
}
|
|
4764
4885
|
_sendMic(track) {
|
|
4765
4886
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4766
|
-
logger$
|
|
4887
|
+
logger$2.info("_sendMic() [track:%o]", track);
|
|
4767
4888
|
this._micTrack = track;
|
|
4768
4889
|
if (this._micProducer) {
|
|
4769
4890
|
return yield this._replaceMicTrack();
|
|
@@ -4789,7 +4910,7 @@ class VegaRtcManager {
|
|
|
4789
4910
|
this._micScoreProducer.send(JSON.stringify({ score }));
|
|
4790
4911
|
}
|
|
4791
4912
|
catch (ex) {
|
|
4792
|
-
logger$
|
|
4913
|
+
logger$2.error("_sendMicScore failed [error:%o]", ex);
|
|
4793
4914
|
}
|
|
4794
4915
|
return;
|
|
4795
4916
|
}
|
|
@@ -4800,7 +4921,7 @@ class VegaRtcManager {
|
|
|
4800
4921
|
_internalSendWebcam() {
|
|
4801
4922
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4802
4923
|
var _a;
|
|
4803
|
-
logger$
|
|
4924
|
+
logger$2.info("_internalSendWebcam()");
|
|
4804
4925
|
if (!this._sendTransport ||
|
|
4805
4926
|
this._webcamProducer ||
|
|
4806
4927
|
this._webcamProducerPromise ||
|
|
@@ -4823,7 +4944,7 @@ class VegaRtcManager {
|
|
|
4823
4944
|
this._qualityMonitor.addProducer(this._selfId, producer.id);
|
|
4824
4945
|
producer.observer.once("close", () => {
|
|
4825
4946
|
var _a;
|
|
4826
|
-
logger$
|
|
4947
|
+
logger$2.info('webcamProducer "close" event');
|
|
4827
4948
|
if (producer.appData.localClosed)
|
|
4828
4949
|
(_a = this._vegaConnection) === null || _a === void 0 ? void 0 : _a.message("closeProducers", { producerIds: [producer.id] });
|
|
4829
4950
|
this._webcamProducer = null;
|
|
@@ -4838,7 +4959,7 @@ class VegaRtcManager {
|
|
|
4838
4959
|
this._pauseResumeWebcam();
|
|
4839
4960
|
}
|
|
4840
4961
|
catch (error) {
|
|
4841
|
-
logger$
|
|
4962
|
+
logger$2.error("webcamProducer failed:%o", error);
|
|
4842
4963
|
}
|
|
4843
4964
|
finally {
|
|
4844
4965
|
this._webcamProducerPromise = null;
|
|
@@ -4852,7 +4973,7 @@ class VegaRtcManager {
|
|
|
4852
4973
|
}
|
|
4853
4974
|
_replaceWebcamTrack() {
|
|
4854
4975
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4855
|
-
logger$
|
|
4976
|
+
logger$2.info("_replaceWebcamTrack()");
|
|
4856
4977
|
if (!this._sendTransport || !this._webcamTrack || this._webcamProducerPromise)
|
|
4857
4978
|
return;
|
|
4858
4979
|
if (!this._webcamProducer && this._webcamTrack.enabled) {
|
|
@@ -4867,7 +4988,7 @@ class VegaRtcManager {
|
|
|
4867
4988
|
}
|
|
4868
4989
|
_pauseResumeWebcam() {
|
|
4869
4990
|
var _a, _b;
|
|
4870
|
-
logger$
|
|
4991
|
+
logger$2.info("_pauseResumeWebcam()");
|
|
4871
4992
|
if (!this._webcamProducer || this._webcamProducer.closed)
|
|
4872
4993
|
return;
|
|
4873
4994
|
if (this._webcamPaused !== this._webcamProducer.paused) {
|
|
@@ -4888,7 +5009,7 @@ class VegaRtcManager {
|
|
|
4888
5009
|
}
|
|
4889
5010
|
_sendWebcam(track) {
|
|
4890
5011
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4891
|
-
logger$
|
|
5012
|
+
logger$2.info("_sendWebcam() [track:%o]", track);
|
|
4892
5013
|
this._webcamTrack = track;
|
|
4893
5014
|
if (this._webcamProducer) {
|
|
4894
5015
|
return yield this._replaceWebcamTrack();
|
|
@@ -4902,7 +5023,7 @@ class VegaRtcManager {
|
|
|
4902
5023
|
}
|
|
4903
5024
|
_internalSendScreenVideo() {
|
|
4904
5025
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4905
|
-
logger$
|
|
5026
|
+
logger$2.info("_internalSendScreenVideo()");
|
|
4906
5027
|
this._screenVideoProducerPromise = (() => __awaiter(this, void 0, void 0, function* () {
|
|
4907
5028
|
var _a, _b;
|
|
4908
5029
|
try {
|
|
@@ -4924,7 +5045,7 @@ class VegaRtcManager {
|
|
|
4924
5045
|
this._qualityMonitor.addProducer(this._selfId, producer.id);
|
|
4925
5046
|
producer.observer.once("close", () => {
|
|
4926
5047
|
var _a;
|
|
4927
|
-
logger$
|
|
5048
|
+
logger$2.info('screenVideoProducer "close" event');
|
|
4928
5049
|
if (producer.appData.localClosed)
|
|
4929
5050
|
(_a = this._vegaConnection) === null || _a === void 0 ? void 0 : _a.message("closeProducers", { producerIds: [producer.id] });
|
|
4930
5051
|
this._screenVideoProducer = null;
|
|
@@ -4935,7 +5056,7 @@ class VegaRtcManager {
|
|
|
4935
5056
|
yield this._replaceScreenVideoTrack();
|
|
4936
5057
|
}
|
|
4937
5058
|
catch (error) {
|
|
4938
|
-
logger$
|
|
5059
|
+
logger$2.error("screenVideoProducer failed:%o", error);
|
|
4939
5060
|
}
|
|
4940
5061
|
finally {
|
|
4941
5062
|
this._screenVideoProducerPromise = null;
|
|
@@ -4949,7 +5070,7 @@ class VegaRtcManager {
|
|
|
4949
5070
|
}
|
|
4950
5071
|
_replaceScreenVideoTrack() {
|
|
4951
5072
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4952
|
-
logger$
|
|
5073
|
+
logger$2.info("_replaceScreenVideoTrack()");
|
|
4953
5074
|
if (!this._screenVideoTrack || !this._screenVideoProducer || this._screenVideoProducer.closed)
|
|
4954
5075
|
return;
|
|
4955
5076
|
if (this._screenVideoProducer.track !== this._screenVideoTrack) {
|
|
@@ -4960,7 +5081,7 @@ class VegaRtcManager {
|
|
|
4960
5081
|
}
|
|
4961
5082
|
_sendScreenVideo(track) {
|
|
4962
5083
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4963
|
-
logger$
|
|
5084
|
+
logger$2.info("_sendScreenVideo() [track:%o]", track);
|
|
4964
5085
|
this._screenVideoTrack = track;
|
|
4965
5086
|
if (this._screenVideoProducer) {
|
|
4966
5087
|
return yield this._replaceScreenVideoTrack();
|
|
@@ -4974,7 +5095,7 @@ class VegaRtcManager {
|
|
|
4974
5095
|
}
|
|
4975
5096
|
_internalSendScreenAudio() {
|
|
4976
5097
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4977
|
-
logger$
|
|
5098
|
+
logger$2.info("_internalSendScreenAudio()");
|
|
4978
5099
|
this._screenAudioProducerPromise = (() => __awaiter(this, void 0, void 0, function* () {
|
|
4979
5100
|
try {
|
|
4980
5101
|
if (!this._screenAudioTrack || !this._sendTransport || this._screenAudioProducer) {
|
|
@@ -4992,7 +5113,7 @@ class VegaRtcManager {
|
|
|
4992
5113
|
this._qualityMonitor.addProducer(this._selfId, producer.id);
|
|
4993
5114
|
producer.observer.once("close", () => {
|
|
4994
5115
|
var _a;
|
|
4995
|
-
logger$
|
|
5116
|
+
logger$2.info('screenAudioProducer "close" event');
|
|
4996
5117
|
if (producer.appData.localClosed)
|
|
4997
5118
|
(_a = this._vegaConnection) === null || _a === void 0 ? void 0 : _a.message("closeProducers", { producerIds: [producer.id] });
|
|
4998
5119
|
this._screenAudioProducer = null;
|
|
@@ -5003,7 +5124,7 @@ class VegaRtcManager {
|
|
|
5003
5124
|
yield this._replaceScreenAudioTrack();
|
|
5004
5125
|
}
|
|
5005
5126
|
catch (error) {
|
|
5006
|
-
logger$
|
|
5127
|
+
logger$2.error("screenAudioProducer failed:%o", error);
|
|
5007
5128
|
}
|
|
5008
5129
|
finally {
|
|
5009
5130
|
this._screenAudioProducerPromise = null;
|
|
@@ -5017,7 +5138,7 @@ class VegaRtcManager {
|
|
|
5017
5138
|
}
|
|
5018
5139
|
_replaceScreenAudioTrack() {
|
|
5019
5140
|
return __awaiter(this, void 0, void 0, function* () {
|
|
5020
|
-
logger$
|
|
5141
|
+
logger$2.info("_replaceScreenAudioTrack()");
|
|
5021
5142
|
if (!this._screenAudioTrack || !this._screenAudioProducer || this._screenAudioProducer.closed)
|
|
5022
5143
|
return;
|
|
5023
5144
|
if (this._screenAudioProducer.track !== this._screenAudioTrack) {
|
|
@@ -5028,7 +5149,7 @@ class VegaRtcManager {
|
|
|
5028
5149
|
}
|
|
5029
5150
|
_sendScreenAudio(track) {
|
|
5030
5151
|
return __awaiter(this, void 0, void 0, function* () {
|
|
5031
|
-
logger$
|
|
5152
|
+
logger$2.info("_sendScreenAudio() [track:%o]", track);
|
|
5032
5153
|
this._screenAudioTrack = track;
|
|
5033
5154
|
if (this._screenAudioProducer) {
|
|
5034
5155
|
return yield this._replaceScreenAudioTrack();
|
|
@@ -5041,7 +5162,7 @@ class VegaRtcManager {
|
|
|
5041
5162
|
});
|
|
5042
5163
|
}
|
|
5043
5164
|
_stopProducer(producer) {
|
|
5044
|
-
logger$
|
|
5165
|
+
logger$2.info("_stopProducer()");
|
|
5045
5166
|
if (!producer || producer.closed)
|
|
5046
5167
|
return;
|
|
5047
5168
|
producer.appData.localClosed = true;
|
|
@@ -5078,7 +5199,7 @@ class VegaRtcManager {
|
|
|
5078
5199
|
}
|
|
5079
5200
|
disconnect(clientIdOrStreamId, _activeBreakout, eventClaim) {
|
|
5080
5201
|
var _a;
|
|
5081
|
-
logger$
|
|
5202
|
+
logger$2.info("disconnect() [clientIdOrStreamId:%s, eventClaim:%s]", clientIdOrStreamId, eventClaim);
|
|
5082
5203
|
const clientState = this._clientStates.get(clientIdOrStreamId);
|
|
5083
5204
|
if (clientState) {
|
|
5084
5205
|
clientState.hasAcceptedWebcamStream = false;
|
|
@@ -5107,7 +5228,7 @@ class VegaRtcManager {
|
|
|
5107
5228
|
}
|
|
5108
5229
|
}
|
|
5109
5230
|
removeStream(streamId, _stream, requestedByClientId) {
|
|
5110
|
-
logger$
|
|
5231
|
+
logger$2.info("removeStream() [streamId:%s, requestedByClientId:%s]", streamId, requestedByClientId);
|
|
5111
5232
|
this._emitToSignal(PROTOCOL_REQUESTS.STOP_SCREENSHARE, {
|
|
5112
5233
|
streamId: OUTBOUND_SCREEN_OUTBOUND_STREAM_ID,
|
|
5113
5234
|
requestedByClientId,
|
|
@@ -5191,7 +5312,7 @@ class VegaRtcManager {
|
|
|
5191
5312
|
}
|
|
5192
5313
|
}
|
|
5193
5314
|
stopOrResumeAudio(stream, enabled) {
|
|
5194
|
-
logger$
|
|
5315
|
+
logger$2.info("stopOrResumeAudio() [enabled:%s]", enabled);
|
|
5195
5316
|
this._micPaused = !enabled;
|
|
5196
5317
|
this._pauseResumeMic();
|
|
5197
5318
|
}
|
|
@@ -5209,7 +5330,7 @@ class VegaRtcManager {
|
|
|
5209
5330
|
}
|
|
5210
5331
|
stopOrResumeVideo(localStream, enable) {
|
|
5211
5332
|
var _a;
|
|
5212
|
-
logger$
|
|
5333
|
+
logger$2.info("stopOrResumeVideo() [enable:%s]", enable);
|
|
5213
5334
|
this._webcamPaused = !enable;
|
|
5214
5335
|
this._pauseResumeWebcam();
|
|
5215
5336
|
if (!["chrome", "safari"].includes(browserName)) {
|
|
@@ -5253,7 +5374,7 @@ class VegaRtcManager {
|
|
|
5253
5374
|
return true;
|
|
5254
5375
|
}
|
|
5255
5376
|
acceptNewStream({ streamId, clientId }) {
|
|
5256
|
-
logger$
|
|
5377
|
+
logger$2.info("acceptNewStream()", { streamId, clientId });
|
|
5257
5378
|
const clientState = this._getOrCreateClientState(clientId);
|
|
5258
5379
|
const isScreenShare = streamId !== clientId;
|
|
5259
5380
|
if (isScreenShare) {
|
|
@@ -5268,7 +5389,7 @@ class VegaRtcManager {
|
|
|
5268
5389
|
}
|
|
5269
5390
|
updateStreamResolution(streamId, _ignored, { width, height, }) {
|
|
5270
5391
|
var _a, _b;
|
|
5271
|
-
logger$
|
|
5392
|
+
logger$2.info("updateStreamResolution()", { streamId, width, height });
|
|
5272
5393
|
const consumerId = this._streamIdToVideoConsumerId.get(streamId);
|
|
5273
5394
|
const consumer = this._consumers.get(consumerId);
|
|
5274
5395
|
if (!consumer) {
|
|
@@ -5376,18 +5497,18 @@ class VegaRtcManager {
|
|
|
5376
5497
|
case "producerScore":
|
|
5377
5498
|
return this._onProducerScore(data);
|
|
5378
5499
|
default:
|
|
5379
|
-
logger$
|
|
5500
|
+
logger$2.info(`unknown message method "${method}"`);
|
|
5380
5501
|
return;
|
|
5381
5502
|
}
|
|
5382
5503
|
})
|
|
5383
5504
|
.catch((error) => {
|
|
5384
|
-
logger$
|
|
5505
|
+
logger$2.error('"message" failed [error:%o]', error);
|
|
5385
5506
|
});
|
|
5386
5507
|
});
|
|
5387
5508
|
}
|
|
5388
5509
|
_onConsumerReady(options) {
|
|
5389
5510
|
return __awaiter(this, void 0, void 0, function* () {
|
|
5390
|
-
logger$
|
|
5511
|
+
logger$2.info("_onConsumerReady()", { id: options.id, producerId: options.producerId });
|
|
5391
5512
|
const consumer = yield this._receiveTransport.consume(options);
|
|
5392
5513
|
consumer.pause();
|
|
5393
5514
|
consumer.appData.localPaused = true;
|
|
@@ -5405,7 +5526,7 @@ class VegaRtcManager {
|
|
|
5405
5526
|
consumer.rtpReceiver.playoutDelayHint = MEDIA_JITTER_BUFFER_TARGET / 1000;
|
|
5406
5527
|
}
|
|
5407
5528
|
catch (error) {
|
|
5408
|
-
logger$
|
|
5529
|
+
logger$2.error("Error during setting jitter buffer target:", error);
|
|
5409
5530
|
}
|
|
5410
5531
|
}
|
|
5411
5532
|
const { sourceClientId: clientId, screenShare, streamId } = consumer.appData;
|
|
@@ -5439,12 +5560,12 @@ class VegaRtcManager {
|
|
|
5439
5560
|
_onConsumerClosed(_a) {
|
|
5440
5561
|
return __awaiter(this, arguments, void 0, function* ({ consumerId, reason }) {
|
|
5441
5562
|
var _b;
|
|
5442
|
-
logger$
|
|
5563
|
+
logger$2.info("_onConsumerClosed()", { consumerId, reason });
|
|
5443
5564
|
(_b = this._consumers.get(consumerId)) === null || _b === void 0 ? void 0 : _b.close();
|
|
5444
5565
|
});
|
|
5445
5566
|
}
|
|
5446
5567
|
_onConsumerPaused({ consumerId }) {
|
|
5447
|
-
logger$
|
|
5568
|
+
logger$2.info("_onConsumerPaused()", { consumerId });
|
|
5448
5569
|
const consumer = this._consumers.get(consumerId);
|
|
5449
5570
|
if (!consumer)
|
|
5450
5571
|
return;
|
|
@@ -5452,7 +5573,7 @@ class VegaRtcManager {
|
|
|
5452
5573
|
consumer.pause();
|
|
5453
5574
|
}
|
|
5454
5575
|
_onConsumerResumed({ consumerId }) {
|
|
5455
|
-
logger$
|
|
5576
|
+
logger$2.info("_onConsumerResumed()", { consumerId });
|
|
5456
5577
|
const consumer = this._consumers.get(consumerId);
|
|
5457
5578
|
if (!consumer)
|
|
5458
5579
|
return;
|
|
@@ -5462,14 +5583,14 @@ class VegaRtcManager {
|
|
|
5462
5583
|
}
|
|
5463
5584
|
}
|
|
5464
5585
|
_onConsumerScore({ consumerId, kind, score }) {
|
|
5465
|
-
logger$
|
|
5586
|
+
logger$2.info("_onConsumerScore()", { consumerId, kind, score });
|
|
5466
5587
|
const { appData: { sourceClientId }, } = this._consumers.get(consumerId) || { appData: {} };
|
|
5467
5588
|
if (sourceClientId) {
|
|
5468
5589
|
this._qualityMonitor.addConsumerScore(sourceClientId, consumerId, kind, score);
|
|
5469
5590
|
}
|
|
5470
5591
|
}
|
|
5471
5592
|
_onProducerScore({ producerId, kind, score }) {
|
|
5472
|
-
logger$
|
|
5593
|
+
logger$2.info("_onProducerScore()", { producerId, kind, score });
|
|
5473
5594
|
[this._micProducer, this._webcamProducer, this._screenVideoProducer, this._screenAudioProducer].forEach((producer) => {
|
|
5474
5595
|
if ((producer === null || producer === void 0 ? void 0 : producer.id) === producerId) {
|
|
5475
5596
|
this._qualityMonitor.addProducerScore(this._selfId, producerId, kind, score);
|
|
@@ -5478,7 +5599,7 @@ class VegaRtcManager {
|
|
|
5478
5599
|
}
|
|
5479
5600
|
_onDataConsumerReady(options) {
|
|
5480
5601
|
return __awaiter(this, void 0, void 0, function* () {
|
|
5481
|
-
logger$
|
|
5602
|
+
logger$2.info("_onDataConsumerReady()", { id: options.id, producerId: options.producerId });
|
|
5482
5603
|
const consumer = yield this._receiveTransport.consumeData(options);
|
|
5483
5604
|
this._dataConsumers.set(consumer.id, consumer);
|
|
5484
5605
|
consumer.once("close", () => {
|
|
@@ -5501,7 +5622,7 @@ class VegaRtcManager {
|
|
|
5501
5622
|
}
|
|
5502
5623
|
_onDataConsumerClosed(_a) {
|
|
5503
5624
|
return __awaiter(this, arguments, void 0, function* ({ dataConsumerId, reason }) {
|
|
5504
|
-
logger$
|
|
5625
|
+
logger$2.info("_onDataConsumerClosed()", { dataConsumerId, reason });
|
|
5505
5626
|
const consumer = this._dataConsumers.get(dataConsumerId);
|
|
5506
5627
|
consumer === null || consumer === void 0 ? void 0 : consumer.close();
|
|
5507
5628
|
});
|
|
@@ -5676,119 +5797,11 @@ const getRoomMode = () => {
|
|
|
5676
5797
|
return roomMode;
|
|
5677
5798
|
};
|
|
5678
5799
|
|
|
5679
|
-
const logger$2 = new Logger();
|
|
5680
|
-
const debugLogger = {
|
|
5681
|
-
print: (...args) => console.debug(args[0], ...args.slice(1)),
|
|
5682
|
-
};
|
|
5683
|
-
logger$2.withDebugLogger(debugLogger);
|
|
5684
|
-
class PacketLossAnalyser {
|
|
5685
|
-
constructor() {
|
|
5686
|
-
this.BEGIN_PACKET_LOSS_PERIOD_THRESHOLD = 0.04;
|
|
5687
|
-
this.END_PACKET_LOSS_PERIOD_THRESHOLD = 0.005;
|
|
5688
|
-
this.INTERVAL_DIFF_THRESHOLD_MS = 4000;
|
|
5689
|
-
this.STALE_MEASUREMENT_TIMEOUT_MS = 10000;
|
|
5690
|
-
this.MINIMUM_INTERVAL_MS = 30000;
|
|
5691
|
-
this.ssrcsHistory = new Map();
|
|
5692
|
-
this.staleMeasurementTimeouts = new Map();
|
|
5693
|
-
}
|
|
5694
|
-
addPacketLossMeasurement(id, packetLoss, timestamp) {
|
|
5695
|
-
this.handleStaleMeasurements(id);
|
|
5696
|
-
const beginNewPacketLossPeriod = packetLoss > this.BEGIN_PACKET_LOSS_PERIOD_THRESHOLD;
|
|
5697
|
-
let history = this.ssrcsHistory.get(id);
|
|
5698
|
-
if (!history) {
|
|
5699
|
-
history = {
|
|
5700
|
-
id,
|
|
5701
|
-
hasActivePacketLoss: beginNewPacketLossPeriod,
|
|
5702
|
-
currPeriod: beginNewPacketLossPeriod ? { begin: timestamp } : undefined,
|
|
5703
|
-
hasPeriodicPacketLoss: false,
|
|
5704
|
-
};
|
|
5705
|
-
this.ssrcsHistory.set(id, history);
|
|
5706
|
-
return;
|
|
5707
|
-
}
|
|
5708
|
-
if (history.hasActivePacketLoss) {
|
|
5709
|
-
if (packetLoss < this.END_PACKET_LOSS_PERIOD_THRESHOLD) {
|
|
5710
|
-
this.endPacketLossPeriod(history, timestamp);
|
|
5711
|
-
if (history.prevIntervalInMs && history.prevIntervalInMs < this.MINIMUM_INTERVAL_MS) {
|
|
5712
|
-
this.ssrcsHistory.delete(id);
|
|
5713
|
-
}
|
|
5714
|
-
}
|
|
5715
|
-
return;
|
|
5716
|
-
}
|
|
5717
|
-
if (beginNewPacketLossPeriod) {
|
|
5718
|
-
history.hasActivePacketLoss = true;
|
|
5719
|
-
history.currPeriod = {
|
|
5720
|
-
begin: timestamp,
|
|
5721
|
-
};
|
|
5722
|
-
}
|
|
5723
|
-
}
|
|
5724
|
-
hasPeriodicPacketLoss(id, timestamp) {
|
|
5725
|
-
const history = this.ssrcsHistory.get(id);
|
|
5726
|
-
if (history && this.prevIntervalExceeded(history, timestamp)) {
|
|
5727
|
-
this.ssrcsHistory.delete(history.id);
|
|
5728
|
-
return false;
|
|
5729
|
-
}
|
|
5730
|
-
return (history === null || history === void 0 ? void 0 : history.hasPeriodicPacketLoss) || false;
|
|
5731
|
-
}
|
|
5732
|
-
prevIntervalExceeded(history, timestamp) {
|
|
5733
|
-
if (history.prevPeriod && history.prevIntervalInMs) {
|
|
5734
|
-
const intervalLimitTimestamp = this.calculatePeriodCenterTimestamp(history.prevPeriod) +
|
|
5735
|
-
history.prevIntervalInMs +
|
|
5736
|
-
this.INTERVAL_DIFF_THRESHOLD_MS;
|
|
5737
|
-
return timestamp > intervalLimitTimestamp;
|
|
5738
|
-
}
|
|
5739
|
-
return false;
|
|
5740
|
-
}
|
|
5741
|
-
handleStaleMeasurements(id) {
|
|
5742
|
-
const staleMeasurementTimeout = this.staleMeasurementTimeouts.get(id);
|
|
5743
|
-
if (staleMeasurementTimeout) {
|
|
5744
|
-
clearTimeout(staleMeasurementTimeout);
|
|
5745
|
-
}
|
|
5746
|
-
this.staleMeasurementTimeouts.set(id, setTimeout(() => {
|
|
5747
|
-
logger$2.debug("handleStaleMeasurements() [measurements invalid for ssrc: %s]", id);
|
|
5748
|
-
this.ssrcsHistory.delete(id);
|
|
5749
|
-
}, this.STALE_MEASUREMENT_TIMEOUT_MS));
|
|
5750
|
-
}
|
|
5751
|
-
endPacketLossPeriod(history, timestamp) {
|
|
5752
|
-
logger$2.debug("endPacketLossPeriod() [ssrcId: %s, timestamp: %s]", history.id, timestamp);
|
|
5753
|
-
if (!history.currPeriod)
|
|
5754
|
-
throw new Error("No packet loss period for " + history.id);
|
|
5755
|
-
if (!history.prevPeriod) {
|
|
5756
|
-
history.prevPeriod = Object.assign(Object.assign({}, history.currPeriod), { end: timestamp });
|
|
5757
|
-
}
|
|
5758
|
-
else {
|
|
5759
|
-
history.currPeriod.end = timestamp;
|
|
5760
|
-
this.addNewPacketLossInterval(history);
|
|
5761
|
-
}
|
|
5762
|
-
delete history.currPeriod;
|
|
5763
|
-
history.hasActivePacketLoss = false;
|
|
5764
|
-
}
|
|
5765
|
-
addNewPacketLossInterval(history) {
|
|
5766
|
-
logger$2.debug("addNewPacketLossInterval() [ssrcId: %s, prevIntervalInMs: %s]", history.id, history.prevIntervalInMs);
|
|
5767
|
-
if (!history.currPeriod || !history.prevPeriod)
|
|
5768
|
-
throw new Error("missing period timestamps");
|
|
5769
|
-
const prevPeriodCenter = this.calculatePeriodCenterTimestamp(history.prevPeriod);
|
|
5770
|
-
const currPeriodCenter = this.calculatePeriodCenterTimestamp(history.currPeriod);
|
|
5771
|
-
const currIntervalInMs = currPeriodCenter - prevPeriodCenter;
|
|
5772
|
-
if (history.prevIntervalInMs) {
|
|
5773
|
-
const intervalDiffInMs = Math.abs(history.prevIntervalInMs - currIntervalInMs);
|
|
5774
|
-
history.hasPeriodicPacketLoss = intervalDiffInMs < this.INTERVAL_DIFF_THRESHOLD_MS;
|
|
5775
|
-
logger$2.debug("addNewPacketLossInterval() [hasPeriodicPacketLoss: %s, intervalDiffInMs: %s]", intervalDiffInMs < this.INTERVAL_DIFF_THRESHOLD_MS, intervalDiffInMs);
|
|
5776
|
-
}
|
|
5777
|
-
history.prevIntervalInMs = currIntervalInMs;
|
|
5778
|
-
history.prevPeriod = history.currPeriod;
|
|
5779
|
-
}
|
|
5780
|
-
calculatePeriodCenterTimestamp(period) {
|
|
5781
|
-
if (!period.end)
|
|
5782
|
-
throw new Error("Missing period end timestamp");
|
|
5783
|
-
return period.begin + (period.end - period.begin) / 2;
|
|
5784
|
-
}
|
|
5785
|
-
}
|
|
5786
|
-
|
|
5787
5800
|
const packetLossAnalyser = new PacketLossAnalyser();
|
|
5788
5801
|
const periodicPacketLossDetector = {
|
|
5789
5802
|
id: "periodic-packet-loss",
|
|
5790
5803
|
enabled: ({ client, hasLiveTrack, ssrc0 }) => {
|
|
5791
|
-
return (client.isLocalClient &&
|
|
5804
|
+
return (!!client.isLocalClient &&
|
|
5792
5805
|
hasLiveTrack &&
|
|
5793
5806
|
!!(ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.ssrc) &&
|
|
5794
5807
|
(ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.direction) === "out" &&
|
|
@@ -5904,7 +5917,7 @@ const issueDetectors = [
|
|
|
5904
5917
|
dryTrackIssueDetector,
|
|
5905
5918
|
{
|
|
5906
5919
|
id: "denoiser-context-suspended",
|
|
5907
|
-
enabled: ({ client, kind }) => { var _a, _b; return client.isLocalClient && kind === "audio" && !!((_b = (_a = client.audio) === null || _a === void 0 ? void 0 : _a.track) === null || _b === void 0 ? void 0 : _b._denoiserCtx); },
|
|
5920
|
+
enabled: ({ client, kind }) => { var _a, _b; return !!client.isLocalClient && kind === "audio" && !!((_b = (_a = client.audio) === null || _a === void 0 ? void 0 : _a.track) === null || _b === void 0 ? void 0 : _b._denoiserCtx); },
|
|
5908
5921
|
check: ({ track }) => {
|
|
5909
5922
|
var _a;
|
|
5910
5923
|
if (!track || !("_denoiserCtx" in track))
|
|
@@ -5930,7 +5943,7 @@ const issueDetectors = [
|
|
|
5930
5943
|
if (remoteClients.some((c) => c.isAudioOnlyModeEnabled))
|
|
5931
5944
|
return false;
|
|
5932
5945
|
}
|
|
5933
|
-
return hasLiveTrack && client.isLocalClient && kind === "video" && !!stats;
|
|
5946
|
+
return hasLiveTrack && !!client.isLocalClient && kind === "video" && !!stats;
|
|
5934
5947
|
},
|
|
5935
5948
|
check: ({ stats }) => {
|
|
5936
5949
|
if (!stats)
|
|
@@ -5940,7 +5953,7 @@ const issueDetectors = [
|
|
|
5940
5953
|
},
|
|
5941
5954
|
{
|
|
5942
5955
|
id: "quality-limitation-cpu",
|
|
5943
|
-
enabled: ({ hasLiveTrack, stats, client, kind }) => hasLiveTrack && client.isLocalClient && kind === "video" && !!stats,
|
|
5956
|
+
enabled: ({ hasLiveTrack, stats, client, kind }) => hasLiveTrack && !!client.isLocalClient && kind === "video" && !!stats,
|
|
5944
5957
|
check: ({ stats }) => {
|
|
5945
5958
|
if (!stats)
|
|
5946
5959
|
return false;
|
|
@@ -6043,12 +6056,12 @@ const metrics = [
|
|
|
6043
6056
|
{
|
|
6044
6057
|
id: "height",
|
|
6045
6058
|
enabled: ({ hasLiveTrack, track, trackStats, ssrc0, kind }) => hasLiveTrack && kind === "video" && !!trackStats && !!track && !!ssrc0 && !!ssrc0.height,
|
|
6046
|
-
value: ({ trackStats }) => Object.values((trackStats === null || trackStats === void 0 ? void 0 : trackStats.ssrcs) || {}).reduce((max, ssrc) => Math.max(max, ssrc.fps > 0 ? ssrc.height : 0), 0),
|
|
6059
|
+
value: ({ trackStats }) => Object.values((trackStats === null || trackStats === void 0 ? void 0 : trackStats.ssrcs) || {}).reduce((max, ssrc) => Math.max(max, ssrc.fps || 0 > 0 ? ssrc.height || 0 : 0), 0),
|
|
6047
6060
|
},
|
|
6048
6061
|
{
|
|
6049
6062
|
id: "sourceHeight",
|
|
6050
6063
|
enabled: ({ hasLiveTrack, track, ssrc0, kind }) => hasLiveTrack && kind === "video" && !!track && !!ssrc0 && !!ssrc0.sourceHeight && ssrc0.direction === "out",
|
|
6051
|
-
value: ({ ssrc0 }) => ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.sourceHeight,
|
|
6064
|
+
value: ({ ssrc0 }) => (ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.sourceHeight) || NaN,
|
|
6052
6065
|
},
|
|
6053
6066
|
{
|
|
6054
6067
|
id: "packetloss",
|
|
@@ -6058,7 +6071,7 @@ const metrics = [
|
|
|
6058
6071
|
{
|
|
6059
6072
|
id: "jitter",
|
|
6060
6073
|
enabled: ({ hasLiveTrack, ssrc0 }) => hasLiveTrack && !!ssrc0 && !!ssrc0.bitrate && ssrc0.direction === "in",
|
|
6061
|
-
value: ({ ssrc0 }) => ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.jitter,
|
|
6074
|
+
value: ({ ssrc0 }) => (ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.jitter) || NaN,
|
|
6062
6075
|
},
|
|
6063
6076
|
{
|
|
6064
6077
|
id: "mos",
|
|
@@ -6092,13 +6105,13 @@ const metrics = [
|
|
|
6092
6105
|
id: "turn-usage",
|
|
6093
6106
|
global: true,
|
|
6094
6107
|
enabled: ({ stats }) => !!Object.values((stats === null || stats === void 0 ? void 0 : stats.candidatePairs) || {}).length,
|
|
6095
|
-
value: ({ stats }) => Object.values((stats === null || stats === void 0 ? void 0 : stats.candidatePairs) || {}).some((cp) => cp.usingTurn),
|
|
6108
|
+
value: ({ stats }) => (Object.values((stats === null || stats === void 0 ? void 0 : stats.candidatePairs) || {}).some((cp) => cp.usingTurn) ? 1 : 0),
|
|
6096
6109
|
},
|
|
6097
6110
|
{
|
|
6098
6111
|
id: "turn-tls-usage",
|
|
6099
6112
|
global: true,
|
|
6100
6113
|
enabled: ({ stats }) => !!Object.values((stats === null || stats === void 0 ? void 0 : stats.candidatePairs) || {}).length,
|
|
6101
|
-
value: ({ stats }) => Object.values((stats === null || stats === void 0 ? void 0 : stats.candidatePairs) || {}).some((cp) => cp.turnProtocol === "tls"),
|
|
6114
|
+
value: ({ stats }) => Object.values((stats === null || stats === void 0 ? void 0 : stats.candidatePairs) || {}).some((cp) => cp.turnProtocol === "tls") ? 1 : 0,
|
|
6102
6115
|
},
|
|
6103
6116
|
{
|
|
6104
6117
|
id: "concealment",
|
|
@@ -6108,7 +6121,7 @@ const metrics = [
|
|
|
6108
6121
|
ssrc0.direction === "in" &&
|
|
6109
6122
|
kind === "audio" &&
|
|
6110
6123
|
(ssrc0.audioLevel || 0) >= 0.001,
|
|
6111
|
-
value: ({ ssrc0 }) => ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.audioConcealment,
|
|
6124
|
+
value: ({ ssrc0 }) => (ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.audioConcealment) || NaN,
|
|
6112
6125
|
},
|
|
6113
6126
|
{
|
|
6114
6127
|
id: "deceleration",
|
|
@@ -6118,7 +6131,7 @@ const metrics = [
|
|
|
6118
6131
|
ssrc0.direction === "in" &&
|
|
6119
6132
|
kind === "audio" &&
|
|
6120
6133
|
(ssrc0.audioLevel || 0) >= 0.001,
|
|
6121
|
-
value: ({ ssrc0 }) => ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.audioDeceleration,
|
|
6134
|
+
value: ({ ssrc0 }) => (ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.audioDeceleration) || NaN,
|
|
6122
6135
|
},
|
|
6123
6136
|
{
|
|
6124
6137
|
id: "acceleration",
|
|
@@ -6128,7 +6141,7 @@ const metrics = [
|
|
|
6128
6141
|
ssrc0.direction === "in" &&
|
|
6129
6142
|
kind === "audio" &&
|
|
6130
6143
|
(ssrc0.audioLevel || 0) >= 0.001,
|
|
6131
|
-
value: ({ ssrc0 }) => ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.audioAcceleration,
|
|
6144
|
+
value: ({ ssrc0 }) => (ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.audioAcceleration) || NaN,
|
|
6132
6145
|
},
|
|
6133
6146
|
{
|
|
6134
6147
|
id: "qpf",
|
|
@@ -6171,9 +6184,6 @@ function onUpdatedStats(statsByView, clients) {
|
|
|
6171
6184
|
clients.forEach((client) => {
|
|
6172
6185
|
const stats = statsByView[client.id];
|
|
6173
6186
|
["video", "audio", "global"].forEach((kind) => {
|
|
6174
|
-
var _a, _b;
|
|
6175
|
-
if (!(kind === "global" && !client.isPresentation) && !((_a = client[kind]) === null || _a === void 0 ? void 0 : _a.enabled))
|
|
6176
|
-
return;
|
|
6177
6187
|
if (kind === "global" && !client.isLocalClient)
|
|
6178
6188
|
return;
|
|
6179
6189
|
let issuesAndMetrics = issuesAndMetricsByView[client.id];
|
|
@@ -6181,7 +6191,7 @@ function onUpdatedStats(statsByView, clients) {
|
|
|
6181
6191
|
issuesAndMetrics = { issues: {}, metrics: {} };
|
|
6182
6192
|
issuesAndMetricsByView[client.id] = issuesAndMetrics;
|
|
6183
6193
|
}
|
|
6184
|
-
const track =
|
|
6194
|
+
const track = kind === "audio" || kind === "video" ? client[kind].track : undefined;
|
|
6185
6195
|
const hasLiveTrack = !!track && track.readyState !== "ended";
|
|
6186
6196
|
const trackStats = track && stats && stats.tracks[track.id];
|
|
6187
6197
|
const ssrcs = trackStats
|