@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.cjs
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var mediasoupClient = require('mediasoup-client');
|
|
3
4
|
var adapterRaw = require('webrtc-adapter');
|
|
5
|
+
var EventEmitter = require('events');
|
|
4
6
|
var rtcstats = require('rtcstats');
|
|
5
7
|
var uuid = require('uuid');
|
|
8
|
+
var socket_ioClient = require('socket.io-client');
|
|
6
9
|
var SDPUtils = require('sdp');
|
|
7
10
|
var sdpTransform = require('sdp-transform');
|
|
8
11
|
var ipAddress = require('ip-address');
|
|
9
12
|
var checkIp = require('check-ip');
|
|
10
13
|
var validate = require('uuid-validate');
|
|
11
|
-
var mediasoupClient = require('mediasoup-client');
|
|
12
|
-
var EventEmitter = require('events');
|
|
13
|
-
var socket_ioClient = require('socket.io-client');
|
|
14
14
|
|
|
15
15
|
function _interopNamespaceDefault(e) {
|
|
16
16
|
var n = Object.create(null);
|
|
@@ -31,7 +31,164 @@ function _interopNamespaceDefault(e) {
|
|
|
31
31
|
|
|
32
32
|
var sdpTransform__namespace = /*#__PURE__*/_interopNamespaceDefault(sdpTransform);
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
class AssertionError extends Error {
|
|
35
|
+
constructor(options) {
|
|
36
|
+
super(options.message);
|
|
37
|
+
this.name = "AssertionError";
|
|
38
|
+
this.code = "ERR_ASSERTION";
|
|
39
|
+
this.actual = options.actual;
|
|
40
|
+
this.expected = options.expected;
|
|
41
|
+
this.operator = options.operator;
|
|
42
|
+
if (Error.captureStackTrace) {
|
|
43
|
+
Error.captureStackTrace(this, options.stackStartFn);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function innerOk(fn, argLen, value, message) {
|
|
48
|
+
if (!value) {
|
|
49
|
+
let generatedMessage = false;
|
|
50
|
+
if (argLen === 0) {
|
|
51
|
+
generatedMessage = true;
|
|
52
|
+
message = "No value argument passed to `assert.ok()`";
|
|
53
|
+
}
|
|
54
|
+
else if (message instanceof Error) {
|
|
55
|
+
throw message;
|
|
56
|
+
}
|
|
57
|
+
const err = new AssertionError({
|
|
58
|
+
actual: value,
|
|
59
|
+
expected: true,
|
|
60
|
+
message,
|
|
61
|
+
operator: "==",
|
|
62
|
+
stackStartFn: fn,
|
|
63
|
+
});
|
|
64
|
+
err.generatedMessage = generatedMessage;
|
|
65
|
+
throw err;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function innerFail(obj) {
|
|
69
|
+
if (obj.message instanceof Error)
|
|
70
|
+
throw obj.message;
|
|
71
|
+
throw new AssertionError(obj);
|
|
72
|
+
}
|
|
73
|
+
function ok(...args) {
|
|
74
|
+
innerOk(ok, args.length, ...args);
|
|
75
|
+
}
|
|
76
|
+
const assert = {
|
|
77
|
+
fail: (message) => {
|
|
78
|
+
innerFail({
|
|
79
|
+
actual: "fail()",
|
|
80
|
+
expected: "fail() should not be called",
|
|
81
|
+
message,
|
|
82
|
+
operator: "fail",
|
|
83
|
+
stackStartFn: assert.fail,
|
|
84
|
+
});
|
|
85
|
+
},
|
|
86
|
+
ok,
|
|
87
|
+
};
|
|
88
|
+
assert.notEqual = function notEqual(actual, expected, message) {
|
|
89
|
+
if (arguments.length < 2) {
|
|
90
|
+
throw new Error("'actual' and 'expected' arguments are required");
|
|
91
|
+
}
|
|
92
|
+
if (actual == expected) {
|
|
93
|
+
innerFail({
|
|
94
|
+
actual,
|
|
95
|
+
expected,
|
|
96
|
+
message,
|
|
97
|
+
operator: "!=",
|
|
98
|
+
stackStartFn: notEqual,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
assert.ok = ok;
|
|
103
|
+
|
|
104
|
+
const createWorker = (fn) => {
|
|
105
|
+
return new Worker(URL.createObjectURL(new Blob(["self.onmessage = ", fn.toString()], { type: "text/javascript" })));
|
|
106
|
+
};
|
|
107
|
+
const generateByteString = (count) => {
|
|
108
|
+
if (count === 0) {
|
|
109
|
+
return "";
|
|
110
|
+
}
|
|
111
|
+
const count2 = count / 2;
|
|
112
|
+
let result = "F";
|
|
113
|
+
while (result.length <= count2) {
|
|
114
|
+
result += result;
|
|
115
|
+
}
|
|
116
|
+
return result + result.substring(0, count - result.length);
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/******************************************************************************
|
|
120
|
+
Copyright (c) Microsoft Corporation.
|
|
121
|
+
|
|
122
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
123
|
+
purpose with or without fee is hereby granted.
|
|
124
|
+
|
|
125
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
126
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
127
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
128
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
129
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
130
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
131
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
132
|
+
***************************************************************************** */
|
|
133
|
+
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
137
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
138
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
139
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
140
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
141
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
142
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
147
|
+
var e = new Error(message);
|
|
148
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const getMediasoupDeviceAsync = (features) => __awaiter(void 0, void 0, void 0, function* () {
|
|
152
|
+
if (features.isNodeSdk) {
|
|
153
|
+
return new mediasoupClient.Device({ handlerName: "Safari12" });
|
|
154
|
+
}
|
|
155
|
+
let handlerName = (yield mediasoupClient.detectDeviceAsync()) ||
|
|
156
|
+
(/applecoremedia|applewebkit|safari/i.test(navigator.userAgent) ? "Safari12" : undefined);
|
|
157
|
+
if (/iphone|ipad/i.test(navigator.userAgent)) {
|
|
158
|
+
handlerName = "Safari12";
|
|
159
|
+
}
|
|
160
|
+
return new mediasoupClient.Device({ handlerName });
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const word = "[a-fA-F\\d:]";
|
|
164
|
+
const boundry = (options) => options && options.includeBoundaries ? `(?:(?<=\\s|^)(?=${word})|(?<=${word})(?=\\s|$))` : "";
|
|
165
|
+
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}";
|
|
166
|
+
const v6segment = "[a-fA-F\\d]{1,4}";
|
|
167
|
+
const v6 = `
|
|
168
|
+
(?:
|
|
169
|
+
(?:${v6segment}:){7}(?:${v6segment}|:)| // 1:2:3:4:5:6:7:: 1:2:3:4:5:6:7:8
|
|
170
|
+
(?:${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
|
|
171
|
+
(?:${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
|
|
172
|
+
(?:${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
|
|
173
|
+
(?:${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
|
|
174
|
+
(?:${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
|
|
175
|
+
(?:${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
|
|
176
|
+
(?::(?:(?::${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
|
|
177
|
+
)(?:%[0-9a-zA-Z]{1,})? // %eth0 %1
|
|
178
|
+
`
|
|
179
|
+
.replace(/\s*\/\/.*$/gm, "")
|
|
180
|
+
.replace(/\n/g, "")
|
|
181
|
+
.trim();
|
|
182
|
+
const v46Exact = new RegExp(`(?:^${v4}$)|(?:^${v6}$)`);
|
|
183
|
+
const v4exact = new RegExp(`^${v4}$`);
|
|
184
|
+
const v6exact = new RegExp(`^${v6}$`);
|
|
185
|
+
const ipRegex = (options) => options && options.exact
|
|
186
|
+
? v46Exact
|
|
187
|
+
: new RegExp(`(?:${boundry(options)}${v4}${boundry(options)})|(?:${boundry(options)}${v6}${boundry(options)})`, "g");
|
|
188
|
+
ipRegex.v4 = (options) => options && options.exact ? v4exact : new RegExp(`${boundry(options)}${v4}${boundry(options)}`, "g");
|
|
189
|
+
ipRegex.v6 = (options) => options && options.exact ? v6exact : new RegExp(`${boundry(options)}${v6}${boundry(options)}`, "g");
|
|
190
|
+
|
|
191
|
+
const debugOn = new URLSearchParams(window.location.search).has("debug");
|
|
35
192
|
class Logger {
|
|
36
193
|
constructor() {
|
|
37
194
|
this._isEnabled = false;
|
|
@@ -86,209 +243,195 @@ class Logger {
|
|
|
86
243
|
}
|
|
87
244
|
}
|
|
88
245
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
96
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
97
|
-
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
98
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
99
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
100
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
101
|
-
PERFORMANCE OF THIS SOFTWARE.
|
|
102
|
-
***************************************************************************** */
|
|
103
|
-
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
function __awaiter(thisArg, _arguments, P, generator) {
|
|
107
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
108
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
109
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
110
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
111
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
112
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
117
|
-
var e = new Error(message);
|
|
118
|
-
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
246
|
+
const AUDIO_SETTINGS = {
|
|
247
|
+
codecOptions: {
|
|
248
|
+
opusDtx: true,
|
|
249
|
+
opusFec: true,
|
|
250
|
+
},
|
|
251
|
+
encodings: [{ dtx: true }],
|
|
119
252
|
};
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
253
|
+
const VIDEO_SETTINGS_HD = {
|
|
254
|
+
codecOptions: {
|
|
255
|
+
videoGoogleStartBitrate: 500,
|
|
256
|
+
},
|
|
257
|
+
encodings: [
|
|
258
|
+
{ scaleResolutionDownBy: 4, maxBitrate: 150000 },
|
|
259
|
+
{ scaleResolutionDownBy: 2, maxBitrate: 500000 },
|
|
260
|
+
{ scaleResolutionDownBy: 1, maxBitrate: 1000000 },
|
|
261
|
+
],
|
|
128
262
|
};
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const buffer = [];
|
|
133
|
-
let ws;
|
|
134
|
-
let organizationId;
|
|
135
|
-
let clientId;
|
|
136
|
-
let displayName;
|
|
137
|
-
let userRole;
|
|
138
|
-
let roomSessionId;
|
|
139
|
-
let connectionShouldBeOpen;
|
|
140
|
-
let connectionAttempt = 0;
|
|
141
|
-
let hasPassedOnRoomSessionId = false;
|
|
142
|
-
let getStatsBufferUsed = 0;
|
|
143
|
-
let deviceId;
|
|
144
|
-
let roomProduct;
|
|
145
|
-
let roomMode;
|
|
146
|
-
let sfuServer;
|
|
147
|
-
let featureFlags;
|
|
148
|
-
const connection = {
|
|
149
|
-
connected: false,
|
|
150
|
-
trace: (...args) => {
|
|
151
|
-
args.push(Date.now());
|
|
152
|
-
if (args[0] === "customEvent" && args[2].type === "roomSessionId") {
|
|
153
|
-
const oldRoomSessionIdValue = roomSessionId && roomSessionId[2].value.roomSessionId;
|
|
154
|
-
const newRoomSessionIdValue = args[2].value.roomSessionId;
|
|
155
|
-
roomSessionId = args;
|
|
156
|
-
if (hasPassedOnRoomSessionId &&
|
|
157
|
-
newRoomSessionIdValue &&
|
|
158
|
-
newRoomSessionIdValue !== oldRoomSessionIdValue) {
|
|
159
|
-
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
160
|
-
}
|
|
161
|
-
if (newRoomSessionIdValue)
|
|
162
|
-
hasPassedOnRoomSessionId = true;
|
|
163
|
-
}
|
|
164
|
-
else if (args[0] === "customEvent" && args[2].type === "clientId") {
|
|
165
|
-
clientId = args;
|
|
166
|
-
}
|
|
167
|
-
else if (args[0] === "customEvent" && args[2].type === "organizationId") {
|
|
168
|
-
organizationId = args;
|
|
169
|
-
}
|
|
170
|
-
else if (args[0] === "customEvent" && args[2].type === "displayName") {
|
|
171
|
-
displayName = args;
|
|
172
|
-
}
|
|
173
|
-
else if (args[0] === "customEvent" && args[2].type === "userRole") {
|
|
174
|
-
userRole = args;
|
|
175
|
-
}
|
|
176
|
-
else if (args[0] === "customEvent" && args[2].type === "deviceId") {
|
|
177
|
-
deviceId = args;
|
|
178
|
-
}
|
|
179
|
-
else if (args[0] === "customEvent" && args[2].type === "roomProduct") {
|
|
180
|
-
roomProduct = args;
|
|
181
|
-
}
|
|
182
|
-
else if (args[0] === "customEvent" && args[2].type === "roomMode") {
|
|
183
|
-
roomMode = args;
|
|
184
|
-
}
|
|
185
|
-
else if (args[0] === "customEvent" && args[2].type === "sfuServer") {
|
|
186
|
-
sfuServer = args;
|
|
187
|
-
}
|
|
188
|
-
else if (args[0] === "customEvent" && args[2].type === "featureFlags") {
|
|
189
|
-
featureFlags = args;
|
|
190
|
-
}
|
|
191
|
-
if ((ws === null || ws === void 0 ? void 0 : ws.readyState) === WebSocket.OPEN) {
|
|
192
|
-
connectionAttempt = 0;
|
|
193
|
-
ws.send(JSON.stringify(args));
|
|
194
|
-
}
|
|
195
|
-
else if (args[0] === "getstats") {
|
|
196
|
-
if (getStatsBufferUsed < GETSTATS_BUFFER_SIZE) {
|
|
197
|
-
getStatsBufferUsed++;
|
|
198
|
-
buffer.push(args);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
else if (args[0] === "customEvent" && args[2].type === "insightsStats") ;
|
|
202
|
-
else {
|
|
203
|
-
buffer.push(args);
|
|
204
|
-
}
|
|
205
|
-
if ((ws === null || ws === void 0 ? void 0 : ws.readyState) === WebSocket.CLOSED && connectionShouldBeOpen) {
|
|
206
|
-
setTimeout(() => {
|
|
207
|
-
if (ws.readyState === WebSocket.CLOSED && connectionShouldBeOpen) {
|
|
208
|
-
connection.connect();
|
|
209
|
-
}
|
|
210
|
-
}, 1000 * connectionAttempt);
|
|
211
|
-
}
|
|
212
|
-
},
|
|
213
|
-
close: () => {
|
|
214
|
-
connectionShouldBeOpen = false;
|
|
215
|
-
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
216
|
-
},
|
|
217
|
-
connect: () => {
|
|
218
|
-
connectionShouldBeOpen = true;
|
|
219
|
-
connectionAttempt += 1;
|
|
220
|
-
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
221
|
-
connection.connected = true;
|
|
222
|
-
ws = new WebSocket(wsURL + window.location.pathname, RTCSTATS_PROTOCOL_VERSION);
|
|
223
|
-
ws.onerror = (e) => {
|
|
224
|
-
connection.connected = false;
|
|
225
|
-
logger.warn(`[RTCSTATS] WebSocket error`, e);
|
|
226
|
-
};
|
|
227
|
-
ws.onclose = (e) => {
|
|
228
|
-
connection.connected = false;
|
|
229
|
-
logger.info(`[RTCSTATS] Closed ${e.code}`);
|
|
230
|
-
resetDelta();
|
|
231
|
-
};
|
|
232
|
-
ws.onopen = () => {
|
|
233
|
-
clientInfo.connectionNumber++;
|
|
234
|
-
ws.send(JSON.stringify(["clientInfo", null, clientInfo]));
|
|
235
|
-
if (organizationId) {
|
|
236
|
-
ws.send(JSON.stringify(organizationId));
|
|
237
|
-
}
|
|
238
|
-
if (clientId) {
|
|
239
|
-
ws.send(JSON.stringify(clientId));
|
|
240
|
-
}
|
|
241
|
-
if (roomSessionId) {
|
|
242
|
-
ws.send(JSON.stringify(roomSessionId));
|
|
243
|
-
}
|
|
244
|
-
if (displayName) {
|
|
245
|
-
ws.send(JSON.stringify(displayName));
|
|
246
|
-
}
|
|
247
|
-
if (userRole) {
|
|
248
|
-
ws.send(JSON.stringify(userRole));
|
|
249
|
-
}
|
|
250
|
-
if (deviceId) {
|
|
251
|
-
ws.send(JSON.stringify(deviceId));
|
|
252
|
-
}
|
|
253
|
-
if (roomMode) {
|
|
254
|
-
ws.send(JSON.stringify(roomMode));
|
|
255
|
-
}
|
|
256
|
-
if (roomProduct) {
|
|
257
|
-
ws.send(JSON.stringify(roomProduct));
|
|
258
|
-
}
|
|
259
|
-
if (sfuServer) {
|
|
260
|
-
ws.send(JSON.stringify(sfuServer));
|
|
261
|
-
}
|
|
262
|
-
if (featureFlags) {
|
|
263
|
-
ws.send(JSON.stringify(featureFlags));
|
|
264
|
-
}
|
|
265
|
-
while (buffer.length) {
|
|
266
|
-
ws.send(JSON.stringify(buffer.shift()));
|
|
267
|
-
}
|
|
268
|
-
getStatsBufferUsed = 0;
|
|
269
|
-
};
|
|
270
|
-
},
|
|
271
|
-
};
|
|
272
|
-
return connection;
|
|
273
|
-
}
|
|
274
|
-
const server = rtcStatsConnection(process.env.RTCSTATS_URL || "wss://rtcstats.srv.whereby.com");
|
|
275
|
-
const stats = rtcstats(server.trace, 10000, [""]);
|
|
276
|
-
resetDelta = (stats === null || stats === void 0 ? void 0 : stats.resetDelta) || noop;
|
|
277
|
-
const rtcStats = {
|
|
278
|
-
sendEvent: (type, value) => {
|
|
279
|
-
server.trace("customEvent", null, {
|
|
280
|
-
type,
|
|
281
|
-
value,
|
|
282
|
-
});
|
|
263
|
+
const VIDEO_SETTINGS_SD = {
|
|
264
|
+
codecOptions: {
|
|
265
|
+
videoGoogleStartBitrate: 500,
|
|
283
266
|
},
|
|
284
|
-
|
|
285
|
-
|
|
267
|
+
encodings: [
|
|
268
|
+
{ scaleResolutionDownBy: 2, maxBitrate: 150000 },
|
|
269
|
+
{ scaleResolutionDownBy: 1, maxBitrate: 500000 },
|
|
270
|
+
],
|
|
271
|
+
};
|
|
272
|
+
const VIDEO_SETTINGS_VP9 = {
|
|
273
|
+
codecOptions: {
|
|
274
|
+
videoGoogleStartBitrate: 500,
|
|
286
275
|
},
|
|
287
|
-
|
|
288
|
-
|
|
276
|
+
encodings: [{ scalabilityMode: "L3T2", maxBitrate: 1000000 }],
|
|
277
|
+
};
|
|
278
|
+
const VIDEO_SETTINGS_VP9_LOW_BANDWIDTH = {
|
|
279
|
+
codecOptions: {
|
|
280
|
+
videoGoogleStartBitrate: 500,
|
|
289
281
|
},
|
|
290
|
-
|
|
282
|
+
encodings: [{ scalabilityMode: "L2T2", maxBitrate: 500000 }],
|
|
283
|
+
};
|
|
284
|
+
const SCREEN_SHARE_SETTINGS = {
|
|
285
|
+
encodings: [{}],
|
|
286
|
+
};
|
|
287
|
+
const SCREEN_SHARE_SIMULCAST_SETTINGS = {
|
|
288
|
+
encodings: [
|
|
289
|
+
{ scaleResolutionDownBy: 2, dtx: true, maxBitrate: 500000 },
|
|
290
|
+
{ scaleResolutionDownBy: 1, dtx: true, maxBitrate: 1500000 },
|
|
291
|
+
],
|
|
292
|
+
};
|
|
293
|
+
const ADDITIONAL_SCREEN_SHARE_SETTINGS = {
|
|
294
|
+
encodings: [
|
|
295
|
+
{ scaleResolutionDownBy: 4, dtx: true, maxBitrate: 150000 },
|
|
296
|
+
{ scaleResolutionDownBy: 2, dtx: true, maxBitrate: 500000 },
|
|
297
|
+
{ scaleResolutionDownBy: 1, dtx: true, maxBitrate: 1500000 },
|
|
298
|
+
],
|
|
299
|
+
};
|
|
300
|
+
const getMediaSettings = (kind, isScreenShare, features, isSomeoneAlreadyPresenting = false) => {
|
|
301
|
+
const { lowDataModeEnabled, simulcastScreenshareOn, vp9On } = features;
|
|
302
|
+
if (kind === "audio") {
|
|
303
|
+
return AUDIO_SETTINGS;
|
|
304
|
+
}
|
|
305
|
+
const isChrome = adapterRaw.browserDetails.browser === "chrome";
|
|
306
|
+
const isVp9Available = isChrome && vp9On;
|
|
307
|
+
if (isScreenShare) {
|
|
308
|
+
return getScreenShareMediaSettings({
|
|
309
|
+
isSomeoneAlreadyPresenting,
|
|
310
|
+
simulcastScreenshareOn,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
return getCameraMediaSettings({
|
|
315
|
+
lowBandwidth: lowDataModeEnabled,
|
|
316
|
+
isVp9Available,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
const getCameraMediaSettings = ({ lowBandwidth, isVp9Available, }) => {
|
|
321
|
+
if (lowBandwidth) {
|
|
322
|
+
if (isVp9Available) {
|
|
323
|
+
return VIDEO_SETTINGS_VP9_LOW_BANDWIDTH;
|
|
324
|
+
}
|
|
325
|
+
return VIDEO_SETTINGS_SD;
|
|
326
|
+
}
|
|
327
|
+
if (isVp9Available) {
|
|
328
|
+
return VIDEO_SETTINGS_VP9;
|
|
329
|
+
}
|
|
330
|
+
return VIDEO_SETTINGS_HD;
|
|
331
|
+
};
|
|
332
|
+
const getScreenShareMediaSettings = ({ isSomeoneAlreadyPresenting, simulcastScreenshareOn, }) => {
|
|
333
|
+
if (isSomeoneAlreadyPresenting) {
|
|
334
|
+
return ADDITIONAL_SCREEN_SHARE_SETTINGS;
|
|
335
|
+
}
|
|
336
|
+
if (simulcastScreenshareOn)
|
|
337
|
+
return SCREEN_SHARE_SIMULCAST_SETTINGS;
|
|
338
|
+
return SCREEN_SHARE_SETTINGS;
|
|
339
|
+
};
|
|
340
|
+
var PrioritizableCodec;
|
|
341
|
+
(function (PrioritizableCodec) {
|
|
342
|
+
PrioritizableCodec["H264"] = "video/h264";
|
|
343
|
+
PrioritizableCodec["VP9"] = "video/vp9";
|
|
344
|
+
})(PrioritizableCodec || (PrioritizableCodec = {}));
|
|
345
|
+
const modifyMediaCapabilities = (routerRtpCapabilities, features) => {
|
|
346
|
+
const { vp9On, h264On } = features;
|
|
347
|
+
const isChrome = adapterRaw.browserDetails.browser === "chrome";
|
|
348
|
+
if (!(routerRtpCapabilities === null || routerRtpCapabilities === void 0 ? void 0 : routerRtpCapabilities.codecs)) {
|
|
349
|
+
return routerRtpCapabilities;
|
|
350
|
+
}
|
|
351
|
+
if (vp9On && isChrome) {
|
|
352
|
+
const sorted = prioritizeRouterRtpCapabilitiesCodecs(routerRtpCapabilities.codecs, PrioritizableCodec.VP9);
|
|
353
|
+
return Object.assign(Object.assign({}, routerRtpCapabilities), { codecs: sorted });
|
|
354
|
+
}
|
|
355
|
+
else if (h264On) {
|
|
356
|
+
const sorted = prioritizeRouterRtpCapabilitiesCodecs(routerRtpCapabilities.codecs, PrioritizableCodec.H264);
|
|
357
|
+
return Object.assign(Object.assign({}, routerRtpCapabilities), { codecs: sorted });
|
|
358
|
+
}
|
|
359
|
+
return routerRtpCapabilities;
|
|
291
360
|
};
|
|
361
|
+
function prioritizeRouterRtpCapabilitiesCodecs(codecs, preferredCodec) {
|
|
362
|
+
const preferredCodecEntry = codecs.find(({ mimeType }) => mimeType.toLowerCase() === preferredCodec);
|
|
363
|
+
if (!preferredCodecEntry) {
|
|
364
|
+
return codecs;
|
|
365
|
+
}
|
|
366
|
+
return [...codecs].sort((left, right) => {
|
|
367
|
+
var _a;
|
|
368
|
+
if (left.mimeType.toLowerCase() === preferredCodec) {
|
|
369
|
+
return -1;
|
|
370
|
+
}
|
|
371
|
+
if (left.mimeType.toLowerCase() === "video/rtx" &&
|
|
372
|
+
((_a = left.parameters) === null || _a === void 0 ? void 0 : _a.apt) === preferredCodecEntry.preferredPayloadType) {
|
|
373
|
+
if (right.mimeType.toLowerCase() === preferredCodec) {
|
|
374
|
+
return 1;
|
|
375
|
+
}
|
|
376
|
+
return -1;
|
|
377
|
+
}
|
|
378
|
+
return 0;
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
function getPreferredOrder(availableCodecs, { av1On }) {
|
|
382
|
+
availableCodecs.unshift("video/vp9");
|
|
383
|
+
if (av1On) {
|
|
384
|
+
availableCodecs.unshift("video/av1");
|
|
385
|
+
}
|
|
386
|
+
return availableCodecs;
|
|
387
|
+
}
|
|
388
|
+
function sortCodecsByMimeType(codecs, features) {
|
|
389
|
+
const availableCodecs = codecs
|
|
390
|
+
.map(({ mimeType }) => mimeType)
|
|
391
|
+
.filter((value, index, array) => array.indexOf(value) === index);
|
|
392
|
+
const preferredOrder = getPreferredOrder(availableCodecs, features);
|
|
393
|
+
return codecs.sort((a, b) => {
|
|
394
|
+
const indexA = preferredOrder.indexOf(a.mimeType.toLowerCase());
|
|
395
|
+
const indexB = preferredOrder.indexOf(b.mimeType.toLowerCase());
|
|
396
|
+
const orderA = indexA >= 0 ? indexA : Number.MAX_VALUE;
|
|
397
|
+
const orderB = indexB >= 0 ? indexB : Number.MAX_VALUE;
|
|
398
|
+
return orderA - orderB;
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
function getIsCodecDecodingPowerEfficient(codec) {
|
|
402
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
403
|
+
const { powerEfficient } = yield navigator.mediaCapabilities.decodingInfo({
|
|
404
|
+
type: "webrtc",
|
|
405
|
+
video: {
|
|
406
|
+
width: 1280,
|
|
407
|
+
height: 720,
|
|
408
|
+
bitrate: 2580,
|
|
409
|
+
framerate: 24,
|
|
410
|
+
contentType: codec,
|
|
411
|
+
},
|
|
412
|
+
});
|
|
413
|
+
return powerEfficient;
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
function sortCodecsByPowerEfficiency(codecs) {
|
|
417
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
418
|
+
const codecPowerEfficiencyEntries = yield Promise.all(codecs.map(({ mimeType }) => getIsCodecDecodingPowerEfficient(mimeType).then((val) => [mimeType, val])));
|
|
419
|
+
const codecPowerEfficiencies = Object.fromEntries(codecPowerEfficiencyEntries);
|
|
420
|
+
const sorted = codecs.sort((a, b) => {
|
|
421
|
+
const aPowerEfficient = codecPowerEfficiencies[a.mimeType];
|
|
422
|
+
const bPowerEfficient = codecPowerEfficiencies[b.mimeType];
|
|
423
|
+
return aPowerEfficient === bPowerEfficient ? 0 : aPowerEfficient ? -1 : 1;
|
|
424
|
+
});
|
|
425
|
+
return sorted;
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
function sortCodecs(codecs, features) {
|
|
429
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
430
|
+
let sortedCodecs = sortCodecsByMimeType(codecs, features);
|
|
431
|
+
sortedCodecs = yield sortCodecsByPowerEfficiency(codecs);
|
|
432
|
+
return sortedCodecs;
|
|
433
|
+
});
|
|
434
|
+
}
|
|
292
435
|
|
|
293
436
|
function captureCandidatePairInfoMetrics(cpMetrics, currentCptats, prevCptats, timeDiff, report) {
|
|
294
437
|
const bytesReceivedDiff = currentCptats.bytesReceived - ((prevCptats === null || prevCptats === void 0 ? void 0 : prevCptats.bytesReceived) || 0);
|
|
@@ -307,7 +450,7 @@ function captureCandidatePairInfoMetrics(cpMetrics, currentCptats, prevCptats, t
|
|
|
307
450
|
const local = report.get(currentCptats.localCandidateId);
|
|
308
451
|
cpMetrics.usingTurn = false;
|
|
309
452
|
if (local) {
|
|
310
|
-
if (/relay/i.test(local.candidateType ||
|
|
453
|
+
if (/relay/i.test(local.candidateType || "")) {
|
|
311
454
|
cpMetrics.usingTurn = true;
|
|
312
455
|
cpMetrics.turnProtocol = local.relayProtocol;
|
|
313
456
|
}
|
|
@@ -464,6 +607,179 @@ function captureVideoSsrcMetrics(ssrcMetrics, currentSsrcStats, prevSsrcStats, t
|
|
|
464
607
|
}
|
|
465
608
|
}
|
|
466
609
|
|
|
610
|
+
var _a$7;
|
|
611
|
+
(_a$7 = adapterRaw.default) !== null && _a$7 !== void 0 ? _a$7 : adapterRaw;
|
|
612
|
+
const RTCSTATS_PROTOCOL_VERSION = "1.0";
|
|
613
|
+
const GETSTATS_BUFFER_SIZE = 20;
|
|
614
|
+
const clientInfo = {
|
|
615
|
+
id: uuid.v4(),
|
|
616
|
+
connectionNumber: 0,
|
|
617
|
+
};
|
|
618
|
+
const noop = () => { };
|
|
619
|
+
let resetDelta = noop;
|
|
620
|
+
function rtcStatsConnection(wsURL, logger = console) {
|
|
621
|
+
const buffer = [];
|
|
622
|
+
let ws;
|
|
623
|
+
let organizationId;
|
|
624
|
+
let clientId;
|
|
625
|
+
let displayName;
|
|
626
|
+
let userRole;
|
|
627
|
+
let roomSessionId;
|
|
628
|
+
let connectionShouldBeOpen;
|
|
629
|
+
let connectionAttempt = 0;
|
|
630
|
+
let hasPassedOnRoomSessionId = false;
|
|
631
|
+
let getStatsBufferUsed = 0;
|
|
632
|
+
let deviceId;
|
|
633
|
+
let roomProduct;
|
|
634
|
+
let roomMode;
|
|
635
|
+
let sfuServer;
|
|
636
|
+
let featureFlags;
|
|
637
|
+
const connection = {
|
|
638
|
+
connected: false,
|
|
639
|
+
trace: (...args) => {
|
|
640
|
+
args.push(Date.now());
|
|
641
|
+
if (args[0] === "customEvent" && args[2].type === "roomSessionId") {
|
|
642
|
+
const oldRoomSessionIdValue = roomSessionId && roomSessionId[2].value.roomSessionId;
|
|
643
|
+
const newRoomSessionIdValue = args[2].value.roomSessionId;
|
|
644
|
+
roomSessionId = args;
|
|
645
|
+
if (hasPassedOnRoomSessionId &&
|
|
646
|
+
newRoomSessionIdValue &&
|
|
647
|
+
newRoomSessionIdValue !== oldRoomSessionIdValue) {
|
|
648
|
+
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
649
|
+
}
|
|
650
|
+
if (newRoomSessionIdValue)
|
|
651
|
+
hasPassedOnRoomSessionId = true;
|
|
652
|
+
}
|
|
653
|
+
else if (args[0] === "customEvent" && args[2].type === "clientId") {
|
|
654
|
+
clientId = args;
|
|
655
|
+
}
|
|
656
|
+
else if (args[0] === "customEvent" && args[2].type === "organizationId") {
|
|
657
|
+
organizationId = args;
|
|
658
|
+
}
|
|
659
|
+
else if (args[0] === "customEvent" && args[2].type === "displayName") {
|
|
660
|
+
displayName = args;
|
|
661
|
+
}
|
|
662
|
+
else if (args[0] === "customEvent" && args[2].type === "userRole") {
|
|
663
|
+
userRole = args;
|
|
664
|
+
}
|
|
665
|
+
else if (args[0] === "customEvent" && args[2].type === "deviceId") {
|
|
666
|
+
deviceId = args;
|
|
667
|
+
}
|
|
668
|
+
else if (args[0] === "customEvent" && args[2].type === "roomProduct") {
|
|
669
|
+
roomProduct = args;
|
|
670
|
+
}
|
|
671
|
+
else if (args[0] === "customEvent" && args[2].type === "roomMode") {
|
|
672
|
+
roomMode = args;
|
|
673
|
+
}
|
|
674
|
+
else if (args[0] === "customEvent" && args[2].type === "sfuServer") {
|
|
675
|
+
sfuServer = args;
|
|
676
|
+
}
|
|
677
|
+
else if (args[0] === "customEvent" && args[2].type === "featureFlags") {
|
|
678
|
+
featureFlags = args;
|
|
679
|
+
}
|
|
680
|
+
if ((ws === null || ws === void 0 ? void 0 : ws.readyState) === WebSocket.OPEN) {
|
|
681
|
+
connectionAttempt = 0;
|
|
682
|
+
ws.send(JSON.stringify(args));
|
|
683
|
+
}
|
|
684
|
+
else if (args[0] === "getstats") {
|
|
685
|
+
if (getStatsBufferUsed < GETSTATS_BUFFER_SIZE) {
|
|
686
|
+
getStatsBufferUsed++;
|
|
687
|
+
buffer.push(args);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
else if (args[0] === "customEvent" && args[2].type === "insightsStats") ;
|
|
691
|
+
else {
|
|
692
|
+
buffer.push(args);
|
|
693
|
+
}
|
|
694
|
+
if ((ws === null || ws === void 0 ? void 0 : ws.readyState) === WebSocket.CLOSED && connectionShouldBeOpen) {
|
|
695
|
+
setTimeout(() => {
|
|
696
|
+
if (ws.readyState === WebSocket.CLOSED && connectionShouldBeOpen) {
|
|
697
|
+
connection.connect();
|
|
698
|
+
}
|
|
699
|
+
}, 1000 * connectionAttempt);
|
|
700
|
+
}
|
|
701
|
+
},
|
|
702
|
+
close: () => {
|
|
703
|
+
connectionShouldBeOpen = false;
|
|
704
|
+
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
705
|
+
},
|
|
706
|
+
connect: () => {
|
|
707
|
+
connectionShouldBeOpen = true;
|
|
708
|
+
connectionAttempt += 1;
|
|
709
|
+
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
710
|
+
connection.connected = true;
|
|
711
|
+
ws = new WebSocket(wsURL + window.location.pathname, RTCSTATS_PROTOCOL_VERSION);
|
|
712
|
+
ws.onerror = (e) => {
|
|
713
|
+
connection.connected = false;
|
|
714
|
+
logger.warn(`[RTCSTATS] WebSocket error`, e);
|
|
715
|
+
};
|
|
716
|
+
ws.onclose = (e) => {
|
|
717
|
+
connection.connected = false;
|
|
718
|
+
logger.info(`[RTCSTATS] Closed ${e.code}`);
|
|
719
|
+
resetDelta();
|
|
720
|
+
};
|
|
721
|
+
ws.onopen = () => {
|
|
722
|
+
clientInfo.connectionNumber++;
|
|
723
|
+
ws.send(JSON.stringify(["clientInfo", null, clientInfo]));
|
|
724
|
+
if (organizationId) {
|
|
725
|
+
ws.send(JSON.stringify(organizationId));
|
|
726
|
+
}
|
|
727
|
+
if (clientId) {
|
|
728
|
+
ws.send(JSON.stringify(clientId));
|
|
729
|
+
}
|
|
730
|
+
if (roomSessionId) {
|
|
731
|
+
ws.send(JSON.stringify(roomSessionId));
|
|
732
|
+
}
|
|
733
|
+
if (displayName) {
|
|
734
|
+
ws.send(JSON.stringify(displayName));
|
|
735
|
+
}
|
|
736
|
+
if (userRole) {
|
|
737
|
+
ws.send(JSON.stringify(userRole));
|
|
738
|
+
}
|
|
739
|
+
if (deviceId) {
|
|
740
|
+
ws.send(JSON.stringify(deviceId));
|
|
741
|
+
}
|
|
742
|
+
if (roomMode) {
|
|
743
|
+
ws.send(JSON.stringify(roomMode));
|
|
744
|
+
}
|
|
745
|
+
if (roomProduct) {
|
|
746
|
+
ws.send(JSON.stringify(roomProduct));
|
|
747
|
+
}
|
|
748
|
+
if (sfuServer) {
|
|
749
|
+
ws.send(JSON.stringify(sfuServer));
|
|
750
|
+
}
|
|
751
|
+
if (featureFlags) {
|
|
752
|
+
ws.send(JSON.stringify(featureFlags));
|
|
753
|
+
}
|
|
754
|
+
while (buffer.length) {
|
|
755
|
+
ws.send(JSON.stringify(buffer.shift()));
|
|
756
|
+
}
|
|
757
|
+
getStatsBufferUsed = 0;
|
|
758
|
+
};
|
|
759
|
+
},
|
|
760
|
+
};
|
|
761
|
+
return connection;
|
|
762
|
+
}
|
|
763
|
+
const RTCSTATS_URL = "wss://rtcstats.srv.whereby.com";
|
|
764
|
+
const server = rtcStatsConnection(RTCSTATS_URL);
|
|
765
|
+
const stats = rtcstats(server.trace, 10000, [""]);
|
|
766
|
+
resetDelta = (stats === null || stats === void 0 ? void 0 : stats.resetDelta) || noop;
|
|
767
|
+
const rtcStats = {
|
|
768
|
+
sendEvent: (type, value) => {
|
|
769
|
+
server.trace("customEvent", null, {
|
|
770
|
+
type,
|
|
771
|
+
value,
|
|
772
|
+
});
|
|
773
|
+
},
|
|
774
|
+
sendAudioMuted: (muted) => {
|
|
775
|
+
rtcStats.sendEvent("audio_muted", { muted });
|
|
776
|
+
},
|
|
777
|
+
sendVideoMuted: (muted) => {
|
|
778
|
+
rtcStats.sendEvent("video_muted", { muted });
|
|
779
|
+
},
|
|
780
|
+
server,
|
|
781
|
+
};
|
|
782
|
+
|
|
467
783
|
let peerConnections = [];
|
|
468
784
|
let peerConnectionCounter = 0;
|
|
469
785
|
const peerConnectionData = new WeakMap();
|
|
@@ -492,10 +808,10 @@ const getCurrentPeerConnections = () => peerConnections;
|
|
|
492
808
|
const getPeerConnectionIndex = (pc) => { var _a; return (_a = peerConnectionData.get(pc)) === null || _a === void 0 ? void 0 : _a.index; };
|
|
493
809
|
const setPeerConnectionsForTests = (pcs) => (peerConnections = pcs);
|
|
494
810
|
|
|
495
|
-
const
|
|
811
|
+
const PC_DATA_BY_PC = new WeakMap();
|
|
496
812
|
let numMissingTrackSsrcLookups = 0;
|
|
497
813
|
let numFailedTrackSsrcLookups = 0;
|
|
498
|
-
const getPeerConnectionsWithStatsReports = () => Promise.all(getCurrentPeerConnections().map((pc) => __awaiter(void 0, void 0, void 0, function* () {
|
|
814
|
+
const getPeerConnectionsWithStatsReports = (pcDataByPc = PC_DATA_BY_PC) => Promise.all(getCurrentPeerConnections().map((pc) => __awaiter(void 0, void 0, void 0, function* () {
|
|
499
815
|
let pcData = pcDataByPc.get(pc);
|
|
500
816
|
if (!pcData) {
|
|
501
817
|
pcData = { ssrcToTrackId: {} };
|
|
@@ -564,7 +880,7 @@ const getPeerConnectionsWithStatsReports = () => Promise.all(getCurrentPeerConne
|
|
|
564
880
|
const getOrCreateSsrcMetricsContainer = (statsByView, time, pcIndex, clientId, trackId, ssrc) => {
|
|
565
881
|
let viewStats = statsByView[clientId];
|
|
566
882
|
if (!viewStats) {
|
|
567
|
-
viewStats = { tracks: {}, startTime: time, updated: time };
|
|
883
|
+
viewStats = { candidatePairs: {}, tracks: {}, startTime: time, updated: time };
|
|
568
884
|
statsByView[clientId] = viewStats;
|
|
569
885
|
}
|
|
570
886
|
viewStats.updated = time;
|
|
@@ -588,7 +904,7 @@ const getOrCreateSsrcMetricsContainer = (statsByView, time, pcIndex, clientId, t
|
|
|
588
904
|
};
|
|
589
905
|
const removeNonUpdatedStats = (statsByView, time) => {
|
|
590
906
|
Object.entries(statsByView).forEach(([viewId, viewStats]) => {
|
|
591
|
-
if (viewStats.updated < time) {
|
|
907
|
+
if (viewStats.updated !== undefined && viewStats.updated < time) {
|
|
592
908
|
delete statsByView[viewId];
|
|
593
909
|
}
|
|
594
910
|
else {
|
|
@@ -607,12 +923,21 @@ const removeNonUpdatedStats = (statsByView, time) => {
|
|
|
607
923
|
}
|
|
608
924
|
});
|
|
609
925
|
};
|
|
926
|
+
const DEFAULT_CLIENT = {
|
|
927
|
+
id: "unknown",
|
|
928
|
+
clientId: "unknown",
|
|
929
|
+
audio: { enabled: false, track: undefined },
|
|
930
|
+
video: { enabled: false, track: undefined },
|
|
931
|
+
isAudioOnlyModeEnabled: false,
|
|
932
|
+
isLocalClient: true,
|
|
933
|
+
isPresentation: false,
|
|
934
|
+
};
|
|
610
935
|
function collectStats(state_1, _a, immediate_1) {
|
|
611
936
|
return __awaiter(this, arguments, void 0, function* (state, { logger, interval }, immediate) {
|
|
612
937
|
const collectStatsBound = collectStats.bind(null, state, { interval, logger });
|
|
613
938
|
try {
|
|
614
939
|
const clients = state.getClients();
|
|
615
|
-
const defaultClient = clients.find((c) => c.isLocalClient && !c.isPresentation) ||
|
|
940
|
+
const defaultClient = clients.find((c) => c.isLocalClient && !c.isPresentation) || DEFAULT_CLIENT;
|
|
616
941
|
let defaultViewStats = state.statsByView[defaultClient.id];
|
|
617
942
|
if (!defaultViewStats) {
|
|
618
943
|
defaultViewStats = { tracks: {}, candidatePairs: {}, pressure: null };
|
|
@@ -630,6 +955,9 @@ function collectStats(state_1, _a, immediate_1) {
|
|
|
630
955
|
state.lastUpdateTime = Date.now();
|
|
631
956
|
(yield getPeerConnectionsWithStatsReports()).forEach(([pc, report, pcData]) => {
|
|
632
957
|
const pcIndex = getPeerConnectionIndex(pc);
|
|
958
|
+
if (pcIndex === undefined) {
|
|
959
|
+
logger.warn("Could not find index for PeerConnection");
|
|
960
|
+
}
|
|
633
961
|
if (pc.connectionState === "closed") {
|
|
634
962
|
report = new Map();
|
|
635
963
|
removePeerConnection(pc);
|
|
@@ -637,7 +965,7 @@ function collectStats(state_1, _a, immediate_1) {
|
|
|
637
965
|
pcData.previousSSRCs = pcData.currentSSRCs || {};
|
|
638
966
|
pcData.currentSSRCs = {};
|
|
639
967
|
report.forEach((currentRtcStats) => {
|
|
640
|
-
var _a, _b
|
|
968
|
+
var _a, _b;
|
|
641
969
|
if (currentRtcStats.type === "candidate-pair" && /inprogress|succeeded/.test(currentRtcStats.state)) {
|
|
642
970
|
const prevRtcStats = (_a = pcData._oldReport) === null || _a === void 0 ? void 0 : _a.get(currentRtcStats.id);
|
|
643
971
|
const timeDiff = prevRtcStats ? currentRtcStats.timestamp - prevRtcStats.timestamp : interval;
|
|
@@ -651,7 +979,7 @@ function collectStats(state_1, _a, immediate_1) {
|
|
|
651
979
|
cpMetrics.lastRtcStatsTime = state.lastUpdateTime;
|
|
652
980
|
}
|
|
653
981
|
if (currentRtcStats.type === "inbound-rtp" || currentRtcStats.type === "outbound-rtp") {
|
|
654
|
-
const kind = currentRtcStats.mediaType || currentRtcStats.kind;
|
|
982
|
+
const kind = (currentRtcStats.mediaType || currentRtcStats.kind);
|
|
655
983
|
const ssrc = currentRtcStats.ssrc;
|
|
656
984
|
let trackId = currentRtcStats.trackIdentifier || pcData.ssrcToTrackId[ssrc];
|
|
657
985
|
let prevRtcStats = (_b = pcData._oldReport) === null || _b === void 0 ? void 0 : _b.get(currentRtcStats.id);
|
|
@@ -663,12 +991,13 @@ function collectStats(state_1, _a, immediate_1) {
|
|
|
663
991
|
}
|
|
664
992
|
}
|
|
665
993
|
const client = clients.find((c) => { var _a; return ((_a = c[kind].track) === null || _a === void 0 ? void 0 : _a.id) === trackId; }) || defaultClient;
|
|
994
|
+
const clientTrack = client[kind].track;
|
|
666
995
|
if (!currentRtcStats.trackIdentifier &&
|
|
667
996
|
pcData.ssrcToTrackId[ssrc] &&
|
|
668
|
-
(
|
|
669
|
-
|
|
670
|
-
trackId =
|
|
671
|
-
pcData.ssrcToTrackId[ssrc] =
|
|
997
|
+
(clientTrack === null || clientTrack === void 0 ? void 0 : clientTrack.id) &&
|
|
998
|
+
clientTrack.id !== pcData.ssrcToTrackId[ssrc]) {
|
|
999
|
+
trackId = clientTrack.id;
|
|
1000
|
+
pcData.ssrcToTrackId[ssrc] = clientTrack.id;
|
|
672
1001
|
}
|
|
673
1002
|
pcData.currentSSRCs[ssrc] = client.id;
|
|
674
1003
|
if (prevRtcStats) {
|
|
@@ -829,8 +1158,7 @@ function startStatsMonitor(state, { interval, logger }) {
|
|
|
829
1158
|
},
|
|
830
1159
|
stop: () => {
|
|
831
1160
|
clearTimeout(state.nextTimeout);
|
|
832
|
-
|
|
833
|
-
cpuObserver.stop();
|
|
1161
|
+
cpuObserver === null || cpuObserver === void 0 ? void 0 : cpuObserver.stop();
|
|
834
1162
|
},
|
|
835
1163
|
};
|
|
836
1164
|
}
|
|
@@ -850,1598 +1178,1391 @@ function subscribeStats(subscription, options = OPTIONS, state = STATE) {
|
|
|
850
1178
|
};
|
|
851
1179
|
}
|
|
852
1180
|
|
|
853
|
-
|
|
854
|
-
|
|
1181
|
+
const PROTOCOL_REQUESTS = {
|
|
1182
|
+
BLOCK_CLIENT: "block_client",
|
|
1183
|
+
CLAIM_ROOM: "claim_room",
|
|
1184
|
+
CLEAR_CHAT_HISTORY: "clear_chat_history",
|
|
1185
|
+
ENABLE_AUDIO: "enable_audio",
|
|
1186
|
+
ENABLE_VIDEO: "enable_video",
|
|
1187
|
+
END_STREAM: "end_stream",
|
|
1188
|
+
FETCH_MEDIASERVER_CONFIG: "fetch_mediaserver_config",
|
|
1189
|
+
HANDLE_KNOCK: "handle_knock",
|
|
1190
|
+
IDENTIFY_DEVICE: "identify_device",
|
|
1191
|
+
INVITE_CLIENT_AS_MEMBER: "invite_client_as_member",
|
|
1192
|
+
JOIN_ROOM: "join_room",
|
|
1193
|
+
KICK_CLIENT: "kick_client",
|
|
1194
|
+
KNOCK_ROOM: "knock_room",
|
|
1195
|
+
LEAVE_ROOM: "leave_room",
|
|
1196
|
+
SEND_CLIENT_METADATA: "send_client_metadata",
|
|
1197
|
+
SET_LOCK: "set_lock",
|
|
1198
|
+
SHARE_MEDIA: "share_media",
|
|
1199
|
+
START_NEW_STREAM: "start_new_stream",
|
|
1200
|
+
START_SCREENSHARE: "start_screenshare",
|
|
1201
|
+
STOP_SCREENSHARE: "stop_screenshare",
|
|
1202
|
+
START_URL_EMBED: "start_url_embed",
|
|
1203
|
+
STOP_URL_EMBED: "stop_url_embed",
|
|
1204
|
+
START_RECORDING: "start_recording",
|
|
1205
|
+
STOP_RECORDING: "stop_recording",
|
|
1206
|
+
};
|
|
1207
|
+
const PROTOCOL_RESPONSES = {
|
|
1208
|
+
AUDIO_ENABLED: "audio_enabled",
|
|
1209
|
+
BACKGROUND_IMAGE_CHANGED: "background_image_changed",
|
|
1210
|
+
BLOCK_ADDED: "block_added",
|
|
1211
|
+
BLOCK_REMOVED: "block_removed",
|
|
1212
|
+
CHAT_HISTORY_CLEARED: "chat_history_cleared",
|
|
1213
|
+
CLIENT_BLOCKED: "client_blocked",
|
|
1214
|
+
CLIENT_INVITED_AS_MEMBER: "client_invited_as_member",
|
|
1215
|
+
CLIENT_KICKED: "client_kicked",
|
|
1216
|
+
CLIENT_LEFT: "client_left",
|
|
1217
|
+
CLIENT_METADATA_RECEIVED: "client_metadata_received",
|
|
1218
|
+
CLIENT_READY: "client_ready",
|
|
1219
|
+
CLIENT_ROLE_CHANGED: "client_role_changed",
|
|
1220
|
+
CLIENT_USER_ID_CHANGED: "client_user_id_changed",
|
|
1221
|
+
CONTACTS_UPDATED: "contacts_updated",
|
|
1222
|
+
DEVICE_IDENTIFIED: "device_identified",
|
|
1223
|
+
ROOM_ROLES_UPDATED: "room_roles_updated",
|
|
1224
|
+
KNOCK_HANDLED: "knock_handled",
|
|
1225
|
+
KNOCK_PAGE_BACKGROUND_CHANGED: "knock_page_background_changed",
|
|
1226
|
+
KNOCKER_LEFT: "knocker_left",
|
|
1227
|
+
MEDIASERVER_CONFIG: "mediaserver_config",
|
|
1228
|
+
MEDIA_SHARED: "media_shared",
|
|
1229
|
+
MEMBER_INVITE: "member_invite",
|
|
1230
|
+
NEW_CLIENT: "new_client",
|
|
1231
|
+
NEW_STREAM_STARTED: "new_stream_started",
|
|
1232
|
+
SCREENSHARE_STARTED: "screenshare_started",
|
|
1233
|
+
SCREENSHARE_STOPPED: "screenshare_stopped",
|
|
1234
|
+
OWNER_NOTIFIED: "owner_notified",
|
|
1235
|
+
OWNERS_CHANGED: "owners_changed",
|
|
1236
|
+
PLAY_CLIENT_STICKER: "play_client_sticker",
|
|
1237
|
+
ROOM_INTEGRATION_ENABLED: "room_integration_enabled",
|
|
1238
|
+
ROOM_INTEGRATION_DISABLED: "room_integration_disabled",
|
|
1239
|
+
ROOM_JOINED: "room_joined",
|
|
1240
|
+
ROOM_KNOCKED: "room_knocked",
|
|
1241
|
+
ROOM_LEFT: "room_left",
|
|
1242
|
+
ROOM_LOCKED: "room_locked",
|
|
1243
|
+
ROOM_PERMISSIONS_CHANGED: "room_permissions_changed",
|
|
1244
|
+
ROOM_LOGO_CHANGED: "room_logo_changed",
|
|
1245
|
+
ROOM_TYPE_CHANGED: "room_type_changed",
|
|
1246
|
+
ROOM_MODE_CHANGED: "room_mode_changed",
|
|
1247
|
+
SOCKET_USER_ID_CHANGED: "socket_user_id_changed",
|
|
1248
|
+
STICKERS_UNLOCKED: "stickers_unlocked",
|
|
1249
|
+
STREAM_ENDED: "stream_ended",
|
|
1250
|
+
URL_EMBED_STARTED: "url_embed_started",
|
|
1251
|
+
URL_EMBED_STOPPED: "url_embed_stopped",
|
|
1252
|
+
RECORDING_STARTED: "recording_started",
|
|
1253
|
+
RECORDING_STOPPED: "recording_stopped",
|
|
1254
|
+
USER_NOTIFIED: "user_notified",
|
|
1255
|
+
VIDEO_ENABLED: "video_enabled",
|
|
1256
|
+
CLIENT_UNABLE_TO_JOIN: "client_unable_to_join",
|
|
1257
|
+
LIVE_TRANSCRIPTION_STARTED: "live_transcription_started",
|
|
1258
|
+
LIVE_TRANSCRIPTION_STOPPED: "live_transcription_stopped",
|
|
1259
|
+
};
|
|
1260
|
+
const PROTOCOL_ERRORS = {
|
|
1261
|
+
CANNOT_INVITE_YOURSELF: "cannot_invite_yourself",
|
|
1262
|
+
CLIENT_MISSING_DEVICE_ID: "client_missing_device_id",
|
|
1263
|
+
FORBIDDEN: "forbidden",
|
|
1264
|
+
INTERNAL_SERVER_ERROR: "internal_server_error",
|
|
1265
|
+
INVALID_AVATAR: "invalid_avatar",
|
|
1266
|
+
INVALID_PARAMETERS: "invalid_parameters",
|
|
1267
|
+
INVALID_ROOM_NAME: "invalid_room_name",
|
|
1268
|
+
MISSING_PARAMETERS: "missing_parameters",
|
|
1269
|
+
MISSING_ROOM_NAME: "missing_room_name",
|
|
1270
|
+
NOT_AN_OWNER: "not_an_owner",
|
|
1271
|
+
NOT_IN_A_ROOM: "not_in_a_room",
|
|
1272
|
+
ROOM_ALREADY_CLAIMED: "room_already_claimed",
|
|
1273
|
+
ROOM_EMAIL_MISSING: "room_email_missing",
|
|
1274
|
+
ROOM_FULL: "room_full",
|
|
1275
|
+
ROOM_UNCLAIMED: "room_unclaimed",
|
|
1276
|
+
CLIENT_BLOCKED: "client_blocked",
|
|
1277
|
+
ROOM_LOCKED: "room_locked",
|
|
1278
|
+
TOO_LONG_TEXT: "too_long_text",
|
|
1279
|
+
VIDEO_STICKER_DOES_NOT_EXIST: "video_sticker_does_not_exist",
|
|
1280
|
+
VIDEO_STICKER_FORMAT_ERROR: "video_sticker_format_error",
|
|
1281
|
+
UNSUPPORTED_VIDEO_ENCODING: "unsupported_video_encoding",
|
|
1282
|
+
};
|
|
1283
|
+
const RELAY_MESSAGES = {
|
|
1284
|
+
CHAT_MESSAGE: "chat_message",
|
|
1285
|
+
CHAT_READ_STATE: "chat_read_state",
|
|
1286
|
+
CHAT_STATE: "chat_state",
|
|
1287
|
+
ICE_CANDIDATE: "ice_candidate",
|
|
1288
|
+
ICE_END_OF_CANDIDATES: "ice_endofcandidates",
|
|
1289
|
+
READY_TO_RECEIVE_OFFER: "ready_to_receive_offer",
|
|
1290
|
+
REMOTE_CLIENT_MEDIA_REQUEST: "remote_client_media_request",
|
|
1291
|
+
SDP_ANSWER: "sdp_answer",
|
|
1292
|
+
SDP_OFFER: "sdp_offer",
|
|
1293
|
+
VIDEO_STICKER: "video_sticker",
|
|
1294
|
+
};
|
|
1295
|
+
const KNOCK_MESSAGES = {
|
|
1296
|
+
actions: {
|
|
1297
|
+
ACCEPT: "accept",
|
|
1298
|
+
HOLD: "hold",
|
|
1299
|
+
REJECT: "reject",
|
|
1300
|
+
},
|
|
1301
|
+
resolutions: {
|
|
1302
|
+
ACCEPTED: "accepted",
|
|
1303
|
+
ON_HOLD: "on_hold",
|
|
1304
|
+
REJECTED: "rejected",
|
|
1305
|
+
},
|
|
1306
|
+
};
|
|
1307
|
+
const PROTOCOL_EVENTS = {
|
|
1308
|
+
PENDING_CLIENT_LEFT: "pending_client_left",
|
|
1309
|
+
MEDIA_QUALITY_CHANGED: "media_quality_changed",
|
|
1310
|
+
};
|
|
1311
|
+
|
|
855
1312
|
const logger$a = new Logger();
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
1313
|
+
class ReconnectManager extends EventEmitter {
|
|
1314
|
+
constructor(socket) {
|
|
1315
|
+
super();
|
|
1316
|
+
this.reconnectThresholdInMs = 0;
|
|
1317
|
+
this._socket = socket;
|
|
1318
|
+
this._clients = {};
|
|
1319
|
+
this._signalDisconnectTime = undefined;
|
|
1320
|
+
this.rtcManager = undefined;
|
|
1321
|
+
this.metrics = {
|
|
1322
|
+
roomJoinedLate: 0,
|
|
1323
|
+
pendingClientCanceled: 0,
|
|
1324
|
+
evaluationFailed: 0,
|
|
1325
|
+
roomJoined: 0,
|
|
1326
|
+
};
|
|
1327
|
+
socket.on("disconnect", () => {
|
|
1328
|
+
this._signalDisconnectTime = Date.now();
|
|
1329
|
+
});
|
|
1330
|
+
socket.on(PROTOCOL_RESPONSES.ROOM_JOINED, (payload) => this._onRoomJoined(payload));
|
|
1331
|
+
socket.on(PROTOCOL_RESPONSES.NEW_CLIENT, (payload) => this._onNewClient(payload));
|
|
1332
|
+
socket.on(PROTOCOL_RESPONSES.CLIENT_LEFT, (payload) => this._onClientLeft(payload));
|
|
1333
|
+
socket.on(PROTOCOL_EVENTS.PENDING_CLIENT_LEFT, (payload) => this._onPendingClientLeft(payload));
|
|
1334
|
+
socket.on(PROTOCOL_RESPONSES.AUDIO_ENABLED, (payload) => this._onAudioEnabled(payload));
|
|
1335
|
+
socket.on(PROTOCOL_RESPONSES.VIDEO_ENABLED, (payload) => this._onVideoEnabled(payload));
|
|
1336
|
+
socket.on(PROTOCOL_RESPONSES.SCREENSHARE_STARTED, (payload) => this._onScreenshareChanged(payload, true));
|
|
1337
|
+
socket.on(PROTOCOL_RESPONSES.SCREENSHARE_STOPPED, (payload) => this._onScreenshareChanged(payload, false));
|
|
1338
|
+
}
|
|
1339
|
+
_onRoomJoined(payload) {
|
|
1340
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1341
|
+
var _a;
|
|
1342
|
+
this.reconnectThresholdInMs = (payload.disconnectTimeout || 0) * 0.8;
|
|
1343
|
+
if (payload === null || payload === void 0 ? void 0 : payload.error) {
|
|
1344
|
+
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1347
|
+
if (!payload.selfId) {
|
|
1348
|
+
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
const myDeviceId = (_a = payload.room.clients.find((c) => payload.selfId === c.id)) === null || _a === void 0 ? void 0 : _a.deviceId;
|
|
1352
|
+
if (!myDeviceId) {
|
|
1353
|
+
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1354
|
+
return;
|
|
1355
|
+
}
|
|
1356
|
+
if (!this._signalDisconnectTime) {
|
|
1357
|
+
this._resetClientState(payload);
|
|
1358
|
+
payload.room.clients = payload.room.clients.filter((c) => !(c.deviceId === myDeviceId && c.isPendingToLeave));
|
|
1359
|
+
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1360
|
+
return;
|
|
1361
|
+
}
|
|
1362
|
+
const RECONNECT_THRESHOLD = payload.disconnectTimeout * 0.8;
|
|
1363
|
+
const timeSinceDisconnect = Date.now() - this._signalDisconnectTime;
|
|
1364
|
+
if (timeSinceDisconnect > RECONNECT_THRESHOLD) {
|
|
1365
|
+
this._resetClientState(payload);
|
|
1366
|
+
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1367
|
+
this.metrics.roomJoinedLate++;
|
|
1368
|
+
return;
|
|
876
1369
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
1370
|
+
payload.room.clients = payload.room.clients.filter((c) => !(c.deviceId === myDeviceId && c.isPendingToLeave));
|
|
1371
|
+
const allStats = yield getUpdatedStats();
|
|
1372
|
+
payload.room.clients.forEach((client) => {
|
|
1373
|
+
var _a;
|
|
1374
|
+
try {
|
|
1375
|
+
if (client.id === payload.selfId)
|
|
1376
|
+
return;
|
|
1377
|
+
if (!this._clients[client.id]) {
|
|
1378
|
+
this._addClientToState(client);
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
if (!((_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.hasClient(client.id))) {
|
|
1382
|
+
return;
|
|
1383
|
+
}
|
|
1384
|
+
if (this._hasClientStateChanged({
|
|
1385
|
+
clientId: client.id,
|
|
1386
|
+
webcam: client.isVideoEnabled,
|
|
1387
|
+
mic: client.isAudioEnabled,
|
|
1388
|
+
screenShare: client.streams.length > 1,
|
|
1389
|
+
})) {
|
|
1390
|
+
return;
|
|
1391
|
+
}
|
|
1392
|
+
if (this._wasClientSendingMedia(client.id)) {
|
|
1393
|
+
if (!this._isClientMediaActive(allStats, client.id)) {
|
|
1394
|
+
return;
|
|
887
1395
|
}
|
|
888
1396
|
}
|
|
1397
|
+
client.mergeWithOldClientState = true;
|
|
889
1398
|
}
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
sdpObject.media.forEach((mediaObject) => {
|
|
903
|
-
const usedPayloads = {};
|
|
904
|
-
if (mediaObject.payloads)
|
|
905
|
-
mediaObject.payloads = ("" + mediaObject.payloads)
|
|
906
|
-
.split(" ")
|
|
907
|
-
.filter((p) => !usedPayloads[p] && (usedPayloads[p] = true))
|
|
908
|
-
.join(" ");
|
|
909
|
-
const usedRtps = {};
|
|
910
|
-
mediaObject.rtp = mediaObject.rtp.filter((p) => !p.payload || (usedPayloads[p.payload] && !usedRtps[p.payload] && (usedRtps[p.payload] = true)));
|
|
911
|
-
const usedFmtps = {};
|
|
912
|
-
if (mediaObject.fmtp)
|
|
913
|
-
mediaObject.fmtp = mediaObject.fmtp.filter((p) => !p.payload ||
|
|
914
|
-
(usedPayloads[p.payload] && !usedFmtps[p.payload] && (usedFmtps[p.payload] = true)));
|
|
915
|
-
const usedRtcpFb = {};
|
|
916
|
-
if (mediaObject.rtcpFb)
|
|
917
|
-
mediaObject.rtcpFb = mediaObject.rtcpFb.filter((p) => !p.payload ||
|
|
918
|
-
(usedPayloads[p.payload] &&
|
|
919
|
-
!usedRtcpFb[p.payload + p.type + p.subtype] &&
|
|
920
|
-
(usedRtcpFb[p.payload + p.type + p.subtype] = true)));
|
|
1399
|
+
catch (error) {
|
|
1400
|
+
logger$a.error("Failed to evaluate if we should merge client state %o", error);
|
|
1401
|
+
this.metrics.evaluationFailed++;
|
|
1402
|
+
}
|
|
1403
|
+
});
|
|
1404
|
+
payload.room.clients.forEach((c) => {
|
|
1405
|
+
if (c.isPendingToLeave) {
|
|
1406
|
+
this._onPendingClientLeft({ clientId: c.id });
|
|
1407
|
+
}
|
|
1408
|
+
});
|
|
1409
|
+
this.metrics.roomJoined++;
|
|
1410
|
+
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
921
1411
|
});
|
|
922
|
-
return sdpTransform__namespace.write(sdpObject);
|
|
923
1412
|
}
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
1413
|
+
_onClientLeft(payload) {
|
|
1414
|
+
var _a;
|
|
1415
|
+
const { clientId } = payload;
|
|
1416
|
+
const client = this._clients[clientId];
|
|
1417
|
+
if (client) {
|
|
1418
|
+
clearTimeout(client.timeout);
|
|
1419
|
+
delete this._clients[clientId];
|
|
1420
|
+
}
|
|
1421
|
+
(_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.disconnect(clientId, null, payload.eventClaim);
|
|
1422
|
+
this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, payload);
|
|
930
1423
|
}
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
1424
|
+
_onPendingClientLeft(payload) {
|
|
1425
|
+
const { clientId } = payload;
|
|
1426
|
+
const client = this._clients[clientId];
|
|
1427
|
+
if (!client) {
|
|
1428
|
+
logger$a.warn(`client ${clientId} not found`);
|
|
1429
|
+
return;
|
|
935
1430
|
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
return SDPUtils.parseRtpMap(line);
|
|
939
|
-
})
|
|
940
|
-
.map((codec) => {
|
|
941
|
-
return codec.name.toUpperCase();
|
|
942
|
-
});
|
|
943
|
-
if (codecs.indexOf("H264") === -1 &&
|
|
944
|
-
sections[i][8] === "9") {
|
|
945
|
-
sections[i] = sections[i].replace("m=video 9 ", "m=video 0 ");
|
|
1431
|
+
if (client.isPendingToLeave) {
|
|
1432
|
+
return;
|
|
946
1433
|
}
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
return SDPUtils.splitSections(sdp)
|
|
952
|
-
.map((section) => {
|
|
953
|
-
if (SDPUtils.getKind(section) !== "video")
|
|
954
|
-
return section;
|
|
955
|
-
const h264payloadTypes = SDPUtils.matchPrefix(section, "a=rtpmap:")
|
|
956
|
-
.map((line) => SDPUtils.parseRtpMap(line))
|
|
957
|
-
.filter((codec) => /h264/i.test(codec.name))
|
|
958
|
-
.map((codec) => "" + codec.payloadType);
|
|
959
|
-
if (!h264payloadTypes.length)
|
|
960
|
-
return section;
|
|
961
|
-
const mline = SDPUtils.matchPrefix(section, "m=video")[0];
|
|
962
|
-
const mlinePayloadsSectionExec = /(\s\d+)+$/i.exec(mline);
|
|
963
|
-
const mlinePayloadsSection = mlinePayloadsSectionExec ? mlinePayloadsSectionExec[0] : "";
|
|
964
|
-
const mlinePayloadsNonH264 = mlinePayloadsSection
|
|
965
|
-
.split(" ")
|
|
966
|
-
.filter((payloadType) => payloadType && !h264payloadTypes.includes(payloadType));
|
|
967
|
-
const reorderedPayloads = [...mlinePayloadsNonH264, ...h264payloadTypes].join(" ");
|
|
968
|
-
const newmline = mline.replace(mlinePayloadsSection, " " + reorderedPayloads);
|
|
969
|
-
return section.replace(mline, newmline);
|
|
970
|
-
})
|
|
971
|
-
.join("");
|
|
972
|
-
}
|
|
973
|
-
function replaceSSRCs(currentDescription, newDescription) {
|
|
974
|
-
let ssrcs = currentDescription.match(/a=ssrc-group:FID (\d+) (\d+)\r\n/);
|
|
975
|
-
let newssrcs = newDescription.match(/a=ssrc-group:FID (\d+) (\d+)\r\n/);
|
|
976
|
-
if (!ssrcs) {
|
|
977
|
-
ssrcs = currentDescription.match(/a=ssrc:(\d+) cname:(.*)\r\n/g)[1].match(/a=ssrc:(\d+)/);
|
|
978
|
-
newssrcs = newDescription.match(/a=ssrc:(\d+) cname:(.*)\r\n/g)[1].match(/a=ssrc:(\d+)/);
|
|
979
|
-
}
|
|
980
|
-
for (let i = 1; i < ssrcs.length; i++) {
|
|
981
|
-
newDescription = newDescription.replace(new RegExp(newssrcs[i], "g"), ssrcs[i]);
|
|
982
|
-
}
|
|
983
|
-
return newDescription;
|
|
984
|
-
}
|
|
985
|
-
function filterMidExtension(sdp) {
|
|
986
|
-
if (browserName$2 !== "safari" &&
|
|
987
|
-
(browserName$2 !== "firefox" || (browserVersion$1 && browserVersion$1 >= 63) || browserVersion$1 === 60)) {
|
|
988
|
-
return sdp;
|
|
989
|
-
}
|
|
990
|
-
return (SDPUtils.splitLines(sdp.trim())
|
|
991
|
-
.filter((line) => {
|
|
992
|
-
if (!line.startsWith("a=extmap:")) {
|
|
993
|
-
return true;
|
|
1434
|
+
client.isPendingToLeave = true;
|
|
1435
|
+
if (this._wasClientSendingMedia(clientId)) {
|
|
1436
|
+
client.checkActiveMediaAttempts = 0;
|
|
1437
|
+
this._abortIfNotActive(payload);
|
|
994
1438
|
}
|
|
995
|
-
const extmap = SDPUtils.parseExtmap(line);
|
|
996
|
-
return extmap.uri !== "urn:ietf:params:rtp-hdrext:sdes:mid";
|
|
997
|
-
})
|
|
998
|
-
.join("\r\n") + "\r\n");
|
|
999
|
-
}
|
|
1000
|
-
function filterMsidSemantic(sdp) {
|
|
1001
|
-
if (browserName$2 !== "firefox") {
|
|
1002
|
-
return sdp;
|
|
1003
1439
|
}
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
.map((section) => {
|
|
1013
|
-
const currentDirection = SDPUtils.getDirection(section, SDPUtils.getKind(section));
|
|
1014
|
-
return section.replace("a=" + currentDirection, "a=" + (active ? "recvonly" : "inactive"));
|
|
1015
|
-
})
|
|
1016
|
-
.join(""));
|
|
1017
|
-
}
|
|
1018
|
-
function addExtMap(sdp, extmapUri, modifyAudio = false, modifyVideo = false) {
|
|
1019
|
-
var _a, _b;
|
|
1020
|
-
try {
|
|
1021
|
-
const sdpObj = sdpTransform__namespace.parse(sdp);
|
|
1022
|
-
if (((_a = sdpObj === null || sdpObj === void 0 ? void 0 : sdpObj.ext) === null || _a === void 0 ? void 0 : _a.length) && sdpObj.ext.length > 0) {
|
|
1023
|
-
return sdp;
|
|
1440
|
+
_onNewClient(payload) {
|
|
1441
|
+
const { client: { id: clientId, deviceId }, } = payload;
|
|
1442
|
+
const client = this._clients[clientId];
|
|
1443
|
+
if (client && client.isPendingToLeave) {
|
|
1444
|
+
clearTimeout(client.timeoutHandler);
|
|
1445
|
+
client.isPendingToLeave = false;
|
|
1446
|
+
this.metrics.pendingClientCanceled++;
|
|
1447
|
+
return;
|
|
1024
1448
|
}
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1449
|
+
this._getPendingClientsByDeviceId(deviceId).forEach((client) => {
|
|
1450
|
+
clearTimeout(client.timeoutHandler);
|
|
1451
|
+
client.isPendingToLeave = undefined;
|
|
1452
|
+
this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, { clientId: client.clientId });
|
|
1453
|
+
});
|
|
1454
|
+
this._addClientToState(payload.client);
|
|
1455
|
+
this.emit(PROTOCOL_RESPONSES.NEW_CLIENT, payload);
|
|
1456
|
+
}
|
|
1457
|
+
_abortIfNotActive(payload) {
|
|
1458
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1459
|
+
const { clientId } = payload;
|
|
1460
|
+
let client = this._clients[clientId];
|
|
1461
|
+
if (!(client === null || client === void 0 ? void 0 : client.isPendingToLeave))
|
|
1462
|
+
return;
|
|
1463
|
+
client.checkActiveMediaAttempts++;
|
|
1464
|
+
if (client.checkActiveMediaAttempts > 3) {
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1467
|
+
const stillActive = yield this._checkIsActive(clientId);
|
|
1468
|
+
if (stillActive) {
|
|
1469
|
+
client.timeoutHandler = setTimeout(() => this._abortIfNotActive(payload), 500);
|
|
1470
|
+
return;
|
|
1043
1471
|
}
|
|
1472
|
+
client = this._clients[clientId];
|
|
1473
|
+
if (client === null || client === void 0 ? void 0 : client.isPendingToLeave) {
|
|
1474
|
+
clearTimeout(client.timeoutHandler);
|
|
1475
|
+
delete this._clients[clientId];
|
|
1476
|
+
this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, payload);
|
|
1477
|
+
}
|
|
1478
|
+
});
|
|
1479
|
+
}
|
|
1480
|
+
_checkIsActive(clientId) {
|
|
1481
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1482
|
+
const allStats = yield getUpdatedStats();
|
|
1483
|
+
return this._isClientMediaActive(allStats, clientId);
|
|
1044
1484
|
});
|
|
1045
|
-
return sdpTransform__namespace.write(sdpObj);
|
|
1046
1485
|
}
|
|
1047
|
-
|
|
1048
|
-
|
|
1486
|
+
_isClientMediaActive(stats, clientId) {
|
|
1487
|
+
const clientStats = stats === null || stats === void 0 ? void 0 : stats[clientId];
|
|
1488
|
+
let isActive = false;
|
|
1489
|
+
if (clientStats) {
|
|
1490
|
+
Object.entries(clientStats.tracks).forEach(([trackId, trackStats]) => {
|
|
1491
|
+
if (trackId !== "probator")
|
|
1492
|
+
Object.values(trackStats.ssrcs).forEach((ssrcStats) => {
|
|
1493
|
+
if ((ssrcStats.bitrate || 0) > 0)
|
|
1494
|
+
isActive = true;
|
|
1495
|
+
});
|
|
1496
|
+
});
|
|
1497
|
+
}
|
|
1498
|
+
return isActive;
|
|
1049
1499
|
}
|
|
1050
|
-
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
|
-
const absCaptureTimeUri = "http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time";
|
|
1054
|
-
return addExtMap(sdp, absCaptureTimeUri, true, true);
|
|
1055
|
-
}
|
|
1056
|
-
|
|
1057
|
-
function setVideoBandwidthUsingSetParameters(pc, bandwidth, logger = console) {
|
|
1058
|
-
const sender = pc.getSenders().find((s) => s.track && s.track.kind === "video");
|
|
1059
|
-
if (!sender) {
|
|
1060
|
-
return Promise.resolve();
|
|
1500
|
+
_onAudioEnabled(payload) {
|
|
1501
|
+
const { clientId, isAudioEnabled } = payload;
|
|
1502
|
+
this._clients[clientId] = Object.assign(Object.assign({}, (this._clients[clientId] || {})), { isAudioEnabled });
|
|
1061
1503
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1504
|
+
_onVideoEnabled(payload) {
|
|
1505
|
+
const { clientId, isVideoEnabled } = payload;
|
|
1506
|
+
this._clients[clientId] = Object.assign(Object.assign({}, (this._clients[clientId] || {})), { isVideoEnabled });
|
|
1065
1507
|
}
|
|
1066
|
-
|
|
1067
|
-
|
|
1508
|
+
_onScreenshareChanged(payload, action) {
|
|
1509
|
+
const { clientId } = payload;
|
|
1510
|
+
this._clients[clientId] = Object.assign(Object.assign({}, (this._clients[clientId] || {})), { isScreenshareEnabled: action });
|
|
1068
1511
|
}
|
|
1069
|
-
|
|
1070
|
-
|
|
1512
|
+
_hasClientStateChanged({ clientId, webcam, mic, screenShare, }) {
|
|
1513
|
+
const state = this._clients[clientId];
|
|
1514
|
+
if (!state) {
|
|
1515
|
+
throw new Error(`Client ${clientId} not found in ReconnectManager state`);
|
|
1516
|
+
}
|
|
1517
|
+
if (webcam !== state.isVideoEnabled) {
|
|
1518
|
+
return true;
|
|
1519
|
+
}
|
|
1520
|
+
if (mic !== state.isAudioEnabled) {
|
|
1521
|
+
return true;
|
|
1522
|
+
}
|
|
1523
|
+
if (screenShare !== state.isScreenshareEnabled) {
|
|
1524
|
+
return true;
|
|
1525
|
+
}
|
|
1526
|
+
return false;
|
|
1071
1527
|
}
|
|
1072
|
-
|
|
1073
|
-
|
|
1528
|
+
_addClientToState(newClient) {
|
|
1529
|
+
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 });
|
|
1074
1530
|
}
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
this.peerConnectionId = peerConnectionId;
|
|
1086
|
-
this.relayCandidateSeen = false;
|
|
1087
|
-
this.serverReflexiveCandidateSeen = false;
|
|
1088
|
-
this.publicHostCandidateSeen = false;
|
|
1089
|
-
this.ipv6HostCandidateSeen = false;
|
|
1090
|
-
this.ipv6HostCandidateTeredoSeen = false;
|
|
1091
|
-
this.ipv6HostCandidate6to4Seen = false;
|
|
1092
|
-
this.mdnsHostCandidateSeen = false;
|
|
1093
|
-
this.pc = null;
|
|
1094
|
-
this.wasEverConnected = false;
|
|
1095
|
-
this.connectionStatus = null;
|
|
1096
|
-
this.stats = {
|
|
1097
|
-
totalSent: 0,
|
|
1098
|
-
totalRecv: 0,
|
|
1099
|
-
};
|
|
1100
|
-
this.bandwidth = bandwidth || 0;
|
|
1101
|
-
this.pending = [];
|
|
1102
|
-
this.isOperationPending = false;
|
|
1103
|
-
this.streamIds = [];
|
|
1104
|
-
this.streams = [];
|
|
1105
|
-
this.earlyIceCandidates = [];
|
|
1106
|
-
this.afterConnected = new Promise((resolve) => {
|
|
1107
|
-
this.registerConnected = resolve;
|
|
1531
|
+
_wasClientSendingMedia(clientId) {
|
|
1532
|
+
const client = this._clients[clientId];
|
|
1533
|
+
if (!client) {
|
|
1534
|
+
throw new Error(`Client ${clientId} not found in ReconnectManager state`);
|
|
1535
|
+
}
|
|
1536
|
+
return client.isAudioEnabled || client.isVideoEnabled || client.isScreenshareEnabled;
|
|
1537
|
+
}
|
|
1538
|
+
_getPendingClientsByDeviceId(deviceId) {
|
|
1539
|
+
return Object.values(this._clients).filter((clientState) => {
|
|
1540
|
+
return clientState.deviceId === deviceId && clientState.isPendingToLeave;
|
|
1108
1541
|
});
|
|
1109
|
-
this.offerOptions = { offerToReceiveAudio: true, offerToReceiveVideo: true };
|
|
1110
|
-
this._deprioritizeH264Encoding = deprioritizeH264Encoding;
|
|
1111
1542
|
}
|
|
1112
|
-
|
|
1113
|
-
this.
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
this.pc = new RTCPeerConnection(peerConnectionConfig);
|
|
1117
|
-
this.signalingState = this.pc.signalingState;
|
|
1118
|
-
this.pc.addEventListener("signalingstatechange", () => {
|
|
1119
|
-
if (this.signalingState === this.pc.signalingState) {
|
|
1543
|
+
_resetClientState(payload) {
|
|
1544
|
+
this._clients = {};
|
|
1545
|
+
payload.room.clients.forEach((client) => {
|
|
1546
|
+
if (client.id === payload.selfId) {
|
|
1120
1547
|
return;
|
|
1121
1548
|
}
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
this.isOperationPending = false;
|
|
1125
|
-
const action = this.pending.shift();
|
|
1126
|
-
if (action) {
|
|
1127
|
-
action.apply();
|
|
1128
|
-
}
|
|
1549
|
+
else {
|
|
1550
|
+
this._addClientToState(client);
|
|
1129
1551
|
}
|
|
1130
1552
|
});
|
|
1131
|
-
return this.pc;
|
|
1132
|
-
}
|
|
1133
|
-
addStream(stream) {
|
|
1134
|
-
this.streamIds.push(stream.id);
|
|
1135
|
-
this.streams.push(stream);
|
|
1136
|
-
if (RTCPeerConnection.prototype.addTrack) {
|
|
1137
|
-
stream.getAudioTracks().forEach((track) => {
|
|
1138
|
-
this.pc.addTrack(track, stream);
|
|
1139
|
-
});
|
|
1140
|
-
stream.getVideoTracks().forEach((track) => {
|
|
1141
|
-
this.pc.addTrack(track, stream);
|
|
1142
|
-
});
|
|
1143
|
-
}
|
|
1144
|
-
else {
|
|
1145
|
-
this.pc.addStream(stream);
|
|
1146
|
-
}
|
|
1147
|
-
}
|
|
1148
|
-
addTrack(track, stream) {
|
|
1149
|
-
if (!stream) {
|
|
1150
|
-
stream = this.streams[0];
|
|
1151
|
-
}
|
|
1152
|
-
stream === null || stream === void 0 ? void 0 : stream.addTrack(track);
|
|
1153
|
-
this.pc.addTrack(track, stream);
|
|
1154
|
-
}
|
|
1155
|
-
removeTrack(track) {
|
|
1156
|
-
const stream = this.streams[0];
|
|
1157
|
-
stream.removeTrack(track);
|
|
1158
|
-
const sender = this.pc.getSenders().find((sender) => sender.track === track);
|
|
1159
|
-
if (sender) {
|
|
1160
|
-
this.pc.removeTrack(sender);
|
|
1161
|
-
}
|
|
1162
1553
|
}
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
var _a$6;
|
|
1557
|
+
const adapter$6 = (_a$6 = adapterRaw.default) !== null && _a$6 !== void 0 ? _a$6 : adapterRaw;
|
|
1558
|
+
const DEFAULT_SOCKET_PATH = "/protocol/socket.io/v4";
|
|
1559
|
+
const NOOP_KEEPALIVE_INTERVAL = 2000;
|
|
1560
|
+
class ServerSocket {
|
|
1561
|
+
constructor(hostName, optionsOverrides, glitchFree = false) {
|
|
1562
|
+
this._wasConnectedUsingWebsocket = false;
|
|
1563
|
+
this._reconnectManager = null;
|
|
1564
|
+
this._socket = socket_ioClient.io(hostName, Object.assign({ path: DEFAULT_SOCKET_PATH, randomizationFactor: 0.5, reconnectionDelay: 250, reconnectionDelayMax: 5000, timeout: 5000, transports: ["websocket"], withCredentials: true }, optionsOverrides));
|
|
1565
|
+
this._socket.io.on("reconnect", () => {
|
|
1566
|
+
this._socket.sendBuffer = [];
|
|
1567
|
+
});
|
|
1568
|
+
this._socket.io.on("reconnect_attempt", () => {
|
|
1569
|
+
if (this._wasConnectedUsingWebsocket) {
|
|
1570
|
+
this._socket.io.opts.transports = ["websocket"];
|
|
1571
|
+
if (adapter$6.browserDetails.browser !== "safari")
|
|
1572
|
+
delete this._wasConnectedUsingWebsocket;
|
|
1168
1573
|
}
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
if (this.pc.removeTrack) {
|
|
1172
|
-
stream.getTracks().forEach((track) => {
|
|
1173
|
-
const sender = this.pc.getSenders().find((sender) => sender.track === track);
|
|
1174
|
-
if (sender) {
|
|
1175
|
-
this.pc.removeTrack(sender);
|
|
1176
|
-
}
|
|
1177
|
-
});
|
|
1574
|
+
else {
|
|
1575
|
+
this._socket.io.opts.transports = ["websocket", "polling"];
|
|
1178
1576
|
}
|
|
1179
|
-
|
|
1180
|
-
|
|
1577
|
+
});
|
|
1578
|
+
if (glitchFree)
|
|
1579
|
+
this._reconnectManager = new ReconnectManager(this._socket);
|
|
1580
|
+
this._socket.on("connect", () => {
|
|
1581
|
+
const transport = this.getTransport();
|
|
1582
|
+
if (transport === "websocket") {
|
|
1583
|
+
this._wasConnectedUsingWebsocket = true;
|
|
1584
|
+
if (!this.noopKeepaliveInterval)
|
|
1585
|
+
this.noopKeepaliveInterval = setInterval(() => {
|
|
1586
|
+
try {
|
|
1587
|
+
if (this._socket.connected) {
|
|
1588
|
+
this._socket.io.engine.sendPacket("noop");
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
catch (ex) { }
|
|
1592
|
+
}, NOOP_KEEPALIVE_INTERVAL);
|
|
1181
1593
|
}
|
|
1182
|
-
}
|
|
1183
|
-
}
|
|
1184
|
-
_setRemoteDescription(desc) {
|
|
1185
|
-
if (this._deprioritizeH264Encoding)
|
|
1186
|
-
desc.sdp = deprioritizeH264(desc.sdp);
|
|
1187
|
-
this.srdComplete = this.pc.setRemoteDescription(desc);
|
|
1188
|
-
return this.srdComplete.then(() => {
|
|
1189
|
-
this.earlyIceCandidates.forEach((candidate) => this.pc.addIceCandidate(candidate));
|
|
1190
|
-
this.earlyIceCandidates = [];
|
|
1191
1594
|
});
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
this.
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
this.isOperationPending = true;
|
|
1200
|
-
let sdp = message.sdp;
|
|
1201
|
-
sdp = filterMidExtension(sdp);
|
|
1202
|
-
sdp = filterMsidSemantic(sdp);
|
|
1203
|
-
const desc = { type: message.type, sdp };
|
|
1204
|
-
let answerToSignal;
|
|
1205
|
-
return this._setRemoteDescription(desc)
|
|
1206
|
-
.then(() => {
|
|
1207
|
-
return this.pc.createAnswer();
|
|
1208
|
-
})
|
|
1209
|
-
.then((answer) => {
|
|
1210
|
-
answerToSignal = answer;
|
|
1211
|
-
return this.pc.setLocalDescription(answer);
|
|
1212
|
-
})
|
|
1213
|
-
.then(() => {
|
|
1214
|
-
return setVideoBandwidthUsingSetParameters(this.pc, this.bandwidth);
|
|
1215
|
-
})
|
|
1216
|
-
.then(() => {
|
|
1217
|
-
return answerToSignal;
|
|
1595
|
+
this._socket.on("disconnect", () => {
|
|
1596
|
+
this.disconnectTimestamp = Date.now();
|
|
1597
|
+
if (this.noopKeepaliveInterval) {
|
|
1598
|
+
clearInterval(this.noopKeepaliveInterval);
|
|
1599
|
+
this.noopKeepaliveInterval = null;
|
|
1600
|
+
}
|
|
1218
1601
|
});
|
|
1219
1602
|
}
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
return setVideoBandwidthUsingSetParameters(this.pc, this.bandwidth);
|
|
1225
|
-
}, (e) => {
|
|
1226
|
-
logger$9.warn("Could not set remote description from remote answer: ", e);
|
|
1227
|
-
});
|
|
1603
|
+
setRtcManager(rtcManager) {
|
|
1604
|
+
if (this._reconnectManager) {
|
|
1605
|
+
this._reconnectManager.rtcManager = rtcManager;
|
|
1606
|
+
}
|
|
1228
1607
|
}
|
|
1229
|
-
|
|
1230
|
-
if (
|
|
1231
|
-
this.earlyIceCandidates.push(candidate);
|
|
1608
|
+
connect() {
|
|
1609
|
+
if (this.isConnected() || this.isConnecting()) {
|
|
1232
1610
|
return;
|
|
1233
1611
|
}
|
|
1234
|
-
this.
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
this.
|
|
1242
|
-
logger$9.warn("Failed to add ICE candidate ('%s'): %s", candidate ? candidate.candidate : null, e);
|
|
1243
|
-
});
|
|
1612
|
+
this._socket.open();
|
|
1613
|
+
}
|
|
1614
|
+
disconnect() {
|
|
1615
|
+
this._socket.disconnect();
|
|
1616
|
+
}
|
|
1617
|
+
disconnectOnConnect() {
|
|
1618
|
+
this._socket.once("connect", () => {
|
|
1619
|
+
this._socket.disconnect();
|
|
1244
1620
|
});
|
|
1245
1621
|
}
|
|
1246
|
-
|
|
1247
|
-
|
|
1622
|
+
emit(eventName, ...args) {
|
|
1623
|
+
this._socket.emit.apply(this._socket, arguments);
|
|
1248
1624
|
}
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
if (!pc) {
|
|
1625
|
+
emitIfConnected(eventName, data) {
|
|
1626
|
+
if (!this.isConnected()) {
|
|
1252
1627
|
return;
|
|
1253
1628
|
}
|
|
1254
|
-
|
|
1255
|
-
pc.onicecandidate = null;
|
|
1256
|
-
pc.ontrack = null;
|
|
1257
|
-
try {
|
|
1258
|
-
pc.close();
|
|
1259
|
-
}
|
|
1260
|
-
catch (e) {
|
|
1261
|
-
logger$9.warn("failures during close of session", e);
|
|
1262
|
-
}
|
|
1629
|
+
this.emit(eventName, data);
|
|
1263
1630
|
}
|
|
1264
|
-
|
|
1265
|
-
return this.
|
|
1631
|
+
getTransport() {
|
|
1632
|
+
return (this._socket &&
|
|
1633
|
+
this._socket.io &&
|
|
1634
|
+
this._socket.io.engine &&
|
|
1635
|
+
this._socket.io.engine.transport &&
|
|
1636
|
+
this._socket.io.engine.transport.name);
|
|
1266
1637
|
}
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
if (!pc)
|
|
1270
|
-
return false;
|
|
1271
|
-
const senders = pc.getSenders();
|
|
1272
|
-
if (!oldTrack) {
|
|
1273
|
-
oldTrack = (senders.find((s) => s.track && s.track.kind === newTrack.kind) || {}).track;
|
|
1274
|
-
}
|
|
1275
|
-
if (window.RTCRtpSender && window.RTCRtpSender.prototype.replaceTrack) {
|
|
1276
|
-
if (oldTrack) {
|
|
1277
|
-
const process = () => {
|
|
1278
|
-
for (let i = 0; i < senders.length; i++) {
|
|
1279
|
-
const sender = senders[i];
|
|
1280
|
-
const track = sender.track;
|
|
1281
|
-
if ((track === null || track === void 0 ? void 0 : track.id) === newTrack.id) {
|
|
1282
|
-
return Promise.resolve(newTrack);
|
|
1283
|
-
}
|
|
1284
|
-
if ((track === null || track === void 0 ? void 0 : track.id) === oldTrack.id) {
|
|
1285
|
-
return senders[i].replaceTrack(newTrack);
|
|
1286
|
-
}
|
|
1287
|
-
}
|
|
1288
|
-
return null;
|
|
1289
|
-
};
|
|
1290
|
-
let result = process();
|
|
1291
|
-
if (result) {
|
|
1292
|
-
return result;
|
|
1293
|
-
}
|
|
1294
|
-
let resolve = null;
|
|
1295
|
-
let reject = null;
|
|
1296
|
-
result = new Promise((_resolve, _reject) => {
|
|
1297
|
-
resolve = _resolve;
|
|
1298
|
-
reject = _reject;
|
|
1299
|
-
});
|
|
1300
|
-
let retried = 0;
|
|
1301
|
-
let timer = setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
1302
|
-
const trackReplacedPromise = process();
|
|
1303
|
-
if (!trackReplacedPromise) {
|
|
1304
|
-
if (3 < ++retried) {
|
|
1305
|
-
clearInterval(timer);
|
|
1306
|
-
timer = null;
|
|
1307
|
-
reject("No sender track to replace");
|
|
1308
|
-
}
|
|
1309
|
-
return;
|
|
1310
|
-
}
|
|
1311
|
-
clearInterval(timer);
|
|
1312
|
-
timer = null;
|
|
1313
|
-
const trackReplaced = yield trackReplacedPromise;
|
|
1314
|
-
resolve(trackReplaced);
|
|
1315
|
-
}), 1000);
|
|
1316
|
-
return result;
|
|
1317
|
-
}
|
|
1318
|
-
const stream = this.streams.find((s) => s.getTracks().find((t) => t.id === newTrack.id)) || this.streams[0];
|
|
1319
|
-
if (!stream) {
|
|
1320
|
-
return Promise.reject(new Error("replaceTrack: No stream?"));
|
|
1321
|
-
}
|
|
1322
|
-
return pc.addTrack(newTrack, stream);
|
|
1323
|
-
}
|
|
1324
|
-
if (!this.canModifyPeerConnection()) {
|
|
1325
|
-
this.pending.push(() => {
|
|
1326
|
-
this.replaceTrack(oldTrack, newTrack);
|
|
1327
|
-
});
|
|
1328
|
-
return;
|
|
1329
|
-
}
|
|
1330
|
-
this.isOperationPending = true;
|
|
1331
|
-
const onn = pc.onnegotiationneeded;
|
|
1332
|
-
pc.onnegotiationneeded = null;
|
|
1333
|
-
this.removeTrack(oldTrack);
|
|
1334
|
-
this.addTrack(newTrack);
|
|
1335
|
-
setTimeout(() => {
|
|
1336
|
-
pc.onnegotiationneeded = onn;
|
|
1337
|
-
}, 0);
|
|
1338
|
-
if (pc.localDescription.type === "offer") {
|
|
1339
|
-
return pc
|
|
1340
|
-
.createOffer()
|
|
1341
|
-
.then((offer) => {
|
|
1342
|
-
offer.sdp = replaceSSRCs(pc.localDescription.sdp, offer.sdp);
|
|
1343
|
-
return pc.setLocalDescription(offer);
|
|
1344
|
-
})
|
|
1345
|
-
.then(() => {
|
|
1346
|
-
return this._setRemoteDescription(pc.remoteDescription);
|
|
1347
|
-
});
|
|
1348
|
-
}
|
|
1349
|
-
else {
|
|
1350
|
-
return this._setRemoteDescription(pc.remoteDescription)
|
|
1351
|
-
.then(() => {
|
|
1352
|
-
return pc.createAnswer();
|
|
1353
|
-
})
|
|
1354
|
-
.then((answer) => {
|
|
1355
|
-
answer.sdp = replaceSSRCs(pc.localDescription.sdp, answer.sdp);
|
|
1356
|
-
return pc.setLocalDescription(answer);
|
|
1357
|
-
});
|
|
1358
|
-
}
|
|
1638
|
+
getManager() {
|
|
1639
|
+
return this._socket.io;
|
|
1359
1640
|
}
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1641
|
+
isConnecting() {
|
|
1642
|
+
return this._socket && this._socket.connecting;
|
|
1643
|
+
}
|
|
1644
|
+
isConnected() {
|
|
1645
|
+
return this._socket && this._socket.connected;
|
|
1646
|
+
}
|
|
1647
|
+
on(eventName, handler) {
|
|
1648
|
+
const relayableEvents = [
|
|
1649
|
+
PROTOCOL_RESPONSES.ROOM_JOINED,
|
|
1650
|
+
PROTOCOL_RESPONSES.CLIENT_LEFT,
|
|
1651
|
+
PROTOCOL_RESPONSES.NEW_CLIENT,
|
|
1652
|
+
];
|
|
1653
|
+
if (this._reconnectManager && relayableEvents.includes(eventName)) {
|
|
1654
|
+
return this._interceptEvent(eventName, handler);
|
|
1367
1655
|
}
|
|
1368
|
-
this.
|
|
1369
|
-
|
|
1370
|
-
|
|
1656
|
+
this._socket.on(eventName, handler);
|
|
1657
|
+
return () => {
|
|
1658
|
+
this._socket.off(eventName, handler);
|
|
1659
|
+
};
|
|
1660
|
+
}
|
|
1661
|
+
onEngineEvent(eventName, handler) {
|
|
1662
|
+
var _a;
|
|
1663
|
+
(_a = this._socket.io) === null || _a === void 0 ? void 0 : _a.on(eventName, handler);
|
|
1664
|
+
return () => {
|
|
1665
|
+
var _a;
|
|
1666
|
+
(_a = this._socket.io) === null || _a === void 0 ? void 0 : _a.off(eventName, handler);
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1669
|
+
once(eventName, handler) {
|
|
1670
|
+
this._socket.once(eventName, handler);
|
|
1671
|
+
}
|
|
1672
|
+
off(eventName, handler) {
|
|
1673
|
+
this._socket.off(eventName, handler);
|
|
1674
|
+
}
|
|
1675
|
+
_interceptEvent(eventName, handler) {
|
|
1676
|
+
if (this._reconnectManager) {
|
|
1677
|
+
this._reconnectManager.on(eventName, handler);
|
|
1371
1678
|
}
|
|
1372
|
-
|
|
1679
|
+
return () => {
|
|
1680
|
+
if (this._reconnectManager)
|
|
1681
|
+
this._reconnectManager.removeListener(eventName, handler);
|
|
1682
|
+
};
|
|
1373
1683
|
}
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
!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) &&
|
|
1382
|
-
!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);
|
|
1383
|
-
})
|
|
1384
|
-
.forEach((videoTransceiver) => {
|
|
1385
|
-
videoTransceiver.direction = enable ? "sendonly" : "sendrecv";
|
|
1386
|
-
});
|
|
1684
|
+
getGlitchFreeMetrics() {
|
|
1685
|
+
var _a;
|
|
1686
|
+
return (_a = this._reconnectManager) === null || _a === void 0 ? void 0 : _a.metrics;
|
|
1687
|
+
}
|
|
1688
|
+
getReconnectThreshold() {
|
|
1689
|
+
var _a;
|
|
1690
|
+
return (_a = this._reconnectManager) === null || _a === void 0 ? void 0 : _a.reconnectThresholdInMs;
|
|
1387
1691
|
}
|
|
1388
1692
|
}
|
|
1389
1693
|
|
|
1390
|
-
const
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
const adapter$4 = (_a$4 = adapterRaw.default) !== null && _a$4 !== void 0 ? _a$4 : adapterRaw;
|
|
1394
|
-
function detectMicrophoneNotWorking(pc) {
|
|
1395
|
-
if (adapter$4.browserDetails.browser !== "chrome" ||
|
|
1396
|
-
adapter$4.browserDetails.browser < 58 ||
|
|
1397
|
-
pc.signalingState === "closed") {
|
|
1398
|
-
return Promise.resolve(false);
|
|
1694
|
+
const maybeTurnOnly = (iceConfig, features) => {
|
|
1695
|
+
if (!features.useOnlyTURN) {
|
|
1696
|
+
return;
|
|
1399
1697
|
}
|
|
1400
|
-
|
|
1401
|
-
const
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
receivingAudio) {
|
|
1415
|
-
if (report.bytesReceived === 0) {
|
|
1416
|
-
microphoneFailed = "inbound";
|
|
1417
|
-
}
|
|
1698
|
+
iceConfig.iceTransportPolicy = "relay";
|
|
1699
|
+
const filter = {
|
|
1700
|
+
onlyudp: /^turn:.*transport=udp$/,
|
|
1701
|
+
onlytcp: /^turn:.*transport=tcp$/,
|
|
1702
|
+
onlytls: /^turns:.*transport=tcp$/,
|
|
1703
|
+
}[features.useOnlyTURN];
|
|
1704
|
+
if (filter) {
|
|
1705
|
+
iceConfig.iceServers = iceConfig.iceServers.filter((entry) => {
|
|
1706
|
+
if (entry.url && entry.url.match(filter))
|
|
1707
|
+
return entry;
|
|
1708
|
+
if (entry.urls) {
|
|
1709
|
+
entry.urls = (entry.urls.some ? entry.urls : [entry.urls]).filter((url) => url.match(filter));
|
|
1710
|
+
if (entry.urls.length > 0)
|
|
1711
|
+
return entry;
|
|
1418
1712
|
}
|
|
1419
1713
|
});
|
|
1420
|
-
|
|
1421
|
-
});
|
|
1422
|
-
}
|
|
1423
|
-
|
|
1424
|
-
const PROTOCOL_REQUESTS = {
|
|
1425
|
-
BLOCK_CLIENT: "block_client",
|
|
1426
|
-
CLAIM_ROOM: "claim_room",
|
|
1427
|
-
CLEAR_CHAT_HISTORY: "clear_chat_history",
|
|
1428
|
-
ENABLE_AUDIO: "enable_audio",
|
|
1429
|
-
ENABLE_VIDEO: "enable_video",
|
|
1430
|
-
END_STREAM: "end_stream",
|
|
1431
|
-
FETCH_MEDIASERVER_CONFIG: "fetch_mediaserver_config",
|
|
1432
|
-
HANDLE_KNOCK: "handle_knock",
|
|
1433
|
-
IDENTIFY_DEVICE: "identify_device",
|
|
1434
|
-
INVITE_CLIENT_AS_MEMBER: "invite_client_as_member",
|
|
1435
|
-
JOIN_ROOM: "join_room",
|
|
1436
|
-
KICK_CLIENT: "kick_client",
|
|
1437
|
-
KNOCK_ROOM: "knock_room",
|
|
1438
|
-
LEAVE_ROOM: "leave_room",
|
|
1439
|
-
SEND_CLIENT_METADATA: "send_client_metadata",
|
|
1440
|
-
SET_LOCK: "set_lock",
|
|
1441
|
-
SHARE_MEDIA: "share_media",
|
|
1442
|
-
START_NEW_STREAM: "start_new_stream",
|
|
1443
|
-
START_SCREENSHARE: "start_screenshare",
|
|
1444
|
-
STOP_SCREENSHARE: "stop_screenshare",
|
|
1445
|
-
START_URL_EMBED: "start_url_embed",
|
|
1446
|
-
STOP_URL_EMBED: "stop_url_embed",
|
|
1447
|
-
START_RECORDING: "start_recording",
|
|
1448
|
-
STOP_RECORDING: "stop_recording",
|
|
1449
|
-
};
|
|
1450
|
-
const PROTOCOL_RESPONSES = {
|
|
1451
|
-
AUDIO_ENABLED: "audio_enabled",
|
|
1452
|
-
BACKGROUND_IMAGE_CHANGED: "background_image_changed",
|
|
1453
|
-
BLOCK_ADDED: "block_added",
|
|
1454
|
-
BLOCK_REMOVED: "block_removed",
|
|
1455
|
-
CHAT_HISTORY_CLEARED: "chat_history_cleared",
|
|
1456
|
-
CLIENT_BLOCKED: "client_blocked",
|
|
1457
|
-
CLIENT_INVITED_AS_MEMBER: "client_invited_as_member",
|
|
1458
|
-
CLIENT_KICKED: "client_kicked",
|
|
1459
|
-
CLIENT_LEFT: "client_left",
|
|
1460
|
-
CLIENT_METADATA_RECEIVED: "client_metadata_received",
|
|
1461
|
-
CLIENT_READY: "client_ready",
|
|
1462
|
-
CLIENT_ROLE_CHANGED: "client_role_changed",
|
|
1463
|
-
CLIENT_USER_ID_CHANGED: "client_user_id_changed",
|
|
1464
|
-
CONTACTS_UPDATED: "contacts_updated",
|
|
1465
|
-
DEVICE_IDENTIFIED: "device_identified",
|
|
1466
|
-
ROOM_ROLES_UPDATED: "room_roles_updated",
|
|
1467
|
-
KNOCK_HANDLED: "knock_handled",
|
|
1468
|
-
KNOCK_PAGE_BACKGROUND_CHANGED: "knock_page_background_changed",
|
|
1469
|
-
KNOCKER_LEFT: "knocker_left",
|
|
1470
|
-
MEDIASERVER_CONFIG: "mediaserver_config",
|
|
1471
|
-
MEDIA_SHARED: "media_shared",
|
|
1472
|
-
MEMBER_INVITE: "member_invite",
|
|
1473
|
-
NEW_CLIENT: "new_client",
|
|
1474
|
-
NEW_STREAM_STARTED: "new_stream_started",
|
|
1475
|
-
SCREENSHARE_STARTED: "screenshare_started",
|
|
1476
|
-
SCREENSHARE_STOPPED: "screenshare_stopped",
|
|
1477
|
-
OWNER_NOTIFIED: "owner_notified",
|
|
1478
|
-
OWNERS_CHANGED: "owners_changed",
|
|
1479
|
-
PLAY_CLIENT_STICKER: "play_client_sticker",
|
|
1480
|
-
ROOM_INTEGRATION_ENABLED: "room_integration_enabled",
|
|
1481
|
-
ROOM_INTEGRATION_DISABLED: "room_integration_disabled",
|
|
1482
|
-
ROOM_JOINED: "room_joined",
|
|
1483
|
-
ROOM_KNOCKED: "room_knocked",
|
|
1484
|
-
ROOM_LEFT: "room_left",
|
|
1485
|
-
ROOM_LOCKED: "room_locked",
|
|
1486
|
-
ROOM_PERMISSIONS_CHANGED: "room_permissions_changed",
|
|
1487
|
-
ROOM_LOGO_CHANGED: "room_logo_changed",
|
|
1488
|
-
ROOM_TYPE_CHANGED: "room_type_changed",
|
|
1489
|
-
ROOM_MODE_CHANGED: "room_mode_changed",
|
|
1490
|
-
SOCKET_USER_ID_CHANGED: "socket_user_id_changed",
|
|
1491
|
-
STICKERS_UNLOCKED: "stickers_unlocked",
|
|
1492
|
-
STREAM_ENDED: "stream_ended",
|
|
1493
|
-
URL_EMBED_STARTED: "url_embed_started",
|
|
1494
|
-
URL_EMBED_STOPPED: "url_embed_stopped",
|
|
1495
|
-
RECORDING_STARTED: "recording_started",
|
|
1496
|
-
RECORDING_STOPPED: "recording_stopped",
|
|
1497
|
-
USER_NOTIFIED: "user_notified",
|
|
1498
|
-
VIDEO_ENABLED: "video_enabled",
|
|
1499
|
-
CLIENT_UNABLE_TO_JOIN: "client_unable_to_join",
|
|
1500
|
-
LIVE_TRANSCRIPTION_STARTED: "live_transcription_started",
|
|
1501
|
-
LIVE_TRANSCRIPTION_STOPPED: "live_transcription_stopped",
|
|
1502
|
-
};
|
|
1503
|
-
const PROTOCOL_ERRORS = {
|
|
1504
|
-
CANNOT_INVITE_YOURSELF: "cannot_invite_yourself",
|
|
1505
|
-
CLIENT_MISSING_DEVICE_ID: "client_missing_device_id",
|
|
1506
|
-
FORBIDDEN: "forbidden",
|
|
1507
|
-
INTERNAL_SERVER_ERROR: "internal_server_error",
|
|
1508
|
-
INVALID_AVATAR: "invalid_avatar",
|
|
1509
|
-
INVALID_PARAMETERS: "invalid_parameters",
|
|
1510
|
-
INVALID_ROOM_NAME: "invalid_room_name",
|
|
1511
|
-
MISSING_PARAMETERS: "missing_parameters",
|
|
1512
|
-
MISSING_ROOM_NAME: "missing_room_name",
|
|
1513
|
-
NOT_AN_OWNER: "not_an_owner",
|
|
1514
|
-
NOT_IN_A_ROOM: "not_in_a_room",
|
|
1515
|
-
ROOM_ALREADY_CLAIMED: "room_already_claimed",
|
|
1516
|
-
ROOM_EMAIL_MISSING: "room_email_missing",
|
|
1517
|
-
ROOM_FULL: "room_full",
|
|
1518
|
-
ROOM_UNCLAIMED: "room_unclaimed",
|
|
1519
|
-
CLIENT_BLOCKED: "client_blocked",
|
|
1520
|
-
ROOM_LOCKED: "room_locked",
|
|
1521
|
-
TOO_LONG_TEXT: "too_long_text",
|
|
1522
|
-
VIDEO_STICKER_DOES_NOT_EXIST: "video_sticker_does_not_exist",
|
|
1523
|
-
VIDEO_STICKER_FORMAT_ERROR: "video_sticker_format_error",
|
|
1524
|
-
UNSUPPORTED_VIDEO_ENCODING: "unsupported_video_encoding",
|
|
1525
|
-
};
|
|
1526
|
-
const RELAY_MESSAGES = {
|
|
1527
|
-
CHAT_MESSAGE: "chat_message",
|
|
1528
|
-
CHAT_READ_STATE: "chat_read_state",
|
|
1529
|
-
CHAT_STATE: "chat_state",
|
|
1530
|
-
ICE_CANDIDATE: "ice_candidate",
|
|
1531
|
-
ICE_END_OF_CANDIDATES: "ice_endofcandidates",
|
|
1532
|
-
READY_TO_RECEIVE_OFFER: "ready_to_receive_offer",
|
|
1533
|
-
REMOTE_CLIENT_MEDIA_REQUEST: "remote_client_media_request",
|
|
1534
|
-
SDP_ANSWER: "sdp_answer",
|
|
1535
|
-
SDP_OFFER: "sdp_offer",
|
|
1536
|
-
VIDEO_STICKER: "video_sticker",
|
|
1714
|
+
}
|
|
1537
1715
|
};
|
|
1538
|
-
const
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1716
|
+
const external_stun_servers = (iceConfig, features) => {
|
|
1717
|
+
if (features.addGoogleStunServers) {
|
|
1718
|
+
iceConfig.iceServers = [
|
|
1719
|
+
{ urls: "stun:stun.l.google.com:19302" },
|
|
1720
|
+
{ urls: "stun:stun2.l.google.com:19302" },
|
|
1721
|
+
...iceConfig.iceServers,
|
|
1722
|
+
];
|
|
1723
|
+
}
|
|
1724
|
+
if (features.addCloudflareStunServers) {
|
|
1725
|
+
iceConfig.iceServers = [
|
|
1726
|
+
{ urls: "stun:stun.cloudflare.com:3478" },
|
|
1727
|
+
{ urls: "stun:stun.cloudflare.com:53" },
|
|
1728
|
+
...iceConfig.iceServers,
|
|
1729
|
+
];
|
|
1730
|
+
}
|
|
1549
1731
|
};
|
|
1550
|
-
const
|
|
1551
|
-
|
|
1552
|
-
|
|
1732
|
+
const turnServerOverride = (iceServers, overrideHost) => {
|
|
1733
|
+
if (overrideHost && iceServers) {
|
|
1734
|
+
const host = overrideHost;
|
|
1735
|
+
const port = host.indexOf(":") > 0 ? "" : ":443";
|
|
1736
|
+
const override = ":" + host + port;
|
|
1737
|
+
return iceServers.map((original) => {
|
|
1738
|
+
const entry = Object.assign({}, original);
|
|
1739
|
+
if (entry.url) {
|
|
1740
|
+
entry.url = entry.url.replace(/:[^?]*/, override);
|
|
1741
|
+
}
|
|
1742
|
+
if (entry.urls) {
|
|
1743
|
+
entry.urls = entry.urls.map((url) => url.replace(/:[^?]*/, override));
|
|
1744
|
+
}
|
|
1745
|
+
return entry;
|
|
1746
|
+
});
|
|
1747
|
+
}
|
|
1748
|
+
else {
|
|
1749
|
+
return iceServers;
|
|
1750
|
+
}
|
|
1553
1751
|
};
|
|
1554
1752
|
|
|
1555
|
-
const
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
}
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1753
|
+
const defaultSubdomainPattern = /^(?:([^.]+)[.])?((:?[^.]+[.]){1,}[^.]+)$/;
|
|
1754
|
+
const localstackPattern = /^(?:([^.]+)-)?(ip-[^.]*[.](?:hereby[.]dev|rfc1918[.]disappear[.]at)(?::\d+|))$/;
|
|
1755
|
+
const localhostPattern = /^(?:([^.]+)[.])?(localhost:?\d*)/;
|
|
1756
|
+
const serverPattern = /^(?:([^.]+)[.])?(server:?\d*)/;
|
|
1757
|
+
const ipv4Pattern = /^(?:([^.]+)[.])?((\d+[.]){3}:?\d*)$/;
|
|
1758
|
+
const subdomainPatterns = [
|
|
1759
|
+
{ pattern: serverPattern, separator: "." },
|
|
1760
|
+
{ pattern: localhostPattern, separator: "." },
|
|
1761
|
+
{ pattern: ipv4Pattern, separator: "." },
|
|
1762
|
+
{ pattern: localstackPattern, separator: "-" },
|
|
1763
|
+
{ pattern: defaultSubdomainPattern, separator: "." },
|
|
1764
|
+
];
|
|
1765
|
+
function fromLocation({ host = "whereby.com", protocol = "https:" } = {}) {
|
|
1766
|
+
let subdomain = "";
|
|
1767
|
+
let domain = host;
|
|
1768
|
+
let subdomainSeparator = ".";
|
|
1769
|
+
for (const { separator, pattern } of subdomainPatterns) {
|
|
1770
|
+
const match = pattern.exec(host);
|
|
1771
|
+
if (match) {
|
|
1772
|
+
subdomain = match[1] || "";
|
|
1773
|
+
domain = match[2];
|
|
1774
|
+
subdomainSeparator = separator;
|
|
1775
|
+
break;
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
const organizationDomain = !subdomain ? domain : `${subdomain}${subdomainSeparator}${domain}`;
|
|
1779
|
+
return {
|
|
1780
|
+
domain,
|
|
1781
|
+
domainWithSeparator: `${subdomainSeparator}${domain}`,
|
|
1782
|
+
organizationDomain,
|
|
1783
|
+
organization: `${protocol}//${organizationDomain}`,
|
|
1784
|
+
service: `${protocol}//${domain}`,
|
|
1785
|
+
subdomain,
|
|
1786
|
+
};
|
|
1787
|
+
}
|
|
1788
|
+
fromLocation(window && window.location);
|
|
1571
1789
|
|
|
1572
|
-
const
|
|
1573
|
-
const
|
|
1574
|
-
|
|
1575
|
-
SCREEN_SHARE: "screen_share",
|
|
1790
|
+
const logger$9 = new Logger();
|
|
1791
|
+
const debugLogger = {
|
|
1792
|
+
print: (...args) => console.debug(args[0], ...args.slice(1)),
|
|
1576
1793
|
};
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
this.
|
|
1581
|
-
this.
|
|
1582
|
-
this.
|
|
1583
|
-
this.
|
|
1584
|
-
this.
|
|
1585
|
-
this.
|
|
1586
|
-
this.
|
|
1587
|
-
|
|
1794
|
+
logger$9.withDebugLogger(debugLogger);
|
|
1795
|
+
class PacketLossAnalyser {
|
|
1796
|
+
constructor() {
|
|
1797
|
+
this.BEGIN_PACKET_LOSS_PERIOD_THRESHOLD = 0.04;
|
|
1798
|
+
this.END_PACKET_LOSS_PERIOD_THRESHOLD = 0.005;
|
|
1799
|
+
this.INTERVAL_DIFF_THRESHOLD_MS = 4000;
|
|
1800
|
+
this.STALE_MEASUREMENT_TIMEOUT_MS = 10000;
|
|
1801
|
+
this.MINIMUM_INTERVAL_MS = 30000;
|
|
1802
|
+
this.ssrcsHistory = new Map();
|
|
1803
|
+
this.staleMeasurementTimeouts = new Map();
|
|
1804
|
+
}
|
|
1805
|
+
addPacketLossMeasurement(id, packetLoss, timestamp) {
|
|
1806
|
+
this.handleStaleMeasurements(id);
|
|
1807
|
+
const beginNewPacketLossPeriod = packetLoss > this.BEGIN_PACKET_LOSS_PERIOD_THRESHOLD;
|
|
1808
|
+
let history = this.ssrcsHistory.get(id);
|
|
1809
|
+
if (!history) {
|
|
1810
|
+
history = {
|
|
1811
|
+
id,
|
|
1812
|
+
hasActivePacketLoss: beginNewPacketLossPeriod,
|
|
1813
|
+
currPeriod: beginNewPacketLossPeriod ? { begin: timestamp } : undefined,
|
|
1814
|
+
hasPeriodicPacketLoss: false,
|
|
1815
|
+
};
|
|
1816
|
+
this.ssrcsHistory.set(id, history);
|
|
1817
|
+
return;
|
|
1818
|
+
}
|
|
1819
|
+
if (history.hasActivePacketLoss) {
|
|
1820
|
+
if (packetLoss < this.END_PACKET_LOSS_PERIOD_THRESHOLD) {
|
|
1821
|
+
this.endPacketLossPeriod(history, timestamp);
|
|
1822
|
+
if (history.prevIntervalInMs && history.prevIntervalInMs < this.MINIMUM_INTERVAL_MS) {
|
|
1823
|
+
this.ssrcsHistory.delete(id);
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
return;
|
|
1827
|
+
}
|
|
1828
|
+
if (beginNewPacketLossPeriod) {
|
|
1829
|
+
history.hasActivePacketLoss = true;
|
|
1830
|
+
history.currPeriod = {
|
|
1831
|
+
begin: timestamp,
|
|
1832
|
+
};
|
|
1833
|
+
}
|
|
1588
1834
|
}
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
this.
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1835
|
+
hasPeriodicPacketLoss(id, timestamp) {
|
|
1836
|
+
const history = this.ssrcsHistory.get(id);
|
|
1837
|
+
if (history && this.prevIntervalExceeded(history, timestamp)) {
|
|
1838
|
+
this.ssrcsHistory.delete(history.id);
|
|
1839
|
+
return false;
|
|
1840
|
+
}
|
|
1841
|
+
return (history === null || history === void 0 ? void 0 : history.hasPeriodicPacketLoss) || false;
|
|
1595
1842
|
}
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1843
|
+
prevIntervalExceeded(history, timestamp) {
|
|
1844
|
+
if (history.prevPeriod && history.prevIntervalInMs) {
|
|
1845
|
+
const intervalLimitTimestamp = this.calculatePeriodCenterTimestamp(history.prevPeriod) +
|
|
1846
|
+
history.prevIntervalInMs +
|
|
1847
|
+
this.INTERVAL_DIFF_THRESHOLD_MS;
|
|
1848
|
+
return timestamp > intervalLimitTimestamp;
|
|
1849
|
+
}
|
|
1850
|
+
return false;
|
|
1599
1851
|
}
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
if (
|
|
1603
|
-
|
|
1852
|
+
handleStaleMeasurements(id) {
|
|
1853
|
+
const staleMeasurementTimeout = this.staleMeasurementTimeouts.get(id);
|
|
1854
|
+
if (staleMeasurementTimeout) {
|
|
1855
|
+
clearTimeout(staleMeasurementTimeout);
|
|
1604
1856
|
}
|
|
1605
|
-
this.
|
|
1606
|
-
|
|
1607
|
-
|
|
1857
|
+
this.staleMeasurementTimeouts.set(id, setTimeout(() => {
|
|
1858
|
+
logger$9.debug("handleStaleMeasurements() [measurements invalid for ssrc: %s]", id);
|
|
1859
|
+
this.ssrcsHistory.delete(id);
|
|
1860
|
+
}, this.STALE_MEASUREMENT_TIMEOUT_MS));
|
|
1608
1861
|
}
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
if (!
|
|
1612
|
-
|
|
1862
|
+
endPacketLossPeriod(history, timestamp) {
|
|
1863
|
+
logger$9.debug("endPacketLossPeriod() [ssrcId: %s, timestamp: %s]", history.id, timestamp);
|
|
1864
|
+
if (!history.currPeriod)
|
|
1865
|
+
throw new Error("No packet loss period for " + history.id);
|
|
1866
|
+
if (!history.prevPeriod) {
|
|
1867
|
+
history.prevPeriod = Object.assign(Object.assign({}, history.currPeriod), { end: timestamp });
|
|
1613
1868
|
}
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1869
|
+
else {
|
|
1870
|
+
history.currPeriod.end = timestamp;
|
|
1871
|
+
this.addNewPacketLossInterval(history);
|
|
1872
|
+
}
|
|
1873
|
+
delete history.currPeriod;
|
|
1874
|
+
history.hasActivePacketLoss = false;
|
|
1617
1875
|
}
|
|
1618
|
-
|
|
1619
|
-
|
|
1876
|
+
addNewPacketLossInterval(history) {
|
|
1877
|
+
logger$9.debug("addNewPacketLossInterval() [ssrcId: %s, prevIntervalInMs: %s]", history.id, history.prevIntervalInMs);
|
|
1878
|
+
if (!history.currPeriod || !history.prevPeriod)
|
|
1879
|
+
throw new Error("missing period timestamps");
|
|
1880
|
+
const prevPeriodCenter = this.calculatePeriodCenterTimestamp(history.prevPeriod);
|
|
1881
|
+
const currPeriodCenter = this.calculatePeriodCenterTimestamp(history.currPeriod);
|
|
1882
|
+
const currIntervalInMs = currPeriodCenter - prevPeriodCenter;
|
|
1883
|
+
if (history.prevIntervalInMs) {
|
|
1884
|
+
const intervalDiffInMs = Math.abs(history.prevIntervalInMs - currIntervalInMs);
|
|
1885
|
+
history.hasPeriodicPacketLoss = intervalDiffInMs < this.INTERVAL_DIFF_THRESHOLD_MS;
|
|
1886
|
+
logger$9.debug("addNewPacketLossInterval() [hasPeriodicPacketLoss: %s, intervalDiffInMs: %s]", intervalDiffInMs < this.INTERVAL_DIFF_THRESHOLD_MS, intervalDiffInMs);
|
|
1887
|
+
}
|
|
1888
|
+
history.prevIntervalInMs = currIntervalInMs;
|
|
1889
|
+
history.prevPeriod = history.currPeriod;
|
|
1620
1890
|
}
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1891
|
+
calculatePeriodCenterTimestamp(period) {
|
|
1892
|
+
if (!period.end)
|
|
1893
|
+
throw new Error("Missing period end timestamp");
|
|
1894
|
+
return period.begin + (period.end - period.begin) / 2;
|
|
1624
1895
|
}
|
|
1625
1896
|
}
|
|
1626
1897
|
|
|
1627
|
-
|
|
1628
|
-
const
|
|
1629
|
-
const
|
|
1630
|
-
const
|
|
1631
|
-
const
|
|
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
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1898
|
+
var _a$5;
|
|
1899
|
+
const adapter$5 = (_a$5 = adapterRaw.default) !== null && _a$5 !== void 0 ? _a$5 : adapterRaw;
|
|
1900
|
+
const logger$8 = new Logger();
|
|
1901
|
+
const browserName$2 = adapter$5.browserDetails.browser;
|
|
1902
|
+
const browserVersion$1 = adapter$5.browserDetails.version;
|
|
1903
|
+
function setCodecPreferenceSDP(sdp, redOn) {
|
|
1904
|
+
var _a, _b;
|
|
1905
|
+
try {
|
|
1906
|
+
const sdpObject = sdpTransform__namespace.parse(sdp);
|
|
1907
|
+
if (Array.isArray(sdpObject === null || sdpObject === void 0 ? void 0 : sdpObject.media)) {
|
|
1908
|
+
const mediaAudio = sdpObject.media.find((m) => m.type === "audio");
|
|
1909
|
+
if (Array.isArray(mediaAudio === null || mediaAudio === void 0 ? void 0 : mediaAudio.rtp)) {
|
|
1910
|
+
const rtp = mediaAudio.rtp;
|
|
1911
|
+
for (let i = 0; i < rtp.length; i++) {
|
|
1912
|
+
if (redOn && rtp[i].codec === "red") {
|
|
1913
|
+
const payloads = (_a = mediaAudio.payloads) === null || _a === void 0 ? void 0 : _a.split(" ");
|
|
1914
|
+
const pt = payloads === null || payloads === void 0 ? void 0 : payloads.indexOf("" + rtp[i].payload);
|
|
1915
|
+
if (pt && pt !== -1 && pt >= 0) {
|
|
1916
|
+
payloads === null || payloads === void 0 ? void 0 : payloads.unshift(payloads.splice(pt, 1)[0]);
|
|
1917
|
+
mediaAudio.payloads = payloads === null || payloads === void 0 ? void 0 : payloads.join(" ");
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
const mediaVideo = sdpObject.media.find((m) => m.type === "video");
|
|
1923
|
+
if (Array.isArray(mediaVideo === null || mediaVideo === void 0 ? void 0 : mediaVideo.rtp)) {
|
|
1924
|
+
const rtp = mediaVideo.rtp;
|
|
1925
|
+
for (let i = 0; i < rtp.length; i++) {
|
|
1926
|
+
if (rtp[i].codec === "VP9") {
|
|
1927
|
+
const payloads = (_b = mediaVideo.payloads) === null || _b === void 0 ? void 0 : _b.split(" ");
|
|
1928
|
+
const pt = payloads === null || payloads === void 0 ? void 0 : payloads.indexOf("" + rtp[i].payload);
|
|
1929
|
+
if (pt && pt !== -1 && pt >= 0) {
|
|
1930
|
+
payloads === null || payloads === void 0 ? void 0 : payloads.unshift(payloads.splice(pt, 1)[0]);
|
|
1931
|
+
mediaVideo.payloads = payloads === null || payloads === void 0 ? void 0 : payloads.join(" ");
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
const newSdp = sdpTransform__namespace.write(sdpObject);
|
|
1938
|
+
return newSdp;
|
|
1939
|
+
}
|
|
1940
|
+
catch (error) {
|
|
1941
|
+
logger$8.error("setCodecPreferenceSDP error:", error);
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
function cleanSdp(sdp) {
|
|
1945
|
+
try {
|
|
1946
|
+
const sdpObject = sdpTransform__namespace.parse(sdp);
|
|
1947
|
+
sdpObject.media.forEach((mediaObject) => {
|
|
1948
|
+
const usedPayloads = {};
|
|
1949
|
+
if (mediaObject.payloads)
|
|
1950
|
+
mediaObject.payloads = ("" + mediaObject.payloads)
|
|
1951
|
+
.split(" ")
|
|
1952
|
+
.filter((p) => !usedPayloads[p] && (usedPayloads[p] = true))
|
|
1953
|
+
.join(" ");
|
|
1954
|
+
const usedRtps = {};
|
|
1955
|
+
mediaObject.rtp = mediaObject.rtp.filter((p) => !p.payload || (usedPayloads[p.payload] && !usedRtps[p.payload] && (usedRtps[p.payload] = true)));
|
|
1956
|
+
const usedFmtps = {};
|
|
1957
|
+
if (mediaObject.fmtp)
|
|
1958
|
+
mediaObject.fmtp = mediaObject.fmtp.filter((p) => !p.payload ||
|
|
1959
|
+
(usedPayloads[p.payload] && !usedFmtps[p.payload] && (usedFmtps[p.payload] = true)));
|
|
1960
|
+
const usedRtcpFb = {};
|
|
1961
|
+
if (mediaObject.rtcpFb)
|
|
1962
|
+
mediaObject.rtcpFb = mediaObject.rtcpFb.filter((p) => !p.payload ||
|
|
1963
|
+
(usedPayloads[p.payload] &&
|
|
1964
|
+
!usedRtcpFb[p.payload + p.type + p.subtype] &&
|
|
1965
|
+
(usedRtcpFb[p.payload + p.type + p.subtype] = true)));
|
|
1966
|
+
});
|
|
1967
|
+
return sdpTransform__namespace.write(sdpObject);
|
|
1968
|
+
}
|
|
1969
|
+
catch (_) { }
|
|
1970
|
+
return sdp;
|
|
1971
|
+
}
|
|
1972
|
+
function maybeRejectNoH264(sdp) {
|
|
1973
|
+
if (browserName$2 !== "safari") {
|
|
1974
|
+
return sdp;
|
|
1975
|
+
}
|
|
1976
|
+
const sections = SDPUtils.splitSections(sdp);
|
|
1977
|
+
for (let i = 1; i < sections.length; i++) {
|
|
1978
|
+
if (SDPUtils.getKind(sections[i]) !== "video") {
|
|
1979
|
+
continue;
|
|
1980
|
+
}
|
|
1981
|
+
const codecs = SDPUtils.matchPrefix(sections[i], "a=rtpmap:")
|
|
1982
|
+
.map((line) => {
|
|
1983
|
+
return SDPUtils.parseRtpMap(line);
|
|
1984
|
+
})
|
|
1985
|
+
.map((codec) => {
|
|
1986
|
+
return codec.name.toUpperCase();
|
|
1987
|
+
});
|
|
1988
|
+
if (codecs.indexOf("H264") === -1 &&
|
|
1989
|
+
sections[i][8] === "9") {
|
|
1990
|
+
sections[i] = sections[i].replace("m=video 9 ", "m=video 0 ");
|
|
1687
1991
|
}
|
|
1688
1992
|
}
|
|
1993
|
+
return sections.join("");
|
|
1994
|
+
}
|
|
1995
|
+
function deprioritizeH264(sdp) {
|
|
1996
|
+
return SDPUtils.splitSections(sdp)
|
|
1997
|
+
.map((section) => {
|
|
1998
|
+
if (SDPUtils.getKind(section) !== "video")
|
|
1999
|
+
return section;
|
|
2000
|
+
const h264payloadTypes = SDPUtils.matchPrefix(section, "a=rtpmap:")
|
|
2001
|
+
.map((line) => SDPUtils.parseRtpMap(line))
|
|
2002
|
+
.filter((codec) => /h264/i.test(codec.name))
|
|
2003
|
+
.map((codec) => "" + codec.payloadType);
|
|
2004
|
+
if (!h264payloadTypes.length)
|
|
2005
|
+
return section;
|
|
2006
|
+
const mline = SDPUtils.matchPrefix(section, "m=video")[0];
|
|
2007
|
+
const mlinePayloadsSectionExec = /(\s\d+)+$/i.exec(mline);
|
|
2008
|
+
const mlinePayloadsSection = mlinePayloadsSectionExec ? mlinePayloadsSectionExec[0] : "";
|
|
2009
|
+
const mlinePayloadsNonH264 = mlinePayloadsSection
|
|
2010
|
+
.split(" ")
|
|
2011
|
+
.filter((payloadType) => payloadType && !h264payloadTypes.includes(payloadType));
|
|
2012
|
+
const reorderedPayloads = [...mlinePayloadsNonH264, ...h264payloadTypes].join(" ");
|
|
2013
|
+
const newmline = mline.replace(mlinePayloadsSection, " " + reorderedPayloads);
|
|
2014
|
+
return section.replace(mline, newmline);
|
|
2015
|
+
})
|
|
2016
|
+
.join("");
|
|
2017
|
+
}
|
|
2018
|
+
function replaceSSRCs(currentDescription, newDescription) {
|
|
2019
|
+
let ssrcs = currentDescription.match(/a=ssrc-group:FID (\d+) (\d+)\r\n/);
|
|
2020
|
+
let newssrcs = newDescription.match(/a=ssrc-group:FID (\d+) (\d+)\r\n/);
|
|
2021
|
+
if (!ssrcs) {
|
|
2022
|
+
ssrcs = currentDescription.match(/a=ssrc:(\d+) cname:(.*)\r\n/g)[1].match(/a=ssrc:(\d+)/);
|
|
2023
|
+
newssrcs = newDescription.match(/a=ssrc:(\d+) cname:(.*)\r\n/g)[1].match(/a=ssrc:(\d+)/);
|
|
2024
|
+
}
|
|
2025
|
+
for (let i = 1; i < ssrcs.length; i++) {
|
|
2026
|
+
newDescription = newDescription.replace(new RegExp(newssrcs[i], "g"), ssrcs[i]);
|
|
2027
|
+
}
|
|
2028
|
+
return newDescription;
|
|
1689
2029
|
}
|
|
1690
|
-
function
|
|
1691
|
-
if (
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
generatedMessage = true;
|
|
1695
|
-
message = "No value argument passed to `assert.ok()`";
|
|
1696
|
-
}
|
|
1697
|
-
else if (message instanceof Error) {
|
|
1698
|
-
throw message;
|
|
1699
|
-
}
|
|
1700
|
-
const err = new AssertionError({
|
|
1701
|
-
actual: value,
|
|
1702
|
-
expected: true,
|
|
1703
|
-
message,
|
|
1704
|
-
operator: "==",
|
|
1705
|
-
stackStartFn: fn,
|
|
1706
|
-
});
|
|
1707
|
-
err.generatedMessage = generatedMessage;
|
|
1708
|
-
throw err;
|
|
2030
|
+
function filterMidExtension(sdp) {
|
|
2031
|
+
if (browserName$2 !== "safari" &&
|
|
2032
|
+
(browserName$2 !== "firefox" || (browserVersion$1 && browserVersion$1 >= 63) || browserVersion$1 === 60)) {
|
|
2033
|
+
return sdp;
|
|
1709
2034
|
}
|
|
2035
|
+
return (SDPUtils.splitLines(sdp.trim())
|
|
2036
|
+
.filter((line) => {
|
|
2037
|
+
if (!line.startsWith("a=extmap:")) {
|
|
2038
|
+
return true;
|
|
2039
|
+
}
|
|
2040
|
+
const extmap = SDPUtils.parseExtmap(line);
|
|
2041
|
+
return extmap.uri !== "urn:ietf:params:rtp-hdrext:sdes:mid";
|
|
2042
|
+
})
|
|
2043
|
+
.join("\r\n") + "\r\n");
|
|
1710
2044
|
}
|
|
1711
|
-
function
|
|
1712
|
-
if (
|
|
1713
|
-
|
|
1714
|
-
|
|
2045
|
+
function filterMsidSemantic(sdp) {
|
|
2046
|
+
if (browserName$2 !== "firefox") {
|
|
2047
|
+
return sdp;
|
|
2048
|
+
}
|
|
2049
|
+
return (SDPUtils.splitLines(sdp.trim())
|
|
2050
|
+
.map((line) => (line.startsWith("a=msid-semantic:") ? "a=msid-semantic: WMS *" : line))
|
|
2051
|
+
.join("\r\n") + "\r\n");
|
|
1715
2052
|
}
|
|
1716
|
-
function
|
|
1717
|
-
|
|
2053
|
+
function changeMediaDirection(sdp, active) {
|
|
2054
|
+
const sections = SDPUtils.splitSections(sdp);
|
|
2055
|
+
return (sections.shift() +
|
|
2056
|
+
sections
|
|
2057
|
+
.map((section) => {
|
|
2058
|
+
const currentDirection = SDPUtils.getDirection(section, SDPUtils.getKind(section));
|
|
2059
|
+
return section.replace("a=" + currentDirection, "a=" + (active ? "recvonly" : "inactive"));
|
|
2060
|
+
})
|
|
2061
|
+
.join(""));
|
|
1718
2062
|
}
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
2063
|
+
function addExtMap(sdp, extmapUri, modifyAudio = false, modifyVideo = false) {
|
|
2064
|
+
var _a, _b;
|
|
2065
|
+
try {
|
|
2066
|
+
const sdpObj = sdpTransform__namespace.parse(sdp);
|
|
2067
|
+
if (((_a = sdpObj === null || sdpObj === void 0 ? void 0 : sdpObj.ext) === null || _a === void 0 ? void 0 : _a.length) && sdpObj.ext.length > 0) {
|
|
2068
|
+
return sdp;
|
|
2069
|
+
}
|
|
2070
|
+
if ((sdpObj === null || sdpObj === void 0 ? void 0 : sdpObj.media.length) < 1)
|
|
2071
|
+
return sdp;
|
|
2072
|
+
const allHeaderExtensions = sdpObj === null || sdpObj === void 0 ? void 0 : sdpObj.media.flatMap((section) => section.ext || []);
|
|
2073
|
+
const extmapId = ((_b = allHeaderExtensions.find((ext) => ext.uri === extmapUri)) === null || _b === void 0 ? void 0 : _b.value) ||
|
|
2074
|
+
[...new Set([0, 15, ...allHeaderExtensions.map((ext) => ext.value)])]
|
|
2075
|
+
.sort((a, b) => a - b)
|
|
2076
|
+
.find((n, i, arr) => n + 1 !== arr[i + 1]) + 1;
|
|
2077
|
+
sdpObj.media.forEach((mediaSection) => {
|
|
2078
|
+
var _a;
|
|
2079
|
+
if ((modifyAudio && mediaSection.type === "audio") || (modifyVideo && mediaSection.type === "video")) {
|
|
2080
|
+
if (!((_a = mediaSection.ext) === null || _a === void 0 ? void 0 : _a.find((e) => e.uri === extmapUri))) {
|
|
2081
|
+
if (Array.isArray(mediaSection.ext)) {
|
|
2082
|
+
mediaSection["ext"].push({ value: extmapId, uri: extmapUri });
|
|
2083
|
+
}
|
|
2084
|
+
else {
|
|
2085
|
+
mediaSection["ext"] = [{ value: extmapId, uri: extmapUri }];
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
1727
2089
|
});
|
|
1728
|
-
|
|
1729
|
-
ok,
|
|
1730
|
-
};
|
|
1731
|
-
assert.notEqual = function notEqual(actual, expected, message) {
|
|
1732
|
-
if (arguments.length < 2) {
|
|
1733
|
-
throw new Error("'actual' and 'expected' arguments are required");
|
|
2090
|
+
return sdpTransform__namespace.write(sdpObj);
|
|
1734
2091
|
}
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
actual,
|
|
1738
|
-
expected,
|
|
1739
|
-
message,
|
|
1740
|
-
operator: "!=",
|
|
1741
|
-
stackStartFn: notEqual,
|
|
1742
|
-
});
|
|
2092
|
+
catch (error) {
|
|
2093
|
+
console.error("Error during addAbsCaptureTimeExtMap: ", error);
|
|
1743
2094
|
}
|
|
1744
|
-
|
|
1745
|
-
|
|
2095
|
+
return sdp;
|
|
2096
|
+
}
|
|
2097
|
+
function addAbsCaptureTimeExtMap(sdp) {
|
|
2098
|
+
const absCaptureTimeUri = "http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time";
|
|
2099
|
+
return addExtMap(sdp, absCaptureTimeUri, true, true);
|
|
2100
|
+
}
|
|
1746
2101
|
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
if (count === 0) {
|
|
1752
|
-
return "";
|
|
2102
|
+
function setVideoBandwidthUsingSetParameters(pc, bandwidth, logger = console) {
|
|
2103
|
+
const sender = pc.getSenders().find((s) => s.track && s.track.kind === "video");
|
|
2104
|
+
if (!sender) {
|
|
2105
|
+
return Promise.resolve();
|
|
1753
2106
|
}
|
|
1754
|
-
const
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
result += result;
|
|
2107
|
+
const parameters = sender.getParameters();
|
|
2108
|
+
if (parameters.encodings && parameters.encodings.length === 0) {
|
|
2109
|
+
return Promise.resolve();
|
|
1758
2110
|
}
|
|
1759
|
-
|
|
1760
|
-
};
|
|
1761
|
-
|
|
1762
|
-
const getMediasoupDeviceAsync = (features) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1763
|
-
if (features.isNodeSdk) {
|
|
1764
|
-
return new mediasoupClient.Device({ handlerName: "Safari12" });
|
|
2111
|
+
if (!parameters.encodings) {
|
|
2112
|
+
parameters.encodings = [{}];
|
|
1765
2113
|
}
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
if (/iphone|ipad/i.test(navigator.userAgent)) {
|
|
1769
|
-
handlerName = "Safari12";
|
|
2114
|
+
if (bandwidth === 0) {
|
|
2115
|
+
delete parameters.encodings[0].maxBitrate;
|
|
1770
2116
|
}
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
const AUDIO_SETTINGS = {
|
|
1775
|
-
codecOptions: {
|
|
1776
|
-
opusDtx: true,
|
|
1777
|
-
opusFec: true,
|
|
1778
|
-
},
|
|
1779
|
-
encodings: [{ dtx: true }],
|
|
1780
|
-
};
|
|
1781
|
-
const VIDEO_SETTINGS_HD = {
|
|
1782
|
-
codecOptions: {
|
|
1783
|
-
videoGoogleStartBitrate: 500,
|
|
1784
|
-
},
|
|
1785
|
-
encodings: [
|
|
1786
|
-
{ scaleResolutionDownBy: 4, maxBitrate: 150000 },
|
|
1787
|
-
{ scaleResolutionDownBy: 2, maxBitrate: 500000 },
|
|
1788
|
-
{ scaleResolutionDownBy: 1, maxBitrate: 1000000 },
|
|
1789
|
-
],
|
|
1790
|
-
};
|
|
1791
|
-
const VIDEO_SETTINGS_SD = {
|
|
1792
|
-
codecOptions: {
|
|
1793
|
-
videoGoogleStartBitrate: 500,
|
|
1794
|
-
},
|
|
1795
|
-
encodings: [
|
|
1796
|
-
{ scaleResolutionDownBy: 2, maxBitrate: 150000 },
|
|
1797
|
-
{ scaleResolutionDownBy: 1, maxBitrate: 500000 },
|
|
1798
|
-
],
|
|
1799
|
-
};
|
|
1800
|
-
const VIDEO_SETTINGS_VP9 = {
|
|
1801
|
-
codecOptions: {
|
|
1802
|
-
videoGoogleStartBitrate: 500,
|
|
1803
|
-
},
|
|
1804
|
-
encodings: [{ scalabilityMode: "L3T2", maxBitrate: 1000000 }],
|
|
1805
|
-
};
|
|
1806
|
-
const VIDEO_SETTINGS_VP9_LOW_BANDWIDTH = {
|
|
1807
|
-
codecOptions: {
|
|
1808
|
-
videoGoogleStartBitrate: 500,
|
|
1809
|
-
},
|
|
1810
|
-
encodings: [{ scalabilityMode: "L2T2", maxBitrate: 500000 }],
|
|
1811
|
-
};
|
|
1812
|
-
const SCREEN_SHARE_SETTINGS = {
|
|
1813
|
-
encodings: [{}],
|
|
1814
|
-
};
|
|
1815
|
-
const SCREEN_SHARE_SIMULCAST_SETTINGS = {
|
|
1816
|
-
encodings: [
|
|
1817
|
-
{ scaleResolutionDownBy: 2, dtx: true, maxBitrate: 500000 },
|
|
1818
|
-
{ scaleResolutionDownBy: 1, dtx: true, maxBitrate: 1500000 },
|
|
1819
|
-
],
|
|
1820
|
-
};
|
|
1821
|
-
const ADDITIONAL_SCREEN_SHARE_SETTINGS = {
|
|
1822
|
-
encodings: [
|
|
1823
|
-
{ scaleResolutionDownBy: 4, dtx: true, maxBitrate: 150000 },
|
|
1824
|
-
{ scaleResolutionDownBy: 2, dtx: true, maxBitrate: 500000 },
|
|
1825
|
-
{ scaleResolutionDownBy: 1, dtx: true, maxBitrate: 1500000 },
|
|
1826
|
-
],
|
|
1827
|
-
};
|
|
1828
|
-
const getMediaSettings = (kind, isScreenShare, features, isSomeoneAlreadyPresenting = false) => {
|
|
1829
|
-
const { lowDataModeEnabled, simulcastScreenshareOn, vp9On } = features;
|
|
1830
|
-
if (kind === "audio") {
|
|
1831
|
-
return AUDIO_SETTINGS;
|
|
2117
|
+
else {
|
|
2118
|
+
parameters.encodings[0].maxBitrate = bandwidth * 1000;
|
|
1832
2119
|
}
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
2120
|
+
return sender.setParameters(parameters).catch((err) => {
|
|
2121
|
+
logger.error("setParameters err: ", err);
|
|
2122
|
+
});
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
var _a$4;
|
|
2126
|
+
const adapter$4 = (_a$4 = adapterRaw.default) !== null && _a$4 !== void 0 ? _a$4 : adapterRaw;
|
|
2127
|
+
const logger$7 = new Logger();
|
|
2128
|
+
class Session {
|
|
2129
|
+
constructor({ peerConnectionId, bandwidth, deprioritizeH264Encoding, }) {
|
|
2130
|
+
this.peerConnectionId = peerConnectionId;
|
|
2131
|
+
this.relayCandidateSeen = false;
|
|
2132
|
+
this.serverReflexiveCandidateSeen = false;
|
|
2133
|
+
this.publicHostCandidateSeen = false;
|
|
2134
|
+
this.ipv6HostCandidateSeen = false;
|
|
2135
|
+
this.ipv6HostCandidateTeredoSeen = false;
|
|
2136
|
+
this.ipv6HostCandidate6to4Seen = false;
|
|
2137
|
+
this.mdnsHostCandidateSeen = false;
|
|
2138
|
+
this.pc = null;
|
|
2139
|
+
this.wasEverConnected = false;
|
|
2140
|
+
this.connectionStatus = null;
|
|
2141
|
+
this.stats = {
|
|
2142
|
+
totalSent: 0,
|
|
2143
|
+
totalRecv: 0,
|
|
2144
|
+
};
|
|
2145
|
+
this.bandwidth = bandwidth || 0;
|
|
2146
|
+
this.pending = [];
|
|
2147
|
+
this.isOperationPending = false;
|
|
2148
|
+
this.streamIds = [];
|
|
2149
|
+
this.streams = [];
|
|
2150
|
+
this.earlyIceCandidates = [];
|
|
2151
|
+
this.afterConnected = new Promise((resolve) => {
|
|
2152
|
+
this.registerConnected = resolve;
|
|
1839
2153
|
});
|
|
2154
|
+
this.offerOptions = { offerToReceiveAudio: true, offerToReceiveVideo: true };
|
|
2155
|
+
this._deprioritizeH264Encoding = deprioritizeH264Encoding;
|
|
1840
2156
|
}
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
2157
|
+
setAndGetPeerConnection({ clientId, constraints, peerConnectionConfig, shouldAddLocalVideo, }) {
|
|
2158
|
+
this.peerConnectionConfig = peerConnectionConfig;
|
|
2159
|
+
this.shouldAddLocalVideo = shouldAddLocalVideo;
|
|
2160
|
+
this.clientId = clientId;
|
|
2161
|
+
this.pc = new RTCPeerConnection(peerConnectionConfig);
|
|
2162
|
+
this.signalingState = this.pc.signalingState;
|
|
2163
|
+
this.pc.addEventListener("signalingstatechange", () => {
|
|
2164
|
+
if (this.signalingState === this.pc.signalingState) {
|
|
2165
|
+
return;
|
|
2166
|
+
}
|
|
2167
|
+
this.signalingState = this.pc.signalingState;
|
|
2168
|
+
if (this.pc.signalingState === "stable") {
|
|
2169
|
+
this.isOperationPending = false;
|
|
2170
|
+
const action = this.pending.shift();
|
|
2171
|
+
if (action) {
|
|
2172
|
+
action.apply();
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
1845
2175
|
});
|
|
2176
|
+
return this.pc;
|
|
1846
2177
|
}
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
if (
|
|
1851
|
-
|
|
2178
|
+
addStream(stream) {
|
|
2179
|
+
this.streamIds.push(stream.id);
|
|
2180
|
+
this.streams.push(stream);
|
|
2181
|
+
if (RTCPeerConnection.prototype.addTrack) {
|
|
2182
|
+
stream.getAudioTracks().forEach((track) => {
|
|
2183
|
+
this.pc.addTrack(track, stream);
|
|
2184
|
+
});
|
|
2185
|
+
stream.getVideoTracks().forEach((track) => {
|
|
2186
|
+
this.pc.addTrack(track, stream);
|
|
2187
|
+
});
|
|
2188
|
+
}
|
|
2189
|
+
else {
|
|
2190
|
+
this.pc.addStream(stream);
|
|
1852
2191
|
}
|
|
1853
|
-
return VIDEO_SETTINGS_SD;
|
|
1854
|
-
}
|
|
1855
|
-
if (isVp9Available) {
|
|
1856
|
-
return VIDEO_SETTINGS_VP9;
|
|
1857
|
-
}
|
|
1858
|
-
return VIDEO_SETTINGS_HD;
|
|
1859
|
-
};
|
|
1860
|
-
const getScreenShareMediaSettings = ({ isSomeoneAlreadyPresenting, simulcastScreenshareOn, }) => {
|
|
1861
|
-
if (isSomeoneAlreadyPresenting) {
|
|
1862
|
-
return ADDITIONAL_SCREEN_SHARE_SETTINGS;
|
|
1863
|
-
}
|
|
1864
|
-
if (simulcastScreenshareOn)
|
|
1865
|
-
return SCREEN_SHARE_SIMULCAST_SETTINGS;
|
|
1866
|
-
return SCREEN_SHARE_SETTINGS;
|
|
1867
|
-
};
|
|
1868
|
-
var PrioritizableCodec;
|
|
1869
|
-
(function (PrioritizableCodec) {
|
|
1870
|
-
PrioritizableCodec["H264"] = "video/h264";
|
|
1871
|
-
PrioritizableCodec["VP9"] = "video/vp9";
|
|
1872
|
-
})(PrioritizableCodec || (PrioritizableCodec = {}));
|
|
1873
|
-
const modifyMediaCapabilities = (routerRtpCapabilities, features) => {
|
|
1874
|
-
const { vp9On, h264On } = features;
|
|
1875
|
-
const isChrome = adapterRaw.browserDetails.browser === "chrome";
|
|
1876
|
-
if (!(routerRtpCapabilities === null || routerRtpCapabilities === void 0 ? void 0 : routerRtpCapabilities.codecs)) {
|
|
1877
|
-
return routerRtpCapabilities;
|
|
1878
|
-
}
|
|
1879
|
-
if (vp9On && isChrome) {
|
|
1880
|
-
const sorted = prioritizeRouterRtpCapabilitiesCodecs(routerRtpCapabilities.codecs, PrioritizableCodec.VP9);
|
|
1881
|
-
return Object.assign(Object.assign({}, routerRtpCapabilities), { codecs: sorted });
|
|
1882
2192
|
}
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
2193
|
+
addTrack(track, stream) {
|
|
2194
|
+
if (!stream) {
|
|
2195
|
+
stream = this.streams[0];
|
|
2196
|
+
}
|
|
2197
|
+
stream === null || stream === void 0 ? void 0 : stream.addTrack(track);
|
|
2198
|
+
this.pc.addTrack(track, stream);
|
|
1886
2199
|
}
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
2200
|
+
removeTrack(track) {
|
|
2201
|
+
const stream = this.streams[0];
|
|
2202
|
+
stream.removeTrack(track);
|
|
2203
|
+
const sender = this.pc.getSenders().find((sender) => sender.track === track);
|
|
2204
|
+
if (sender) {
|
|
2205
|
+
this.pc.removeTrack(sender);
|
|
2206
|
+
}
|
|
1893
2207
|
}
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
2208
|
+
removeStream(stream) {
|
|
2209
|
+
for (let i = 0; i < this.streamIds.length; i++) {
|
|
2210
|
+
if (this.streamIds[i] === stream.id) {
|
|
2211
|
+
this.streamIds.splice(i, 1);
|
|
2212
|
+
this.streams.splice(i, 1);
|
|
2213
|
+
}
|
|
1898
2214
|
}
|
|
1899
|
-
if (
|
|
1900
|
-
(
|
|
1901
|
-
|
|
1902
|
-
|
|
2215
|
+
if (this.pc) {
|
|
2216
|
+
if (this.pc.removeTrack) {
|
|
2217
|
+
stream.getTracks().forEach((track) => {
|
|
2218
|
+
const sender = this.pc.getSenders().find((sender) => sender.track === track);
|
|
2219
|
+
if (sender) {
|
|
2220
|
+
this.pc.removeTrack(sender);
|
|
2221
|
+
}
|
|
2222
|
+
});
|
|
2223
|
+
}
|
|
2224
|
+
else if (this.pc.removeStream) {
|
|
2225
|
+
this.pc.removeStream(stream);
|
|
1903
2226
|
}
|
|
1904
|
-
return -1;
|
|
1905
2227
|
}
|
|
1906
|
-
return 0;
|
|
1907
|
-
});
|
|
1908
|
-
}
|
|
1909
|
-
function getPreferredOrder(availableCodecs, { av1On }) {
|
|
1910
|
-
availableCodecs.unshift("video/vp9");
|
|
1911
|
-
if (av1On) {
|
|
1912
|
-
availableCodecs.unshift("video/av1");
|
|
1913
2228
|
}
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
.
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
return codecs.sort((a, b) => {
|
|
1922
|
-
const indexA = preferredOrder.indexOf(a.mimeType.toLowerCase());
|
|
1923
|
-
const indexB = preferredOrder.indexOf(b.mimeType.toLowerCase());
|
|
1924
|
-
const orderA = indexA >= 0 ? indexA : Number.MAX_VALUE;
|
|
1925
|
-
const orderB = indexB >= 0 ? indexB : Number.MAX_VALUE;
|
|
1926
|
-
return orderA - orderB;
|
|
1927
|
-
});
|
|
1928
|
-
}
|
|
1929
|
-
function getIsCodecDecodingPowerEfficient(codec) {
|
|
1930
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
1931
|
-
const { powerEfficient } = yield navigator.mediaCapabilities.decodingInfo({
|
|
1932
|
-
type: "webrtc",
|
|
1933
|
-
video: {
|
|
1934
|
-
width: 1280,
|
|
1935
|
-
height: 720,
|
|
1936
|
-
bitrate: 2580,
|
|
1937
|
-
framerate: 24,
|
|
1938
|
-
contentType: codec,
|
|
1939
|
-
},
|
|
2229
|
+
_setRemoteDescription(desc) {
|
|
2230
|
+
if (this._deprioritizeH264Encoding)
|
|
2231
|
+
desc.sdp = deprioritizeH264(desc.sdp);
|
|
2232
|
+
this.srdComplete = this.pc.setRemoteDescription(desc);
|
|
2233
|
+
return this.srdComplete.then(() => {
|
|
2234
|
+
this.earlyIceCandidates.forEach((candidate) => this.pc.addIceCandidate(candidate));
|
|
2235
|
+
this.earlyIceCandidates = [];
|
|
1940
2236
|
});
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
2237
|
+
}
|
|
2238
|
+
handleOffer(message) {
|
|
2239
|
+
if (!this.canModifyPeerConnection()) {
|
|
2240
|
+
return new Promise((resolve) => {
|
|
2241
|
+
this.pending.push(() => this.handleOffer(message).then(resolve));
|
|
2242
|
+
});
|
|
2243
|
+
}
|
|
2244
|
+
this.isOperationPending = true;
|
|
2245
|
+
let sdp = message.sdp;
|
|
2246
|
+
sdp = filterMidExtension(sdp);
|
|
2247
|
+
sdp = filterMsidSemantic(sdp);
|
|
2248
|
+
const desc = { type: message.type, sdp };
|
|
2249
|
+
let answerToSignal;
|
|
2250
|
+
return this._setRemoteDescription(desc)
|
|
2251
|
+
.then(() => {
|
|
2252
|
+
return this.pc.createAnswer();
|
|
2253
|
+
})
|
|
2254
|
+
.then((answer) => {
|
|
2255
|
+
answerToSignal = answer;
|
|
2256
|
+
return this.pc.setLocalDescription(answer);
|
|
2257
|
+
})
|
|
2258
|
+
.then(() => {
|
|
2259
|
+
return setVideoBandwidthUsingSetParameters(this.pc, this.bandwidth);
|
|
2260
|
+
})
|
|
2261
|
+
.then(() => {
|
|
2262
|
+
return answerToSignal;
|
|
1952
2263
|
});
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
});
|
|
1962
|
-
}
|
|
1963
|
-
|
|
1964
|
-
const logger$8 = new Logger();
|
|
1965
|
-
class ReconnectManager extends EventEmitter {
|
|
1966
|
-
constructor(socket) {
|
|
1967
|
-
super();
|
|
1968
|
-
this.reconnectThresholdInMs = 0;
|
|
1969
|
-
this._socket = socket;
|
|
1970
|
-
this._clients = {};
|
|
1971
|
-
this._signalDisconnectTime = undefined;
|
|
1972
|
-
this.rtcManager = undefined;
|
|
1973
|
-
this.metrics = {
|
|
1974
|
-
roomJoinedLate: 0,
|
|
1975
|
-
pendingClientCanceled: 0,
|
|
1976
|
-
evaluationFailed: 0,
|
|
1977
|
-
roomJoined: 0,
|
|
1978
|
-
};
|
|
1979
|
-
socket.on("disconnect", () => {
|
|
1980
|
-
this._signalDisconnectTime = Date.now();
|
|
2264
|
+
}
|
|
2265
|
+
handleAnswer(message) {
|
|
2266
|
+
const sdp = filterMsidSemantic(message.sdp);
|
|
2267
|
+
const desc = { type: message.type, sdp };
|
|
2268
|
+
return this._setRemoteDescription(desc).then(() => {
|
|
2269
|
+
return setVideoBandwidthUsingSetParameters(this.pc, this.bandwidth);
|
|
2270
|
+
}, (e) => {
|
|
2271
|
+
logger$7.warn("Could not set remote description from remote answer: ", e);
|
|
1981
2272
|
});
|
|
1982
|
-
socket.on(PROTOCOL_RESPONSES.ROOM_JOINED, (payload) => this._onRoomJoined(payload));
|
|
1983
|
-
socket.on(PROTOCOL_RESPONSES.NEW_CLIENT, (payload) => this._onNewClient(payload));
|
|
1984
|
-
socket.on(PROTOCOL_RESPONSES.CLIENT_LEFT, (payload) => this._onClientLeft(payload));
|
|
1985
|
-
socket.on(PROTOCOL_EVENTS.PENDING_CLIENT_LEFT, (payload) => this._onPendingClientLeft(payload));
|
|
1986
|
-
socket.on(PROTOCOL_RESPONSES.AUDIO_ENABLED, (payload) => this._onAudioEnabled(payload));
|
|
1987
|
-
socket.on(PROTOCOL_RESPONSES.VIDEO_ENABLED, (payload) => this._onVideoEnabled(payload));
|
|
1988
|
-
socket.on(PROTOCOL_RESPONSES.SCREENSHARE_STARTED, (payload) => this._onScreenshareChanged(payload, true));
|
|
1989
|
-
socket.on(PROTOCOL_RESPONSES.SCREENSHARE_STOPPED, (payload) => this._onScreenshareChanged(payload, false));
|
|
1990
2273
|
}
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
}
|
|
1999
|
-
if (!payload.selfId) {
|
|
2000
|
-
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
2001
|
-
return;
|
|
2002
|
-
}
|
|
2003
|
-
const myDeviceId = (_a = payload.room.clients.find((c) => payload.selfId === c.id)) === null || _a === void 0 ? void 0 : _a.deviceId;
|
|
2004
|
-
if (!myDeviceId) {
|
|
2005
|
-
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
2006
|
-
return;
|
|
2007
|
-
}
|
|
2008
|
-
if (!this._signalDisconnectTime) {
|
|
2009
|
-
this._resetClientState(payload);
|
|
2010
|
-
payload.room.clients = payload.room.clients.filter((c) => !(c.deviceId === myDeviceId && c.isPendingToLeave));
|
|
2011
|
-
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
2274
|
+
addIceCandidate(candidate) {
|
|
2275
|
+
if (!this.srdComplete) {
|
|
2276
|
+
this.earlyIceCandidates.push(candidate);
|
|
2277
|
+
return;
|
|
2278
|
+
}
|
|
2279
|
+
this.srdComplete.then(() => {
|
|
2280
|
+
if (this.pc.signalingState === "closed") {
|
|
2012
2281
|
return;
|
|
2013
2282
|
}
|
|
2014
|
-
|
|
2015
|
-
const timeSinceDisconnect = Date.now() - this._signalDisconnectTime;
|
|
2016
|
-
if (timeSinceDisconnect > RECONNECT_THRESHOLD) {
|
|
2017
|
-
this._resetClientState(payload);
|
|
2018
|
-
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
2019
|
-
this.metrics.roomJoinedLate++;
|
|
2283
|
+
if (adapter$4.browserDetails.browser === "safari" && candidate && candidate.candidate === "") {
|
|
2020
2284
|
return;
|
|
2021
2285
|
}
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
payload.room.clients.forEach((client) => {
|
|
2025
|
-
var _a;
|
|
2026
|
-
try {
|
|
2027
|
-
if (client.id === payload.selfId)
|
|
2028
|
-
return;
|
|
2029
|
-
if (!this._clients[client.id]) {
|
|
2030
|
-
this._addClientToState(client);
|
|
2031
|
-
return;
|
|
2032
|
-
}
|
|
2033
|
-
if (!((_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.hasClient(client.id))) {
|
|
2034
|
-
return;
|
|
2035
|
-
}
|
|
2036
|
-
if (this._hasClientStateChanged({
|
|
2037
|
-
clientId: client.id,
|
|
2038
|
-
webcam: client.isVideoEnabled,
|
|
2039
|
-
mic: client.isAudioEnabled,
|
|
2040
|
-
screenShare: client.streams.length > 1,
|
|
2041
|
-
})) {
|
|
2042
|
-
return;
|
|
2043
|
-
}
|
|
2044
|
-
if (this._wasClientSendingMedia(client.id)) {
|
|
2045
|
-
if (!this._isClientMediaActive(allStats, client.id)) {
|
|
2046
|
-
return;
|
|
2047
|
-
}
|
|
2048
|
-
}
|
|
2049
|
-
client.mergeWithOldClientState = true;
|
|
2050
|
-
}
|
|
2051
|
-
catch (error) {
|
|
2052
|
-
logger$8.error("Failed to evaluate if we should merge client state %o", error);
|
|
2053
|
-
this.metrics.evaluationFailed++;
|
|
2054
|
-
}
|
|
2055
|
-
});
|
|
2056
|
-
payload.room.clients.forEach((c) => {
|
|
2057
|
-
if (c.isPendingToLeave) {
|
|
2058
|
-
this._onPendingClientLeft({ clientId: c.id });
|
|
2059
|
-
}
|
|
2286
|
+
this.pc.addIceCandidate(candidate).catch((e) => {
|
|
2287
|
+
logger$7.warn("Failed to add ICE candidate ('%s'): %s", candidate ? candidate.candidate : null, e);
|
|
2060
2288
|
});
|
|
2061
|
-
this.metrics.roomJoined++;
|
|
2062
|
-
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
2063
2289
|
});
|
|
2064
2290
|
}
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
const { clientId } = payload;
|
|
2068
|
-
const client = this._clients[clientId];
|
|
2069
|
-
if (client) {
|
|
2070
|
-
clearTimeout(client.timeout);
|
|
2071
|
-
delete this._clients[clientId];
|
|
2072
|
-
}
|
|
2073
|
-
(_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.disconnect(clientId, null, payload.eventClaim);
|
|
2074
|
-
this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, payload);
|
|
2291
|
+
canModifyPeerConnection() {
|
|
2292
|
+
return this.pc.signalingState === "stable" && !this.isOperationPending;
|
|
2075
2293
|
}
|
|
2076
|
-
|
|
2077
|
-
const
|
|
2078
|
-
|
|
2079
|
-
if (!client) {
|
|
2080
|
-
logger$8.warn(`client ${clientId} not found`);
|
|
2294
|
+
close() {
|
|
2295
|
+
const pc = this.pc;
|
|
2296
|
+
if (!pc) {
|
|
2081
2297
|
return;
|
|
2082
2298
|
}
|
|
2083
|
-
|
|
2084
|
-
|
|
2299
|
+
pc.oniceconnectionstatechange = null;
|
|
2300
|
+
pc.onicecandidate = null;
|
|
2301
|
+
pc.ontrack = null;
|
|
2302
|
+
try {
|
|
2303
|
+
pc.close();
|
|
2085
2304
|
}
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
client.checkActiveMediaAttempts = 0;
|
|
2089
|
-
this._abortIfNotActive(payload);
|
|
2305
|
+
catch (e) {
|
|
2306
|
+
logger$7.warn("failures during close of session", e);
|
|
2090
2307
|
}
|
|
2091
2308
|
}
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
const client = this._clients[clientId];
|
|
2095
|
-
if (client && client.isPendingToLeave) {
|
|
2096
|
-
clearTimeout(client.timeoutHandler);
|
|
2097
|
-
client.isPendingToLeave = false;
|
|
2098
|
-
this.metrics.pendingClientCanceled++;
|
|
2099
|
-
return;
|
|
2100
|
-
}
|
|
2101
|
-
this._getPendingClientsByDeviceId(deviceId).forEach((client) => {
|
|
2102
|
-
clearTimeout(client.timeoutHandler);
|
|
2103
|
-
client.isPendingToLeave = undefined;
|
|
2104
|
-
this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, { clientId: client.clientId });
|
|
2105
|
-
});
|
|
2106
|
-
this._addClientToState(payload.client);
|
|
2107
|
-
this.emit(PROTOCOL_RESPONSES.NEW_CLIENT, payload);
|
|
2309
|
+
hasConnectedPeerConnection() {
|
|
2310
|
+
return this.pc && this.pc.connectionState === "connected";
|
|
2108
2311
|
}
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2312
|
+
replaceTrack(oldTrack, newTrack) {
|
|
2313
|
+
const pc = this.pc;
|
|
2314
|
+
if (!pc)
|
|
2315
|
+
return false;
|
|
2316
|
+
const senders = pc.getSenders();
|
|
2317
|
+
if (!oldTrack) {
|
|
2318
|
+
oldTrack = (senders.find((s) => s.track && s.track.kind === newTrack.kind) || {}).track;
|
|
2319
|
+
}
|
|
2320
|
+
if (window.RTCRtpSender && window.RTCRtpSender.prototype.replaceTrack) {
|
|
2321
|
+
if (oldTrack) {
|
|
2322
|
+
const process = () => {
|
|
2323
|
+
for (let i = 0; i < senders.length; i++) {
|
|
2324
|
+
const sender = senders[i];
|
|
2325
|
+
const track = sender.track;
|
|
2326
|
+
if ((track === null || track === void 0 ? void 0 : track.id) === newTrack.id) {
|
|
2327
|
+
return Promise.resolve(newTrack);
|
|
2328
|
+
}
|
|
2329
|
+
if ((track === null || track === void 0 ? void 0 : track.id) === oldTrack.id) {
|
|
2330
|
+
return senders[i].replaceTrack(newTrack);
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
return null;
|
|
2334
|
+
};
|
|
2335
|
+
let result = process();
|
|
2336
|
+
if (result) {
|
|
2337
|
+
return result;
|
|
2338
|
+
}
|
|
2339
|
+
let resolve = null;
|
|
2340
|
+
let reject = null;
|
|
2341
|
+
result = new Promise((_resolve, _reject) => {
|
|
2342
|
+
resolve = _resolve;
|
|
2343
|
+
reject = _reject;
|
|
2344
|
+
});
|
|
2345
|
+
let retried = 0;
|
|
2346
|
+
let timer = setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
2347
|
+
const trackReplacedPromise = process();
|
|
2348
|
+
if (!trackReplacedPromise) {
|
|
2349
|
+
if (3 < ++retried) {
|
|
2350
|
+
clearInterval(timer);
|
|
2351
|
+
timer = null;
|
|
2352
|
+
reject("No sender track to replace");
|
|
2353
|
+
}
|
|
2354
|
+
return;
|
|
2355
|
+
}
|
|
2356
|
+
clearInterval(timer);
|
|
2357
|
+
timer = null;
|
|
2358
|
+
const trackReplaced = yield trackReplacedPromise;
|
|
2359
|
+
resolve(trackReplaced);
|
|
2360
|
+
}), 1000);
|
|
2361
|
+
return result;
|
|
2123
2362
|
}
|
|
2124
|
-
|
|
2125
|
-
if (
|
|
2126
|
-
|
|
2127
|
-
delete this._clients[clientId];
|
|
2128
|
-
this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, payload);
|
|
2363
|
+
const stream = this.streams.find((s) => s.getTracks().find((t) => t.id === newTrack.id)) || this.streams[0];
|
|
2364
|
+
if (!stream) {
|
|
2365
|
+
return Promise.reject(new Error("replaceTrack: No stream?"));
|
|
2129
2366
|
}
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
const
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2367
|
+
return pc.addTrack(newTrack, stream);
|
|
2368
|
+
}
|
|
2369
|
+
if (!this.canModifyPeerConnection()) {
|
|
2370
|
+
this.pending.push(() => {
|
|
2371
|
+
this.replaceTrack(oldTrack, newTrack);
|
|
2372
|
+
});
|
|
2373
|
+
return;
|
|
2374
|
+
}
|
|
2375
|
+
this.isOperationPending = true;
|
|
2376
|
+
const onn = pc.onnegotiationneeded;
|
|
2377
|
+
pc.onnegotiationneeded = null;
|
|
2378
|
+
this.removeTrack(oldTrack);
|
|
2379
|
+
this.addTrack(newTrack);
|
|
2380
|
+
setTimeout(() => {
|
|
2381
|
+
pc.onnegotiationneeded = onn;
|
|
2382
|
+
}, 0);
|
|
2383
|
+
if (pc.localDescription.type === "offer") {
|
|
2384
|
+
return pc
|
|
2385
|
+
.createOffer()
|
|
2386
|
+
.then((offer) => {
|
|
2387
|
+
offer.sdp = replaceSSRCs(pc.localDescription.sdp, offer.sdp);
|
|
2388
|
+
return pc.setLocalDescription(offer);
|
|
2389
|
+
})
|
|
2390
|
+
.then(() => {
|
|
2391
|
+
return this._setRemoteDescription(pc.remoteDescription);
|
|
2392
|
+
});
|
|
2393
|
+
}
|
|
2394
|
+
else {
|
|
2395
|
+
return this._setRemoteDescription(pc.remoteDescription)
|
|
2396
|
+
.then(() => {
|
|
2397
|
+
return pc.createAnswer();
|
|
2398
|
+
})
|
|
2399
|
+
.then((answer) => {
|
|
2400
|
+
answer.sdp = replaceSSRCs(pc.localDescription.sdp, answer.sdp);
|
|
2401
|
+
return pc.setLocalDescription(answer);
|
|
2148
2402
|
});
|
|
2149
2403
|
}
|
|
2150
|
-
return isActive;
|
|
2151
|
-
}
|
|
2152
|
-
_onAudioEnabled(payload) {
|
|
2153
|
-
const { clientId, isAudioEnabled } = payload;
|
|
2154
|
-
this._clients[clientId] = Object.assign(Object.assign({}, (this._clients[clientId] || {})), { isAudioEnabled });
|
|
2155
|
-
}
|
|
2156
|
-
_onVideoEnabled(payload) {
|
|
2157
|
-
const { clientId, isVideoEnabled } = payload;
|
|
2158
|
-
this._clients[clientId] = Object.assign(Object.assign({}, (this._clients[clientId] || {})), { isVideoEnabled });
|
|
2159
|
-
}
|
|
2160
|
-
_onScreenshareChanged(payload, action) {
|
|
2161
|
-
const { clientId } = payload;
|
|
2162
|
-
this._clients[clientId] = Object.assign(Object.assign({}, (this._clients[clientId] || {})), { isScreenshareEnabled: action });
|
|
2163
2404
|
}
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
throw new Error(`Client ${clientId} not found in ReconnectManager state`);
|
|
2168
|
-
}
|
|
2169
|
-
if (webcam !== state.isVideoEnabled) {
|
|
2170
|
-
return true;
|
|
2171
|
-
}
|
|
2172
|
-
if (mic !== state.isAudioEnabled) {
|
|
2173
|
-
return true;
|
|
2405
|
+
changeBandwidth(bandwidth) {
|
|
2406
|
+
if (bandwidth === this.bandwidth) {
|
|
2407
|
+
return;
|
|
2174
2408
|
}
|
|
2175
|
-
if (
|
|
2176
|
-
|
|
2409
|
+
if (!this.canModifyPeerConnection()) {
|
|
2410
|
+
this.pending.push(() => this.changeBandwidth(bandwidth));
|
|
2411
|
+
return;
|
|
2177
2412
|
}
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
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 });
|
|
2182
|
-
}
|
|
2183
|
-
_wasClientSendingMedia(clientId) {
|
|
2184
|
-
const client = this._clients[clientId];
|
|
2185
|
-
if (!client) {
|
|
2186
|
-
throw new Error(`Client ${clientId} not found in ReconnectManager state`);
|
|
2413
|
+
this.bandwidth = bandwidth;
|
|
2414
|
+
if (!this.pc.localDescription || this.pc.localDescription.type === "") {
|
|
2415
|
+
return;
|
|
2187
2416
|
}
|
|
2188
|
-
|
|
2189
|
-
}
|
|
2190
|
-
_getPendingClientsByDeviceId(deviceId) {
|
|
2191
|
-
return Object.values(this._clients).filter((clientState) => {
|
|
2192
|
-
return clientState.deviceId === deviceId && clientState.isPendingToLeave;
|
|
2193
|
-
});
|
|
2417
|
+
setVideoBandwidthUsingSetParameters(this.pc, this.bandwidth);
|
|
2194
2418
|
}
|
|
2195
|
-
|
|
2196
|
-
this.
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2419
|
+
setAudioOnly(enable, excludedTrackIds = []) {
|
|
2420
|
+
this.pc
|
|
2421
|
+
.getTransceivers()
|
|
2422
|
+
.filter((videoTransceiver) => {
|
|
2423
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2424
|
+
return (videoTransceiver === null || videoTransceiver === void 0 ? void 0 : videoTransceiver.direction) !== "recvonly" &&
|
|
2425
|
+
((_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" &&
|
|
2426
|
+
!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) &&
|
|
2427
|
+
!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);
|
|
2428
|
+
})
|
|
2429
|
+
.forEach((videoTransceiver) => {
|
|
2430
|
+
videoTransceiver.direction = enable ? "sendonly" : "sendrecv";
|
|
2204
2431
|
});
|
|
2205
2432
|
}
|
|
2206
2433
|
}
|
|
2207
2434
|
|
|
2435
|
+
const MEDIA_JITTER_BUFFER_TARGET = 400;
|
|
2436
|
+
|
|
2208
2437
|
var _a$3;
|
|
2209
2438
|
const adapter$3 = (_a$3 = adapterRaw.default) !== null && _a$3 !== void 0 ? _a$3 : adapterRaw;
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
if (
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
this._socket.io.opts.transports = ["websocket", "polling"];
|
|
2228
|
-
}
|
|
2229
|
-
});
|
|
2230
|
-
if (glitchFree)
|
|
2231
|
-
this._reconnectManager = new ReconnectManager(this._socket);
|
|
2232
|
-
this._socket.on("connect", () => {
|
|
2233
|
-
const transport = this.getTransport();
|
|
2234
|
-
if (transport === "websocket") {
|
|
2235
|
-
this._wasConnectedUsingWebsocket = true;
|
|
2236
|
-
if (!this.noopKeepaliveInterval)
|
|
2237
|
-
this.noopKeepaliveInterval = setInterval(() => {
|
|
2238
|
-
try {
|
|
2239
|
-
if (this._socket.connected) {
|
|
2240
|
-
this._socket.io.engine.sendPacket("noop");
|
|
2241
|
-
}
|
|
2242
|
-
}
|
|
2243
|
-
catch (ex) { }
|
|
2244
|
-
}, NOOP_KEEPALIVE_INTERVAL);
|
|
2439
|
+
function detectMicrophoneNotWorking(pc) {
|
|
2440
|
+
if (adapter$3.browserDetails.browser !== "chrome" ||
|
|
2441
|
+
adapter$3.browserDetails.browser < 58 ||
|
|
2442
|
+
pc.signalingState === "closed") {
|
|
2443
|
+
return Promise.resolve(false);
|
|
2444
|
+
}
|
|
2445
|
+
const sendingAudio = pc.getSenders().some((sender) => sender.track && sender.track.kind === "audio");
|
|
2446
|
+
const receivingAudio = pc.getReceivers().some((receiver) => receiver.track && receiver.track.kind === "audio");
|
|
2447
|
+
return pc.getStats(null).then((result) => {
|
|
2448
|
+
let microphoneFailed = false;
|
|
2449
|
+
result.forEach((report) => {
|
|
2450
|
+
if (report.type === "outbound-rtp" &&
|
|
2451
|
+
(report.kind === "audio" || report.mediaType === "audio") &&
|
|
2452
|
+
sendingAudio) {
|
|
2453
|
+
if (report.bytesSent === 0) {
|
|
2454
|
+
microphoneFailed = "outbound";
|
|
2455
|
+
}
|
|
2245
2456
|
}
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2457
|
+
else if (report.type === "inbound-rtp" &&
|
|
2458
|
+
(report.kind === "audio" || report.mediaType === "audio") &&
|
|
2459
|
+
receivingAudio) {
|
|
2460
|
+
if (report.bytesReceived === 0) {
|
|
2461
|
+
microphoneFailed = "inbound";
|
|
2462
|
+
}
|
|
2252
2463
|
}
|
|
2253
2464
|
});
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
if (this._reconnectManager) {
|
|
2257
|
-
this._reconnectManager.rtcManager = rtcManager;
|
|
2258
|
-
}
|
|
2259
|
-
}
|
|
2260
|
-
connect() {
|
|
2261
|
-
if (this.isConnected() || this.isConnecting()) {
|
|
2262
|
-
return;
|
|
2263
|
-
}
|
|
2264
|
-
this._socket.open();
|
|
2265
|
-
}
|
|
2266
|
-
disconnect() {
|
|
2267
|
-
this._socket.disconnect();
|
|
2268
|
-
}
|
|
2269
|
-
disconnectOnConnect() {
|
|
2270
|
-
this._socket.once("connect", () => {
|
|
2271
|
-
this._socket.disconnect();
|
|
2272
|
-
});
|
|
2273
|
-
}
|
|
2274
|
-
emit(eventName, ...args) {
|
|
2275
|
-
this._socket.emit.apply(this._socket, arguments);
|
|
2276
|
-
}
|
|
2277
|
-
emitIfConnected(eventName, data) {
|
|
2278
|
-
if (!this.isConnected()) {
|
|
2279
|
-
return;
|
|
2280
|
-
}
|
|
2281
|
-
this.emit(eventName, data);
|
|
2282
|
-
}
|
|
2283
|
-
getTransport() {
|
|
2284
|
-
return (this._socket &&
|
|
2285
|
-
this._socket.io &&
|
|
2286
|
-
this._socket.io.engine &&
|
|
2287
|
-
this._socket.io.engine.transport &&
|
|
2288
|
-
this._socket.io.engine.transport.name);
|
|
2289
|
-
}
|
|
2290
|
-
getManager() {
|
|
2291
|
-
return this._socket.io;
|
|
2292
|
-
}
|
|
2293
|
-
isConnecting() {
|
|
2294
|
-
return this._socket && this._socket.connecting;
|
|
2295
|
-
}
|
|
2296
|
-
isConnected() {
|
|
2297
|
-
return this._socket && this._socket.connected;
|
|
2298
|
-
}
|
|
2299
|
-
on(eventName, handler) {
|
|
2300
|
-
const relayableEvents = [
|
|
2301
|
-
PROTOCOL_RESPONSES.ROOM_JOINED,
|
|
2302
|
-
PROTOCOL_RESPONSES.CLIENT_LEFT,
|
|
2303
|
-
PROTOCOL_RESPONSES.NEW_CLIENT,
|
|
2304
|
-
];
|
|
2305
|
-
if (this._reconnectManager && relayableEvents.includes(eventName)) {
|
|
2306
|
-
return this._interceptEvent(eventName, handler);
|
|
2307
|
-
}
|
|
2308
|
-
this._socket.on(eventName, handler);
|
|
2309
|
-
return () => {
|
|
2310
|
-
this._socket.off(eventName, handler);
|
|
2311
|
-
};
|
|
2312
|
-
}
|
|
2313
|
-
onEngineEvent(eventName, handler) {
|
|
2314
|
-
var _a;
|
|
2315
|
-
(_a = this._socket.io) === null || _a === void 0 ? void 0 : _a.on(eventName, handler);
|
|
2316
|
-
return () => {
|
|
2317
|
-
var _a;
|
|
2318
|
-
(_a = this._socket.io) === null || _a === void 0 ? void 0 : _a.off(eventName, handler);
|
|
2319
|
-
};
|
|
2320
|
-
}
|
|
2321
|
-
once(eventName, handler) {
|
|
2322
|
-
this._socket.once(eventName, handler);
|
|
2323
|
-
}
|
|
2324
|
-
off(eventName, handler) {
|
|
2325
|
-
this._socket.off(eventName, handler);
|
|
2326
|
-
}
|
|
2327
|
-
_interceptEvent(eventName, handler) {
|
|
2328
|
-
if (this._reconnectManager) {
|
|
2329
|
-
this._reconnectManager.on(eventName, handler);
|
|
2330
|
-
}
|
|
2331
|
-
return () => {
|
|
2332
|
-
if (this._reconnectManager)
|
|
2333
|
-
this._reconnectManager.removeListener(eventName, handler);
|
|
2334
|
-
};
|
|
2335
|
-
}
|
|
2336
|
-
getGlitchFreeMetrics() {
|
|
2337
|
-
var _a;
|
|
2338
|
-
return (_a = this._reconnectManager) === null || _a === void 0 ? void 0 : _a.metrics;
|
|
2339
|
-
}
|
|
2340
|
-
getReconnectThreshold() {
|
|
2341
|
-
var _a;
|
|
2342
|
-
return (_a = this._reconnectManager) === null || _a === void 0 ? void 0 : _a.reconnectThresholdInMs;
|
|
2343
|
-
}
|
|
2465
|
+
return microphoneFailed;
|
|
2466
|
+
});
|
|
2344
2467
|
}
|
|
2345
2468
|
|
|
2346
|
-
const
|
|
2347
|
-
|
|
2348
|
-
|
|
2469
|
+
const EVENTS = {
|
|
2470
|
+
CLIENT_CONNECTION_STATUS_CHANGED: "client_connection_status_changed",
|
|
2471
|
+
STREAM_ADDED: "stream_added",
|
|
2472
|
+
RTC_MANAGER_CREATED: "rtc_manager_created",
|
|
2473
|
+
RTC_MANAGER_DESTROYED: "rtc_manager_destroyed",
|
|
2474
|
+
LOCAL_STREAM_TRACK_ADDED: "local_stream_track_added",
|
|
2475
|
+
LOCAL_STREAM_TRACK_REMOVED: "local_stream_track_removed",
|
|
2476
|
+
REMOTE_STREAM_TRACK_ADDED: "remote_stream_track_added",
|
|
2477
|
+
REMOTE_STREAM_TRACK_REMOVED: "remote_stream_track_removed",
|
|
2478
|
+
};
|
|
2479
|
+
const TYPES = {
|
|
2480
|
+
CONNECTING: "connecting",
|
|
2481
|
+
CONNECTION_FAILED: "connection_failed",
|
|
2482
|
+
CONNECTION_SUCCESSFUL: "connection_successful",
|
|
2483
|
+
CONNECTION_DISCONNECTED: "connection_disconnected",
|
|
2484
|
+
};
|
|
2485
|
+
|
|
2486
|
+
const CAMERA_STREAM_ID$1 = "0";
|
|
2487
|
+
const STREAM_TYPES = {
|
|
2488
|
+
CAMERA: "camera",
|
|
2489
|
+
SCREEN_SHARE: "screen_share",
|
|
2490
|
+
};
|
|
2491
|
+
class RtcStream {
|
|
2492
|
+
constructor(id, type) {
|
|
2493
|
+
this.id = "" + id;
|
|
2494
|
+
this.type = type;
|
|
2495
|
+
this.isEnabled = true;
|
|
2496
|
+
this.hasSupportForAutoSuperSize = false;
|
|
2497
|
+
this.isAudioEnabled = true;
|
|
2498
|
+
this.isVideoEnabled = true;
|
|
2499
|
+
this.status = TYPES.CONNECTING;
|
|
2500
|
+
this.stream = null;
|
|
2501
|
+
this.streamId = null;
|
|
2349
2502
|
}
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
if (filter) {
|
|
2357
|
-
iceConfig.iceServers = iceConfig.iceServers.filter((entry) => {
|
|
2358
|
-
if (entry.url && entry.url.match(filter))
|
|
2359
|
-
return entry;
|
|
2360
|
-
if (entry.urls) {
|
|
2361
|
-
entry.urls = (entry.urls.some ? entry.urls : [entry.urls]).filter((url) => url.match(filter));
|
|
2362
|
-
if (entry.urls.length > 0)
|
|
2363
|
-
return entry;
|
|
2364
|
-
}
|
|
2365
|
-
});
|
|
2503
|
+
setup(stream) {
|
|
2504
|
+
this.stream = stream;
|
|
2505
|
+
this.streamId = stream.id;
|
|
2506
|
+
this.setVideoEnabled(this.isVideoEnabled && stream.getVideoTracks().length > 0);
|
|
2507
|
+
this.setAudioEnabled(this.isAudioEnabled && stream.getAudioTracks().length > 0);
|
|
2508
|
+
return this;
|
|
2366
2509
|
}
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
iceConfig.iceServers = [
|
|
2371
|
-
{ urls: "stun:stun.l.google.com:19302" },
|
|
2372
|
-
{ urls: "stun:stun2.l.google.com:19302" },
|
|
2373
|
-
...iceConfig.iceServers,
|
|
2374
|
-
];
|
|
2510
|
+
setStatus(status) {
|
|
2511
|
+
this.status = status;
|
|
2512
|
+
return this;
|
|
2375
2513
|
}
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2514
|
+
setVideoEnabled(isEnabled) {
|
|
2515
|
+
this.isVideoEnabled = isEnabled;
|
|
2516
|
+
if (!this.stream) {
|
|
2517
|
+
return;
|
|
2518
|
+
}
|
|
2519
|
+
this.stream.getVideoTracks().forEach((track) => {
|
|
2520
|
+
track.enabled = isEnabled;
|
|
2521
|
+
});
|
|
2382
2522
|
}
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
const entry = Object.assign({}, original);
|
|
2391
|
-
if (entry.url) {
|
|
2392
|
-
entry.url = entry.url.replace(/:[^?]*/, override);
|
|
2393
|
-
}
|
|
2394
|
-
if (entry.urls) {
|
|
2395
|
-
entry.urls = entry.urls.map((url) => url.replace(/:[^?]*/, override));
|
|
2396
|
-
}
|
|
2397
|
-
return entry;
|
|
2523
|
+
setAudioEnabled(isEnabled) {
|
|
2524
|
+
this.isAudioEnabled = isEnabled;
|
|
2525
|
+
if (!this.stream) {
|
|
2526
|
+
return;
|
|
2527
|
+
}
|
|
2528
|
+
this.stream.getAudioTracks().forEach((track) => {
|
|
2529
|
+
track.enabled = isEnabled;
|
|
2398
2530
|
});
|
|
2399
2531
|
}
|
|
2400
|
-
|
|
2401
|
-
return
|
|
2532
|
+
static getCameraId() {
|
|
2533
|
+
return CAMERA_STREAM_ID$1;
|
|
2402
2534
|
}
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
const localstackPattern = /^(?:([^.]+)-)?(ip-[^.]*[.](?:hereby[.]dev|rfc1918[.]disappear[.]at)(?::\d+|))$/;
|
|
2407
|
-
const localhostPattern = /^(?:([^.]+)[.])?(localhost:?\d*)/;
|
|
2408
|
-
const serverPattern = /^(?:([^.]+)[.])?(server:?\d*)/;
|
|
2409
|
-
const ipv4Pattern = /^(?:([^.]+)[.])?((\d+[.]){3}:?\d*)$/;
|
|
2410
|
-
const subdomainPatterns = [
|
|
2411
|
-
{ pattern: serverPattern, separator: "." },
|
|
2412
|
-
{ pattern: localhostPattern, separator: "." },
|
|
2413
|
-
{ pattern: ipv4Pattern, separator: "." },
|
|
2414
|
-
{ pattern: localstackPattern, separator: "-" },
|
|
2415
|
-
{ pattern: defaultSubdomainPattern, separator: "." },
|
|
2416
|
-
];
|
|
2417
|
-
function fromLocation({ host = "whereby.com", protocol = "https:" } = {}) {
|
|
2418
|
-
let subdomain = "";
|
|
2419
|
-
let domain = host;
|
|
2420
|
-
let subdomainSeparator = ".";
|
|
2421
|
-
for (const { separator, pattern } of subdomainPatterns) {
|
|
2422
|
-
const match = pattern.exec(host);
|
|
2423
|
-
if (match) {
|
|
2424
|
-
subdomain = match[1] || "";
|
|
2425
|
-
domain = match[2];
|
|
2426
|
-
subdomainSeparator = separator;
|
|
2427
|
-
break;
|
|
2428
|
-
}
|
|
2535
|
+
static getTypeFromId(id) {
|
|
2536
|
+
const streamId = "" + id;
|
|
2537
|
+
return streamId === CAMERA_STREAM_ID$1 ? STREAM_TYPES.CAMERA : STREAM_TYPES.SCREEN_SHARE;
|
|
2429
2538
|
}
|
|
2430
|
-
const organizationDomain = !subdomain ? domain : `${subdomain}${subdomainSeparator}${domain}`;
|
|
2431
|
-
return {
|
|
2432
|
-
domain,
|
|
2433
|
-
domainWithSeparator: `${subdomainSeparator}${domain}`,
|
|
2434
|
-
organizationDomain,
|
|
2435
|
-
organization: `${protocol}//${organizationDomain}`,
|
|
2436
|
-
service: `${protocol}//${domain}`,
|
|
2437
|
-
subdomain,
|
|
2438
|
-
};
|
|
2439
2539
|
}
|
|
2440
|
-
|
|
2540
|
+
|
|
2541
|
+
var rtcManagerEvents = {
|
|
2542
|
+
CAMERA_NOT_WORKING: "camera_not_working",
|
|
2543
|
+
CONNECTION_BLOCKED_BY_NETWORK: "connection_blocked_by_network",
|
|
2544
|
+
ICE_IPV6_SEEN: "ice_ipv6_seen",
|
|
2545
|
+
ICE_MDNS_SEEN: "ice_mdns_seen",
|
|
2546
|
+
ICE_NO_PUBLIC_IP_GATHERED: "ice_no_public_ip_gathered",
|
|
2547
|
+
ICE_NO_PUBLIC_IP_GATHERED_3SEC: "ice_no_public_ip_gathered_3sec",
|
|
2548
|
+
ICE_RESTART: "ice_restart",
|
|
2549
|
+
MICROPHONE_NOT_WORKING: "microphone_not_working",
|
|
2550
|
+
MICROPHONE_STOPPED_WORKING: "microphone_stopped_working",
|
|
2551
|
+
CAMERA_STOPPED_WORKING: "camera_stopped_working",
|
|
2552
|
+
NEW_PC: "new_pc",
|
|
2553
|
+
SFU_CONNECTION_OPEN: "sfu_connection_open",
|
|
2554
|
+
SFU_CONNECTION_CLOSED: "sfu_connection_closed",
|
|
2555
|
+
SFU_CONNECTION_INFO: "sfu_connection_info",
|
|
2556
|
+
COLOCATION_SPEAKER: "colocation_speaker",
|
|
2557
|
+
DOMINANT_SPEAKER: "dominant_speaker",
|
|
2558
|
+
PC_SLD_FAILURE: "pc_sld_failure",
|
|
2559
|
+
PC_ON_ANSWER_FAILURE: "pc_on_answer_failure",
|
|
2560
|
+
PC_ON_OFFER_FAILURE: "pc_on_offer_failure",
|
|
2561
|
+
};
|
|
2441
2562
|
|
|
2442
2563
|
var _a$2, _b;
|
|
2443
2564
|
const adapter$2 = (_a$2 = adapterRaw.default) !== null && _a$2 !== void 0 ? _a$2 : adapterRaw;
|
|
2444
|
-
const logger$
|
|
2565
|
+
const logger$6 = new Logger();
|
|
2445
2566
|
const ICE_PUBLIC_IP_GATHERING_TIMEOUT = 3 * 1000;
|
|
2446
2567
|
const CAMERA_STREAM_ID = RtcStream.getCameraId();
|
|
2447
2568
|
const browserName$1 = adapter$2.browserDetails.browser;
|
|
@@ -2589,7 +2710,7 @@ class P2pRtcManager {
|
|
|
2589
2710
|
() => this._clearMediaServersRefresh(),
|
|
2590
2711
|
this._serverSocket.on(PROTOCOL_RESPONSES.MEDIASERVER_CONFIG, (data) => {
|
|
2591
2712
|
if (data.error) {
|
|
2592
|
-
logger$
|
|
2713
|
+
logger$6.warn("FETCH_MEDIASERVER_CONFIG failed:", data.error);
|
|
2593
2714
|
return;
|
|
2594
2715
|
}
|
|
2595
2716
|
this._updateAndScheduleMediaServersRefresh(data);
|
|
@@ -2600,7 +2721,7 @@ class P2pRtcManager {
|
|
|
2600
2721
|
this._serverSocket.on(RELAY_MESSAGES.ICE_CANDIDATE, (data) => {
|
|
2601
2722
|
const session = this._getSession(data.clientId);
|
|
2602
2723
|
if (!session) {
|
|
2603
|
-
logger$
|
|
2724
|
+
logger$6.warn("No RTCPeerConnection on ICE_CANDIDATE", data);
|
|
2604
2725
|
return;
|
|
2605
2726
|
}
|
|
2606
2727
|
session.addIceCandidate(data.message);
|
|
@@ -2608,7 +2729,7 @@ class P2pRtcManager {
|
|
|
2608
2729
|
this._serverSocket.on(RELAY_MESSAGES.ICE_END_OF_CANDIDATES, (data) => {
|
|
2609
2730
|
const session = this._getSession(data.clientId);
|
|
2610
2731
|
if (!session) {
|
|
2611
|
-
logger$
|
|
2732
|
+
logger$6.warn("No RTCPeerConnection on ICE_END_OF_CANDIDATES", data);
|
|
2612
2733
|
return;
|
|
2613
2734
|
}
|
|
2614
2735
|
session.addIceCandidate(null);
|
|
@@ -2617,7 +2738,7 @@ class P2pRtcManager {
|
|
|
2617
2738
|
var _a, _b;
|
|
2618
2739
|
const session = this._getSession(data.clientId);
|
|
2619
2740
|
if (!session) {
|
|
2620
|
-
logger$
|
|
2741
|
+
logger$6.warn("No RTCPeerConnection on SDP_OFFER", data);
|
|
2621
2742
|
return;
|
|
2622
2743
|
}
|
|
2623
2744
|
const offer = this._transformIncomingSdp(data.message, session.pc);
|
|
@@ -2636,7 +2757,7 @@ class P2pRtcManager {
|
|
|
2636
2757
|
var _a, _b;
|
|
2637
2758
|
const session = this._getSession(data.clientId);
|
|
2638
2759
|
if (!session) {
|
|
2639
|
-
logger$
|
|
2760
|
+
logger$6.warn("No RTCPeerConnection on SDP_ANSWER", data);
|
|
2640
2761
|
return;
|
|
2641
2762
|
}
|
|
2642
2763
|
const answer = this._transformIncomingSdp(data.message, session.pc);
|
|
@@ -2658,7 +2779,7 @@ class P2pRtcManager {
|
|
|
2658
2779
|
}
|
|
2659
2780
|
const screenshareStream = this.localStreams[screenShareStreamId];
|
|
2660
2781
|
if (!screenshareStream) {
|
|
2661
|
-
logger$
|
|
2782
|
+
logger$6.warn("screenshare stream %s not found", screenShareStreamId);
|
|
2662
2783
|
return;
|
|
2663
2784
|
}
|
|
2664
2785
|
const hasAudioTrack = screenshareStream.getAudioTracks().length > 0;
|
|
@@ -2735,7 +2856,7 @@ class P2pRtcManager {
|
|
|
2735
2856
|
});
|
|
2736
2857
|
}
|
|
2737
2858
|
catch (error) {
|
|
2738
|
-
logger$
|
|
2859
|
+
logger$6.error("Error during setting jitter buffer target:", error);
|
|
2739
2860
|
}
|
|
2740
2861
|
}
|
|
2741
2862
|
_emitServerEvent(eventName, data, callback) {
|
|
@@ -2955,7 +3076,7 @@ class P2pRtcManager {
|
|
|
2955
3076
|
_cleanup(peerConnectionId) {
|
|
2956
3077
|
const session = this._getSession(peerConnectionId);
|
|
2957
3078
|
if (!session) {
|
|
2958
|
-
logger$
|
|
3079
|
+
logger$6.warn("No RTCPeerConnection in RTCManager.disconnect()", peerConnectionId);
|
|
2959
3080
|
return;
|
|
2960
3081
|
}
|
|
2961
3082
|
session.close();
|
|
@@ -2980,17 +3101,17 @@ class P2pRtcManager {
|
|
|
2980
3101
|
const promises = [];
|
|
2981
3102
|
this._forEachPeerConnection((session) => {
|
|
2982
3103
|
if (!session.hasConnectedPeerConnection()) {
|
|
2983
|
-
logger$
|
|
3104
|
+
logger$6.info("Session doesn't have a connected PeerConnection, adding pending action!");
|
|
2984
3105
|
const pendingActions = this._pendingActionsForConnectedPeerConnections;
|
|
2985
3106
|
if (!pendingActions) {
|
|
2986
|
-
logger$
|
|
3107
|
+
logger$6.warn(`No pending action is created to replace track, because the pending actions array is null`);
|
|
2987
3108
|
return;
|
|
2988
3109
|
}
|
|
2989
3110
|
const promise = new Promise((resolve, reject) => {
|
|
2990
3111
|
const action = () => {
|
|
2991
3112
|
const replacedTrackPromise = session.replaceTrack(oldTrack, newTrack);
|
|
2992
3113
|
if (!replacedTrackPromise) {
|
|
2993
|
-
logger$
|
|
3114
|
+
logger$6.error("replaceTrack returned false!");
|
|
2994
3115
|
reject(`ReplaceTrack returned false`);
|
|
2995
3116
|
return;
|
|
2996
3117
|
}
|
|
@@ -3003,7 +3124,7 @@ class P2pRtcManager {
|
|
|
3003
3124
|
}
|
|
3004
3125
|
const replacedTrackResult = session.replaceTrack(oldTrack, newTrack);
|
|
3005
3126
|
if (!replacedTrackResult) {
|
|
3006
|
-
logger$
|
|
3127
|
+
logger$6.error("replaceTrack returned false!");
|
|
3007
3128
|
return;
|
|
3008
3129
|
}
|
|
3009
3130
|
promises.push(replacedTrackResult);
|
|
@@ -3065,7 +3186,7 @@ class P2pRtcManager {
|
|
|
3065
3186
|
let session = this._getSession(clientId);
|
|
3066
3187
|
let initialBandwidth = (session && session.bandwidth) || 0;
|
|
3067
3188
|
if (session) {
|
|
3068
|
-
logger$
|
|
3189
|
+
logger$6.warn("Replacing peer session", clientId);
|
|
3069
3190
|
this._cleanup(clientId);
|
|
3070
3191
|
}
|
|
3071
3192
|
else {
|
|
@@ -3135,13 +3256,13 @@ class P2pRtcManager {
|
|
|
3135
3256
|
})));
|
|
3136
3257
|
}
|
|
3137
3258
|
catch (error) {
|
|
3138
|
-
logger$
|
|
3259
|
+
logger$6.error("Error during setting setCodecPreferences:", error);
|
|
3139
3260
|
}
|
|
3140
3261
|
});
|
|
3141
3262
|
}
|
|
3142
3263
|
_negotiatePeerConnection(clientId, session, constraints) {
|
|
3143
3264
|
if (!session) {
|
|
3144
|
-
logger$
|
|
3265
|
+
logger$6.warn("No RTCPeerConnection in negotiatePeerConnection()", clientId);
|
|
3145
3266
|
return;
|
|
3146
3267
|
}
|
|
3147
3268
|
const pc = session.pc;
|
|
@@ -3165,7 +3286,7 @@ class P2pRtcManager {
|
|
|
3165
3286
|
offer.sdp = cleanSdp(offer.sdp);
|
|
3166
3287
|
pc.setLocalDescription(offer)
|
|
3167
3288
|
.catch((e) => {
|
|
3168
|
-
logger$
|
|
3289
|
+
logger$6.warn("RTCPeerConnection.setLocalDescription() failed with local offer", e);
|
|
3169
3290
|
this._emit(rtcManagerEvents.PC_SLD_FAILURE, e);
|
|
3170
3291
|
throw e;
|
|
3171
3292
|
})
|
|
@@ -3177,7 +3298,7 @@ class P2pRtcManager {
|
|
|
3177
3298
|
});
|
|
3178
3299
|
})
|
|
3179
3300
|
.catch((e) => {
|
|
3180
|
-
logger$
|
|
3301
|
+
logger$6.warn("RTCPeerConnection.createOffer() failed to create local offer", e);
|
|
3181
3302
|
}));
|
|
3182
3303
|
}
|
|
3183
3304
|
_withForcedRenegotiation(session, action) {
|
|
@@ -3292,7 +3413,7 @@ class P2pRtcManager {
|
|
|
3292
3413
|
}
|
|
3293
3414
|
}
|
|
3294
3415
|
catch (error) {
|
|
3295
|
-
logger$
|
|
3416
|
+
logger$6.info("Error during parsing candidates! Error: ", { error });
|
|
3296
3417
|
}
|
|
3297
3418
|
break;
|
|
3298
3419
|
case "srflx":
|
|
@@ -3348,7 +3469,7 @@ class P2pRtcManager {
|
|
|
3348
3469
|
}
|
|
3349
3470
|
let initialBandwidth = (session && session.bandwidth) || 0;
|
|
3350
3471
|
if (session) {
|
|
3351
|
-
logger$
|
|
3472
|
+
logger$6.warn("Replacing peer session", clientId);
|
|
3352
3473
|
this._cleanup(clientId);
|
|
3353
3474
|
}
|
|
3354
3475
|
else {
|
|
@@ -3565,7 +3686,7 @@ const defaultParams = {
|
|
|
3565
3686
|
scoreFormula: "300 * bands[1].avg / Math.max(bands[1].avg + bands[0].avg, 0.01)",
|
|
3566
3687
|
outFormula: "score",
|
|
3567
3688
|
};
|
|
3568
|
-
const logger$
|
|
3689
|
+
const logger$5 = new Logger();
|
|
3569
3690
|
function createMicAnalyser({ micTrack, params, onScoreUpdated, }) {
|
|
3570
3691
|
const audioCtx = new AudioContext();
|
|
3571
3692
|
let analyser = null;
|
|
@@ -3587,7 +3708,7 @@ function createMicAnalyser({ micTrack, params, onScoreUpdated, }) {
|
|
|
3587
3708
|
lastTrackWasOurs = true;
|
|
3588
3709
|
}
|
|
3589
3710
|
catch (ex) {
|
|
3590
|
-
logger$
|
|
3711
|
+
logger$5.warn("unable to fetch new track for colocation speaker analysis, using current", ex);
|
|
3591
3712
|
}
|
|
3592
3713
|
}
|
|
3593
3714
|
lastTrack = track;
|
|
@@ -3674,7 +3795,7 @@ function createMicAnalyser({ micTrack, params, onScoreUpdated, }) {
|
|
|
3674
3795
|
};
|
|
3675
3796
|
}
|
|
3676
3797
|
|
|
3677
|
-
const logger$
|
|
3798
|
+
const logger$4 = new Logger();
|
|
3678
3799
|
const MEDIA_QUALITY = Object.freeze({
|
|
3679
3800
|
ok: "ok",
|
|
3680
3801
|
warning: "warning",
|
|
@@ -3744,7 +3865,7 @@ class VegaMediaQualityMonitor extends EventEmitter {
|
|
|
3744
3865
|
}
|
|
3745
3866
|
addProducer(clientId, producerId) {
|
|
3746
3867
|
if (!clientId || !producerId || !(typeof clientId === "string" && typeof producerId === "string")) {
|
|
3747
|
-
logger$
|
|
3868
|
+
logger$4.warn("Missing clientId or producerId");
|
|
3748
3869
|
return;
|
|
3749
3870
|
}
|
|
3750
3871
|
if (!this._producers[clientId]) {
|
|
@@ -3760,7 +3881,7 @@ class VegaMediaQualityMonitor extends EventEmitter {
|
|
|
3760
3881
|
}
|
|
3761
3882
|
addConsumer(clientId, consumerId) {
|
|
3762
3883
|
if (!clientId || !consumerId) {
|
|
3763
|
-
logger$
|
|
3884
|
+
logger$4.warn("Missing clientId or consumerId");
|
|
3764
3885
|
return;
|
|
3765
3886
|
}
|
|
3766
3887
|
if (!this._producers[clientId]) {
|
|
@@ -3778,14 +3899,14 @@ class VegaMediaQualityMonitor extends EventEmitter {
|
|
|
3778
3899
|
if (!Array.isArray(score) ||
|
|
3779
3900
|
score.length === 0 ||
|
|
3780
3901
|
score.some((s) => !s || !s.hasOwnProperty("score") || typeof s.score !== "number" || isNaN(s.score))) {
|
|
3781
|
-
logger$
|
|
3902
|
+
logger$4.warn("Unexpected producer score format");
|
|
3782
3903
|
return;
|
|
3783
3904
|
}
|
|
3784
3905
|
this._producers[clientId][producerId] = { kind, score: this._calcAvgProducerScore(score.map((s) => s.score)) };
|
|
3785
3906
|
}
|
|
3786
3907
|
addConsumerScore(clientId, consumerId, kind, score) {
|
|
3787
3908
|
if (!score || !score.hasOwnProperty("producerScores") || !Array.isArray(score.producerScores)) {
|
|
3788
|
-
logger$
|
|
3909
|
+
logger$4.warn("Unexpected consumer score format");
|
|
3789
3910
|
return;
|
|
3790
3911
|
}
|
|
3791
3912
|
this._producers[clientId][consumerId] = { kind, score: this._calcAvgProducerScore(score.producerScores) };
|
|
@@ -3822,7 +3943,7 @@ class VegaMediaQualityMonitor extends EventEmitter {
|
|
|
3822
3943
|
}
|
|
3823
3944
|
}
|
|
3824
3945
|
catch (error) {
|
|
3825
|
-
logger$
|
|
3946
|
+
logger$4.error(error);
|
|
3826
3947
|
return 0;
|
|
3827
3948
|
}
|
|
3828
3949
|
}
|
|
@@ -3963,7 +4084,7 @@ class SfuV2Parser {
|
|
|
3963
4084
|
}
|
|
3964
4085
|
}
|
|
3965
4086
|
|
|
3966
|
-
const logger$
|
|
4087
|
+
const logger$3 = new Logger();
|
|
3967
4088
|
class VegaConnection extends EventEmitter.EventEmitter {
|
|
3968
4089
|
constructor(wsUrl, protocol = "whereby-sfu#v4") {
|
|
3969
4090
|
super();
|
|
@@ -3996,12 +4117,12 @@ class VegaConnection extends EventEmitter.EventEmitter {
|
|
|
3996
4117
|
(_a = this.socket) === null || _a === void 0 ? void 0 : _a.close();
|
|
3997
4118
|
}
|
|
3998
4119
|
_onOpen() {
|
|
3999
|
-
logger$
|
|
4120
|
+
logger$3.info("Connected");
|
|
4000
4121
|
this.emit("open");
|
|
4001
4122
|
}
|
|
4002
4123
|
_onMessage(event) {
|
|
4003
4124
|
const socketMessage = SfuV2Parser.parse(event.data);
|
|
4004
|
-
logger$
|
|
4125
|
+
logger$3.info("Received message", socketMessage);
|
|
4005
4126
|
if (socketMessage === null || socketMessage === void 0 ? void 0 : socketMessage.response) {
|
|
4006
4127
|
this._handleResponse(socketMessage);
|
|
4007
4128
|
}
|
|
@@ -4010,11 +4131,11 @@ class VegaConnection extends EventEmitter.EventEmitter {
|
|
|
4010
4131
|
}
|
|
4011
4132
|
}
|
|
4012
4133
|
_onClose() {
|
|
4013
|
-
logger$
|
|
4134
|
+
logger$3.info("Disconnected");
|
|
4014
4135
|
this._tearDown();
|
|
4015
4136
|
}
|
|
4016
4137
|
_onError(error) {
|
|
4017
|
-
logger$
|
|
4138
|
+
logger$3.info("Error", error);
|
|
4018
4139
|
}
|
|
4019
4140
|
_handleResponse(socketMessage) {
|
|
4020
4141
|
const sent = this.sents.get(socketMessage.id);
|
|
@@ -4250,7 +4371,7 @@ function createVegaConnectionManager(config) {
|
|
|
4250
4371
|
|
|
4251
4372
|
var _a$1;
|
|
4252
4373
|
const adapter$1 = (_a$1 = adapterRaw.default) !== null && _a$1 !== void 0 ? _a$1 : adapterRaw;
|
|
4253
|
-
const logger$
|
|
4374
|
+
const logger$2 = new Logger();
|
|
4254
4375
|
const browserName = adapter$1.browserDetails.browser;
|
|
4255
4376
|
let unloading = false;
|
|
4256
4377
|
const RESTARTICE_ERROR_RETRY_THRESHOLD_IN_MS = 3500;
|
|
@@ -4380,7 +4501,7 @@ class VegaRtcManager {
|
|
|
4380
4501
|
setupSocketListeners() {
|
|
4381
4502
|
this._socketListenerDeregisterFunctions.push(() => this._clearMediaServersRefresh(), this._serverSocket.on(PROTOCOL_RESPONSES.MEDIASERVER_CONFIG, (data) => {
|
|
4382
4503
|
if (data.error) {
|
|
4383
|
-
logger$
|
|
4504
|
+
logger$2.warn("FETCH_MEDIASERVER_CONFIG failed:", data.error);
|
|
4384
4505
|
return;
|
|
4385
4506
|
}
|
|
4386
4507
|
this._updateAndScheduleMediaServersRefresh(data);
|
|
@@ -4452,7 +4573,7 @@ class VegaRtcManager {
|
|
|
4452
4573
|
}
|
|
4453
4574
|
_onClose() {
|
|
4454
4575
|
var _a, _b;
|
|
4455
|
-
logger$
|
|
4576
|
+
logger$2.info("_onClose()");
|
|
4456
4577
|
(_a = this._sendTransport) === null || _a === void 0 ? void 0 : _a.close();
|
|
4457
4578
|
(_b = this._receiveTransport) === null || _b === void 0 ? void 0 : _b.close();
|
|
4458
4579
|
this._sendTransport = null;
|
|
@@ -4468,7 +4589,7 @@ class VegaRtcManager {
|
|
|
4468
4589
|
_join() {
|
|
4469
4590
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4470
4591
|
var _a, _b;
|
|
4471
|
-
logger$
|
|
4592
|
+
logger$2.info("join()");
|
|
4472
4593
|
this._emitToPWA(rtcManagerEvents.SFU_CONNECTION_OPEN);
|
|
4473
4594
|
try {
|
|
4474
4595
|
const { routerRtpCapabilities } = yield this._vegaConnection.request("getCapabilities");
|
|
@@ -4495,7 +4616,7 @@ class VegaRtcManager {
|
|
|
4495
4616
|
yield Promise.all(mediaPromises);
|
|
4496
4617
|
}
|
|
4497
4618
|
catch (error) {
|
|
4498
|
-
logger$
|
|
4619
|
+
logger$2.error("_join() [error:%o]", error);
|
|
4499
4620
|
}
|
|
4500
4621
|
});
|
|
4501
4622
|
}
|
|
@@ -4523,7 +4644,7 @@ class VegaRtcManager {
|
|
|
4523
4644
|
maybeTurnOnly(transportOptions, this._features);
|
|
4524
4645
|
const transport = (_a = (yield this._mediasoupDeviceInitializedAsync)) === null || _a === void 0 ? void 0 : _a[creator](transportOptions);
|
|
4525
4646
|
const onConnectionStateListener = (connectionState) => __awaiter(this, void 0, void 0, function* () {
|
|
4526
|
-
logger$
|
|
4647
|
+
logger$2.info(`Transport ConnectionStateChanged ${connectionState}`);
|
|
4527
4648
|
if (connectionState !== "disconnected" && connectionState !== "failed") {
|
|
4528
4649
|
return;
|
|
4529
4650
|
}
|
|
@@ -4597,15 +4718,15 @@ class VegaRtcManager {
|
|
|
4597
4718
|
_restartIce(transport_1) {
|
|
4598
4719
|
return __awaiter(this, arguments, void 0, function* (transport, retried = 0) {
|
|
4599
4720
|
if (!transport || !("closed" in transport) || !("connectionState" in transport)) {
|
|
4600
|
-
logger$
|
|
4721
|
+
logger$2.info("_restartIce: No transport or property closed or connectionState!");
|
|
4601
4722
|
return;
|
|
4602
4723
|
}
|
|
4603
4724
|
if (transport.closed) {
|
|
4604
|
-
logger$
|
|
4725
|
+
logger$2.info("_restartIce: Transport is closed!");
|
|
4605
4726
|
return;
|
|
4606
4727
|
}
|
|
4607
4728
|
if (transport.connectionState !== "disconnected" && transport.connectionState !== "failed") {
|
|
4608
|
-
logger$
|
|
4729
|
+
logger$2.info("_restartIce: Connection is healthy ICE restart no loneger needed!");
|
|
4609
4730
|
return;
|
|
4610
4731
|
}
|
|
4611
4732
|
const { iceRestartStarted } = transport.appData;
|
|
@@ -4615,21 +4736,21 @@ class VegaRtcManager {
|
|
|
4615
4736
|
}
|
|
4616
4737
|
transport.appData.iceRestartStarted = now;
|
|
4617
4738
|
if (RESTARTICE_ERROR_MAX_RETRY_COUNT <= retried) {
|
|
4618
|
-
logger$
|
|
4739
|
+
logger$2.info("_restartIce: Reached restart ICE maximum retry count!");
|
|
4619
4740
|
return;
|
|
4620
4741
|
}
|
|
4621
4742
|
if (!this._vegaConnection) {
|
|
4622
|
-
logger$
|
|
4743
|
+
logger$2.info(`_restartIce: Connection is undefined`);
|
|
4623
4744
|
return;
|
|
4624
4745
|
}
|
|
4625
4746
|
const { iceParameters } = yield this._vegaConnection.request("restartIce", { transportId: transport.id });
|
|
4626
|
-
logger$
|
|
4747
|
+
logger$2.info("_restartIce: ICE restart iceParameters received from SFU: ", iceParameters);
|
|
4627
4748
|
const error = yield transport
|
|
4628
4749
|
.restartIce({ iceParameters })
|
|
4629
4750
|
.then(() => null)
|
|
4630
4751
|
.catch((err) => err);
|
|
4631
4752
|
if (error) {
|
|
4632
|
-
logger$
|
|
4753
|
+
logger$2.error(`_restartIce: ICE restart failed: ${error}`);
|
|
4633
4754
|
switch (error.message) {
|
|
4634
4755
|
case "missing transportId":
|
|
4635
4756
|
case "no such transport":
|
|
@@ -4658,7 +4779,7 @@ class VegaRtcManager {
|
|
|
4658
4779
|
}
|
|
4659
4780
|
_internalSendMic() {
|
|
4660
4781
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4661
|
-
logger$
|
|
4782
|
+
logger$2.info("_internalSendMic()");
|
|
4662
4783
|
this._micProducerPromise = (() => __awaiter(this, void 0, void 0, function* () {
|
|
4663
4784
|
try {
|
|
4664
4785
|
if (!this._micTrack || !this._sendTransport || this._micProducer) {
|
|
@@ -4678,7 +4799,7 @@ class VegaRtcManager {
|
|
|
4678
4799
|
this._qualityMonitor.addProducer(this._selfId, producer.id);
|
|
4679
4800
|
producer.observer.once("close", () => {
|
|
4680
4801
|
var _a;
|
|
4681
|
-
logger$
|
|
4802
|
+
logger$2.info('micProducer "close" event');
|
|
4682
4803
|
if (producer.appData.localClosed)
|
|
4683
4804
|
(_a = this._vegaConnection) === null || _a === void 0 ? void 0 : _a.message("closeProducers", { producerIds: [producer.id] });
|
|
4684
4805
|
this._micProducer = null;
|
|
@@ -4691,7 +4812,7 @@ class VegaRtcManager {
|
|
|
4691
4812
|
this._pauseResumeMic();
|
|
4692
4813
|
}
|
|
4693
4814
|
catch (error) {
|
|
4694
|
-
logger$
|
|
4815
|
+
logger$2.error("micProducer failed:%o", error);
|
|
4695
4816
|
}
|
|
4696
4817
|
finally {
|
|
4697
4818
|
this._micProducerPromise = null;
|
|
@@ -4705,7 +4826,7 @@ class VegaRtcManager {
|
|
|
4705
4826
|
}
|
|
4706
4827
|
_internalSetupMicScore() {
|
|
4707
4828
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4708
|
-
logger$
|
|
4829
|
+
logger$2.info("_internalSetupMicScore()");
|
|
4709
4830
|
this._micScoreProducerPromise = (() => __awaiter(this, void 0, void 0, function* () {
|
|
4710
4831
|
try {
|
|
4711
4832
|
if (!this._micProducer || !this._colocation || this._micScoreProducer) {
|
|
@@ -4724,7 +4845,7 @@ class VegaRtcManager {
|
|
|
4724
4845
|
this._micScoreProducer = producer;
|
|
4725
4846
|
producer.observer.once("close", () => {
|
|
4726
4847
|
var _a;
|
|
4727
|
-
logger$
|
|
4848
|
+
logger$2.info('micScoreProducer "close" event');
|
|
4728
4849
|
if (producer.appData.localClosed) {
|
|
4729
4850
|
(_a = this._vegaConnection) === null || _a === void 0 ? void 0 : _a.message("closeDataProducers", { dataProducerIds: [producer.id] });
|
|
4730
4851
|
}
|
|
@@ -4733,7 +4854,7 @@ class VegaRtcManager {
|
|
|
4733
4854
|
});
|
|
4734
4855
|
}
|
|
4735
4856
|
catch (error) {
|
|
4736
|
-
logger$
|
|
4857
|
+
logger$2.error("micScoreProducer failed:%o", error);
|
|
4737
4858
|
}
|
|
4738
4859
|
finally {
|
|
4739
4860
|
this._micScoreProducerPromise = null;
|
|
@@ -4751,7 +4872,7 @@ class VegaRtcManager {
|
|
|
4751
4872
|
_replaceMicTrack() {
|
|
4752
4873
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4753
4874
|
var _a;
|
|
4754
|
-
logger$
|
|
4875
|
+
logger$2.info("_replaceMicTrack()");
|
|
4755
4876
|
if (!this._micTrack || !this._micProducer || this._micProducer.closed)
|
|
4756
4877
|
return;
|
|
4757
4878
|
if (this._micProducer.track !== this._micTrack) {
|
|
@@ -4763,7 +4884,7 @@ class VegaRtcManager {
|
|
|
4763
4884
|
}
|
|
4764
4885
|
_pauseResumeMic() {
|
|
4765
4886
|
var _a, _b;
|
|
4766
|
-
logger$
|
|
4887
|
+
logger$2.info("_pauseResumeMic()");
|
|
4767
4888
|
if (!this._micProducer || this._micProducer.closed)
|
|
4768
4889
|
return;
|
|
4769
4890
|
if (this._micPaused !== this._micProducer.paused) {
|
|
@@ -4784,7 +4905,7 @@ class VegaRtcManager {
|
|
|
4784
4905
|
}
|
|
4785
4906
|
_sendMic(track) {
|
|
4786
4907
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4787
|
-
logger$
|
|
4908
|
+
logger$2.info("_sendMic() [track:%o]", track);
|
|
4788
4909
|
this._micTrack = track;
|
|
4789
4910
|
if (this._micProducer) {
|
|
4790
4911
|
return yield this._replaceMicTrack();
|
|
@@ -4810,7 +4931,7 @@ class VegaRtcManager {
|
|
|
4810
4931
|
this._micScoreProducer.send(JSON.stringify({ score }));
|
|
4811
4932
|
}
|
|
4812
4933
|
catch (ex) {
|
|
4813
|
-
logger$
|
|
4934
|
+
logger$2.error("_sendMicScore failed [error:%o]", ex);
|
|
4814
4935
|
}
|
|
4815
4936
|
return;
|
|
4816
4937
|
}
|
|
@@ -4821,7 +4942,7 @@ class VegaRtcManager {
|
|
|
4821
4942
|
_internalSendWebcam() {
|
|
4822
4943
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4823
4944
|
var _a;
|
|
4824
|
-
logger$
|
|
4945
|
+
logger$2.info("_internalSendWebcam()");
|
|
4825
4946
|
if (!this._sendTransport ||
|
|
4826
4947
|
this._webcamProducer ||
|
|
4827
4948
|
this._webcamProducerPromise ||
|
|
@@ -4844,7 +4965,7 @@ class VegaRtcManager {
|
|
|
4844
4965
|
this._qualityMonitor.addProducer(this._selfId, producer.id);
|
|
4845
4966
|
producer.observer.once("close", () => {
|
|
4846
4967
|
var _a;
|
|
4847
|
-
logger$
|
|
4968
|
+
logger$2.info('webcamProducer "close" event');
|
|
4848
4969
|
if (producer.appData.localClosed)
|
|
4849
4970
|
(_a = this._vegaConnection) === null || _a === void 0 ? void 0 : _a.message("closeProducers", { producerIds: [producer.id] });
|
|
4850
4971
|
this._webcamProducer = null;
|
|
@@ -4859,7 +4980,7 @@ class VegaRtcManager {
|
|
|
4859
4980
|
this._pauseResumeWebcam();
|
|
4860
4981
|
}
|
|
4861
4982
|
catch (error) {
|
|
4862
|
-
logger$
|
|
4983
|
+
logger$2.error("webcamProducer failed:%o", error);
|
|
4863
4984
|
}
|
|
4864
4985
|
finally {
|
|
4865
4986
|
this._webcamProducerPromise = null;
|
|
@@ -4873,7 +4994,7 @@ class VegaRtcManager {
|
|
|
4873
4994
|
}
|
|
4874
4995
|
_replaceWebcamTrack() {
|
|
4875
4996
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4876
|
-
logger$
|
|
4997
|
+
logger$2.info("_replaceWebcamTrack()");
|
|
4877
4998
|
if (!this._sendTransport || !this._webcamTrack || this._webcamProducerPromise)
|
|
4878
4999
|
return;
|
|
4879
5000
|
if (!this._webcamProducer && this._webcamTrack.enabled) {
|
|
@@ -4888,7 +5009,7 @@ class VegaRtcManager {
|
|
|
4888
5009
|
}
|
|
4889
5010
|
_pauseResumeWebcam() {
|
|
4890
5011
|
var _a, _b;
|
|
4891
|
-
logger$
|
|
5012
|
+
logger$2.info("_pauseResumeWebcam()");
|
|
4892
5013
|
if (!this._webcamProducer || this._webcamProducer.closed)
|
|
4893
5014
|
return;
|
|
4894
5015
|
if (this._webcamPaused !== this._webcamProducer.paused) {
|
|
@@ -4909,7 +5030,7 @@ class VegaRtcManager {
|
|
|
4909
5030
|
}
|
|
4910
5031
|
_sendWebcam(track) {
|
|
4911
5032
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4912
|
-
logger$
|
|
5033
|
+
logger$2.info("_sendWebcam() [track:%o]", track);
|
|
4913
5034
|
this._webcamTrack = track;
|
|
4914
5035
|
if (this._webcamProducer) {
|
|
4915
5036
|
return yield this._replaceWebcamTrack();
|
|
@@ -4923,7 +5044,7 @@ class VegaRtcManager {
|
|
|
4923
5044
|
}
|
|
4924
5045
|
_internalSendScreenVideo() {
|
|
4925
5046
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4926
|
-
logger$
|
|
5047
|
+
logger$2.info("_internalSendScreenVideo()");
|
|
4927
5048
|
this._screenVideoProducerPromise = (() => __awaiter(this, void 0, void 0, function* () {
|
|
4928
5049
|
var _a, _b;
|
|
4929
5050
|
try {
|
|
@@ -4945,7 +5066,7 @@ class VegaRtcManager {
|
|
|
4945
5066
|
this._qualityMonitor.addProducer(this._selfId, producer.id);
|
|
4946
5067
|
producer.observer.once("close", () => {
|
|
4947
5068
|
var _a;
|
|
4948
|
-
logger$
|
|
5069
|
+
logger$2.info('screenVideoProducer "close" event');
|
|
4949
5070
|
if (producer.appData.localClosed)
|
|
4950
5071
|
(_a = this._vegaConnection) === null || _a === void 0 ? void 0 : _a.message("closeProducers", { producerIds: [producer.id] });
|
|
4951
5072
|
this._screenVideoProducer = null;
|
|
@@ -4956,7 +5077,7 @@ class VegaRtcManager {
|
|
|
4956
5077
|
yield this._replaceScreenVideoTrack();
|
|
4957
5078
|
}
|
|
4958
5079
|
catch (error) {
|
|
4959
|
-
logger$
|
|
5080
|
+
logger$2.error("screenVideoProducer failed:%o", error);
|
|
4960
5081
|
}
|
|
4961
5082
|
finally {
|
|
4962
5083
|
this._screenVideoProducerPromise = null;
|
|
@@ -4970,7 +5091,7 @@ class VegaRtcManager {
|
|
|
4970
5091
|
}
|
|
4971
5092
|
_replaceScreenVideoTrack() {
|
|
4972
5093
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4973
|
-
logger$
|
|
5094
|
+
logger$2.info("_replaceScreenVideoTrack()");
|
|
4974
5095
|
if (!this._screenVideoTrack || !this._screenVideoProducer || this._screenVideoProducer.closed)
|
|
4975
5096
|
return;
|
|
4976
5097
|
if (this._screenVideoProducer.track !== this._screenVideoTrack) {
|
|
@@ -4981,7 +5102,7 @@ class VegaRtcManager {
|
|
|
4981
5102
|
}
|
|
4982
5103
|
_sendScreenVideo(track) {
|
|
4983
5104
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4984
|
-
logger$
|
|
5105
|
+
logger$2.info("_sendScreenVideo() [track:%o]", track);
|
|
4985
5106
|
this._screenVideoTrack = track;
|
|
4986
5107
|
if (this._screenVideoProducer) {
|
|
4987
5108
|
return yield this._replaceScreenVideoTrack();
|
|
@@ -4995,7 +5116,7 @@ class VegaRtcManager {
|
|
|
4995
5116
|
}
|
|
4996
5117
|
_internalSendScreenAudio() {
|
|
4997
5118
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4998
|
-
logger$
|
|
5119
|
+
logger$2.info("_internalSendScreenAudio()");
|
|
4999
5120
|
this._screenAudioProducerPromise = (() => __awaiter(this, void 0, void 0, function* () {
|
|
5000
5121
|
try {
|
|
5001
5122
|
if (!this._screenAudioTrack || !this._sendTransport || this._screenAudioProducer) {
|
|
@@ -5013,7 +5134,7 @@ class VegaRtcManager {
|
|
|
5013
5134
|
this._qualityMonitor.addProducer(this._selfId, producer.id);
|
|
5014
5135
|
producer.observer.once("close", () => {
|
|
5015
5136
|
var _a;
|
|
5016
|
-
logger$
|
|
5137
|
+
logger$2.info('screenAudioProducer "close" event');
|
|
5017
5138
|
if (producer.appData.localClosed)
|
|
5018
5139
|
(_a = this._vegaConnection) === null || _a === void 0 ? void 0 : _a.message("closeProducers", { producerIds: [producer.id] });
|
|
5019
5140
|
this._screenAudioProducer = null;
|
|
@@ -5024,7 +5145,7 @@ class VegaRtcManager {
|
|
|
5024
5145
|
yield this._replaceScreenAudioTrack();
|
|
5025
5146
|
}
|
|
5026
5147
|
catch (error) {
|
|
5027
|
-
logger$
|
|
5148
|
+
logger$2.error("screenAudioProducer failed:%o", error);
|
|
5028
5149
|
}
|
|
5029
5150
|
finally {
|
|
5030
5151
|
this._screenAudioProducerPromise = null;
|
|
@@ -5038,7 +5159,7 @@ class VegaRtcManager {
|
|
|
5038
5159
|
}
|
|
5039
5160
|
_replaceScreenAudioTrack() {
|
|
5040
5161
|
return __awaiter(this, void 0, void 0, function* () {
|
|
5041
|
-
logger$
|
|
5162
|
+
logger$2.info("_replaceScreenAudioTrack()");
|
|
5042
5163
|
if (!this._screenAudioTrack || !this._screenAudioProducer || this._screenAudioProducer.closed)
|
|
5043
5164
|
return;
|
|
5044
5165
|
if (this._screenAudioProducer.track !== this._screenAudioTrack) {
|
|
@@ -5049,7 +5170,7 @@ class VegaRtcManager {
|
|
|
5049
5170
|
}
|
|
5050
5171
|
_sendScreenAudio(track) {
|
|
5051
5172
|
return __awaiter(this, void 0, void 0, function* () {
|
|
5052
|
-
logger$
|
|
5173
|
+
logger$2.info("_sendScreenAudio() [track:%o]", track);
|
|
5053
5174
|
this._screenAudioTrack = track;
|
|
5054
5175
|
if (this._screenAudioProducer) {
|
|
5055
5176
|
return yield this._replaceScreenAudioTrack();
|
|
@@ -5062,7 +5183,7 @@ class VegaRtcManager {
|
|
|
5062
5183
|
});
|
|
5063
5184
|
}
|
|
5064
5185
|
_stopProducer(producer) {
|
|
5065
|
-
logger$
|
|
5186
|
+
logger$2.info("_stopProducer()");
|
|
5066
5187
|
if (!producer || producer.closed)
|
|
5067
5188
|
return;
|
|
5068
5189
|
producer.appData.localClosed = true;
|
|
@@ -5099,7 +5220,7 @@ class VegaRtcManager {
|
|
|
5099
5220
|
}
|
|
5100
5221
|
disconnect(clientIdOrStreamId, _activeBreakout, eventClaim) {
|
|
5101
5222
|
var _a;
|
|
5102
|
-
logger$
|
|
5223
|
+
logger$2.info("disconnect() [clientIdOrStreamId:%s, eventClaim:%s]", clientIdOrStreamId, eventClaim);
|
|
5103
5224
|
const clientState = this._clientStates.get(clientIdOrStreamId);
|
|
5104
5225
|
if (clientState) {
|
|
5105
5226
|
clientState.hasAcceptedWebcamStream = false;
|
|
@@ -5128,7 +5249,7 @@ class VegaRtcManager {
|
|
|
5128
5249
|
}
|
|
5129
5250
|
}
|
|
5130
5251
|
removeStream(streamId, _stream, requestedByClientId) {
|
|
5131
|
-
logger$
|
|
5252
|
+
logger$2.info("removeStream() [streamId:%s, requestedByClientId:%s]", streamId, requestedByClientId);
|
|
5132
5253
|
this._emitToSignal(PROTOCOL_REQUESTS.STOP_SCREENSHARE, {
|
|
5133
5254
|
streamId: OUTBOUND_SCREEN_OUTBOUND_STREAM_ID,
|
|
5134
5255
|
requestedByClientId,
|
|
@@ -5212,7 +5333,7 @@ class VegaRtcManager {
|
|
|
5212
5333
|
}
|
|
5213
5334
|
}
|
|
5214
5335
|
stopOrResumeAudio(stream, enabled) {
|
|
5215
|
-
logger$
|
|
5336
|
+
logger$2.info("stopOrResumeAudio() [enabled:%s]", enabled);
|
|
5216
5337
|
this._micPaused = !enabled;
|
|
5217
5338
|
this._pauseResumeMic();
|
|
5218
5339
|
}
|
|
@@ -5230,7 +5351,7 @@ class VegaRtcManager {
|
|
|
5230
5351
|
}
|
|
5231
5352
|
stopOrResumeVideo(localStream, enable) {
|
|
5232
5353
|
var _a;
|
|
5233
|
-
logger$
|
|
5354
|
+
logger$2.info("stopOrResumeVideo() [enable:%s]", enable);
|
|
5234
5355
|
this._webcamPaused = !enable;
|
|
5235
5356
|
this._pauseResumeWebcam();
|
|
5236
5357
|
if (!["chrome", "safari"].includes(browserName)) {
|
|
@@ -5274,7 +5395,7 @@ class VegaRtcManager {
|
|
|
5274
5395
|
return true;
|
|
5275
5396
|
}
|
|
5276
5397
|
acceptNewStream({ streamId, clientId }) {
|
|
5277
|
-
logger$
|
|
5398
|
+
logger$2.info("acceptNewStream()", { streamId, clientId });
|
|
5278
5399
|
const clientState = this._getOrCreateClientState(clientId);
|
|
5279
5400
|
const isScreenShare = streamId !== clientId;
|
|
5280
5401
|
if (isScreenShare) {
|
|
@@ -5289,7 +5410,7 @@ class VegaRtcManager {
|
|
|
5289
5410
|
}
|
|
5290
5411
|
updateStreamResolution(streamId, _ignored, { width, height, }) {
|
|
5291
5412
|
var _a, _b;
|
|
5292
|
-
logger$
|
|
5413
|
+
logger$2.info("updateStreamResolution()", { streamId, width, height });
|
|
5293
5414
|
const consumerId = this._streamIdToVideoConsumerId.get(streamId);
|
|
5294
5415
|
const consumer = this._consumers.get(consumerId);
|
|
5295
5416
|
if (!consumer) {
|
|
@@ -5397,18 +5518,18 @@ class VegaRtcManager {
|
|
|
5397
5518
|
case "producerScore":
|
|
5398
5519
|
return this._onProducerScore(data);
|
|
5399
5520
|
default:
|
|
5400
|
-
logger$
|
|
5521
|
+
logger$2.info(`unknown message method "${method}"`);
|
|
5401
5522
|
return;
|
|
5402
5523
|
}
|
|
5403
5524
|
})
|
|
5404
5525
|
.catch((error) => {
|
|
5405
|
-
logger$
|
|
5526
|
+
logger$2.error('"message" failed [error:%o]', error);
|
|
5406
5527
|
});
|
|
5407
5528
|
});
|
|
5408
5529
|
}
|
|
5409
5530
|
_onConsumerReady(options) {
|
|
5410
5531
|
return __awaiter(this, void 0, void 0, function* () {
|
|
5411
|
-
logger$
|
|
5532
|
+
logger$2.info("_onConsumerReady()", { id: options.id, producerId: options.producerId });
|
|
5412
5533
|
const consumer = yield this._receiveTransport.consume(options);
|
|
5413
5534
|
consumer.pause();
|
|
5414
5535
|
consumer.appData.localPaused = true;
|
|
@@ -5426,7 +5547,7 @@ class VegaRtcManager {
|
|
|
5426
5547
|
consumer.rtpReceiver.playoutDelayHint = MEDIA_JITTER_BUFFER_TARGET / 1000;
|
|
5427
5548
|
}
|
|
5428
5549
|
catch (error) {
|
|
5429
|
-
logger$
|
|
5550
|
+
logger$2.error("Error during setting jitter buffer target:", error);
|
|
5430
5551
|
}
|
|
5431
5552
|
}
|
|
5432
5553
|
const { sourceClientId: clientId, screenShare, streamId } = consumer.appData;
|
|
@@ -5460,12 +5581,12 @@ class VegaRtcManager {
|
|
|
5460
5581
|
_onConsumerClosed(_a) {
|
|
5461
5582
|
return __awaiter(this, arguments, void 0, function* ({ consumerId, reason }) {
|
|
5462
5583
|
var _b;
|
|
5463
|
-
logger$
|
|
5584
|
+
logger$2.info("_onConsumerClosed()", { consumerId, reason });
|
|
5464
5585
|
(_b = this._consumers.get(consumerId)) === null || _b === void 0 ? void 0 : _b.close();
|
|
5465
5586
|
});
|
|
5466
5587
|
}
|
|
5467
5588
|
_onConsumerPaused({ consumerId }) {
|
|
5468
|
-
logger$
|
|
5589
|
+
logger$2.info("_onConsumerPaused()", { consumerId });
|
|
5469
5590
|
const consumer = this._consumers.get(consumerId);
|
|
5470
5591
|
if (!consumer)
|
|
5471
5592
|
return;
|
|
@@ -5473,7 +5594,7 @@ class VegaRtcManager {
|
|
|
5473
5594
|
consumer.pause();
|
|
5474
5595
|
}
|
|
5475
5596
|
_onConsumerResumed({ consumerId }) {
|
|
5476
|
-
logger$
|
|
5597
|
+
logger$2.info("_onConsumerResumed()", { consumerId });
|
|
5477
5598
|
const consumer = this._consumers.get(consumerId);
|
|
5478
5599
|
if (!consumer)
|
|
5479
5600
|
return;
|
|
@@ -5483,14 +5604,14 @@ class VegaRtcManager {
|
|
|
5483
5604
|
}
|
|
5484
5605
|
}
|
|
5485
5606
|
_onConsumerScore({ consumerId, kind, score }) {
|
|
5486
|
-
logger$
|
|
5607
|
+
logger$2.info("_onConsumerScore()", { consumerId, kind, score });
|
|
5487
5608
|
const { appData: { sourceClientId }, } = this._consumers.get(consumerId) || { appData: {} };
|
|
5488
5609
|
if (sourceClientId) {
|
|
5489
5610
|
this._qualityMonitor.addConsumerScore(sourceClientId, consumerId, kind, score);
|
|
5490
5611
|
}
|
|
5491
5612
|
}
|
|
5492
5613
|
_onProducerScore({ producerId, kind, score }) {
|
|
5493
|
-
logger$
|
|
5614
|
+
logger$2.info("_onProducerScore()", { producerId, kind, score });
|
|
5494
5615
|
[this._micProducer, this._webcamProducer, this._screenVideoProducer, this._screenAudioProducer].forEach((producer) => {
|
|
5495
5616
|
if ((producer === null || producer === void 0 ? void 0 : producer.id) === producerId) {
|
|
5496
5617
|
this._qualityMonitor.addProducerScore(this._selfId, producerId, kind, score);
|
|
@@ -5499,7 +5620,7 @@ class VegaRtcManager {
|
|
|
5499
5620
|
}
|
|
5500
5621
|
_onDataConsumerReady(options) {
|
|
5501
5622
|
return __awaiter(this, void 0, void 0, function* () {
|
|
5502
|
-
logger$
|
|
5623
|
+
logger$2.info("_onDataConsumerReady()", { id: options.id, producerId: options.producerId });
|
|
5503
5624
|
const consumer = yield this._receiveTransport.consumeData(options);
|
|
5504
5625
|
this._dataConsumers.set(consumer.id, consumer);
|
|
5505
5626
|
consumer.once("close", () => {
|
|
@@ -5522,7 +5643,7 @@ class VegaRtcManager {
|
|
|
5522
5643
|
}
|
|
5523
5644
|
_onDataConsumerClosed(_a) {
|
|
5524
5645
|
return __awaiter(this, arguments, void 0, function* ({ dataConsumerId, reason }) {
|
|
5525
|
-
logger$
|
|
5646
|
+
logger$2.info("_onDataConsumerClosed()", { dataConsumerId, reason });
|
|
5526
5647
|
const consumer = this._dataConsumers.get(dataConsumerId);
|
|
5527
5648
|
consumer === null || consumer === void 0 ? void 0 : consumer.close();
|
|
5528
5649
|
});
|
|
@@ -5697,119 +5818,11 @@ const getRoomMode = () => {
|
|
|
5697
5818
|
return roomMode;
|
|
5698
5819
|
};
|
|
5699
5820
|
|
|
5700
|
-
const logger$2 = new Logger();
|
|
5701
|
-
const debugLogger = {
|
|
5702
|
-
print: (...args) => console.debug(args[0], ...args.slice(1)),
|
|
5703
|
-
};
|
|
5704
|
-
logger$2.withDebugLogger(debugLogger);
|
|
5705
|
-
class PacketLossAnalyser {
|
|
5706
|
-
constructor() {
|
|
5707
|
-
this.BEGIN_PACKET_LOSS_PERIOD_THRESHOLD = 0.04;
|
|
5708
|
-
this.END_PACKET_LOSS_PERIOD_THRESHOLD = 0.005;
|
|
5709
|
-
this.INTERVAL_DIFF_THRESHOLD_MS = 4000;
|
|
5710
|
-
this.STALE_MEASUREMENT_TIMEOUT_MS = 10000;
|
|
5711
|
-
this.MINIMUM_INTERVAL_MS = 30000;
|
|
5712
|
-
this.ssrcsHistory = new Map();
|
|
5713
|
-
this.staleMeasurementTimeouts = new Map();
|
|
5714
|
-
}
|
|
5715
|
-
addPacketLossMeasurement(id, packetLoss, timestamp) {
|
|
5716
|
-
this.handleStaleMeasurements(id);
|
|
5717
|
-
const beginNewPacketLossPeriod = packetLoss > this.BEGIN_PACKET_LOSS_PERIOD_THRESHOLD;
|
|
5718
|
-
let history = this.ssrcsHistory.get(id);
|
|
5719
|
-
if (!history) {
|
|
5720
|
-
history = {
|
|
5721
|
-
id,
|
|
5722
|
-
hasActivePacketLoss: beginNewPacketLossPeriod,
|
|
5723
|
-
currPeriod: beginNewPacketLossPeriod ? { begin: timestamp } : undefined,
|
|
5724
|
-
hasPeriodicPacketLoss: false,
|
|
5725
|
-
};
|
|
5726
|
-
this.ssrcsHistory.set(id, history);
|
|
5727
|
-
return;
|
|
5728
|
-
}
|
|
5729
|
-
if (history.hasActivePacketLoss) {
|
|
5730
|
-
if (packetLoss < this.END_PACKET_LOSS_PERIOD_THRESHOLD) {
|
|
5731
|
-
this.endPacketLossPeriod(history, timestamp);
|
|
5732
|
-
if (history.prevIntervalInMs && history.prevIntervalInMs < this.MINIMUM_INTERVAL_MS) {
|
|
5733
|
-
this.ssrcsHistory.delete(id);
|
|
5734
|
-
}
|
|
5735
|
-
}
|
|
5736
|
-
return;
|
|
5737
|
-
}
|
|
5738
|
-
if (beginNewPacketLossPeriod) {
|
|
5739
|
-
history.hasActivePacketLoss = true;
|
|
5740
|
-
history.currPeriod = {
|
|
5741
|
-
begin: timestamp,
|
|
5742
|
-
};
|
|
5743
|
-
}
|
|
5744
|
-
}
|
|
5745
|
-
hasPeriodicPacketLoss(id, timestamp) {
|
|
5746
|
-
const history = this.ssrcsHistory.get(id);
|
|
5747
|
-
if (history && this.prevIntervalExceeded(history, timestamp)) {
|
|
5748
|
-
this.ssrcsHistory.delete(history.id);
|
|
5749
|
-
return false;
|
|
5750
|
-
}
|
|
5751
|
-
return (history === null || history === void 0 ? void 0 : history.hasPeriodicPacketLoss) || false;
|
|
5752
|
-
}
|
|
5753
|
-
prevIntervalExceeded(history, timestamp) {
|
|
5754
|
-
if (history.prevPeriod && history.prevIntervalInMs) {
|
|
5755
|
-
const intervalLimitTimestamp = this.calculatePeriodCenterTimestamp(history.prevPeriod) +
|
|
5756
|
-
history.prevIntervalInMs +
|
|
5757
|
-
this.INTERVAL_DIFF_THRESHOLD_MS;
|
|
5758
|
-
return timestamp > intervalLimitTimestamp;
|
|
5759
|
-
}
|
|
5760
|
-
return false;
|
|
5761
|
-
}
|
|
5762
|
-
handleStaleMeasurements(id) {
|
|
5763
|
-
const staleMeasurementTimeout = this.staleMeasurementTimeouts.get(id);
|
|
5764
|
-
if (staleMeasurementTimeout) {
|
|
5765
|
-
clearTimeout(staleMeasurementTimeout);
|
|
5766
|
-
}
|
|
5767
|
-
this.staleMeasurementTimeouts.set(id, setTimeout(() => {
|
|
5768
|
-
logger$2.debug("handleStaleMeasurements() [measurements invalid for ssrc: %s]", id);
|
|
5769
|
-
this.ssrcsHistory.delete(id);
|
|
5770
|
-
}, this.STALE_MEASUREMENT_TIMEOUT_MS));
|
|
5771
|
-
}
|
|
5772
|
-
endPacketLossPeriod(history, timestamp) {
|
|
5773
|
-
logger$2.debug("endPacketLossPeriod() [ssrcId: %s, timestamp: %s]", history.id, timestamp);
|
|
5774
|
-
if (!history.currPeriod)
|
|
5775
|
-
throw new Error("No packet loss period for " + history.id);
|
|
5776
|
-
if (!history.prevPeriod) {
|
|
5777
|
-
history.prevPeriod = Object.assign(Object.assign({}, history.currPeriod), { end: timestamp });
|
|
5778
|
-
}
|
|
5779
|
-
else {
|
|
5780
|
-
history.currPeriod.end = timestamp;
|
|
5781
|
-
this.addNewPacketLossInterval(history);
|
|
5782
|
-
}
|
|
5783
|
-
delete history.currPeriod;
|
|
5784
|
-
history.hasActivePacketLoss = false;
|
|
5785
|
-
}
|
|
5786
|
-
addNewPacketLossInterval(history) {
|
|
5787
|
-
logger$2.debug("addNewPacketLossInterval() [ssrcId: %s, prevIntervalInMs: %s]", history.id, history.prevIntervalInMs);
|
|
5788
|
-
if (!history.currPeriod || !history.prevPeriod)
|
|
5789
|
-
throw new Error("missing period timestamps");
|
|
5790
|
-
const prevPeriodCenter = this.calculatePeriodCenterTimestamp(history.prevPeriod);
|
|
5791
|
-
const currPeriodCenter = this.calculatePeriodCenterTimestamp(history.currPeriod);
|
|
5792
|
-
const currIntervalInMs = currPeriodCenter - prevPeriodCenter;
|
|
5793
|
-
if (history.prevIntervalInMs) {
|
|
5794
|
-
const intervalDiffInMs = Math.abs(history.prevIntervalInMs - currIntervalInMs);
|
|
5795
|
-
history.hasPeriodicPacketLoss = intervalDiffInMs < this.INTERVAL_DIFF_THRESHOLD_MS;
|
|
5796
|
-
logger$2.debug("addNewPacketLossInterval() [hasPeriodicPacketLoss: %s, intervalDiffInMs: %s]", intervalDiffInMs < this.INTERVAL_DIFF_THRESHOLD_MS, intervalDiffInMs);
|
|
5797
|
-
}
|
|
5798
|
-
history.prevIntervalInMs = currIntervalInMs;
|
|
5799
|
-
history.prevPeriod = history.currPeriod;
|
|
5800
|
-
}
|
|
5801
|
-
calculatePeriodCenterTimestamp(period) {
|
|
5802
|
-
if (!period.end)
|
|
5803
|
-
throw new Error("Missing period end timestamp");
|
|
5804
|
-
return period.begin + (period.end - period.begin) / 2;
|
|
5805
|
-
}
|
|
5806
|
-
}
|
|
5807
|
-
|
|
5808
5821
|
const packetLossAnalyser = new PacketLossAnalyser();
|
|
5809
5822
|
const periodicPacketLossDetector = {
|
|
5810
5823
|
id: "periodic-packet-loss",
|
|
5811
5824
|
enabled: ({ client, hasLiveTrack, ssrc0 }) => {
|
|
5812
|
-
return (client.isLocalClient &&
|
|
5825
|
+
return (!!client.isLocalClient &&
|
|
5813
5826
|
hasLiveTrack &&
|
|
5814
5827
|
!!(ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.ssrc) &&
|
|
5815
5828
|
(ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.direction) === "out" &&
|
|
@@ -5925,7 +5938,7 @@ const issueDetectors = [
|
|
|
5925
5938
|
dryTrackIssueDetector,
|
|
5926
5939
|
{
|
|
5927
5940
|
id: "denoiser-context-suspended",
|
|
5928
|
-
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); },
|
|
5941
|
+
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); },
|
|
5929
5942
|
check: ({ track }) => {
|
|
5930
5943
|
var _a;
|
|
5931
5944
|
if (!track || !("_denoiserCtx" in track))
|
|
@@ -5951,7 +5964,7 @@ const issueDetectors = [
|
|
|
5951
5964
|
if (remoteClients.some((c) => c.isAudioOnlyModeEnabled))
|
|
5952
5965
|
return false;
|
|
5953
5966
|
}
|
|
5954
|
-
return hasLiveTrack && client.isLocalClient && kind === "video" && !!stats;
|
|
5967
|
+
return hasLiveTrack && !!client.isLocalClient && kind === "video" && !!stats;
|
|
5955
5968
|
},
|
|
5956
5969
|
check: ({ stats }) => {
|
|
5957
5970
|
if (!stats)
|
|
@@ -5961,7 +5974,7 @@ const issueDetectors = [
|
|
|
5961
5974
|
},
|
|
5962
5975
|
{
|
|
5963
5976
|
id: "quality-limitation-cpu",
|
|
5964
|
-
enabled: ({ hasLiveTrack, stats, client, kind }) => hasLiveTrack && client.isLocalClient && kind === "video" && !!stats,
|
|
5977
|
+
enabled: ({ hasLiveTrack, stats, client, kind }) => hasLiveTrack && !!client.isLocalClient && kind === "video" && !!stats,
|
|
5965
5978
|
check: ({ stats }) => {
|
|
5966
5979
|
if (!stats)
|
|
5967
5980
|
return false;
|
|
@@ -6064,12 +6077,12 @@ const metrics = [
|
|
|
6064
6077
|
{
|
|
6065
6078
|
id: "height",
|
|
6066
6079
|
enabled: ({ hasLiveTrack, track, trackStats, ssrc0, kind }) => hasLiveTrack && kind === "video" && !!trackStats && !!track && !!ssrc0 && !!ssrc0.height,
|
|
6067
|
-
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),
|
|
6080
|
+
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),
|
|
6068
6081
|
},
|
|
6069
6082
|
{
|
|
6070
6083
|
id: "sourceHeight",
|
|
6071
6084
|
enabled: ({ hasLiveTrack, track, ssrc0, kind }) => hasLiveTrack && kind === "video" && !!track && !!ssrc0 && !!ssrc0.sourceHeight && ssrc0.direction === "out",
|
|
6072
|
-
value: ({ ssrc0 }) => ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.sourceHeight,
|
|
6085
|
+
value: ({ ssrc0 }) => (ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.sourceHeight) || NaN,
|
|
6073
6086
|
},
|
|
6074
6087
|
{
|
|
6075
6088
|
id: "packetloss",
|
|
@@ -6079,7 +6092,7 @@ const metrics = [
|
|
|
6079
6092
|
{
|
|
6080
6093
|
id: "jitter",
|
|
6081
6094
|
enabled: ({ hasLiveTrack, ssrc0 }) => hasLiveTrack && !!ssrc0 && !!ssrc0.bitrate && ssrc0.direction === "in",
|
|
6082
|
-
value: ({ ssrc0 }) => ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.jitter,
|
|
6095
|
+
value: ({ ssrc0 }) => (ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.jitter) || NaN,
|
|
6083
6096
|
},
|
|
6084
6097
|
{
|
|
6085
6098
|
id: "mos",
|
|
@@ -6113,13 +6126,13 @@ const metrics = [
|
|
|
6113
6126
|
id: "turn-usage",
|
|
6114
6127
|
global: true,
|
|
6115
6128
|
enabled: ({ stats }) => !!Object.values((stats === null || stats === void 0 ? void 0 : stats.candidatePairs) || {}).length,
|
|
6116
|
-
value: ({ stats }) => Object.values((stats === null || stats === void 0 ? void 0 : stats.candidatePairs) || {}).some((cp) => cp.usingTurn),
|
|
6129
|
+
value: ({ stats }) => (Object.values((stats === null || stats === void 0 ? void 0 : stats.candidatePairs) || {}).some((cp) => cp.usingTurn) ? 1 : 0),
|
|
6117
6130
|
},
|
|
6118
6131
|
{
|
|
6119
6132
|
id: "turn-tls-usage",
|
|
6120
6133
|
global: true,
|
|
6121
6134
|
enabled: ({ stats }) => !!Object.values((stats === null || stats === void 0 ? void 0 : stats.candidatePairs) || {}).length,
|
|
6122
|
-
value: ({ stats }) => Object.values((stats === null || stats === void 0 ? void 0 : stats.candidatePairs) || {}).some((cp) => cp.turnProtocol === "tls"),
|
|
6135
|
+
value: ({ stats }) => Object.values((stats === null || stats === void 0 ? void 0 : stats.candidatePairs) || {}).some((cp) => cp.turnProtocol === "tls") ? 1 : 0,
|
|
6123
6136
|
},
|
|
6124
6137
|
{
|
|
6125
6138
|
id: "concealment",
|
|
@@ -6129,7 +6142,7 @@ const metrics = [
|
|
|
6129
6142
|
ssrc0.direction === "in" &&
|
|
6130
6143
|
kind === "audio" &&
|
|
6131
6144
|
(ssrc0.audioLevel || 0) >= 0.001,
|
|
6132
|
-
value: ({ ssrc0 }) => ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.audioConcealment,
|
|
6145
|
+
value: ({ ssrc0 }) => (ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.audioConcealment) || NaN,
|
|
6133
6146
|
},
|
|
6134
6147
|
{
|
|
6135
6148
|
id: "deceleration",
|
|
@@ -6139,7 +6152,7 @@ const metrics = [
|
|
|
6139
6152
|
ssrc0.direction === "in" &&
|
|
6140
6153
|
kind === "audio" &&
|
|
6141
6154
|
(ssrc0.audioLevel || 0) >= 0.001,
|
|
6142
|
-
value: ({ ssrc0 }) => ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.audioDeceleration,
|
|
6155
|
+
value: ({ ssrc0 }) => (ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.audioDeceleration) || NaN,
|
|
6143
6156
|
},
|
|
6144
6157
|
{
|
|
6145
6158
|
id: "acceleration",
|
|
@@ -6149,7 +6162,7 @@ const metrics = [
|
|
|
6149
6162
|
ssrc0.direction === "in" &&
|
|
6150
6163
|
kind === "audio" &&
|
|
6151
6164
|
(ssrc0.audioLevel || 0) >= 0.001,
|
|
6152
|
-
value: ({ ssrc0 }) => ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.audioAcceleration,
|
|
6165
|
+
value: ({ ssrc0 }) => (ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.audioAcceleration) || NaN,
|
|
6153
6166
|
},
|
|
6154
6167
|
{
|
|
6155
6168
|
id: "qpf",
|
|
@@ -6192,9 +6205,6 @@ function onUpdatedStats(statsByView, clients) {
|
|
|
6192
6205
|
clients.forEach((client) => {
|
|
6193
6206
|
const stats = statsByView[client.id];
|
|
6194
6207
|
["video", "audio", "global"].forEach((kind) => {
|
|
6195
|
-
var _a, _b;
|
|
6196
|
-
if (!(kind === "global" && !client.isPresentation) && !((_a = client[kind]) === null || _a === void 0 ? void 0 : _a.enabled))
|
|
6197
|
-
return;
|
|
6198
6208
|
if (kind === "global" && !client.isLocalClient)
|
|
6199
6209
|
return;
|
|
6200
6210
|
let issuesAndMetrics = issuesAndMetricsByView[client.id];
|
|
@@ -6202,7 +6212,7 @@ function onUpdatedStats(statsByView, clients) {
|
|
|
6202
6212
|
issuesAndMetrics = { issues: {}, metrics: {} };
|
|
6203
6213
|
issuesAndMetricsByView[client.id] = issuesAndMetrics;
|
|
6204
6214
|
}
|
|
6205
|
-
const track =
|
|
6215
|
+
const track = kind === "audio" || kind === "video" ? client[kind].track : undefined;
|
|
6206
6216
|
const hasLiveTrack = !!track && track.readyState !== "ended";
|
|
6207
6217
|
const trackStats = track && stats && stats.tracks[track.id];
|
|
6208
6218
|
const ssrcs = trackStats
|