@whereby.com/media 8.0.4 → 8.0.6
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 +2171 -2313
- package/dist/index.d.cts +1 -7
- package/dist/index.d.mts +1 -7
- package/dist/index.d.ts +1 -7
- package/dist/index.mjs +2171 -2313
- package/dist/legacy-esm.js +2171 -2313
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,99 +1,14 @@
|
|
|
1
|
-
import { Device, detectDeviceAsync } from 'mediasoup-client';
|
|
2
1
|
import adapterRaw from 'webrtc-adapter';
|
|
3
|
-
import EventEmitter, { EventEmitter as EventEmitter$1 } from 'events';
|
|
4
2
|
import rtcstats from 'rtcstats';
|
|
5
3
|
import { v4 as v4$1 } from 'uuid';
|
|
6
|
-
import { io } from 'socket.io-client';
|
|
7
4
|
import SDPUtils from 'sdp';
|
|
8
5
|
import * as sdpTransform from 'sdp-transform';
|
|
9
6
|
import { Address6 } from 'ip-address';
|
|
10
7
|
import checkIp from 'check-ip';
|
|
11
8
|
import validate from 'uuid-validate';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
super(options.message);
|
|
16
|
-
this.name = "AssertionError";
|
|
17
|
-
this.code = "ERR_ASSERTION";
|
|
18
|
-
this.actual = options.actual;
|
|
19
|
-
this.expected = options.expected;
|
|
20
|
-
this.operator = options.operator;
|
|
21
|
-
if (Error.captureStackTrace) {
|
|
22
|
-
Error.captureStackTrace(this, options.stackStartFn);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
function innerOk(fn, argLen, value, message) {
|
|
27
|
-
if (!value) {
|
|
28
|
-
let generatedMessage = false;
|
|
29
|
-
if (argLen === 0) {
|
|
30
|
-
generatedMessage = true;
|
|
31
|
-
message = "No value argument passed to `assert.ok()`";
|
|
32
|
-
}
|
|
33
|
-
else if (message instanceof Error) {
|
|
34
|
-
throw message;
|
|
35
|
-
}
|
|
36
|
-
const err = new AssertionError({
|
|
37
|
-
actual: value,
|
|
38
|
-
expected: true,
|
|
39
|
-
message,
|
|
40
|
-
operator: "==",
|
|
41
|
-
stackStartFn: fn,
|
|
42
|
-
});
|
|
43
|
-
err.generatedMessage = generatedMessage;
|
|
44
|
-
throw err;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
function innerFail(obj) {
|
|
48
|
-
if (obj.message instanceof Error)
|
|
49
|
-
throw obj.message;
|
|
50
|
-
throw new AssertionError(obj);
|
|
51
|
-
}
|
|
52
|
-
function ok(...args) {
|
|
53
|
-
innerOk(ok, args.length, ...args);
|
|
54
|
-
}
|
|
55
|
-
const assert = {
|
|
56
|
-
fail: (message) => {
|
|
57
|
-
innerFail({
|
|
58
|
-
actual: "fail()",
|
|
59
|
-
expected: "fail() should not be called",
|
|
60
|
-
message,
|
|
61
|
-
operator: "fail",
|
|
62
|
-
stackStartFn: assert.fail,
|
|
63
|
-
});
|
|
64
|
-
},
|
|
65
|
-
ok,
|
|
66
|
-
};
|
|
67
|
-
assert.notEqual = function notEqual(actual, expected, message) {
|
|
68
|
-
if (arguments.length < 2) {
|
|
69
|
-
throw new Error("'actual' and 'expected' arguments are required");
|
|
70
|
-
}
|
|
71
|
-
if (actual == expected) {
|
|
72
|
-
innerFail({
|
|
73
|
-
actual,
|
|
74
|
-
expected,
|
|
75
|
-
message,
|
|
76
|
-
operator: "!=",
|
|
77
|
-
stackStartFn: notEqual,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
assert.ok = ok;
|
|
82
|
-
|
|
83
|
-
const createWorker = (fn) => {
|
|
84
|
-
return new Worker(URL.createObjectURL(new Blob(["self.onmessage = ", fn.toString()], { type: "text/javascript" })));
|
|
85
|
-
};
|
|
86
|
-
const generateByteString = (count) => {
|
|
87
|
-
if (count === 0) {
|
|
88
|
-
return "";
|
|
89
|
-
}
|
|
90
|
-
const count2 = count / 2;
|
|
91
|
-
let result = "F";
|
|
92
|
-
while (result.length <= count2) {
|
|
93
|
-
result += result;
|
|
94
|
-
}
|
|
95
|
-
return result + result.substring(0, count - result.length);
|
|
96
|
-
};
|
|
9
|
+
import { Device, detectDeviceAsync } from 'mediasoup-client';
|
|
10
|
+
import EventEmitter, { EventEmitter as EventEmitter$1 } from 'events';
|
|
11
|
+
import { io } from 'socket.io-client';
|
|
97
12
|
|
|
98
13
|
/******************************************************************************
|
|
99
14
|
Copyright (c) Microsoft Corporation.
|
|
@@ -127,2389 +42,2357 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
127
42
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
128
43
|
};
|
|
129
44
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
const
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
class Logger {
|
|
174
|
-
constructor() {
|
|
175
|
-
this._isEnabled = false;
|
|
176
|
-
this._isEnabled = debugOn;
|
|
177
|
-
}
|
|
178
|
-
isEnabled() {
|
|
179
|
-
return this._isEnabled;
|
|
180
|
-
}
|
|
181
|
-
enable() {
|
|
182
|
-
this._isEnabled = true;
|
|
183
|
-
}
|
|
184
|
-
disable() {
|
|
185
|
-
this._isEnabled = false;
|
|
186
|
-
}
|
|
187
|
-
info(...params) {
|
|
188
|
-
if (!this._isEnabled) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
return console.info(...params);
|
|
192
|
-
}
|
|
193
|
-
warn(...params) {
|
|
194
|
-
if (!this._isEnabled) {
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
return console.warn(...params);
|
|
198
|
-
}
|
|
199
|
-
error(...params) {
|
|
200
|
-
if (!this._isEnabled) {
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
return console.error(...params);
|
|
204
|
-
}
|
|
205
|
-
withDebugLogger(myDebugger) {
|
|
206
|
-
this._debugger = myDebugger;
|
|
207
|
-
return this;
|
|
208
|
-
}
|
|
209
|
-
debug(...params) {
|
|
210
|
-
if (!this._isEnabled || !this._debugger) {
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
const suppliedParams = [];
|
|
214
|
-
params.forEach((param) => {
|
|
215
|
-
if (typeof param === "function") {
|
|
216
|
-
const suppliedParam = param();
|
|
217
|
-
suppliedParams.push(suppliedParam);
|
|
45
|
+
var _a$7;
|
|
46
|
+
(_a$7 = adapterRaw.default) !== null && _a$7 !== void 0 ? _a$7 : adapterRaw;
|
|
47
|
+
const RTCSTATS_PROTOCOL_VERSION = "1.0";
|
|
48
|
+
const GETSTATS_BUFFER_SIZE = 20;
|
|
49
|
+
const clientInfo = {
|
|
50
|
+
id: v4$1(),
|
|
51
|
+
connectionNumber: 0,
|
|
52
|
+
};
|
|
53
|
+
const noop = () => { };
|
|
54
|
+
let resetDelta = noop;
|
|
55
|
+
function rtcStatsConnection(wsURL, logger = console) {
|
|
56
|
+
const buffer = [];
|
|
57
|
+
let ws;
|
|
58
|
+
let organizationId;
|
|
59
|
+
let clientId;
|
|
60
|
+
let displayName;
|
|
61
|
+
let userRole;
|
|
62
|
+
let roomSessionId;
|
|
63
|
+
let connectionShouldBeOpen;
|
|
64
|
+
let connectionAttempt = 0;
|
|
65
|
+
let hasPassedOnRoomSessionId = false;
|
|
66
|
+
let getStatsBufferUsed = 0;
|
|
67
|
+
let deviceId;
|
|
68
|
+
let roomProduct;
|
|
69
|
+
let roomMode;
|
|
70
|
+
let sfuServer;
|
|
71
|
+
let featureFlags;
|
|
72
|
+
const connection = {
|
|
73
|
+
connected: false,
|
|
74
|
+
attemptedConnectedAtLeastOnce: false,
|
|
75
|
+
trace: (...args) => {
|
|
76
|
+
args.push(Date.now());
|
|
77
|
+
if (args[0] === "customEvent" && args[2].type === "roomSessionId") {
|
|
78
|
+
const oldRoomSessionIdValue = roomSessionId && roomSessionId[2].value.roomSessionId;
|
|
79
|
+
const newRoomSessionIdValue = args[2].value.roomSessionId;
|
|
80
|
+
roomSessionId = args;
|
|
81
|
+
if (hasPassedOnRoomSessionId &&
|
|
82
|
+
newRoomSessionIdValue &&
|
|
83
|
+
newRoomSessionIdValue !== oldRoomSessionIdValue) {
|
|
84
|
+
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
85
|
+
}
|
|
86
|
+
if (newRoomSessionIdValue)
|
|
87
|
+
hasPassedOnRoomSessionId = true;
|
|
218
88
|
}
|
|
219
|
-
else {
|
|
220
|
-
|
|
89
|
+
else if (args[0] === "customEvent" && args[2].type === "clientId") {
|
|
90
|
+
clientId = args;
|
|
221
91
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
92
|
+
else if (args[0] === "customEvent" && args[2].type === "organizationId") {
|
|
93
|
+
organizationId = args;
|
|
94
|
+
}
|
|
95
|
+
else if (args[0] === "customEvent" && args[2].type === "displayName") {
|
|
96
|
+
displayName = args;
|
|
97
|
+
}
|
|
98
|
+
else if (args[0] === "customEvent" && args[2].type === "userRole") {
|
|
99
|
+
userRole = args;
|
|
100
|
+
}
|
|
101
|
+
else if (args[0] === "customEvent" && args[2].type === "deviceId") {
|
|
102
|
+
deviceId = args;
|
|
103
|
+
}
|
|
104
|
+
else if (args[0] === "customEvent" && args[2].type === "roomProduct") {
|
|
105
|
+
roomProduct = args;
|
|
106
|
+
}
|
|
107
|
+
else if (args[0] === "customEvent" && args[2].type === "roomMode") {
|
|
108
|
+
roomMode = args;
|
|
109
|
+
}
|
|
110
|
+
else if (args[0] === "customEvent" && args[2].type === "sfuServer") {
|
|
111
|
+
sfuServer = args;
|
|
112
|
+
}
|
|
113
|
+
else if (args[0] === "customEvent" && args[2].type === "featureFlags") {
|
|
114
|
+
featureFlags = args;
|
|
115
|
+
}
|
|
116
|
+
if ((ws === null || ws === void 0 ? void 0 : ws.readyState) === WebSocket.OPEN) {
|
|
117
|
+
connectionAttempt = 0;
|
|
118
|
+
ws.send(JSON.stringify(args));
|
|
119
|
+
}
|
|
120
|
+
else if (args[0] === "getstats") {
|
|
121
|
+
if (getStatsBufferUsed < GETSTATS_BUFFER_SIZE) {
|
|
122
|
+
getStatsBufferUsed++;
|
|
123
|
+
buffer.push(args);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else if (args[0] === "customEvent" && args[2].type === "insightsStats") ;
|
|
127
|
+
else {
|
|
128
|
+
buffer.push(args);
|
|
129
|
+
}
|
|
130
|
+
if ((ws === null || ws === void 0 ? void 0 : ws.readyState) === WebSocket.CLOSED && connectionShouldBeOpen) {
|
|
131
|
+
setTimeout(() => {
|
|
132
|
+
if (ws.readyState === WebSocket.CLOSED && connectionShouldBeOpen) {
|
|
133
|
+
connection.connect();
|
|
134
|
+
}
|
|
135
|
+
}, 1000 * connectionAttempt);
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
close: () => {
|
|
139
|
+
connectionShouldBeOpen = false;
|
|
140
|
+
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
141
|
+
},
|
|
142
|
+
connect: () => {
|
|
143
|
+
connectionShouldBeOpen = true;
|
|
144
|
+
connectionAttempt += 1;
|
|
145
|
+
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
146
|
+
connection.connected = true;
|
|
147
|
+
connection.attemptedConnectedAtLeastOnce = true;
|
|
148
|
+
ws = new WebSocket(wsURL + window.location.pathname, RTCSTATS_PROTOCOL_VERSION);
|
|
149
|
+
ws.onerror = (e) => {
|
|
150
|
+
connection.connected = false;
|
|
151
|
+
logger.warn(`[RTCSTATS] WebSocket error`, e);
|
|
152
|
+
};
|
|
153
|
+
ws.onclose = (e) => {
|
|
154
|
+
connection.connected = false;
|
|
155
|
+
logger.info(`[RTCSTATS] Closed ${e.code}`);
|
|
156
|
+
resetDelta();
|
|
157
|
+
};
|
|
158
|
+
ws.onopen = () => {
|
|
159
|
+
clientInfo.connectionNumber++;
|
|
160
|
+
ws.send(JSON.stringify(["clientInfo", null, clientInfo]));
|
|
161
|
+
if (organizationId) {
|
|
162
|
+
ws.send(JSON.stringify(organizationId));
|
|
163
|
+
}
|
|
164
|
+
if (clientId) {
|
|
165
|
+
ws.send(JSON.stringify(clientId));
|
|
166
|
+
}
|
|
167
|
+
if (roomSessionId) {
|
|
168
|
+
ws.send(JSON.stringify(roomSessionId));
|
|
169
|
+
}
|
|
170
|
+
if (displayName) {
|
|
171
|
+
ws.send(JSON.stringify(displayName));
|
|
172
|
+
}
|
|
173
|
+
if (userRole) {
|
|
174
|
+
ws.send(JSON.stringify(userRole));
|
|
175
|
+
}
|
|
176
|
+
if (deviceId) {
|
|
177
|
+
ws.send(JSON.stringify(deviceId));
|
|
178
|
+
}
|
|
179
|
+
if (roomMode) {
|
|
180
|
+
ws.send(JSON.stringify(roomMode));
|
|
181
|
+
}
|
|
182
|
+
if (roomProduct) {
|
|
183
|
+
ws.send(JSON.stringify(roomProduct));
|
|
184
|
+
}
|
|
185
|
+
if (sfuServer) {
|
|
186
|
+
ws.send(JSON.stringify(sfuServer));
|
|
187
|
+
}
|
|
188
|
+
if (featureFlags) {
|
|
189
|
+
ws.send(JSON.stringify(featureFlags));
|
|
190
|
+
}
|
|
191
|
+
while (buffer.length) {
|
|
192
|
+
ws.send(JSON.stringify(buffer.shift()));
|
|
193
|
+
}
|
|
194
|
+
getStatsBufferUsed = 0;
|
|
195
|
+
};
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
return connection;
|
|
199
|
+
}
|
|
200
|
+
const RTCSTATS_URL = "wss://rtcstats.srv.whereby.com";
|
|
201
|
+
const server = rtcStatsConnection(RTCSTATS_URL);
|
|
202
|
+
const stats = rtcstats(server.trace, 10000, [""]);
|
|
203
|
+
resetDelta = (stats === null || stats === void 0 ? void 0 : stats.resetDelta) || noop;
|
|
204
|
+
const rtcStats = {
|
|
205
|
+
sendEvent: (type, value) => {
|
|
206
|
+
server.trace("customEvent", null, {
|
|
207
|
+
type,
|
|
208
|
+
value,
|
|
209
|
+
});
|
|
257
210
|
},
|
|
258
|
-
|
|
259
|
-
};
|
|
260
|
-
const VIDEO_SETTINGS_VP9_LOW_BANDWIDTH = {
|
|
261
|
-
codecOptions: {
|
|
262
|
-
videoGoogleStartBitrate: 500,
|
|
211
|
+
sendAudioMuted: (muted) => {
|
|
212
|
+
rtcStats.sendEvent("audio_muted", { muted });
|
|
263
213
|
},
|
|
264
|
-
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
};
|
|
269
|
-
const SCREEN_SHARE_SIMULCAST_SETTINGS = {
|
|
270
|
-
encodings: [
|
|
271
|
-
{ scaleResolutionDownBy: 2, dtx: true, maxBitrate: 500000 },
|
|
272
|
-
{ scaleResolutionDownBy: 1, dtx: true, maxBitrate: 1500000 },
|
|
273
|
-
],
|
|
274
|
-
};
|
|
275
|
-
const ADDITIONAL_SCREEN_SHARE_SETTINGS = {
|
|
276
|
-
encodings: [
|
|
277
|
-
{ scaleResolutionDownBy: 4, dtx: true, maxBitrate: 150000 },
|
|
278
|
-
{ scaleResolutionDownBy: 2, dtx: true, maxBitrate: 500000 },
|
|
279
|
-
{ scaleResolutionDownBy: 1, dtx: true, maxBitrate: 1500000 },
|
|
280
|
-
],
|
|
214
|
+
sendVideoMuted: (muted) => {
|
|
215
|
+
rtcStats.sendEvent("video_muted", { muted });
|
|
216
|
+
},
|
|
217
|
+
server,
|
|
281
218
|
};
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
const isChrome = ((_a = adapterRaw.browserDetails) === null || _a === void 0 ? void 0 : _a.browser) === "chrome";
|
|
289
|
-
const isVp9Available = isChrome && vp9On;
|
|
290
|
-
if (isScreenShare) {
|
|
291
|
-
return getScreenShareMediaSettings({
|
|
292
|
-
areTooManyAlreadyPresenting,
|
|
293
|
-
simulcastScreenshareOn,
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
else {
|
|
297
|
-
return getCameraMediaSettings({
|
|
298
|
-
lowBandwidth: lowDataModeEnabled,
|
|
299
|
-
isVp9Available,
|
|
300
|
-
});
|
|
219
|
+
|
|
220
|
+
const debugOn = new URLSearchParams(window.location.search).has("debug");
|
|
221
|
+
class Logger {
|
|
222
|
+
constructor() {
|
|
223
|
+
this._isEnabled = false;
|
|
224
|
+
this._isEnabled = debugOn;
|
|
301
225
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if (lowBandwidth) {
|
|
305
|
-
if (isVp9Available) {
|
|
306
|
-
return VIDEO_SETTINGS_VP9_LOW_BANDWIDTH;
|
|
307
|
-
}
|
|
308
|
-
return VIDEO_SETTINGS_SD;
|
|
226
|
+
isEnabled() {
|
|
227
|
+
return this._isEnabled;
|
|
309
228
|
}
|
|
310
|
-
|
|
311
|
-
|
|
229
|
+
enable() {
|
|
230
|
+
this._isEnabled = true;
|
|
312
231
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
const getScreenShareMediaSettings = ({ areTooManyAlreadyPresenting, simulcastScreenshareOn, }) => {
|
|
316
|
-
if (areTooManyAlreadyPresenting) {
|
|
317
|
-
return ADDITIONAL_SCREEN_SHARE_SETTINGS;
|
|
232
|
+
disable() {
|
|
233
|
+
this._isEnabled = false;
|
|
318
234
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
(function (PrioritizableCodec) {
|
|
325
|
-
PrioritizableCodec["H264"] = "video/h264";
|
|
326
|
-
PrioritizableCodec["VP9"] = "video/vp9";
|
|
327
|
-
})(PrioritizableCodec || (PrioritizableCodec = {}));
|
|
328
|
-
const modifyMediaCapabilities = (routerRtpCapabilities, features) => {
|
|
329
|
-
var _a;
|
|
330
|
-
const { vp9On, h264On } = features;
|
|
331
|
-
const isChrome = ((_a = adapterRaw.browserDetails) === null || _a === void 0 ? void 0 : _a.browser) === "chrome";
|
|
332
|
-
if (!(routerRtpCapabilities === null || routerRtpCapabilities === void 0 ? void 0 : routerRtpCapabilities.codecs)) {
|
|
333
|
-
return routerRtpCapabilities;
|
|
235
|
+
info(...params) {
|
|
236
|
+
if (!this._isEnabled) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
return console.info(...params);
|
|
334
240
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
241
|
+
warn(...params) {
|
|
242
|
+
if (!this._isEnabled) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
return console.warn(...params);
|
|
338
246
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
247
|
+
error(...params) {
|
|
248
|
+
if (!this._isEnabled) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
return console.error(...params);
|
|
342
252
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
const preferredCodecEntry = codecs.find(({ mimeType }) => mimeType.toLowerCase() === preferredCodec);
|
|
347
|
-
if (!preferredCodecEntry) {
|
|
348
|
-
return codecs;
|
|
253
|
+
withDebugLogger(myDebugger) {
|
|
254
|
+
this._debugger = myDebugger;
|
|
255
|
+
return this;
|
|
349
256
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
return -1;
|
|
257
|
+
debug(...params) {
|
|
258
|
+
if (!this._isEnabled || !this._debugger) {
|
|
259
|
+
return;
|
|
354
260
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
if (
|
|
358
|
-
|
|
261
|
+
const suppliedParams = [];
|
|
262
|
+
params.forEach((param) => {
|
|
263
|
+
if (typeof param === "function") {
|
|
264
|
+
const suppliedParam = param();
|
|
265
|
+
suppliedParams.push(suppliedParam);
|
|
359
266
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
function getPreferredOrder(availableCodecs, { av1On }) {
|
|
366
|
-
availableCodecs.unshift("video/vp9");
|
|
367
|
-
if (av1On) {
|
|
368
|
-
availableCodecs.unshift("video/av1");
|
|
267
|
+
else {
|
|
268
|
+
suppliedParams.push(param);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
this._debugger.print(...suppliedParams);
|
|
369
272
|
}
|
|
370
|
-
return availableCodecs;
|
|
371
273
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
|
|
274
|
+
|
|
275
|
+
var _a$6, _b$2;
|
|
276
|
+
const adapter$6 = (_a$6 = adapterRaw.default) !== null && _a$6 !== void 0 ? _a$6 : adapterRaw;
|
|
277
|
+
const logger$a = new Logger();
|
|
278
|
+
const browserName$2 = (_b$2 = adapter$6.browserDetails) === null || _b$2 === void 0 ? void 0 : _b$2.browser;
|
|
279
|
+
const browserVersion$1 = adapter$6.browserDetails.version;
|
|
280
|
+
function setCodecPreferenceSDP({ sdp, redOn }) {
|
|
281
|
+
var _a, _b;
|
|
282
|
+
try {
|
|
283
|
+
const sdpObject = sdpTransform.parse(sdp);
|
|
284
|
+
if (Array.isArray(sdpObject === null || sdpObject === void 0 ? void 0 : sdpObject.media)) {
|
|
285
|
+
const mediaAudio = sdpObject.media.find((m) => m.type === "audio");
|
|
286
|
+
if (Array.isArray(mediaAudio === null || mediaAudio === void 0 ? void 0 : mediaAudio.rtp)) {
|
|
287
|
+
const rtp = mediaAudio.rtp;
|
|
288
|
+
for (let i = 0; i < rtp.length; i++) {
|
|
289
|
+
if (redOn && rtp[i].codec === "red") {
|
|
290
|
+
const payloads = (_a = mediaAudio.payloads) === null || _a === void 0 ? void 0 : _a.split(" ");
|
|
291
|
+
const pt = payloads === null || payloads === void 0 ? void 0 : payloads.indexOf("" + rtp[i].payload);
|
|
292
|
+
if (pt && pt !== -1 && pt >= 0) {
|
|
293
|
+
payloads === null || payloads === void 0 ? void 0 : payloads.unshift(payloads.splice(pt, 1)[0]);
|
|
294
|
+
mediaAudio.payloads = payloads === null || payloads === void 0 ? void 0 : payloads.join(" ");
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
const mediaVideo = sdpObject.media.find((m) => m.type === "video");
|
|
300
|
+
if (Array.isArray(mediaVideo === null || mediaVideo === void 0 ? void 0 : mediaVideo.rtp)) {
|
|
301
|
+
const rtp = mediaVideo.rtp;
|
|
302
|
+
for (let i = 0; i < rtp.length; i++) {
|
|
303
|
+
if (rtp[i].codec === "VP9") {
|
|
304
|
+
const payloads = (_b = mediaVideo.payloads) === null || _b === void 0 ? void 0 : _b.split(" ");
|
|
305
|
+
const pt = payloads === null || payloads === void 0 ? void 0 : payloads.indexOf("" + rtp[i].payload);
|
|
306
|
+
if (pt && pt !== -1 && pt >= 0) {
|
|
307
|
+
payloads === null || payloads === void 0 ? void 0 : payloads.unshift(payloads.splice(pt, 1)[0]);
|
|
308
|
+
mediaVideo.payloads = payloads === null || payloads === void 0 ? void 0 : payloads.join(" ");
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
const newSdp = sdpTransform.write(sdpObject);
|
|
315
|
+
return newSdp;
|
|
316
|
+
}
|
|
317
|
+
catch (error) {
|
|
318
|
+
logger$a.error("setCodecPreferenceSDP error:", error);
|
|
319
|
+
return sdp;
|
|
320
|
+
}
|
|
384
321
|
}
|
|
385
|
-
function
|
|
386
|
-
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
}
|
|
322
|
+
function cleanSdp(sdp) {
|
|
323
|
+
try {
|
|
324
|
+
const sdpObject = sdpTransform.parse(sdp);
|
|
325
|
+
sdpObject.media.forEach((mediaObject) => {
|
|
326
|
+
const usedPayloads = {};
|
|
327
|
+
if (mediaObject.payloads)
|
|
328
|
+
mediaObject.payloads = ("" + mediaObject.payloads)
|
|
329
|
+
.split(" ")
|
|
330
|
+
.filter((p) => !usedPayloads[p] && (usedPayloads[p] = true))
|
|
331
|
+
.join(" ");
|
|
332
|
+
const usedRtps = {};
|
|
333
|
+
mediaObject.rtp = mediaObject.rtp.filter((p) => !p.payload || (usedPayloads[p.payload] && !usedRtps[p.payload] && (usedRtps[p.payload] = true)));
|
|
334
|
+
const usedFmtps = {};
|
|
335
|
+
if (mediaObject.fmtp)
|
|
336
|
+
mediaObject.fmtp = mediaObject.fmtp.filter((p) => !p.payload ||
|
|
337
|
+
(usedPayloads[p.payload] && !usedFmtps[p.payload] && (usedFmtps[p.payload] = true)));
|
|
338
|
+
const usedRtcpFb = {};
|
|
339
|
+
if (mediaObject.rtcpFb)
|
|
340
|
+
mediaObject.rtcpFb = mediaObject.rtcpFb.filter((p) => !p.payload ||
|
|
341
|
+
(usedPayloads[p.payload] &&
|
|
342
|
+
!usedRtcpFb[p.payload + p.type + p.subtype] &&
|
|
343
|
+
(usedRtcpFb[p.payload + p.type + p.subtype] = true)));
|
|
396
344
|
});
|
|
397
|
-
return
|
|
398
|
-
}
|
|
345
|
+
return sdpTransform.write(sdpObject);
|
|
346
|
+
}
|
|
347
|
+
catch (_) { }
|
|
348
|
+
return sdp;
|
|
399
349
|
}
|
|
400
|
-
function
|
|
401
|
-
return
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
350
|
+
function deprioritizeH264(sdp) {
|
|
351
|
+
return SDPUtils.splitSections(sdp)
|
|
352
|
+
.map((section) => {
|
|
353
|
+
if (SDPUtils.getKind(section) !== "video")
|
|
354
|
+
return section;
|
|
355
|
+
const h264payloadTypes = SDPUtils.matchPrefix(section, "a=rtpmap:")
|
|
356
|
+
.map((line) => SDPUtils.parseRtpMap(line))
|
|
357
|
+
.filter((codec) => /h264/i.test(codec.name))
|
|
358
|
+
.map((codec) => "" + codec.payloadType);
|
|
359
|
+
if (!h264payloadTypes.length)
|
|
360
|
+
return section;
|
|
361
|
+
const mline = SDPUtils.matchPrefix(section, "m=video")[0];
|
|
362
|
+
const mlinePayloadsSectionExec = /(\s\d+)+$/i.exec(mline);
|
|
363
|
+
const mlinePayloadsSection = mlinePayloadsSectionExec ? mlinePayloadsSectionExec[0] : "";
|
|
364
|
+
const mlinePayloadsNonH264 = mlinePayloadsSection
|
|
365
|
+
.split(" ")
|
|
366
|
+
.filter((payloadType) => payloadType && !h264payloadTypes.includes(payloadType));
|
|
367
|
+
const reorderedPayloads = [...mlinePayloadsNonH264, ...h264payloadTypes].join(" ");
|
|
368
|
+
const newmline = mline.replace(mlinePayloadsSection, " " + reorderedPayloads);
|
|
369
|
+
return section.replace(mline, newmline);
|
|
370
|
+
})
|
|
371
|
+
.join("");
|
|
372
|
+
}
|
|
373
|
+
function filterMidExtension(sdp) {
|
|
374
|
+
if (browserName$2 !== "firefox" || (browserVersion$1 && browserVersion$1 >= 63) || browserVersion$1 === 60) {
|
|
375
|
+
return sdp;
|
|
376
|
+
}
|
|
377
|
+
return (SDPUtils.splitLines(sdp.trim())
|
|
378
|
+
.filter((line) => {
|
|
379
|
+
if (!line.startsWith("a=extmap:")) {
|
|
380
|
+
return true;
|
|
405
381
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
382
|
+
const extmap = SDPUtils.parseExtmap(line);
|
|
383
|
+
return extmap.uri !== "urn:ietf:params:rtp-hdrext:sdes:mid";
|
|
384
|
+
})
|
|
385
|
+
.join("\r\n") + "\r\n");
|
|
386
|
+
}
|
|
387
|
+
function filterMsidSemantic(sdp) {
|
|
388
|
+
if (browserName$2 !== "firefox" && browserVersion$1 < 68) {
|
|
389
|
+
return sdp;
|
|
390
|
+
}
|
|
391
|
+
return (SDPUtils.splitLines(sdp.trim())
|
|
392
|
+
.map((line) => (line.startsWith("a=msid-semantic:") ? "a=msid-semantic: WMS *" : line))
|
|
393
|
+
.join("\r\n") + "\r\n");
|
|
394
|
+
}
|
|
395
|
+
function addExtMap(sdp, extmapUri, modifyAudio = false, modifyVideo = false) {
|
|
396
|
+
var _a, _b;
|
|
397
|
+
try {
|
|
398
|
+
const sdpObj = sdpTransform.parse(sdp);
|
|
399
|
+
if (((_a = sdpObj === null || sdpObj === void 0 ? void 0 : sdpObj.ext) === null || _a === void 0 ? void 0 : _a.length) && sdpObj.ext.length > 0) {
|
|
400
|
+
return sdp;
|
|
409
401
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
402
|
+
if ((sdpObj === null || sdpObj === void 0 ? void 0 : sdpObj.media.length) < 1)
|
|
403
|
+
return sdp;
|
|
404
|
+
const allHeaderExtensions = sdpObj === null || sdpObj === void 0 ? void 0 : sdpObj.media.flatMap((section) => section.ext || []);
|
|
405
|
+
const extmapId = ((_b = allHeaderExtensions.find((ext) => ext.uri === extmapUri)) === null || _b === void 0 ? void 0 : _b.value) ||
|
|
406
|
+
[...new Set([0, 15, ...allHeaderExtensions.map((ext) => ext.value)])]
|
|
407
|
+
.sort((a, b) => a - b)
|
|
408
|
+
.find((n, i, arr) => n + 1 !== arr[i + 1]) + 1;
|
|
409
|
+
sdpObj.media.forEach((mediaSection) => {
|
|
410
|
+
var _a;
|
|
411
|
+
if ((modifyAudio && mediaSection.type === "audio") || (modifyVideo && mediaSection.type === "video")) {
|
|
412
|
+
if (!((_a = mediaSection.ext) === null || _a === void 0 ? void 0 : _a.find((e) => e.uri === extmapUri))) {
|
|
413
|
+
if (Array.isArray(mediaSection.ext)) {
|
|
414
|
+
mediaSection["ext"].push({ value: extmapId, uri: extmapUri });
|
|
415
|
+
}
|
|
416
|
+
else {
|
|
417
|
+
mediaSection["ext"] = [{ value: extmapId, uri: extmapUri }];
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
415
421
|
});
|
|
416
|
-
return
|
|
417
|
-
}
|
|
422
|
+
return sdpTransform.write(sdpObj);
|
|
423
|
+
}
|
|
424
|
+
catch (error) {
|
|
425
|
+
console.error("Error during addAbsCaptureTimeExtMap: ", error);
|
|
426
|
+
}
|
|
427
|
+
return sdp;
|
|
418
428
|
}
|
|
419
|
-
function
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
sortedCodecs = yield sortCodecsByPowerEfficiency(codecs);
|
|
423
|
-
return sortedCodecs;
|
|
424
|
-
});
|
|
429
|
+
function addAbsCaptureTimeExtMap(sdp) {
|
|
430
|
+
const absCaptureTimeUri = "http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time";
|
|
431
|
+
return addExtMap(sdp, absCaptureTimeUri, true, true);
|
|
425
432
|
}
|
|
426
433
|
|
|
427
|
-
function
|
|
428
|
-
const
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
cpMetrics.bitrateOut = (8000 * bytesSentDiff) / timeDiff;
|
|
432
|
-
cpMetrics.state = currentCptats.state;
|
|
433
|
-
cpMetrics.roundTripTime = currentCptats.currentRoundTripTime;
|
|
434
|
-
cpMetrics.requestsSent = currentCptats.requestsSent;
|
|
435
|
-
cpMetrics.responsesReceived = currentCptats.responsesReceived;
|
|
436
|
-
cpMetrics.requestsReceived = currentCptats.requestsReceived;
|
|
437
|
-
cpMetrics.responsesSent = currentCptats.responsesSent;
|
|
438
|
-
cpMetrics.availableOutgoingBitrate = currentCptats.availableOutgoingBitrate;
|
|
439
|
-
cpMetrics.availableIncomingBitrate = currentCptats.availableIncomingBitrate;
|
|
440
|
-
const remote = report.get(currentCptats.remoteCandidateId);
|
|
441
|
-
const local = report.get(currentCptats.localCandidateId);
|
|
442
|
-
cpMetrics.usingTurn = false;
|
|
443
|
-
if (local) {
|
|
444
|
-
if (/relay/i.test(local.candidateType || "")) {
|
|
445
|
-
cpMetrics.usingTurn = true;
|
|
446
|
-
cpMetrics.turnProtocol = local.relayProtocol;
|
|
447
|
-
}
|
|
434
|
+
function setVideoBandwidthUsingSetParameters(pc, bandwidth, logger = console) {
|
|
435
|
+
const sender = pc.getSenders().find((s) => s.track && s.track.kind === "video");
|
|
436
|
+
if (!sender) {
|
|
437
|
+
return Promise.resolve();
|
|
448
438
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
439
|
+
const parameters = sender.getParameters();
|
|
440
|
+
if (parameters.encodings && parameters.encodings.length === 0) {
|
|
441
|
+
return Promise.resolve();
|
|
442
|
+
}
|
|
443
|
+
if (!parameters.encodings) {
|
|
444
|
+
parameters.encodings = [{}];
|
|
452
445
|
}
|
|
446
|
+
if (bandwidth === 0) {
|
|
447
|
+
delete parameters.encodings[0].maxBitrate;
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
parameters.encodings[0].maxBitrate = bandwidth * 1000;
|
|
451
|
+
}
|
|
452
|
+
return sender.setParameters(parameters).catch((err) => {
|
|
453
|
+
logger.error("setParameters err: ", err);
|
|
454
|
+
});
|
|
453
455
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
[
|
|
464
|
-
codecStats.mimeType,
|
|
465
|
-
codecStats.channels && `${codecStats.channels}ch`,
|
|
466
|
-
codecStats.clockRate,
|
|
467
|
-
codecStats.payloadType,
|
|
468
|
-
currentSsrcStats.encoderImplementation || currentSsrcStats.decoderImplementation,
|
|
469
|
-
codecStats.sdpFmtpLine,
|
|
470
|
-
]
|
|
471
|
-
.filter(Boolean)
|
|
472
|
-
.join(" ");
|
|
473
|
-
ssrcMetrics.mid = currentSsrcStats.mid;
|
|
474
|
-
ssrcMetrics.rid = currentSsrcStats.rid;
|
|
456
|
+
|
|
457
|
+
const _trackAnnotations = new WeakMap();
|
|
458
|
+
function trackAnnotations(o) {
|
|
459
|
+
let props = _trackAnnotations.get(o);
|
|
460
|
+
if (!props) {
|
|
461
|
+
props = {};
|
|
462
|
+
_trackAnnotations.set(o, props);
|
|
463
|
+
}
|
|
464
|
+
return props;
|
|
475
465
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
466
|
+
|
|
467
|
+
var _a$5;
|
|
468
|
+
const adapter$5 = (_a$5 = adapterRaw.default) !== null && _a$5 !== void 0 ? _a$5 : adapterRaw;
|
|
469
|
+
const logger$9 = new Logger();
|
|
470
|
+
class Session {
|
|
471
|
+
constructor({ clientId, bandwidth, peerConnectionConfig, deprioritizeH264Encoding, incrementAnalyticMetric, }) {
|
|
472
|
+
this.relayCandidateSeen = false;
|
|
473
|
+
this.serverReflexiveCandidateSeen = false;
|
|
474
|
+
this.publicHostCandidateSeen = false;
|
|
475
|
+
this.ipv6HostCandidateSeen = false;
|
|
476
|
+
this.ipv6HostCandidateTeredoSeen = false;
|
|
477
|
+
this.ipv6HostCandidate6to4Seen = false;
|
|
478
|
+
this.mdnsHostCandidateSeen = false;
|
|
479
|
+
this.pendingReplaceTrackActions = [];
|
|
480
|
+
this.peerConnectionConfig = peerConnectionConfig;
|
|
481
|
+
this.clientId = clientId;
|
|
482
|
+
this.pc = new RTCPeerConnection(this.peerConnectionConfig);
|
|
483
|
+
this.signalingState = this.pc.signalingState;
|
|
484
|
+
this.pc.addEventListener("signalingstatechange", () => {
|
|
485
|
+
if (this.signalingState === this.pc.signalingState) {
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
this.signalingState = this.pc.signalingState;
|
|
489
|
+
if (this.pc.signalingState === "stable") {
|
|
490
|
+
this.isOperationPending = false;
|
|
491
|
+
const action = this.pending.shift();
|
|
492
|
+
if (action) {
|
|
493
|
+
action.apply();
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
this.wasEverConnected = false;
|
|
498
|
+
this.connectionStatus = null;
|
|
499
|
+
this.bandwidth = bandwidth || 0;
|
|
500
|
+
this.pending = [];
|
|
501
|
+
this.isOperationPending = false;
|
|
502
|
+
this.streamIds = [];
|
|
503
|
+
this.streams = [];
|
|
504
|
+
this.earlyIceCandidates = [];
|
|
505
|
+
this.afterConnected = new Promise((resolve) => {
|
|
506
|
+
this.registerConnected = resolve;
|
|
507
|
+
});
|
|
508
|
+
this._deprioritizeH264Encoding = deprioritizeH264Encoding;
|
|
509
|
+
this._incrementAnalyticMetric = incrementAnalyticMetric;
|
|
510
|
+
}
|
|
511
|
+
addStream(stream) {
|
|
512
|
+
this.streamIds.push(stream.id);
|
|
513
|
+
this.streams.push(stream);
|
|
514
|
+
stream.getAudioTracks().forEach((track) => {
|
|
515
|
+
this.pc.addTrack(track, stream);
|
|
516
|
+
});
|
|
517
|
+
stream.getVideoTracks().forEach((track) => {
|
|
518
|
+
this.pc.addTrack(track, stream);
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
addTrack(track, stream) {
|
|
522
|
+
if (!stream) {
|
|
523
|
+
stream = this.streams[0];
|
|
494
524
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
525
|
+
stream === null || stream === void 0 ? void 0 : stream.addTrack(track);
|
|
526
|
+
this.pc.addTrack(track, stream);
|
|
527
|
+
}
|
|
528
|
+
removeTrack(track) {
|
|
529
|
+
const stream = this.streams[0];
|
|
530
|
+
stream.removeTrack(track);
|
|
531
|
+
const sender = this.pc.getSenders().find((sender) => sender.track === track);
|
|
532
|
+
if (sender) {
|
|
533
|
+
this.pc.removeTrack(sender);
|
|
501
534
|
}
|
|
502
|
-
const jitterBufferDelayDiff = (currentSsrcStats.jitterBufferDelay || 0) - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.jitterBufferDelay) || 0);
|
|
503
|
-
const jitterBufferEmittedDiff = (currentSsrcStats.jitterBufferEmittedCount || 0) - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.jitterBufferEmittedCount) || 0);
|
|
504
|
-
ssrcMetrics.jitter = jitterBufferEmittedDiff ? jitterBufferDelayDiff / jitterBufferEmittedDiff : 0;
|
|
505
535
|
}
|
|
506
|
-
|
|
507
|
-
const
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
const byteCountDiff = currentSsrcStats.bytesSent - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.bytesSent) || 0);
|
|
511
|
-
ssrcMetrics.byteCount = (ssrcMetrics.byteCount || 0) + byteCountDiff;
|
|
512
|
-
let headerByteCountDiff = 0;
|
|
513
|
-
if (currentSsrcStats.headerBytesSent) {
|
|
514
|
-
headerByteCountDiff = currentSsrcStats.headerBytesSent - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.headerBytesSent) || 0);
|
|
515
|
-
ssrcMetrics.headerByteCount = (ssrcMetrics.headerByteCount || 0) + headerByteCountDiff;
|
|
536
|
+
removeStream(stream) {
|
|
537
|
+
const streamIdIndex = this.streamIds.indexOf(stream.id);
|
|
538
|
+
if (streamIdIndex !== -1) {
|
|
539
|
+
this.streamIds.splice(streamIdIndex, 1);
|
|
516
540
|
}
|
|
517
|
-
const
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
const sendDelayDiff = currentSsrcStats.totalPacketSendDelay - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.totalPacketSendDelay) || 0);
|
|
521
|
-
ssrcMetrics.sendDelay = sendDelayDiff / packetCountDiff;
|
|
522
|
-
const retransDiff = currentSsrcStats.retransmittedPacketsSent - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.retransmittedPacketsSent) || 0);
|
|
523
|
-
ssrcMetrics.retransRatio = (1000 * (retransDiff / packetCountDiff)) / timeDiff;
|
|
524
|
-
if (currentSsrcStats.remoteId) {
|
|
525
|
-
const remoteReport = report.get(currentSsrcStats.remoteId);
|
|
526
|
-
if (remoteReport) {
|
|
527
|
-
ssrcMetrics.roundTripTime = remoteReport.roundTripTime || 0;
|
|
528
|
-
ssrcMetrics.jitter = remoteReport.jitter || 0;
|
|
529
|
-
ssrcMetrics.fractionLost = remoteReport.fractionLost || 0;
|
|
530
|
-
}
|
|
541
|
+
const streamIndex = this.streams.indexOf(stream);
|
|
542
|
+
if (streamIndex !== -1) {
|
|
543
|
+
this.streams.splice(streamIndex, 1);
|
|
531
544
|
}
|
|
545
|
+
stream.getTracks().forEach((track) => {
|
|
546
|
+
const sender = this.pc.getSenders().find((sender) => sender.track === track);
|
|
547
|
+
if (sender) {
|
|
548
|
+
this.pc.removeTrack(sender);
|
|
549
|
+
}
|
|
550
|
+
});
|
|
532
551
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
const samples = currentSsrcStats.totalSamplesReceived || 0;
|
|
542
|
-
const concealmentEvents = currentSsrcStats.concealmentEvents || 0;
|
|
543
|
-
const samplesDiff = samples - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.totalSamplesReceived) || 0);
|
|
544
|
-
const concealedSamples = currentSsrcStats.concealedSamples || 0;
|
|
545
|
-
const concealedDiff = concealedSamples - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.concealedSamples) || 0);
|
|
546
|
-
const silentConcealedDiff = (currentSsrcStats.silentConcealedSamples || 0) - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.silentConcealedSamples) || 0);
|
|
547
|
-
const insDiff = (currentSsrcStats.insertedSamplesForDeceleration || 0) -
|
|
548
|
-
((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.insertedSamplesForDeceleration) || 0);
|
|
549
|
-
const remDiff = (currentSsrcStats.removedSamplesForAcceleration || 0) - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.removedSamplesForAcceleration) || 0);
|
|
550
|
-
ssrcMetrics.audioSamples = samples;
|
|
551
|
-
ssrcMetrics.audioConcealmentEvents = concealmentEvents;
|
|
552
|
-
ssrcMetrics.audioConcealedSamples = concealedSamples;
|
|
553
|
-
ssrcMetrics.audioConcealment = concealedDiff ? concealedDiff / samplesDiff : 0;
|
|
554
|
-
ssrcMetrics.audioSilentConcealment = silentConcealedDiff ? silentConcealedDiff / samplesDiff : 0;
|
|
555
|
-
ssrcMetrics.audioAcceleration = remDiff ? remDiff / samplesDiff : 0;
|
|
556
|
-
ssrcMetrics.audioDeceleration = insDiff ? insDiff / samplesDiff : 0;
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
function captureVideoSsrcMetrics(ssrcMetrics, currentSsrcStats, prevSsrcStats, timeDiff, report) {
|
|
560
|
-
ssrcMetrics.width = currentSsrcStats.frameWidth;
|
|
561
|
-
ssrcMetrics.height = currentSsrcStats.frameHeight;
|
|
562
|
-
ssrcMetrics.qualityLimitationReason = currentSsrcStats.qualityLimitationReason || "";
|
|
563
|
-
const pliCountDiff = currentSsrcStats.pliCount - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.pliCount) || 0);
|
|
564
|
-
ssrcMetrics.pliCount = (ssrcMetrics.pliCount || 0) + pliCountDiff;
|
|
565
|
-
ssrcMetrics.pliRate = (1000 * pliCountDiff) / timeDiff;
|
|
566
|
-
const firCountDiff = currentSsrcStats.firCount - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.firCount) || 0);
|
|
567
|
-
ssrcMetrics.firCount = (ssrcMetrics.firCount || 0) + firCountDiff;
|
|
568
|
-
ssrcMetrics.firRate = (1000 * firCountDiff) / timeDiff;
|
|
569
|
-
if (ssrcMetrics.direction === "in") {
|
|
570
|
-
const kfCountDiff = currentSsrcStats.keyFramesDecoded - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.keyFramesDecoded) || 0);
|
|
571
|
-
ssrcMetrics.kfCount = (ssrcMetrics.kfCount || 0) + kfCountDiff;
|
|
572
|
-
ssrcMetrics.kfRate = (1000 * kfCountDiff) / timeDiff;
|
|
573
|
-
const frameCountDiff = currentSsrcStats.framesDecoded - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.framesDecoded) || 0);
|
|
574
|
-
ssrcMetrics.frameCount = (ssrcMetrics.frameCount || 0) + frameCountDiff;
|
|
575
|
-
const qpsumDiff = currentSsrcStats.qpSum - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.qpSum) || 0);
|
|
576
|
-
ssrcMetrics.qpf = qpsumDiff / frameCountDiff;
|
|
577
|
-
ssrcMetrics.fps = (frameCountDiff * 1000) / timeDiff;
|
|
552
|
+
_setRemoteDescription(desc) {
|
|
553
|
+
if (this._deprioritizeH264Encoding)
|
|
554
|
+
desc.sdp = deprioritizeH264(desc.sdp);
|
|
555
|
+
this.srdComplete = this.pc.setRemoteDescription(desc);
|
|
556
|
+
return this.srdComplete.then(() => {
|
|
557
|
+
this.earlyIceCandidates.forEach((candidate) => this.pc.addIceCandidate(candidate));
|
|
558
|
+
this.earlyIceCandidates = [];
|
|
559
|
+
});
|
|
578
560
|
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
ssrcMetrics.frameCount = (ssrcMetrics.frameCount || 0) + frameCountDiff;
|
|
585
|
-
const qpsumDiff = currentSsrcStats.qpSum - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.qpSum) || 0);
|
|
586
|
-
ssrcMetrics.qpf = qpsumDiff / frameCountDiff;
|
|
587
|
-
ssrcMetrics.fps = (frameCountDiff * 1000) / timeDiff;
|
|
588
|
-
const encodeTimeDiff = currentSsrcStats.totalEncodeTime - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.totalEncodeTime) || 0);
|
|
589
|
-
ssrcMetrics.encodeTime = encodeTimeDiff / frameCountDiff;
|
|
590
|
-
if (currentSsrcStats.mediaSourceId) {
|
|
591
|
-
const mediaSourceReport = report.get(currentSsrcStats.mediaSourceId);
|
|
592
|
-
if (mediaSourceReport) {
|
|
593
|
-
ssrcMetrics.sourceWidth = mediaSourceReport.width || 0;
|
|
594
|
-
ssrcMetrics.sourceHeight = mediaSourceReport.height || 0;
|
|
595
|
-
ssrcMetrics.sourceFps = mediaSourceReport.framesPerSecond || 0;
|
|
596
|
-
}
|
|
561
|
+
handleOffer(offer) {
|
|
562
|
+
if (!this.canModifyPeerConnection()) {
|
|
563
|
+
return new Promise((resolve) => {
|
|
564
|
+
this.pending.push(() => this.handleOffer(offer).then(resolve));
|
|
565
|
+
});
|
|
597
566
|
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
function rtcStatsConnection(wsURL, logger = console) {
|
|
612
|
-
const buffer = [];
|
|
613
|
-
let ws;
|
|
614
|
-
let organizationId;
|
|
615
|
-
let clientId;
|
|
616
|
-
let displayName;
|
|
617
|
-
let userRole;
|
|
618
|
-
let roomSessionId;
|
|
619
|
-
let connectionShouldBeOpen;
|
|
620
|
-
let connectionAttempt = 0;
|
|
621
|
-
let hasPassedOnRoomSessionId = false;
|
|
622
|
-
let getStatsBufferUsed = 0;
|
|
623
|
-
let deviceId;
|
|
624
|
-
let roomProduct;
|
|
625
|
-
let roomMode;
|
|
626
|
-
let sfuServer;
|
|
627
|
-
let featureFlags;
|
|
628
|
-
const connection = {
|
|
629
|
-
connected: false,
|
|
630
|
-
attemptedConnectedAtLeastOnce: false,
|
|
631
|
-
trace: (...args) => {
|
|
632
|
-
args.push(Date.now());
|
|
633
|
-
if (args[0] === "customEvent" && args[2].type === "roomSessionId") {
|
|
634
|
-
const oldRoomSessionIdValue = roomSessionId && roomSessionId[2].value.roomSessionId;
|
|
635
|
-
const newRoomSessionIdValue = args[2].value.roomSessionId;
|
|
636
|
-
roomSessionId = args;
|
|
637
|
-
if (hasPassedOnRoomSessionId &&
|
|
638
|
-
newRoomSessionIdValue &&
|
|
639
|
-
newRoomSessionIdValue !== oldRoomSessionIdValue) {
|
|
640
|
-
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
641
|
-
}
|
|
642
|
-
if (newRoomSessionIdValue)
|
|
643
|
-
hasPassedOnRoomSessionId = true;
|
|
644
|
-
}
|
|
645
|
-
else if (args[0] === "customEvent" && args[2].type === "clientId") {
|
|
646
|
-
clientId = args;
|
|
647
|
-
}
|
|
648
|
-
else if (args[0] === "customEvent" && args[2].type === "organizationId") {
|
|
649
|
-
organizationId = args;
|
|
567
|
+
this.isOperationPending = true;
|
|
568
|
+
let sdp = offer.sdp;
|
|
569
|
+
sdp = filterMidExtension(sdp);
|
|
570
|
+
sdp = filterMsidSemantic(sdp);
|
|
571
|
+
const desc = { type: offer.type, sdp };
|
|
572
|
+
let answerToSignal;
|
|
573
|
+
return this._setRemoteDescription(desc)
|
|
574
|
+
.then(() => {
|
|
575
|
+
return this.pc.createAnswer();
|
|
576
|
+
})
|
|
577
|
+
.then((answer) => {
|
|
578
|
+
if (!answer.sdp) {
|
|
579
|
+
throw new Error("SDP undefined while creating answer");
|
|
650
580
|
}
|
|
651
|
-
else
|
|
652
|
-
|
|
581
|
+
else {
|
|
582
|
+
answerToSignal = {
|
|
583
|
+
sdp: answer.sdp,
|
|
584
|
+
sdpU: answer.sdp,
|
|
585
|
+
type: answer.type,
|
|
586
|
+
};
|
|
587
|
+
return this.pc.setLocalDescription(answer);
|
|
653
588
|
}
|
|
654
|
-
|
|
655
|
-
|
|
589
|
+
})
|
|
590
|
+
.then(() => {
|
|
591
|
+
return setVideoBandwidthUsingSetParameters(this.pc, this.bandwidth);
|
|
592
|
+
})
|
|
593
|
+
.then(() => {
|
|
594
|
+
return answerToSignal;
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
handleAnswer(message) {
|
|
598
|
+
const sdp = filterMsidSemantic(message.sdp);
|
|
599
|
+
const desc = { type: message.type, sdp };
|
|
600
|
+
return this._setRemoteDescription(desc).then(() => {
|
|
601
|
+
return setVideoBandwidthUsingSetParameters(this.pc, this.bandwidth);
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
addIceCandidate(candidate) {
|
|
605
|
+
if (!this.srdComplete) {
|
|
606
|
+
this.earlyIceCandidates.push(candidate);
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
this.srdComplete.then(() => {
|
|
610
|
+
var _a;
|
|
611
|
+
if (this.pc.signalingState === "closed") {
|
|
612
|
+
return;
|
|
656
613
|
}
|
|
657
|
-
|
|
658
|
-
|
|
614
|
+
if (((_a = adapter$5.browserDetails) === null || _a === void 0 ? void 0 : _a.browser) === "safari" && candidate && candidate.candidate === "") {
|
|
615
|
+
return;
|
|
659
616
|
}
|
|
660
|
-
|
|
661
|
-
|
|
617
|
+
this.pc.addIceCandidate(candidate).catch((e) => {
|
|
618
|
+
logger$9.warn("Failed to add ICE candidate ('%s'): %s", candidate ? candidate.candidate : null, e);
|
|
619
|
+
});
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
canModifyPeerConnection() {
|
|
623
|
+
return this.pc.signalingState === "stable" && !this.isOperationPending;
|
|
624
|
+
}
|
|
625
|
+
close() {
|
|
626
|
+
const pc = this.pc;
|
|
627
|
+
if (!pc) {
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
pc.oniceconnectionstatechange = null;
|
|
631
|
+
pc.onicecandidate = null;
|
|
632
|
+
pc.ontrack = null;
|
|
633
|
+
try {
|
|
634
|
+
pc.close();
|
|
635
|
+
}
|
|
636
|
+
catch (e) {
|
|
637
|
+
logger$9.warn("failures during close of session", e);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
hasConnectedPeerConnection() {
|
|
641
|
+
return this.pc.connectionState === "connected";
|
|
642
|
+
}
|
|
643
|
+
replaceTrack(oldTrack, newTrack) {
|
|
644
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
645
|
+
logger$9.info("replacetrack() [oldTrackId: %s, newTrackId: %s]", oldTrack === null || oldTrack === void 0 ? void 0 : oldTrack.id, newTrack.id);
|
|
646
|
+
if (newTrack.readyState === "ended") {
|
|
647
|
+
throw new Error(`refusing to use ended track with id: ${newTrack.id}, kind: ${newTrack.kind}`);
|
|
662
648
|
}
|
|
663
|
-
|
|
664
|
-
|
|
649
|
+
const pc = this.pc;
|
|
650
|
+
if (oldTrack) {
|
|
651
|
+
const sender = pc.getSenders().find((s) => { var _a; return ((_a = s.track) === null || _a === void 0 ? void 0 : _a.id) === oldTrack.id; });
|
|
652
|
+
if (sender) {
|
|
653
|
+
return yield sender.replaceTrack(newTrack);
|
|
654
|
+
}
|
|
665
655
|
}
|
|
666
|
-
|
|
667
|
-
|
|
656
|
+
const sender = pc.getSenders().find((s) => {
|
|
657
|
+
const track = s.track;
|
|
658
|
+
return (track === null || track === void 0 ? void 0 : track.kind) === newTrack.kind && !trackAnnotations(track).fromGetDisplayMedia;
|
|
659
|
+
});
|
|
660
|
+
if (sender) {
|
|
661
|
+
return yield sender.replaceTrack(newTrack);
|
|
668
662
|
}
|
|
669
|
-
|
|
670
|
-
|
|
663
|
+
let stream = this.streams.find((s) => s.getTracks().find((t) => t.id === newTrack.id));
|
|
664
|
+
if (!stream) {
|
|
665
|
+
rtcStats.sendEvent("P2PReplaceTrackNewTrackNotInStream", {
|
|
666
|
+
oldTrackId: oldTrack === null || oldTrack === void 0 ? void 0 : oldTrack.id,
|
|
667
|
+
oldTrackKind: oldTrack === null || oldTrack === void 0 ? void 0 : oldTrack.kind,
|
|
668
|
+
oldTrackIsEffect: oldTrack && trackAnnotations(oldTrack).isEffectTrack,
|
|
669
|
+
newTrackId: newTrack.id,
|
|
670
|
+
newTrackKind: newTrack.kind,
|
|
671
|
+
newTrackIsEffect: trackAnnotations(newTrack).isEffectTrack,
|
|
672
|
+
});
|
|
673
|
+
this._incrementAnalyticMetric("P2PReplaceTrackNewTrackNotInStream");
|
|
671
674
|
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
+
stream = this.streams[0];
|
|
676
|
+
if (!stream) {
|
|
677
|
+
rtcStats.sendEvent("P2PReplaceTrackNoStream", {});
|
|
678
|
+
this._incrementAnalyticMetric("P2PReplaceTrackNoStream");
|
|
679
|
+
throw new Error("replaceTrack: No stream?");
|
|
675
680
|
}
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
681
|
+
pc.addTrack(newTrack, stream);
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
changeBandwidth(bandwidth) {
|
|
685
|
+
if (bandwidth === this.bandwidth) {
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
if (!this.canModifyPeerConnection()) {
|
|
689
|
+
this.pending.push(() => this.changeBandwidth(bandwidth));
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
this.bandwidth = bandwidth;
|
|
693
|
+
if (!this.pc.localDescription) {
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
setVideoBandwidthUsingSetParameters(this.pc, this.bandwidth);
|
|
697
|
+
}
|
|
698
|
+
setAudioOnly(enable, excludedTrackIds = []) {
|
|
699
|
+
var _a;
|
|
700
|
+
(_a = this.pc) === null || _a === void 0 ? void 0 : _a.getTransceivers().filter((videoTransceiver) => {
|
|
701
|
+
var _a, _b, _c, _d, _e, _f;
|
|
702
|
+
return (videoTransceiver === null || videoTransceiver === void 0 ? void 0 : videoTransceiver.direction) !== "recvonly" &&
|
|
703
|
+
((_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" &&
|
|
704
|
+
!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) &&
|
|
705
|
+
!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);
|
|
706
|
+
}).forEach((videoTransceiver) => {
|
|
707
|
+
videoTransceiver.direction = enable ? "sendonly" : "sendrecv";
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
const MEDIA_JITTER_BUFFER_TARGET = 400;
|
|
713
|
+
|
|
714
|
+
var _a$4;
|
|
715
|
+
const adapter$4 = (_a$4 = adapterRaw.default) !== null && _a$4 !== void 0 ? _a$4 : adapterRaw;
|
|
716
|
+
function detectMicrophoneNotWorking(pc) {
|
|
717
|
+
var _a, _b;
|
|
718
|
+
if (((_a = adapter$4.browserDetails) === null || _a === void 0 ? void 0 : _a.browser) !== "chrome" ||
|
|
719
|
+
((_b = adapter$4.browserDetails) === null || _b === void 0 ? void 0 : _b.browser) < 58 ||
|
|
720
|
+
pc.signalingState === "closed") {
|
|
721
|
+
return Promise.resolve("");
|
|
722
|
+
}
|
|
723
|
+
const sendingAudio = pc.getSenders().some((sender) => { var _a; return ((_a = sender.track) === null || _a === void 0 ? void 0 : _a.kind) === "audio"; });
|
|
724
|
+
const receivingAudio = pc.getReceivers().some((receiver) => { var _a; return ((_a = receiver.track) === null || _a === void 0 ? void 0 : _a.kind) === "audio"; });
|
|
725
|
+
return pc.getStats(null).then((result) => {
|
|
726
|
+
let microphoneFailed = "";
|
|
727
|
+
result.forEach((report) => {
|
|
728
|
+
if (report.type === "outbound-rtp" &&
|
|
729
|
+
(report.kind === "audio" || report.mediaType === "audio") &&
|
|
730
|
+
sendingAudio) {
|
|
731
|
+
if (report.bytesSent === 0) {
|
|
732
|
+
microphoneFailed = "outbound";
|
|
680
733
|
}
|
|
681
734
|
}
|
|
682
|
-
else if (
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
setTimeout(() => {
|
|
688
|
-
if (ws.readyState === WebSocket.CLOSED && connectionShouldBeOpen) {
|
|
689
|
-
connection.connect();
|
|
690
|
-
}
|
|
691
|
-
}, 1000 * connectionAttempt);
|
|
692
|
-
}
|
|
693
|
-
},
|
|
694
|
-
close: () => {
|
|
695
|
-
connectionShouldBeOpen = false;
|
|
696
|
-
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
697
|
-
},
|
|
698
|
-
connect: () => {
|
|
699
|
-
connectionShouldBeOpen = true;
|
|
700
|
-
connectionAttempt += 1;
|
|
701
|
-
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
702
|
-
connection.connected = true;
|
|
703
|
-
connection.attemptedConnectedAtLeastOnce = true;
|
|
704
|
-
ws = new WebSocket(wsURL + window.location.pathname, RTCSTATS_PROTOCOL_VERSION);
|
|
705
|
-
ws.onerror = (e) => {
|
|
706
|
-
connection.connected = false;
|
|
707
|
-
logger.warn(`[RTCSTATS] WebSocket error`, e);
|
|
708
|
-
};
|
|
709
|
-
ws.onclose = (e) => {
|
|
710
|
-
connection.connected = false;
|
|
711
|
-
logger.info(`[RTCSTATS] Closed ${e.code}`);
|
|
712
|
-
resetDelta();
|
|
713
|
-
};
|
|
714
|
-
ws.onopen = () => {
|
|
715
|
-
clientInfo.connectionNumber++;
|
|
716
|
-
ws.send(JSON.stringify(["clientInfo", null, clientInfo]));
|
|
717
|
-
if (organizationId) {
|
|
718
|
-
ws.send(JSON.stringify(organizationId));
|
|
719
|
-
}
|
|
720
|
-
if (clientId) {
|
|
721
|
-
ws.send(JSON.stringify(clientId));
|
|
722
|
-
}
|
|
723
|
-
if (roomSessionId) {
|
|
724
|
-
ws.send(JSON.stringify(roomSessionId));
|
|
725
|
-
}
|
|
726
|
-
if (displayName) {
|
|
727
|
-
ws.send(JSON.stringify(displayName));
|
|
728
|
-
}
|
|
729
|
-
if (userRole) {
|
|
730
|
-
ws.send(JSON.stringify(userRole));
|
|
731
|
-
}
|
|
732
|
-
if (deviceId) {
|
|
733
|
-
ws.send(JSON.stringify(deviceId));
|
|
734
|
-
}
|
|
735
|
-
if (roomMode) {
|
|
736
|
-
ws.send(JSON.stringify(roomMode));
|
|
735
|
+
else if (report.type === "inbound-rtp" &&
|
|
736
|
+
(report.kind === "audio" || report.mediaType === "audio") &&
|
|
737
|
+
receivingAudio) {
|
|
738
|
+
if (report.bytesReceived === 0) {
|
|
739
|
+
microphoneFailed = "inbound";
|
|
737
740
|
}
|
|
738
|
-
|
|
739
|
-
ws.send(JSON.stringify(roomProduct));
|
|
740
|
-
}
|
|
741
|
-
if (sfuServer) {
|
|
742
|
-
ws.send(JSON.stringify(sfuServer));
|
|
743
|
-
}
|
|
744
|
-
if (featureFlags) {
|
|
745
|
-
ws.send(JSON.stringify(featureFlags));
|
|
746
|
-
}
|
|
747
|
-
while (buffer.length) {
|
|
748
|
-
ws.send(JSON.stringify(buffer.shift()));
|
|
749
|
-
}
|
|
750
|
-
getStatsBufferUsed = 0;
|
|
751
|
-
};
|
|
752
|
-
},
|
|
753
|
-
};
|
|
754
|
-
return connection;
|
|
755
|
-
}
|
|
756
|
-
const RTCSTATS_URL = "wss://rtcstats.srv.whereby.com";
|
|
757
|
-
const server = rtcStatsConnection(RTCSTATS_URL);
|
|
758
|
-
const stats = rtcstats(server.trace, 10000, [""]);
|
|
759
|
-
resetDelta = (stats === null || stats === void 0 ? void 0 : stats.resetDelta) || noop;
|
|
760
|
-
const rtcStats = {
|
|
761
|
-
sendEvent: (type, value) => {
|
|
762
|
-
server.trace("customEvent", null, {
|
|
763
|
-
type,
|
|
764
|
-
value,
|
|
741
|
+
}
|
|
765
742
|
});
|
|
743
|
+
return microphoneFailed;
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
const PROTOCOL_REQUESTS = {
|
|
748
|
+
BLOCK_CLIENT: "block_client",
|
|
749
|
+
CANCEL_ROOM_KNOCK: "cancel_room_knock",
|
|
750
|
+
CLAIM_ROOM: "claim_room",
|
|
751
|
+
CLEAR_CHAT_HISTORY: "clear_chat_history",
|
|
752
|
+
ENABLE_AUDIO: "enable_audio",
|
|
753
|
+
ENABLE_VIDEO: "enable_video",
|
|
754
|
+
END_STREAM: "end_stream",
|
|
755
|
+
FETCH_MEDIASERVER_CONFIG: "fetch_mediaserver_config",
|
|
756
|
+
HANDLE_KNOCK: "handle_knock",
|
|
757
|
+
IDENTIFY_DEVICE: "identify_device",
|
|
758
|
+
INVITE_CLIENT_AS_MEMBER: "invite_client_as_member",
|
|
759
|
+
JOIN_ROOM: "join_room",
|
|
760
|
+
KICK_CLIENT: "kick_client",
|
|
761
|
+
KNOCK_ROOM: "knock_room",
|
|
762
|
+
LEAVE_ROOM: "leave_room",
|
|
763
|
+
SEND_CLIENT_METADATA: "send_client_metadata",
|
|
764
|
+
SET_LOCK: "set_lock",
|
|
765
|
+
SHARE_MEDIA: "share_media",
|
|
766
|
+
START_NEW_STREAM: "start_new_stream",
|
|
767
|
+
START_SCREENSHARE: "start_screenshare",
|
|
768
|
+
STOP_SCREENSHARE: "stop_screenshare",
|
|
769
|
+
START_URL_EMBED: "start_url_embed",
|
|
770
|
+
STOP_URL_EMBED: "stop_url_embed",
|
|
771
|
+
START_RECORDING: "start_recording",
|
|
772
|
+
STOP_RECORDING: "stop_recording",
|
|
773
|
+
};
|
|
774
|
+
const PROTOCOL_RESPONSES = {
|
|
775
|
+
AUDIO_ENABLED: "audio_enabled",
|
|
776
|
+
BACKGROUND_IMAGE_CHANGED: "background_image_changed",
|
|
777
|
+
BLOCK_ADDED: "block_added",
|
|
778
|
+
BLOCK_REMOVED: "block_removed",
|
|
779
|
+
CHAT_HISTORY_CLEARED: "chat_history_cleared",
|
|
780
|
+
CLIENT_BLOCKED: "client_blocked",
|
|
781
|
+
CLIENT_INVITED_AS_MEMBER: "client_invited_as_member",
|
|
782
|
+
CLIENT_KICKED: "client_kicked",
|
|
783
|
+
CLIENT_LEFT: "client_left",
|
|
784
|
+
CLIENT_METADATA_RECEIVED: "client_metadata_received",
|
|
785
|
+
CLIENT_READY: "client_ready",
|
|
786
|
+
CLIENT_ROLE_CHANGED: "client_role_changed",
|
|
787
|
+
CLIENT_USER_ID_CHANGED: "client_user_id_changed",
|
|
788
|
+
CONTACTS_UPDATED: "contacts_updated",
|
|
789
|
+
DEVICE_IDENTIFIED: "device_identified",
|
|
790
|
+
ROOM_ROLES_UPDATED: "room_roles_updated",
|
|
791
|
+
KNOCK_HANDLED: "knock_handled",
|
|
792
|
+
KNOCK_PAGE_BACKGROUND_CHANGED: "knock_page_background_changed",
|
|
793
|
+
KNOCKER_LEFT: "knocker_left",
|
|
794
|
+
MEDIASERVER_CONFIG: "mediaserver_config",
|
|
795
|
+
MEDIA_SHARED: "media_shared",
|
|
796
|
+
MEMBER_INVITE: "member_invite",
|
|
797
|
+
NEW_CLIENT: "new_client",
|
|
798
|
+
NEW_STREAM_STARTED: "new_stream_started",
|
|
799
|
+
SCREENSHARE_STARTED: "screenshare_started",
|
|
800
|
+
SCREENSHARE_STOPPED: "screenshare_stopped",
|
|
801
|
+
OWNER_NOTIFIED: "owner_notified",
|
|
802
|
+
OWNERS_CHANGED: "owners_changed",
|
|
803
|
+
PLAY_CLIENT_STICKER: "play_client_sticker",
|
|
804
|
+
ROOM_INTEGRATION_ENABLED: "room_integration_enabled",
|
|
805
|
+
ROOM_INTEGRATION_DISABLED: "room_integration_disabled",
|
|
806
|
+
ROOM_JOINED: "room_joined",
|
|
807
|
+
ROOM_KNOCKED: "room_knocked",
|
|
808
|
+
ROOM_LEFT: "room_left",
|
|
809
|
+
ROOM_LOCKED: "room_locked",
|
|
810
|
+
ROOM_PERMISSIONS_CHANGED: "room_permissions_changed",
|
|
811
|
+
ROOM_LOGO_CHANGED: "room_logo_changed",
|
|
812
|
+
ROOM_TYPE_CHANGED: "room_type_changed",
|
|
813
|
+
ROOM_MODE_CHANGED: "room_mode_changed",
|
|
814
|
+
SOCKET_USER_ID_CHANGED: "socket_user_id_changed",
|
|
815
|
+
STICKERS_UNLOCKED: "stickers_unlocked",
|
|
816
|
+
STREAM_ENDED: "stream_ended",
|
|
817
|
+
URL_EMBED_STARTED: "url_embed_started",
|
|
818
|
+
URL_EMBED_STOPPED: "url_embed_stopped",
|
|
819
|
+
RECORDING_STARTED: "recording_started",
|
|
820
|
+
RECORDING_STOPPED: "recording_stopped",
|
|
821
|
+
USER_NOTIFIED: "user_notified",
|
|
822
|
+
VIDEO_ENABLED: "video_enabled",
|
|
823
|
+
CLIENT_UNABLE_TO_JOIN: "client_unable_to_join",
|
|
824
|
+
LIVE_TRANSCRIPTION_STARTED: "live_transcription_started",
|
|
825
|
+
LIVE_TRANSCRIPTION_STOPPED: "live_transcription_stopped",
|
|
826
|
+
LIVE_CAPTIONS_STARTED: "live_captions_started",
|
|
827
|
+
LIVE_CAPTIONS_STOPPED: "live_captions_stopped",
|
|
828
|
+
};
|
|
829
|
+
const PROTOCOL_ERRORS = {
|
|
830
|
+
CANNOT_INVITE_YOURSELF: "cannot_invite_yourself",
|
|
831
|
+
CLIENT_BLOCKED: "client_blocked",
|
|
832
|
+
CLIENT_MISSING_DEVICE_ID: "client_missing_device_id",
|
|
833
|
+
FORBIDDEN: "forbidden",
|
|
834
|
+
FREE_TIER_EXHAUSTED: "free_tier_exhausted",
|
|
835
|
+
INTERNAL_SERVER_ERROR: "internal_server_error",
|
|
836
|
+
INVALID_AVATAR: "invalid_avatar",
|
|
837
|
+
INVALID_PARAMETERS: "invalid_parameters",
|
|
838
|
+
INVALID_ROOM_NAME: "invalid_room_name",
|
|
839
|
+
MAX_VIEWER_LIMIT_REACHED: "max_viewer_limit_reached",
|
|
840
|
+
MISSING_PARAMETERS: "missing_parameters",
|
|
841
|
+
MISSING_ROOM_NAME: "missing_room_name",
|
|
842
|
+
NOT_AN_OWNER: "not_an_owner",
|
|
843
|
+
NOT_IN_A_ROOM: "not_in_a_room",
|
|
844
|
+
ROOM_ALREADY_CLAIMED: "room_already_claimed",
|
|
845
|
+
ROOM_CONCURRENCY_CONTROL_ERROR: "room_concurrency_control_error",
|
|
846
|
+
ROOM_EMAIL_MISSING: "room_email_missing",
|
|
847
|
+
ROOM_EMPTY: "room_empty",
|
|
848
|
+
ROOM_FULL: "room_full",
|
|
849
|
+
ROOM_JOIN_PERMISSION_DENIED: "room_join_permission_denied",
|
|
850
|
+
ROOM_LOCKED: "room_locked",
|
|
851
|
+
ROOM_MEETING_TIME_EXHAUSTED: "room_meeting_time_exhausted",
|
|
852
|
+
ROOM_UNCLAIMED: "room_unclaimed",
|
|
853
|
+
TOO_LONG_TEXT: "too_long_text",
|
|
854
|
+
UNIQUE_ROLE_ALREADY_IN_ROOM: "unique_role_already_in_room",
|
|
855
|
+
UNSUPPORTED_VIDEO_ENCODING: "unsupported_video_encoding",
|
|
856
|
+
VIDEO_STICKER_DOES_NOT_EXIST: "video_sticker_does_not_exist",
|
|
857
|
+
VIDEO_STICKER_FORMAT_ERROR: "video_sticker_format_error",
|
|
858
|
+
};
|
|
859
|
+
const RELAY_MESSAGES = {
|
|
860
|
+
CHAT_MESSAGE: "chat_message",
|
|
861
|
+
CHAT_READ_STATE: "chat_read_state",
|
|
862
|
+
CHAT_STATE: "chat_state",
|
|
863
|
+
ICE_CANDIDATE: "ice_candidate",
|
|
864
|
+
ICE_END_OF_CANDIDATES: "ice_endofcandidates",
|
|
865
|
+
READY_TO_RECEIVE_OFFER: "ready_to_receive_offer",
|
|
866
|
+
REMOTE_CLIENT_MEDIA_REQUEST: "remote_client_media_request",
|
|
867
|
+
SDP_ANSWER: "sdp_answer",
|
|
868
|
+
SDP_OFFER: "sdp_offer",
|
|
869
|
+
VIDEO_STICKER: "video_sticker",
|
|
870
|
+
};
|
|
871
|
+
const KNOCK_MESSAGES = {
|
|
872
|
+
actions: {
|
|
873
|
+
ACCEPT: "accept",
|
|
874
|
+
HOLD: "hold",
|
|
875
|
+
REJECT: "reject",
|
|
766
876
|
},
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
rtcStats.sendEvent("video_muted", { muted });
|
|
877
|
+
resolutions: {
|
|
878
|
+
ACCEPTED: "accepted",
|
|
879
|
+
ON_HOLD: "on_hold",
|
|
880
|
+
REJECTED: "rejected",
|
|
772
881
|
},
|
|
773
|
-
|
|
882
|
+
};
|
|
883
|
+
const PROTOCOL_EVENTS = {
|
|
884
|
+
PENDING_CLIENT_LEFT: "pending_client_left",
|
|
885
|
+
MEDIA_QUALITY_CHANGED: "media_quality_changed",
|
|
774
886
|
};
|
|
775
887
|
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
888
|
+
const EVENTS = {
|
|
889
|
+
CLIENT_CONNECTION_STATUS_CHANGED: "client_connection_status_changed",
|
|
890
|
+
STREAM_ADDED: "stream_added",
|
|
891
|
+
RTC_MANAGER_CREATED: "rtc_manager_created",
|
|
892
|
+
RTC_MANAGER_DESTROYED: "rtc_manager_destroyed",
|
|
893
|
+
LOCAL_STREAM_TRACK_ADDED: "local_stream_track_added",
|
|
894
|
+
LOCAL_STREAM_TRACK_REMOVED: "local_stream_track_removed",
|
|
895
|
+
REMOTE_STREAM_TRACK_ADDED: "remote_stream_track_added",
|
|
896
|
+
REMOTE_STREAM_TRACK_REMOVED: "remote_stream_track_removed",
|
|
897
|
+
};
|
|
898
|
+
const TYPES = {
|
|
899
|
+
CONNECTING: "connecting",
|
|
900
|
+
CONNECTION_FAILED: "connection_failed",
|
|
901
|
+
CONNECTION_SUCCESSFUL: "connection_successful",
|
|
902
|
+
CONNECTION_DISCONNECTED: "connection_disconnected",
|
|
781
903
|
};
|
|
782
|
-
if (window.RTCPeerConnection) {
|
|
783
|
-
const OriginalRTCPeerConnection = window.RTCPeerConnection;
|
|
784
|
-
function PatchedRTCPeerConnection(rtcConfig) {
|
|
785
|
-
const pc = new OriginalRTCPeerConnection(rtcConfig);
|
|
786
|
-
peerConnections.push(pc);
|
|
787
|
-
peerConnectionData.set(pc, { index: peerConnectionCounter++ });
|
|
788
|
-
const onConnectionStateChange = () => {
|
|
789
|
-
if (pc.connectionState === "closed") {
|
|
790
|
-
removePeerConnection(pc);
|
|
791
|
-
pc.removeEventListener("connectionstatechange", onConnectionStateChange);
|
|
792
|
-
}
|
|
793
|
-
};
|
|
794
|
-
pc.addEventListener("connectionstatechange", onConnectionStateChange);
|
|
795
|
-
return pc;
|
|
796
|
-
}
|
|
797
|
-
PatchedRTCPeerConnection.prototype = OriginalRTCPeerConnection.prototype;
|
|
798
|
-
window.RTCPeerConnection = PatchedRTCPeerConnection;
|
|
799
|
-
}
|
|
800
|
-
const getCurrentPeerConnections = () => peerConnections;
|
|
801
|
-
const getPeerConnectionIndex = (pc) => { var _a; return (_a = peerConnectionData.get(pc)) === null || _a === void 0 ? void 0 : _a.index; };
|
|
802
|
-
const setPeerConnectionsForTests = (pcs) => (peerConnections = pcs);
|
|
803
904
|
|
|
804
|
-
const
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
const
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
const sendersAndReceivers = [...pc.getSenders(), ...pc.getReceivers()];
|
|
845
|
-
const reports = yield Promise.all(sendersAndReceivers.map((o) => o.getStats()));
|
|
846
|
-
reports.forEach((tReport, index) => {
|
|
847
|
-
tReport.forEach((stats) => {
|
|
848
|
-
if (stats.type === "inbound-rtp" || stats.type === "outbound-rtp") {
|
|
849
|
-
pcData.ssrcToTrackId[stats.ssrc] = sendersAndReceivers[index].track.id;
|
|
850
|
-
}
|
|
851
|
-
});
|
|
852
|
-
});
|
|
853
|
-
missingSsrcs.forEach((ssrc) => {
|
|
854
|
-
numMissingTrackSsrcLookups++;
|
|
855
|
-
if (!pcData.ssrcToTrackId[ssrc]) {
|
|
856
|
-
pcData.ssrcToTrackId[ssrc] = "?" + ssrc;
|
|
857
|
-
}
|
|
858
|
-
});
|
|
859
|
-
}
|
|
860
|
-
return [pc, report, pcData];
|
|
861
|
-
}
|
|
862
|
-
catch (e) {
|
|
863
|
-
rtcStats.sendEvent("trackSsrcLookupFailed", {
|
|
864
|
-
name: e === null || e === void 0 ? void 0 : e.name,
|
|
865
|
-
cause: e === null || e === void 0 ? void 0 : e.cause,
|
|
866
|
-
message: e === null || e === void 0 ? void 0 : e.message,
|
|
867
|
-
});
|
|
868
|
-
numFailedTrackSsrcLookups++;
|
|
869
|
-
return [pc, [], pcData];
|
|
870
|
-
}
|
|
871
|
-
})));
|
|
872
|
-
|
|
873
|
-
const getOrCreateSsrcMetricsContainer = (statsByView, time, pcIndex, clientId, trackId, ssrc) => {
|
|
874
|
-
let viewStats = statsByView[clientId];
|
|
875
|
-
if (!viewStats) {
|
|
876
|
-
viewStats = { candidatePairs: {}, tracks: {}, startTime: time, updated: time };
|
|
877
|
-
statsByView[clientId] = viewStats;
|
|
878
|
-
}
|
|
879
|
-
viewStats.updated = time;
|
|
880
|
-
let trackStats = viewStats.tracks[trackId];
|
|
881
|
-
if (!trackStats) {
|
|
882
|
-
trackStats = { ssrcs: {}, startTime: time, updated: time };
|
|
883
|
-
viewStats.tracks[trackId] = trackStats;
|
|
884
|
-
}
|
|
885
|
-
trackStats.updated = time;
|
|
886
|
-
let ssrcStats = trackStats.ssrcs[ssrc];
|
|
887
|
-
if (!ssrcStats) {
|
|
888
|
-
ssrcStats = {
|
|
889
|
-
startTime: time,
|
|
890
|
-
updated: time,
|
|
891
|
-
pcIndex,
|
|
892
|
-
};
|
|
893
|
-
trackStats.ssrcs[ssrc] = ssrcStats;
|
|
894
|
-
}
|
|
895
|
-
ssrcStats.updated = time;
|
|
896
|
-
return ssrcStats;
|
|
897
|
-
};
|
|
898
|
-
const removeNonUpdatedStats = (statsByView, time) => {
|
|
899
|
-
Object.entries(statsByView).forEach(([viewId, viewStats]) => {
|
|
900
|
-
if (viewStats.updated !== undefined && viewStats.updated < time) {
|
|
901
|
-
delete statsByView[viewId];
|
|
902
|
-
}
|
|
903
|
-
else {
|
|
904
|
-
Object.entries(viewStats.tracks).forEach(([trackId, trackStats]) => {
|
|
905
|
-
if (trackStats.updated < time) {
|
|
906
|
-
delete viewStats.tracks[trackId];
|
|
907
|
-
}
|
|
908
|
-
else {
|
|
909
|
-
Object.entries(trackStats.ssrcs).forEach(([ssrc, ssrcStats]) => {
|
|
910
|
-
if (ssrcStats.updated < time) {
|
|
911
|
-
delete trackStats.ssrcs[ssrc];
|
|
912
|
-
}
|
|
913
|
-
});
|
|
914
|
-
}
|
|
915
|
-
});
|
|
916
|
-
}
|
|
917
|
-
});
|
|
918
|
-
};
|
|
919
|
-
const DEFAULT_CLIENT = {
|
|
920
|
-
id: "unknown",
|
|
921
|
-
clientId: "unknown",
|
|
922
|
-
audio: { enabled: false, track: undefined },
|
|
923
|
-
video: { enabled: false, track: undefined },
|
|
924
|
-
isAudioOnlyModeEnabled: false,
|
|
925
|
-
isLocalClient: true,
|
|
926
|
-
isPresentation: false,
|
|
927
|
-
};
|
|
928
|
-
function collectStats(state_1, _a, immediate_1) {
|
|
929
|
-
return __awaiter(this, arguments, void 0, function* (state, { logger, interval }, immediate) {
|
|
930
|
-
const collectStatsBound = collectStats.bind(null, state, { interval, logger });
|
|
931
|
-
try {
|
|
932
|
-
const clients = state.getClients();
|
|
933
|
-
const defaultClient = clients.find((c) => c.isLocalClient && !c.isPresentation) || DEFAULT_CLIENT;
|
|
934
|
-
let defaultViewStats = state.statsByView[defaultClient.id];
|
|
935
|
-
if (!defaultViewStats) {
|
|
936
|
-
defaultViewStats = { tracks: {}, candidatePairs: {}, pressure: null };
|
|
937
|
-
state.statsByView[defaultClient.id] = defaultViewStats;
|
|
938
|
-
}
|
|
939
|
-
defaultViewStats.pressure = state.lastPressureObserverRecord;
|
|
940
|
-
const timeSinceLastUpdate = Date.now() - state.lastUpdateTime;
|
|
941
|
-
if (timeSinceLastUpdate < 400) {
|
|
942
|
-
if (immediate)
|
|
943
|
-
return state.statsByView;
|
|
944
|
-
state.subscriptions.forEach((subscription) => { var _a; return (_a = subscription.onUpdatedStats) === null || _a === void 0 ? void 0 : _a.call(subscription, state.statsByView, clients); });
|
|
945
|
-
state.nextTimeout = setTimeout(collectStatsBound, interval);
|
|
946
|
-
return;
|
|
947
|
-
}
|
|
948
|
-
state.lastUpdateTime = Date.now();
|
|
949
|
-
(yield getPeerConnectionsWithStatsReports()).forEach(([pc, report, pcData]) => {
|
|
950
|
-
const pcIndex = getPeerConnectionIndex(pc);
|
|
951
|
-
if (pcIndex === undefined) {
|
|
952
|
-
logger.warn("Could not find index for PeerConnection");
|
|
953
|
-
}
|
|
954
|
-
if (pc.connectionState === "closed") {
|
|
955
|
-
report = new Map();
|
|
956
|
-
removePeerConnection(pc);
|
|
957
|
-
}
|
|
958
|
-
pcData.previousSSRCs = pcData.currentSSRCs || {};
|
|
959
|
-
pcData.currentSSRCs = {};
|
|
960
|
-
report.forEach((currentRtcStats) => {
|
|
961
|
-
var _a, _b;
|
|
962
|
-
if (currentRtcStats.type === "candidate-pair" && /inprogress|succeeded/.test(currentRtcStats.state)) {
|
|
963
|
-
const prevRtcStats = (_a = pcData._oldReport) === null || _a === void 0 ? void 0 : _a.get(currentRtcStats.id);
|
|
964
|
-
const timeDiff = prevRtcStats ? currentRtcStats.timestamp - prevRtcStats.timestamp : interval;
|
|
965
|
-
const cpId = pcIndex + ":" + currentRtcStats.id;
|
|
966
|
-
let cpMetrics = defaultViewStats.candidatePairs[cpId];
|
|
967
|
-
if (!cpMetrics) {
|
|
968
|
-
cpMetrics = { startTime: state.lastUpdateTime, id: cpId };
|
|
969
|
-
defaultViewStats.candidatePairs[cpId] = cpMetrics;
|
|
970
|
-
}
|
|
971
|
-
captureCandidatePairInfoMetrics(cpMetrics, currentRtcStats, prevRtcStats, timeDiff, report);
|
|
972
|
-
cpMetrics.lastRtcStatsTime = state.lastUpdateTime;
|
|
973
|
-
}
|
|
974
|
-
if (currentRtcStats.type === "inbound-rtp" || currentRtcStats.type === "outbound-rtp") {
|
|
975
|
-
const kind = (currentRtcStats.mediaType || currentRtcStats.kind);
|
|
976
|
-
const ssrc = currentRtcStats.ssrc;
|
|
977
|
-
let trackId = currentRtcStats.trackIdentifier || pcData.ssrcToTrackId[ssrc];
|
|
978
|
-
let prevRtcStats = (_b = pcData._oldReport) === null || _b === void 0 ? void 0 : _b.get(currentRtcStats.id);
|
|
979
|
-
if (prevRtcStats && prevRtcStats.mediaSourceId !== currentRtcStats.mediaSourceId) {
|
|
980
|
-
const mediaSourceStats = report.get(currentRtcStats.mediaSourceId);
|
|
981
|
-
if (mediaSourceStats && mediaSourceStats.trackIdentifier) {
|
|
982
|
-
trackId = mediaSourceStats.trackIdentifier;
|
|
983
|
-
pcData.ssrcToTrackId[ssrc] = trackId;
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
const client = clients.find((c) => { var _a; return ((_a = c[kind].track) === null || _a === void 0 ? void 0 : _a.id) === trackId; }) || defaultClient;
|
|
987
|
-
const clientTrack = client[kind].track;
|
|
988
|
-
if (!currentRtcStats.trackIdentifier &&
|
|
989
|
-
pcData.ssrcToTrackId[ssrc] &&
|
|
990
|
-
(clientTrack === null || clientTrack === void 0 ? void 0 : clientTrack.id) &&
|
|
991
|
-
clientTrack.id !== pcData.ssrcToTrackId[ssrc]) {
|
|
992
|
-
trackId = clientTrack.id;
|
|
993
|
-
pcData.ssrcToTrackId[ssrc] = clientTrack.id;
|
|
994
|
-
}
|
|
995
|
-
pcData.currentSSRCs[ssrc] = client.id;
|
|
996
|
-
if (prevRtcStats) {
|
|
997
|
-
const newTransport = report.get(currentRtcStats.transportId);
|
|
998
|
-
const oldTransport = pcData._oldReport.get(prevRtcStats.transportId);
|
|
999
|
-
if (oldTransport &&
|
|
1000
|
-
(newTransport === null || newTransport === void 0 ? void 0 : newTransport.selectedCandidatePairId) !== oldTransport.selectedCandidatePairId) {
|
|
1001
|
-
prevRtcStats = null;
|
|
1002
|
-
}
|
|
1003
|
-
else if (currentRtcStats.bytesReceived < prevRtcStats.bytesReceived ||
|
|
1004
|
-
currentRtcStats.bytesSent < prevRtcStats.bytesSent) {
|
|
1005
|
-
prevRtcStats = null;
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
const timeDiff = prevRtcStats ? currentRtcStats.timestamp - prevRtcStats.timestamp : interval;
|
|
1009
|
-
const ssrcMetrics = getOrCreateSsrcMetricsContainer(state.statsByView, state.lastUpdateTime, pcIndex, client.id, trackId, ssrc);
|
|
1010
|
-
captureSsrcInfo(ssrcMetrics, currentRtcStats, prevRtcStats, timeDiff, report);
|
|
1011
|
-
captureCommonSsrcMetrics(ssrcMetrics, currentRtcStats, prevRtcStats, timeDiff, report);
|
|
1012
|
-
if (kind === "video") {
|
|
1013
|
-
captureVideoSsrcMetrics(ssrcMetrics, currentRtcStats, prevRtcStats, timeDiff, report);
|
|
1014
|
-
}
|
|
1015
|
-
if (kind === "audio") {
|
|
1016
|
-
captureAudioSsrcMetrics(ssrcMetrics, currentRtcStats, prevRtcStats, timeDiff, report);
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
});
|
|
1020
|
-
pcData._oldReport = report;
|
|
1021
|
-
Object.keys(pcData.previousSSRCs)
|
|
1022
|
-
.filter((ssrc) => !pcData.currentSSRCs[ssrc])
|
|
1023
|
-
.forEach((ssrc) => {
|
|
1024
|
-
const clientId = pcData.previousSSRCs[ssrc];
|
|
1025
|
-
if (clientId) {
|
|
1026
|
-
const clientView = state.statsByView[clientId];
|
|
1027
|
-
if (clientView) {
|
|
1028
|
-
Object.values(clientView.tracks).forEach((trackStats) => {
|
|
1029
|
-
if (trackStats.ssrcs[ssrc]) {
|
|
1030
|
-
delete trackStats.ssrcs[ssrc];
|
|
1031
|
-
}
|
|
1032
|
-
});
|
|
1033
|
-
}
|
|
1034
|
-
}
|
|
1035
|
-
});
|
|
1036
|
-
});
|
|
1037
|
-
removeNonUpdatedStats(state.statsByView, state.lastUpdateTime);
|
|
1038
|
-
Object.entries((defaultViewStats === null || defaultViewStats === void 0 ? void 0 : defaultViewStats.candidatePairs) || {}).forEach(([cpKey, cp]) => {
|
|
1039
|
-
const active = cp.lastRtcStatsTime === state.lastUpdateTime;
|
|
1040
|
-
cp.active = active;
|
|
1041
|
-
if (!active) {
|
|
1042
|
-
cp.state = "old/inactive";
|
|
1043
|
-
if (!cp.inactiveFromTime)
|
|
1044
|
-
cp.inactiveFromTime = state.lastUpdateTime;
|
|
1045
|
-
else {
|
|
1046
|
-
if (state.lastUpdateTime - cp.inactiveFromTime > 4000) {
|
|
1047
|
-
delete defaultViewStats.candidatePairs[cpKey];
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
});
|
|
1052
|
-
if (immediate) {
|
|
1053
|
-
return state.statsByView;
|
|
1054
|
-
}
|
|
1055
|
-
else {
|
|
1056
|
-
state.subscriptions.forEach((subscription) => { var _a; return (_a = subscription.onUpdatedStats) === null || _a === void 0 ? void 0 : _a.call(subscription, state.statsByView, clients); });
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
catch (e) {
|
|
1060
|
-
logger.warn(e);
|
|
1061
|
-
state.numFailedStatsReports++;
|
|
1062
|
-
rtcStats.sendEvent("collectStatsFailed", {
|
|
1063
|
-
name: e === null || e === void 0 ? void 0 : e.name,
|
|
1064
|
-
cause: e === null || e === void 0 ? void 0 : e.cause,
|
|
1065
|
-
message: e === null || e === void 0 ? void 0 : e.message,
|
|
1066
|
-
});
|
|
1067
|
-
}
|
|
1068
|
-
state.nextTimeout = setTimeout(collectStatsBound, interval);
|
|
1069
|
-
});
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
const REGISTERED_TRIALS = {};
|
|
1073
|
-
function registerOriginTrials(trials, registeredTrials = REGISTERED_TRIALS, document = window.document) {
|
|
1074
|
-
trials.forEach(({ hostnamePattern, token }) => {
|
|
1075
|
-
const key = `${hostnamePattern}-${token}`;
|
|
1076
|
-
if (registeredTrials[key]) {
|
|
1077
|
-
return;
|
|
1078
|
-
}
|
|
1079
|
-
if (hostnamePattern.test(document.location.hostname)) {
|
|
1080
|
-
const otMeta = document.createElement("meta");
|
|
1081
|
-
otMeta.httpEquiv = "origin-trial";
|
|
1082
|
-
otMeta.content = token;
|
|
1083
|
-
document.head.append(otMeta);
|
|
1084
|
-
registeredTrials[key] = true;
|
|
1085
|
-
}
|
|
1086
|
-
});
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
const CPU_OBSERVER_OPTIONS = {
|
|
1090
|
-
sampleRate: 1,
|
|
1091
|
-
originTrials: [
|
|
1092
|
-
{
|
|
1093
|
-
hostnamePattern: /hereby\.dev/,
|
|
1094
|
-
token: "AkSNPHJw6EK08X0QU7kORnK9NABzRLAC7dqfXOwk5JwFAQG4Ey7WxLXxsnhieCgC1QHUdevE2EFICy7uBGDANwUAAABqeyJvcmlnaW4iOiJodHRwczovL2hlcmVieS5kZXY6NDQ0MyIsImZlYXR1cmUiOiJDb21wdXRlUHJlc3N1cmVfdjIiLCJleHBpcnkiOjE3MTY5NDA3OTksImlzU3ViZG9tYWluIjp0cnVlfQ==",
|
|
1095
|
-
},
|
|
1096
|
-
{
|
|
1097
|
-
hostnamePattern: /whereby\.com/,
|
|
1098
|
-
token: "Asc2wu8KpSx648i932NICteQDFcB05yl2QUUSHD7AQo8JGP2Fp6FF91TvYVJBsKGzLMH349rysPw5q9tqPC/PAUAAABqeyJvcmlnaW4iOiJodHRwczovL3doZXJlYnkuY29tOjQ0MyIsImZlYXR1cmUiOiJDb21wdXRlUHJlc3N1cmVfdjIiLCJleHBpcnkiOjE3MTY5NDA3OTksImlzU3ViZG9tYWluIjp0cnVlfQ==",
|
|
1099
|
-
},
|
|
1100
|
-
],
|
|
1101
|
-
};
|
|
1102
|
-
function startCpuObserver(cb, { sampleRate, originTrials } = CPU_OBSERVER_OPTIONS, window = globalThis.window) {
|
|
1103
|
-
registerOriginTrials(originTrials);
|
|
1104
|
-
let pressureObserver;
|
|
1105
|
-
if ("PressureObserver" in window) {
|
|
1106
|
-
pressureObserver = new window.PressureObserver(cb, { sampleRate });
|
|
1107
|
-
pressureObserver.observe("cpu", { sampleInterval: sampleRate * 1000 });
|
|
1108
|
-
return {
|
|
1109
|
-
stop: () => {
|
|
1110
|
-
pressureObserver.unobserve("cpu");
|
|
1111
|
-
},
|
|
1112
|
-
};
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
const STATE = {
|
|
1117
|
-
currentMonitor: null,
|
|
1118
|
-
getClients: () => [],
|
|
1119
|
-
lastUpdateTime: 0,
|
|
1120
|
-
statsByView: {},
|
|
1121
|
-
subscriptions: [],
|
|
1122
|
-
numFailedStatsReports: 0,
|
|
1123
|
-
};
|
|
1124
|
-
const OPTIONS = {
|
|
1125
|
-
interval: 2000,
|
|
1126
|
-
logger: new Logger(),
|
|
1127
|
-
};
|
|
1128
|
-
const getStats = () => {
|
|
1129
|
-
return Object.assign({}, STATE.statsByView);
|
|
1130
|
-
};
|
|
1131
|
-
const getNumFailedStatsReports = () => {
|
|
1132
|
-
return STATE.numFailedStatsReports;
|
|
1133
|
-
};
|
|
1134
|
-
const getNumMissingTrackSsrcLookups = () => numMissingTrackSsrcLookups;
|
|
1135
|
-
const getNumFailedTrackSsrcLookups = () => numFailedTrackSsrcLookups;
|
|
1136
|
-
const getUpdatedStats = () => { var _a; return (_a = STATE.currentMonitor) === null || _a === void 0 ? void 0 : _a.getUpdatedStats(); };
|
|
1137
|
-
const setClientProvider = (provider) => (STATE.getClients = provider);
|
|
1138
|
-
function startStatsMonitor(state, { interval, logger }) {
|
|
1139
|
-
const collectStatsBound = collectStats.bind(null, state, { interval, logger });
|
|
1140
|
-
let cpuObserver;
|
|
1141
|
-
try {
|
|
1142
|
-
cpuObserver = startCpuObserver((records) => (state.lastPressureObserverRecord = records.pop()));
|
|
1143
|
-
}
|
|
1144
|
-
catch (ex) {
|
|
1145
|
-
logger.warn("Failed to observe CPU pressure", ex);
|
|
1146
|
-
}
|
|
1147
|
-
setTimeout(collectStatsBound, interval);
|
|
1148
|
-
return {
|
|
1149
|
-
getUpdatedStats: () => {
|
|
1150
|
-
return collectStatsBound(true);
|
|
1151
|
-
},
|
|
1152
|
-
stop: () => {
|
|
1153
|
-
clearTimeout(state.nextTimeout);
|
|
1154
|
-
cpuObserver === null || cpuObserver === void 0 ? void 0 : cpuObserver.stop();
|
|
1155
|
-
},
|
|
1156
|
-
};
|
|
1157
|
-
}
|
|
1158
|
-
function subscribeStats(subscription, options = OPTIONS, state = STATE) {
|
|
1159
|
-
state.subscriptions.push(subscription);
|
|
1160
|
-
if (!state.currentMonitor)
|
|
1161
|
-
state.currentMonitor = startStatsMonitor(state, options);
|
|
1162
|
-
return {
|
|
1163
|
-
stop() {
|
|
1164
|
-
var _a;
|
|
1165
|
-
state.subscriptions = state.subscriptions.filter((s) => s !== subscription);
|
|
1166
|
-
if (!state.subscriptions.length) {
|
|
1167
|
-
(_a = state.currentMonitor) === null || _a === void 0 ? void 0 : _a.stop();
|
|
1168
|
-
state.currentMonitor = null;
|
|
1169
|
-
}
|
|
1170
|
-
},
|
|
1171
|
-
};
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
|
-
const PROTOCOL_REQUESTS = {
|
|
1175
|
-
BLOCK_CLIENT: "block_client",
|
|
1176
|
-
CANCEL_ROOM_KNOCK: "cancel_room_knock",
|
|
1177
|
-
CLAIM_ROOM: "claim_room",
|
|
1178
|
-
CLEAR_CHAT_HISTORY: "clear_chat_history",
|
|
1179
|
-
ENABLE_AUDIO: "enable_audio",
|
|
1180
|
-
ENABLE_VIDEO: "enable_video",
|
|
1181
|
-
END_STREAM: "end_stream",
|
|
1182
|
-
FETCH_MEDIASERVER_CONFIG: "fetch_mediaserver_config",
|
|
1183
|
-
HANDLE_KNOCK: "handle_knock",
|
|
1184
|
-
IDENTIFY_DEVICE: "identify_device",
|
|
1185
|
-
INVITE_CLIENT_AS_MEMBER: "invite_client_as_member",
|
|
1186
|
-
JOIN_ROOM: "join_room",
|
|
1187
|
-
KICK_CLIENT: "kick_client",
|
|
1188
|
-
KNOCK_ROOM: "knock_room",
|
|
1189
|
-
LEAVE_ROOM: "leave_room",
|
|
1190
|
-
SEND_CLIENT_METADATA: "send_client_metadata",
|
|
1191
|
-
SET_LOCK: "set_lock",
|
|
1192
|
-
SHARE_MEDIA: "share_media",
|
|
1193
|
-
START_NEW_STREAM: "start_new_stream",
|
|
1194
|
-
START_SCREENSHARE: "start_screenshare",
|
|
1195
|
-
STOP_SCREENSHARE: "stop_screenshare",
|
|
1196
|
-
START_URL_EMBED: "start_url_embed",
|
|
1197
|
-
STOP_URL_EMBED: "stop_url_embed",
|
|
1198
|
-
START_RECORDING: "start_recording",
|
|
1199
|
-
STOP_RECORDING: "stop_recording",
|
|
1200
|
-
};
|
|
1201
|
-
const PROTOCOL_RESPONSES = {
|
|
1202
|
-
AUDIO_ENABLED: "audio_enabled",
|
|
1203
|
-
BACKGROUND_IMAGE_CHANGED: "background_image_changed",
|
|
1204
|
-
BLOCK_ADDED: "block_added",
|
|
1205
|
-
BLOCK_REMOVED: "block_removed",
|
|
1206
|
-
CHAT_HISTORY_CLEARED: "chat_history_cleared",
|
|
1207
|
-
CLIENT_BLOCKED: "client_blocked",
|
|
1208
|
-
CLIENT_INVITED_AS_MEMBER: "client_invited_as_member",
|
|
1209
|
-
CLIENT_KICKED: "client_kicked",
|
|
1210
|
-
CLIENT_LEFT: "client_left",
|
|
1211
|
-
CLIENT_METADATA_RECEIVED: "client_metadata_received",
|
|
1212
|
-
CLIENT_READY: "client_ready",
|
|
1213
|
-
CLIENT_ROLE_CHANGED: "client_role_changed",
|
|
1214
|
-
CLIENT_USER_ID_CHANGED: "client_user_id_changed",
|
|
1215
|
-
CONTACTS_UPDATED: "contacts_updated",
|
|
1216
|
-
DEVICE_IDENTIFIED: "device_identified",
|
|
1217
|
-
ROOM_ROLES_UPDATED: "room_roles_updated",
|
|
1218
|
-
KNOCK_HANDLED: "knock_handled",
|
|
1219
|
-
KNOCK_PAGE_BACKGROUND_CHANGED: "knock_page_background_changed",
|
|
1220
|
-
KNOCKER_LEFT: "knocker_left",
|
|
1221
|
-
MEDIASERVER_CONFIG: "mediaserver_config",
|
|
1222
|
-
MEDIA_SHARED: "media_shared",
|
|
1223
|
-
MEMBER_INVITE: "member_invite",
|
|
1224
|
-
NEW_CLIENT: "new_client",
|
|
1225
|
-
NEW_STREAM_STARTED: "new_stream_started",
|
|
1226
|
-
SCREENSHARE_STARTED: "screenshare_started",
|
|
1227
|
-
SCREENSHARE_STOPPED: "screenshare_stopped",
|
|
1228
|
-
OWNER_NOTIFIED: "owner_notified",
|
|
1229
|
-
OWNERS_CHANGED: "owners_changed",
|
|
1230
|
-
PLAY_CLIENT_STICKER: "play_client_sticker",
|
|
1231
|
-
ROOM_INTEGRATION_ENABLED: "room_integration_enabled",
|
|
1232
|
-
ROOM_INTEGRATION_DISABLED: "room_integration_disabled",
|
|
1233
|
-
ROOM_JOINED: "room_joined",
|
|
1234
|
-
ROOM_KNOCKED: "room_knocked",
|
|
1235
|
-
ROOM_LEFT: "room_left",
|
|
1236
|
-
ROOM_LOCKED: "room_locked",
|
|
1237
|
-
ROOM_PERMISSIONS_CHANGED: "room_permissions_changed",
|
|
1238
|
-
ROOM_LOGO_CHANGED: "room_logo_changed",
|
|
1239
|
-
ROOM_TYPE_CHANGED: "room_type_changed",
|
|
1240
|
-
ROOM_MODE_CHANGED: "room_mode_changed",
|
|
1241
|
-
SOCKET_USER_ID_CHANGED: "socket_user_id_changed",
|
|
1242
|
-
STICKERS_UNLOCKED: "stickers_unlocked",
|
|
1243
|
-
STREAM_ENDED: "stream_ended",
|
|
1244
|
-
URL_EMBED_STARTED: "url_embed_started",
|
|
1245
|
-
URL_EMBED_STOPPED: "url_embed_stopped",
|
|
1246
|
-
RECORDING_STARTED: "recording_started",
|
|
1247
|
-
RECORDING_STOPPED: "recording_stopped",
|
|
1248
|
-
USER_NOTIFIED: "user_notified",
|
|
1249
|
-
VIDEO_ENABLED: "video_enabled",
|
|
1250
|
-
CLIENT_UNABLE_TO_JOIN: "client_unable_to_join",
|
|
1251
|
-
LIVE_TRANSCRIPTION_STARTED: "live_transcription_started",
|
|
1252
|
-
LIVE_TRANSCRIPTION_STOPPED: "live_transcription_stopped",
|
|
1253
|
-
LIVE_CAPTIONS_STARTED: "live_captions_started",
|
|
1254
|
-
LIVE_CAPTIONS_STOPPED: "live_captions_stopped",
|
|
1255
|
-
};
|
|
1256
|
-
const PROTOCOL_ERRORS = {
|
|
1257
|
-
CANNOT_INVITE_YOURSELF: "cannot_invite_yourself",
|
|
1258
|
-
CLIENT_BLOCKED: "client_blocked",
|
|
1259
|
-
CLIENT_MISSING_DEVICE_ID: "client_missing_device_id",
|
|
1260
|
-
FORBIDDEN: "forbidden",
|
|
1261
|
-
FREE_TIER_EXHAUSTED: "free_tier_exhausted",
|
|
1262
|
-
INTERNAL_SERVER_ERROR: "internal_server_error",
|
|
1263
|
-
INVALID_AVATAR: "invalid_avatar",
|
|
1264
|
-
INVALID_PARAMETERS: "invalid_parameters",
|
|
1265
|
-
INVALID_ROOM_NAME: "invalid_room_name",
|
|
1266
|
-
MAX_VIEWER_LIMIT_REACHED: "max_viewer_limit_reached",
|
|
1267
|
-
MISSING_PARAMETERS: "missing_parameters",
|
|
1268
|
-
MISSING_ROOM_NAME: "missing_room_name",
|
|
1269
|
-
NOT_AN_OWNER: "not_an_owner",
|
|
1270
|
-
NOT_IN_A_ROOM: "not_in_a_room",
|
|
1271
|
-
ROOM_ALREADY_CLAIMED: "room_already_claimed",
|
|
1272
|
-
ROOM_CONCURRENCY_CONTROL_ERROR: "room_concurrency_control_error",
|
|
1273
|
-
ROOM_EMAIL_MISSING: "room_email_missing",
|
|
1274
|
-
ROOM_EMPTY: "room_empty",
|
|
1275
|
-
ROOM_FULL: "room_full",
|
|
1276
|
-
ROOM_JOIN_PERMISSION_DENIED: "room_join_permission_denied",
|
|
1277
|
-
ROOM_LOCKED: "room_locked",
|
|
1278
|
-
ROOM_MEETING_TIME_EXHAUSTED: "room_meeting_time_exhausted",
|
|
1279
|
-
ROOM_UNCLAIMED: "room_unclaimed",
|
|
1280
|
-
TOO_LONG_TEXT: "too_long_text",
|
|
1281
|
-
UNIQUE_ROLE_ALREADY_IN_ROOM: "unique_role_already_in_room",
|
|
1282
|
-
UNSUPPORTED_VIDEO_ENCODING: "unsupported_video_encoding",
|
|
1283
|
-
VIDEO_STICKER_DOES_NOT_EXIST: "video_sticker_does_not_exist",
|
|
1284
|
-
VIDEO_STICKER_FORMAT_ERROR: "video_sticker_format_error",
|
|
1285
|
-
};
|
|
1286
|
-
const RELAY_MESSAGES = {
|
|
1287
|
-
CHAT_MESSAGE: "chat_message",
|
|
1288
|
-
CHAT_READ_STATE: "chat_read_state",
|
|
1289
|
-
CHAT_STATE: "chat_state",
|
|
1290
|
-
ICE_CANDIDATE: "ice_candidate",
|
|
1291
|
-
ICE_END_OF_CANDIDATES: "ice_endofcandidates",
|
|
1292
|
-
READY_TO_RECEIVE_OFFER: "ready_to_receive_offer",
|
|
1293
|
-
REMOTE_CLIENT_MEDIA_REQUEST: "remote_client_media_request",
|
|
1294
|
-
SDP_ANSWER: "sdp_answer",
|
|
1295
|
-
SDP_OFFER: "sdp_offer",
|
|
1296
|
-
VIDEO_STICKER: "video_sticker",
|
|
1297
|
-
};
|
|
1298
|
-
const KNOCK_MESSAGES = {
|
|
1299
|
-
actions: {
|
|
1300
|
-
ACCEPT: "accept",
|
|
1301
|
-
HOLD: "hold",
|
|
1302
|
-
REJECT: "reject",
|
|
1303
|
-
},
|
|
1304
|
-
resolutions: {
|
|
1305
|
-
ACCEPTED: "accepted",
|
|
1306
|
-
ON_HOLD: "on_hold",
|
|
1307
|
-
REJECTED: "rejected",
|
|
1308
|
-
},
|
|
1309
|
-
};
|
|
1310
|
-
const PROTOCOL_EVENTS = {
|
|
1311
|
-
PENDING_CLIENT_LEFT: "pending_client_left",
|
|
1312
|
-
MEDIA_QUALITY_CHANGED: "media_quality_changed",
|
|
905
|
+
const word = "[a-fA-F\\d:]";
|
|
906
|
+
const boundry = (options) => options && options.includeBoundaries ? `(?:(?<=\\s|^)(?=${word})|(?<=${word})(?=\\s|$))` : "";
|
|
907
|
+
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}";
|
|
908
|
+
const v6segment = "[a-fA-F\\d]{1,4}";
|
|
909
|
+
const v6 = `
|
|
910
|
+
(?:
|
|
911
|
+
(?:${v6segment}:){7}(?:${v6segment}|:)| // 1:2:3:4:5:6:7:: 1:2:3:4:5:6:7:8
|
|
912
|
+
(?:${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
|
|
913
|
+
(?:${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
|
|
914
|
+
(?:${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
|
|
915
|
+
(?:${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
|
|
916
|
+
(?:${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
|
|
917
|
+
(?:${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
|
|
918
|
+
(?::(?:(?::${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
|
|
919
|
+
)(?:%[0-9a-zA-Z]{1,})? // %eth0 %1
|
|
920
|
+
`
|
|
921
|
+
.replace(/\s*\/\/.*$/gm, "")
|
|
922
|
+
.replace(/\n/g, "")
|
|
923
|
+
.trim();
|
|
924
|
+
const v46Exact = new RegExp(`(?:^${v4}$)|(?:^${v6}$)`);
|
|
925
|
+
const v4exact = new RegExp(`^${v4}$`);
|
|
926
|
+
const v6exact = new RegExp(`^${v6}$`);
|
|
927
|
+
const ipRegex = (options) => options && options.exact
|
|
928
|
+
? v46Exact
|
|
929
|
+
: new RegExp(`(?:${boundry(options)}${v4}${boundry(options)})|(?:${boundry(options)}${v6}${boundry(options)})`, "g");
|
|
930
|
+
ipRegex.v4 = (options) => options && options.exact ? v4exact : new RegExp(`${boundry(options)}${v4}${boundry(options)}`, "g");
|
|
931
|
+
ipRegex.v6 = (options) => options && options.exact ? v6exact : new RegExp(`${boundry(options)}${v6}${boundry(options)}`, "g");
|
|
932
|
+
|
|
933
|
+
var rtcManagerEvents = {
|
|
934
|
+
CAMERA_NOT_WORKING: "camera_not_working",
|
|
935
|
+
CONNECTION_BLOCKED_BY_NETWORK: "connection_blocked_by_network",
|
|
936
|
+
MICROPHONE_NOT_WORKING: "microphone_not_working",
|
|
937
|
+
MICROPHONE_STOPPED_WORKING: "microphone_stopped_working",
|
|
938
|
+
CAMERA_STOPPED_WORKING: "camera_stopped_working",
|
|
939
|
+
NEW_PC: "new_pc",
|
|
940
|
+
SFU_CONNECTION_OPEN: "sfu_connection_open",
|
|
941
|
+
SFU_CONNECTION_CLOSED: "sfu_connection_closed",
|
|
942
|
+
SFU_CONNECTION_INFO: "sfu_connection_info",
|
|
943
|
+
COLOCATION_SPEAKER: "colocation_speaker",
|
|
944
|
+
DOMINANT_SPEAKER: "dominant_speaker",
|
|
1313
945
|
};
|
|
1314
946
|
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
this.
|
|
1320
|
-
this.
|
|
1321
|
-
this.
|
|
1322
|
-
this.
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
roomJoinedLate: 0,
|
|
1326
|
-
pendingClientCanceled: 0,
|
|
1327
|
-
evaluationFailed: 0,
|
|
1328
|
-
roomJoined: 0,
|
|
1329
|
-
};
|
|
1330
|
-
socket.on("disconnect", () => {
|
|
1331
|
-
this._signalDisconnectTime = Date.now();
|
|
1332
|
-
});
|
|
1333
|
-
socket.on(PROTOCOL_RESPONSES.ROOM_JOINED, (payload) => this._onRoomJoined(payload));
|
|
1334
|
-
socket.on(PROTOCOL_RESPONSES.NEW_CLIENT, (payload) => this._onNewClient(payload));
|
|
1335
|
-
socket.on(PROTOCOL_RESPONSES.CLIENT_LEFT, (payload) => this._onClientLeft(payload));
|
|
1336
|
-
socket.on(PROTOCOL_EVENTS.PENDING_CLIENT_LEFT, (payload) => this._onPendingClientLeft(payload));
|
|
1337
|
-
socket.on(PROTOCOL_RESPONSES.AUDIO_ENABLED, (payload) => this._onAudioEnabled(payload));
|
|
1338
|
-
socket.on(PROTOCOL_RESPONSES.VIDEO_ENABLED, (payload) => this._onVideoEnabled(payload));
|
|
1339
|
-
socket.on(PROTOCOL_RESPONSES.SCREENSHARE_STARTED, (payload) => this._onScreenshareChanged(payload, true));
|
|
1340
|
-
socket.on(PROTOCOL_RESPONSES.SCREENSHARE_STOPPED, (payload) => this._onScreenshareChanged(payload, false));
|
|
1341
|
-
}
|
|
1342
|
-
_onRoomJoined(payload) {
|
|
1343
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
1344
|
-
var _a;
|
|
1345
|
-
this.reconnectThresholdInMs = (payload.disconnectTimeout || 0) * 0.8;
|
|
1346
|
-
if (payload === null || payload === void 0 ? void 0 : payload.error) {
|
|
1347
|
-
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1348
|
-
return;
|
|
1349
|
-
}
|
|
1350
|
-
if (!payload.selfId) {
|
|
1351
|
-
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1352
|
-
return;
|
|
1353
|
-
}
|
|
1354
|
-
const myDeviceId = (_a = payload.room.clients.find((c) => payload.selfId === c.id)) === null || _a === void 0 ? void 0 : _a.deviceId;
|
|
1355
|
-
if (!myDeviceId) {
|
|
1356
|
-
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1357
|
-
return;
|
|
1358
|
-
}
|
|
1359
|
-
if (!this._signalDisconnectTime) {
|
|
1360
|
-
this._resetClientState(payload);
|
|
1361
|
-
payload.room.clients = payload.room.clients.filter((c) => !(c.deviceId === myDeviceId && c.isPendingToLeave));
|
|
1362
|
-
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1363
|
-
return;
|
|
1364
|
-
}
|
|
1365
|
-
const RECONNECT_THRESHOLD = payload.disconnectTimeout * 0.8;
|
|
1366
|
-
const timeSinceDisconnect = Date.now() - this._signalDisconnectTime;
|
|
1367
|
-
if (timeSinceDisconnect > RECONNECT_THRESHOLD) {
|
|
1368
|
-
this._resetClientState(payload);
|
|
1369
|
-
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1370
|
-
this.metrics.roomJoinedLate++;
|
|
1371
|
-
return;
|
|
1372
|
-
}
|
|
1373
|
-
payload.room.clients = payload.room.clients.filter((c) => !(c.deviceId === myDeviceId && c.isPendingToLeave));
|
|
1374
|
-
const allStats = yield getUpdatedStats();
|
|
1375
|
-
payload.room.clients.forEach((client) => {
|
|
1376
|
-
var _a;
|
|
1377
|
-
try {
|
|
1378
|
-
if (client.id === payload.selfId)
|
|
1379
|
-
return;
|
|
1380
|
-
if (!this._clients[client.id]) {
|
|
1381
|
-
this._addClientToState(client);
|
|
1382
|
-
return;
|
|
1383
|
-
}
|
|
1384
|
-
if (!((_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.hasClient(client.id))) {
|
|
1385
|
-
return;
|
|
1386
|
-
}
|
|
1387
|
-
if (this._hasClientStateChanged({
|
|
1388
|
-
clientId: client.id,
|
|
1389
|
-
webcam: client.isVideoEnabled,
|
|
1390
|
-
mic: client.isAudioEnabled,
|
|
1391
|
-
screenShare: client.streams.length > 1,
|
|
1392
|
-
})) {
|
|
1393
|
-
return;
|
|
1394
|
-
}
|
|
1395
|
-
if (this._wasClientSendingMedia(client.id)) {
|
|
1396
|
-
if (!this._isClientMediaActive(allStats, client.id)) {
|
|
1397
|
-
return;
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
client.mergeWithOldClientState = true;
|
|
1401
|
-
}
|
|
1402
|
-
catch (error) {
|
|
1403
|
-
logger$a.error("Failed to evaluate if we should merge client state %o", error);
|
|
1404
|
-
this.metrics.evaluationFailed++;
|
|
1405
|
-
}
|
|
1406
|
-
});
|
|
1407
|
-
payload.room.clients.forEach((c) => {
|
|
1408
|
-
if (c.isPendingToLeave) {
|
|
1409
|
-
this._onPendingClientLeft({ clientId: c.id });
|
|
1410
|
-
}
|
|
1411
|
-
});
|
|
1412
|
-
this.metrics.roomJoined++;
|
|
1413
|
-
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1414
|
-
});
|
|
1415
|
-
}
|
|
1416
|
-
_onClientLeft(payload) {
|
|
1417
|
-
var _a;
|
|
1418
|
-
const { clientId } = payload;
|
|
1419
|
-
const client = this._clients[clientId];
|
|
1420
|
-
if (client) {
|
|
1421
|
-
clearTimeout(client.timeout);
|
|
1422
|
-
delete this._clients[clientId];
|
|
1423
|
-
}
|
|
1424
|
-
(_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.disconnect(clientId, payload.eventClaim);
|
|
1425
|
-
this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, payload);
|
|
1426
|
-
}
|
|
1427
|
-
_onPendingClientLeft(payload) {
|
|
1428
|
-
const { clientId } = payload;
|
|
1429
|
-
const client = this._clients[clientId];
|
|
1430
|
-
if (!client) {
|
|
1431
|
-
logger$a.warn(`client ${clientId} not found`);
|
|
1432
|
-
return;
|
|
1433
|
-
}
|
|
1434
|
-
if (client.isPendingToLeave) {
|
|
1435
|
-
return;
|
|
1436
|
-
}
|
|
1437
|
-
client.isPendingToLeave = true;
|
|
1438
|
-
if (this._wasClientSendingMedia(clientId)) {
|
|
1439
|
-
client.checkActiveMediaAttempts = 0;
|
|
1440
|
-
this._abortIfNotActive(payload);
|
|
1441
|
-
}
|
|
1442
|
-
}
|
|
1443
|
-
_onNewClient(payload) {
|
|
1444
|
-
const { client: { id: clientId, deviceId }, } = payload;
|
|
1445
|
-
const client = this._clients[clientId];
|
|
1446
|
-
if (client && client.isPendingToLeave) {
|
|
1447
|
-
clearTimeout(client.timeoutHandler);
|
|
1448
|
-
client.isPendingToLeave = false;
|
|
1449
|
-
this.metrics.pendingClientCanceled++;
|
|
1450
|
-
return;
|
|
1451
|
-
}
|
|
1452
|
-
this._getPendingClientsByDeviceId(deviceId).forEach((client) => {
|
|
1453
|
-
clearTimeout(client.timeoutHandler);
|
|
1454
|
-
client.isPendingToLeave = undefined;
|
|
1455
|
-
this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, { clientId: client.clientId });
|
|
1456
|
-
});
|
|
1457
|
-
this._addClientToState(payload.client);
|
|
1458
|
-
this.emit(PROTOCOL_RESPONSES.NEW_CLIENT, payload);
|
|
1459
|
-
}
|
|
1460
|
-
_abortIfNotActive(payload) {
|
|
1461
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
1462
|
-
const { clientId } = payload;
|
|
1463
|
-
let client = this._clients[clientId];
|
|
1464
|
-
if (!(client === null || client === void 0 ? void 0 : client.isPendingToLeave))
|
|
1465
|
-
return;
|
|
1466
|
-
client.checkActiveMediaAttempts++;
|
|
1467
|
-
if (client.checkActiveMediaAttempts > 3) {
|
|
1468
|
-
return;
|
|
1469
|
-
}
|
|
1470
|
-
const stillActive = yield this._checkIsActive(clientId);
|
|
1471
|
-
if (stillActive) {
|
|
1472
|
-
client.timeoutHandler = setTimeout(() => this._abortIfNotActive(payload), 500);
|
|
1473
|
-
return;
|
|
1474
|
-
}
|
|
1475
|
-
client = this._clients[clientId];
|
|
1476
|
-
if (client === null || client === void 0 ? void 0 : client.isPendingToLeave) {
|
|
1477
|
-
clearTimeout(client.timeoutHandler);
|
|
1478
|
-
delete this._clients[clientId];
|
|
1479
|
-
this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, payload);
|
|
1480
|
-
}
|
|
1481
|
-
});
|
|
1482
|
-
}
|
|
1483
|
-
_checkIsActive(clientId) {
|
|
1484
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
1485
|
-
const allStats = yield getUpdatedStats();
|
|
1486
|
-
return this._isClientMediaActive(allStats, clientId);
|
|
1487
|
-
});
|
|
1488
|
-
}
|
|
1489
|
-
_isClientMediaActive(stats, clientId) {
|
|
1490
|
-
const clientStats = stats === null || stats === void 0 ? void 0 : stats[clientId];
|
|
1491
|
-
let isActive = false;
|
|
1492
|
-
if (clientStats) {
|
|
1493
|
-
Object.entries(clientStats.tracks).forEach(([trackId, trackStats]) => {
|
|
1494
|
-
if (trackId !== "probator")
|
|
1495
|
-
Object.values(trackStats.ssrcs).forEach((ssrcStats) => {
|
|
1496
|
-
if ((ssrcStats.bitrate || 0) > 0)
|
|
1497
|
-
isActive = true;
|
|
1498
|
-
});
|
|
1499
|
-
});
|
|
947
|
+
class AssertionError extends Error {
|
|
948
|
+
constructor(options) {
|
|
949
|
+
super(options.message);
|
|
950
|
+
this.name = "AssertionError";
|
|
951
|
+
this.code = "ERR_ASSERTION";
|
|
952
|
+
this.actual = options.actual;
|
|
953
|
+
this.expected = options.expected;
|
|
954
|
+
this.operator = options.operator;
|
|
955
|
+
if (Error.captureStackTrace) {
|
|
956
|
+
Error.captureStackTrace(this, options.stackStartFn);
|
|
1500
957
|
}
|
|
1501
|
-
return isActive;
|
|
1502
|
-
}
|
|
1503
|
-
_onAudioEnabled(payload) {
|
|
1504
|
-
const { clientId, isAudioEnabled } = payload;
|
|
1505
|
-
this._clients[clientId] = Object.assign(Object.assign({}, (this._clients[clientId] || {})), { isAudioEnabled });
|
|
1506
|
-
}
|
|
1507
|
-
_onVideoEnabled(payload) {
|
|
1508
|
-
const { clientId, isVideoEnabled } = payload;
|
|
1509
|
-
this._clients[clientId] = Object.assign(Object.assign({}, (this._clients[clientId] || {})), { isVideoEnabled });
|
|
1510
|
-
}
|
|
1511
|
-
_onScreenshareChanged(payload, action) {
|
|
1512
|
-
const { clientId } = payload;
|
|
1513
|
-
this._clients[clientId] = Object.assign(Object.assign({}, (this._clients[clientId] || {})), { isScreenshareEnabled: action });
|
|
1514
958
|
}
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
}
|
|
1523
|
-
if (mic !== state.isAudioEnabled) {
|
|
1524
|
-
return true;
|
|
1525
|
-
}
|
|
1526
|
-
if (screenShare !== state.isScreenshareEnabled) {
|
|
1527
|
-
return true;
|
|
959
|
+
}
|
|
960
|
+
function innerOk(fn, argLen, value, message) {
|
|
961
|
+
if (!value) {
|
|
962
|
+
let generatedMessage = false;
|
|
963
|
+
if (argLen === 0) {
|
|
964
|
+
generatedMessage = true;
|
|
965
|
+
message = "No value argument passed to `assert.ok()`";
|
|
1528
966
|
}
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
_addClientToState(newClient) {
|
|
1532
|
-
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 });
|
|
1533
|
-
}
|
|
1534
|
-
_wasClientSendingMedia(clientId) {
|
|
1535
|
-
const client = this._clients[clientId];
|
|
1536
|
-
if (!client) {
|
|
1537
|
-
throw new Error(`Client ${clientId} not found in ReconnectManager state`);
|
|
967
|
+
else if (message instanceof Error) {
|
|
968
|
+
throw message;
|
|
1538
969
|
}
|
|
1539
|
-
|
|
970
|
+
const err = new AssertionError({
|
|
971
|
+
actual: value,
|
|
972
|
+
expected: true,
|
|
973
|
+
message,
|
|
974
|
+
operator: "==",
|
|
975
|
+
stackStartFn: fn,
|
|
976
|
+
});
|
|
977
|
+
err.generatedMessage = generatedMessage;
|
|
978
|
+
throw err;
|
|
1540
979
|
}
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
980
|
+
}
|
|
981
|
+
function innerFail(obj) {
|
|
982
|
+
if (obj.message instanceof Error)
|
|
983
|
+
throw obj.message;
|
|
984
|
+
throw new AssertionError(obj);
|
|
985
|
+
}
|
|
986
|
+
function ok(...args) {
|
|
987
|
+
innerOk(ok, args.length, ...args);
|
|
988
|
+
}
|
|
989
|
+
const assert = {
|
|
990
|
+
fail: (message) => {
|
|
991
|
+
innerFail({
|
|
992
|
+
actual: "fail()",
|
|
993
|
+
expected: "fail() should not be called",
|
|
994
|
+
message,
|
|
995
|
+
operator: "fail",
|
|
996
|
+
stackStartFn: assert.fail,
|
|
1544
997
|
});
|
|
998
|
+
},
|
|
999
|
+
ok,
|
|
1000
|
+
};
|
|
1001
|
+
assert.notEqual = function notEqual(actual, expected, message) {
|
|
1002
|
+
if (arguments.length < 2) {
|
|
1003
|
+
throw new Error("'actual' and 'expected' arguments are required");
|
|
1545
1004
|
}
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
this._addClientToState(client);
|
|
1554
|
-
}
|
|
1005
|
+
if (actual == expected) {
|
|
1006
|
+
innerFail({
|
|
1007
|
+
actual,
|
|
1008
|
+
expected,
|
|
1009
|
+
message,
|
|
1010
|
+
operator: "!=",
|
|
1011
|
+
stackStartFn: notEqual,
|
|
1555
1012
|
});
|
|
1556
1013
|
}
|
|
1557
|
-
}
|
|
1014
|
+
};
|
|
1015
|
+
assert.ok = ok;
|
|
1558
1016
|
|
|
1559
|
-
const
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
this._disconnectDurationLimitEnabled = false;
|
|
1566
|
-
this.disconnectDurationLimitExceeded = false;
|
|
1567
|
-
this.serverSocket = serverSocket;
|
|
1568
|
-
this.serverSocket.on("connect", () => this.onConnect());
|
|
1569
|
-
this.serverSocket.onEngineEvent("ping", () => this.onPing());
|
|
1570
|
-
this.serverSocket.on("disconnect", () => this.onDisconnect());
|
|
1571
|
-
this.serverSocket.onEngineEvent("reconnect_attempt", () => this.onReconnectAttempt());
|
|
1572
|
-
}
|
|
1573
|
-
enableDisconnectDurationLimit() {
|
|
1574
|
-
this._disconnectDurationLimitEnabled = true;
|
|
1575
|
-
}
|
|
1576
|
-
pingHeartbeat() {
|
|
1577
|
-
clearTimeout(this.pingTimer);
|
|
1578
|
-
this.pingTimer = setTimeout(() => {
|
|
1579
|
-
this.serverSocket._socket.io.engine.close();
|
|
1580
|
-
}, SIGNAL_PING_INTERVAL + SIGNAL_PING_MAX_LATENCY);
|
|
1581
|
-
this.lastPingTimestamp = Date.now();
|
|
1582
|
-
}
|
|
1583
|
-
onConnect() {
|
|
1584
|
-
this.pingHeartbeat();
|
|
1585
|
-
}
|
|
1586
|
-
onPing() {
|
|
1587
|
-
this.pingHeartbeat();
|
|
1588
|
-
}
|
|
1589
|
-
onDisconnect() {
|
|
1590
|
-
clearTimeout(this.pingTimer);
|
|
1017
|
+
const createWorker = (fn) => {
|
|
1018
|
+
return new Worker(URL.createObjectURL(new Blob(["self.onmessage = ", fn.toString()], { type: "text/javascript" })));
|
|
1019
|
+
};
|
|
1020
|
+
const generateByteString = (count) => {
|
|
1021
|
+
if (count === 0) {
|
|
1022
|
+
return "";
|
|
1591
1023
|
}
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
this.serverSocket.disconnect();
|
|
1597
|
-
}
|
|
1598
|
-
}
|
|
1024
|
+
const count2 = count / 2;
|
|
1025
|
+
let result = "F";
|
|
1026
|
+
while (result.length <= count2) {
|
|
1027
|
+
result += result;
|
|
1599
1028
|
}
|
|
1600
|
-
|
|
1029
|
+
return result + result.substring(0, count - result.length);
|
|
1030
|
+
};
|
|
1601
1031
|
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
const NOOP_KEEPALIVE_INTERVAL = 2000;
|
|
1606
|
-
const DISCONNECT_DURATION_LIMIT_MS = 60000;
|
|
1607
|
-
class ServerSocket {
|
|
1608
|
-
constructor(hostName, optionsOverrides, glitchFree = false, disconnectDurationLimitOn = false, serverSideDisconnectDurationLimitOn = false) {
|
|
1609
|
-
this._wasConnectedUsingWebsocket = false;
|
|
1610
|
-
this._disconnectDurationLimitOn = disconnectDurationLimitOn && !serverSideDisconnectDurationLimitOn;
|
|
1611
|
-
this._serverSideDisconnectDurationLimitOn = serverSideDisconnectDurationLimitOn;
|
|
1612
|
-
this._disconnectDurationLimitExceeded = false;
|
|
1613
|
-
this._reconnectManager = null;
|
|
1614
|
-
this._socket = io(hostName, Object.assign({ path: DEFAULT_SOCKET_PATH, randomizationFactor: 0.5, reconnectionDelay: 250, reconnectionDelayMax: 5000, timeout: 5000, transports: ["websocket"], withCredentials: true }, optionsOverrides));
|
|
1615
|
-
this._disconnectDurationLimitEnabled = false;
|
|
1616
|
-
this.joinRoomFinished = false;
|
|
1617
|
-
this._socket.io.on("reconnect", () => {
|
|
1618
|
-
if (this._disconnectDurationLimitOn &&
|
|
1619
|
-
this._didExceedDisconnectDurationLimit(this._disconnectDurationLimitLatestTimestamp)) {
|
|
1620
|
-
this._socket.close();
|
|
1621
|
-
this._disconnectDurationLimitExceeded = true;
|
|
1622
|
-
}
|
|
1623
|
-
this._socket.sendBuffer = [];
|
|
1624
|
-
});
|
|
1625
|
-
this._socket.io.on("reconnect_attempt", () => {
|
|
1626
|
-
var _a;
|
|
1627
|
-
if (this._disconnectDurationLimitOn &&
|
|
1628
|
-
this._didExceedDisconnectDurationLimit(this._disconnectDurationLimitLatestTimestamp)) {
|
|
1629
|
-
this._socket.close();
|
|
1630
|
-
this._disconnectDurationLimitExceeded = true;
|
|
1631
|
-
}
|
|
1632
|
-
if (this._wasConnectedUsingWebsocket) {
|
|
1633
|
-
this._socket.io.opts.transports = ["websocket"];
|
|
1634
|
-
if (((_a = adapter$6.browserDetails) === null || _a === void 0 ? void 0 : _a.browser) !== "safari") {
|
|
1635
|
-
delete this._wasConnectedUsingWebsocket;
|
|
1636
|
-
}
|
|
1637
|
-
}
|
|
1638
|
-
else {
|
|
1639
|
-
this._socket.io.opts.transports = ["websocket", "polling"];
|
|
1640
|
-
}
|
|
1641
|
-
});
|
|
1642
|
-
if (glitchFree)
|
|
1643
|
-
this._reconnectManager = new ReconnectManager(this._socket);
|
|
1644
|
-
if (this._serverSideDisconnectDurationLimitOn)
|
|
1645
|
-
this._keepAliveManager = new KeepAliveManager(this);
|
|
1646
|
-
this._socket.on("room_joined", (payload) => {
|
|
1647
|
-
if (!("error" in payload)) {
|
|
1648
|
-
this.joinRoomFinished = true;
|
|
1649
|
-
}
|
|
1650
|
-
});
|
|
1651
|
-
this._socket.on("connect", () => {
|
|
1652
|
-
const transport = this.getTransport();
|
|
1653
|
-
if (transport === "websocket") {
|
|
1654
|
-
this._wasConnectedUsingWebsocket = true;
|
|
1655
|
-
if (this._serverSideDisconnectDurationLimitOn)
|
|
1656
|
-
return;
|
|
1657
|
-
if (!this.noopKeepaliveInterval) {
|
|
1658
|
-
let disconnectDurationLimitTimestampCandidate = Date.now();
|
|
1659
|
-
this.noopKeepaliveInterval = setInterval(() => {
|
|
1660
|
-
try {
|
|
1661
|
-
if (this._socket.connected) {
|
|
1662
|
-
if (this._disconnectDurationLimitOn &&
|
|
1663
|
-
!this._didExceedDisconnectDurationLimit(disconnectDurationLimitTimestampCandidate)) {
|
|
1664
|
-
this._disconnectDurationLimitLatestTimestamp =
|
|
1665
|
-
disconnectDurationLimitTimestampCandidate;
|
|
1666
|
-
disconnectDurationLimitTimestampCandidate = Date.now();
|
|
1667
|
-
}
|
|
1668
|
-
this._socket.io.engine.sendPacket("noop");
|
|
1669
|
-
}
|
|
1670
|
-
}
|
|
1671
|
-
catch (ex) { }
|
|
1672
|
-
}, NOOP_KEEPALIVE_INTERVAL);
|
|
1673
|
-
}
|
|
1674
|
-
}
|
|
1675
|
-
});
|
|
1676
|
-
this._socket.on("disconnect", () => {
|
|
1677
|
-
this.joinRoomFinished = false;
|
|
1678
|
-
this.disconnectTimestamp = Date.now();
|
|
1679
|
-
if (this._serverSideDisconnectDurationLimitOn)
|
|
1680
|
-
return;
|
|
1681
|
-
if (this._disconnectDurationLimitOn &&
|
|
1682
|
-
this._didExceedDisconnectDurationLimit(this._disconnectDurationLimitLatestTimestamp)) {
|
|
1683
|
-
this._socket.close();
|
|
1684
|
-
this._disconnectDurationLimitExceeded = true;
|
|
1685
|
-
}
|
|
1686
|
-
if (this.noopKeepaliveInterval) {
|
|
1687
|
-
clearInterval(this.noopKeepaliveInterval);
|
|
1688
|
-
this.noopKeepaliveInterval = null;
|
|
1689
|
-
}
|
|
1690
|
-
});
|
|
1032
|
+
const getMediasoupDeviceAsync = (features) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1033
|
+
if (features.isNodeSdk) {
|
|
1034
|
+
return new Device({ handlerName: "Safari12" });
|
|
1691
1035
|
}
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
if (disconnectedDuration > DISCONNECT_DURATION_LIMIT_MS) {
|
|
1697
|
-
return true;
|
|
1698
|
-
}
|
|
1699
|
-
return false;
|
|
1036
|
+
let handlerName = (yield detectDeviceAsync()) ||
|
|
1037
|
+
(/applecoremedia|applewebkit|safari/i.test(navigator.userAgent) ? "Safari12" : undefined);
|
|
1038
|
+
if (/iphone|ipad/i.test(navigator.userAgent)) {
|
|
1039
|
+
handlerName = "Safari12";
|
|
1700
1040
|
}
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1041
|
+
if (!handlerName)
|
|
1042
|
+
handlerName = "Chrome111";
|
|
1043
|
+
return new Device({ handlerName });
|
|
1044
|
+
});
|
|
1045
|
+
|
|
1046
|
+
const logger$8 = new Logger();
|
|
1047
|
+
const AUDIO_SETTINGS = {
|
|
1048
|
+
codecOptions: {
|
|
1049
|
+
opusDtx: true,
|
|
1050
|
+
opusFec: true,
|
|
1051
|
+
},
|
|
1052
|
+
encodings: [{ dtx: true }],
|
|
1053
|
+
};
|
|
1054
|
+
const VIDEO_SETTINGS_HD = {
|
|
1055
|
+
codecOptions: {
|
|
1056
|
+
videoGoogleStartBitrate: 500,
|
|
1057
|
+
},
|
|
1058
|
+
encodings: [
|
|
1059
|
+
{ scaleResolutionDownBy: 4, maxBitrate: 150000 },
|
|
1060
|
+
{ scaleResolutionDownBy: 2, maxBitrate: 500000 },
|
|
1061
|
+
{ scaleResolutionDownBy: 1, maxBitrate: 1000000 },
|
|
1062
|
+
],
|
|
1063
|
+
};
|
|
1064
|
+
const VIDEO_SETTINGS_SD = {
|
|
1065
|
+
codecOptions: {
|
|
1066
|
+
videoGoogleStartBitrate: 500,
|
|
1067
|
+
},
|
|
1068
|
+
encodings: [
|
|
1069
|
+
{ scaleResolutionDownBy: 2, maxBitrate: 150000 },
|
|
1070
|
+
{ scaleResolutionDownBy: 1, maxBitrate: 500000 },
|
|
1071
|
+
],
|
|
1072
|
+
};
|
|
1073
|
+
const VIDEO_SETTINGS_VP9 = {
|
|
1074
|
+
codecOptions: {
|
|
1075
|
+
videoGoogleStartBitrate: 500,
|
|
1076
|
+
},
|
|
1077
|
+
encodings: [{ scalabilityMode: "L3T2", maxBitrate: 1000000 }],
|
|
1078
|
+
};
|
|
1079
|
+
const VIDEO_SETTINGS_VP9_LOW_BANDWIDTH = {
|
|
1080
|
+
codecOptions: {
|
|
1081
|
+
videoGoogleStartBitrate: 500,
|
|
1082
|
+
},
|
|
1083
|
+
encodings: [{ scalabilityMode: "L2T2", maxBitrate: 500000 }],
|
|
1084
|
+
};
|
|
1085
|
+
const SCREEN_SHARE_SETTINGS = {
|
|
1086
|
+
encodings: [{}],
|
|
1087
|
+
};
|
|
1088
|
+
const SCREEN_SHARE_SIMULCAST_SETTINGS = {
|
|
1089
|
+
encodings: [
|
|
1090
|
+
{ scaleResolutionDownBy: 2, dtx: true, maxBitrate: 500000 },
|
|
1091
|
+
{ scaleResolutionDownBy: 1, dtx: true, maxBitrate: 1500000 },
|
|
1092
|
+
],
|
|
1093
|
+
};
|
|
1094
|
+
const ADDITIONAL_SCREEN_SHARE_SETTINGS = {
|
|
1095
|
+
encodings: [
|
|
1096
|
+
{ scaleResolutionDownBy: 4, dtx: true, maxBitrate: 150000 },
|
|
1097
|
+
{ scaleResolutionDownBy: 2, dtx: true, maxBitrate: 500000 },
|
|
1098
|
+
{ scaleResolutionDownBy: 1, dtx: true, maxBitrate: 1500000 },
|
|
1099
|
+
],
|
|
1100
|
+
};
|
|
1101
|
+
const getMediaSettings = (kind, isScreenShare, features, areTooManyAlreadyPresenting = false) => {
|
|
1102
|
+
var _a;
|
|
1103
|
+
const { lowDataModeEnabled, simulcastScreenshareOn, vp9On } = features;
|
|
1104
|
+
if (kind === "audio") {
|
|
1105
|
+
return AUDIO_SETTINGS;
|
|
1710
1106
|
}
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
}
|
|
1107
|
+
const isChrome = ((_a = adapterRaw.browserDetails) === null || _a === void 0 ? void 0 : _a.browser) === "chrome";
|
|
1108
|
+
const isVp9Available = isChrome && vp9On;
|
|
1109
|
+
if (isScreenShare) {
|
|
1110
|
+
return getScreenShareMediaSettings({
|
|
1111
|
+
areTooManyAlreadyPresenting,
|
|
1112
|
+
simulcastScreenshareOn,
|
|
1113
|
+
});
|
|
1719
1114
|
}
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1115
|
+
else {
|
|
1116
|
+
return getCameraMediaSettings({
|
|
1117
|
+
lowBandwidth: lowDataModeEnabled,
|
|
1118
|
+
isVp9Available,
|
|
1119
|
+
});
|
|
1724
1120
|
}
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1121
|
+
};
|
|
1122
|
+
const getCameraMediaSettings = ({ lowBandwidth, isVp9Available, }) => {
|
|
1123
|
+
if (lowBandwidth) {
|
|
1124
|
+
if (isVp9Available) {
|
|
1125
|
+
return VIDEO_SETTINGS_VP9_LOW_BANDWIDTH;
|
|
1728
1126
|
}
|
|
1729
|
-
|
|
1730
|
-
}
|
|
1731
|
-
disconnect() {
|
|
1732
|
-
this._socket.disconnect();
|
|
1127
|
+
return VIDEO_SETTINGS_SD;
|
|
1733
1128
|
}
|
|
1734
|
-
|
|
1735
|
-
|
|
1129
|
+
if (isVp9Available) {
|
|
1130
|
+
return VIDEO_SETTINGS_VP9;
|
|
1736
1131
|
}
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1132
|
+
return VIDEO_SETTINGS_HD;
|
|
1133
|
+
};
|
|
1134
|
+
const getScreenShareMediaSettings = ({ areTooManyAlreadyPresenting, simulcastScreenshareOn, }) => {
|
|
1135
|
+
if (areTooManyAlreadyPresenting) {
|
|
1136
|
+
return ADDITIONAL_SCREEN_SHARE_SETTINGS;
|
|
1740
1137
|
}
|
|
1741
|
-
|
|
1742
|
-
return
|
|
1138
|
+
if (simulcastScreenshareOn)
|
|
1139
|
+
return SCREEN_SHARE_SIMULCAST_SETTINGS;
|
|
1140
|
+
return SCREEN_SHARE_SETTINGS;
|
|
1141
|
+
};
|
|
1142
|
+
var PrioritizableCodec;
|
|
1143
|
+
(function (PrioritizableCodec) {
|
|
1144
|
+
PrioritizableCodec["H264"] = "video/h264";
|
|
1145
|
+
PrioritizableCodec["VP9"] = "video/vp9";
|
|
1146
|
+
})(PrioritizableCodec || (PrioritizableCodec = {}));
|
|
1147
|
+
const modifyMediaCapabilities = (routerRtpCapabilities, features) => {
|
|
1148
|
+
var _a;
|
|
1149
|
+
const { vp9On, h264On } = features;
|
|
1150
|
+
const isChrome = ((_a = adapterRaw.browserDetails) === null || _a === void 0 ? void 0 : _a.browser) === "chrome";
|
|
1151
|
+
if (!(routerRtpCapabilities === null || routerRtpCapabilities === void 0 ? void 0 : routerRtpCapabilities.codecs)) {
|
|
1152
|
+
return routerRtpCapabilities;
|
|
1743
1153
|
}
|
|
1744
|
-
|
|
1745
|
-
|
|
1154
|
+
if (vp9On && isChrome) {
|
|
1155
|
+
const sorted = prioritizeRouterRtpCapabilitiesCodecs(routerRtpCapabilities.codecs, PrioritizableCodec.VP9);
|
|
1156
|
+
return Object.assign(Object.assign({}, routerRtpCapabilities), { codecs: sorted });
|
|
1746
1157
|
}
|
|
1747
|
-
|
|
1748
|
-
|
|
1158
|
+
else if (h264On) {
|
|
1159
|
+
const sorted = prioritizeRouterRtpCapabilitiesCodecs(routerRtpCapabilities.codecs, PrioritizableCodec.H264);
|
|
1160
|
+
return Object.assign(Object.assign({}, routerRtpCapabilities), { codecs: sorted });
|
|
1749
1161
|
}
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
if (this._reconnectManager && relayableEvents.includes(eventName)) {
|
|
1757
|
-
return this._interceptEvent(eventName, handler);
|
|
1758
|
-
}
|
|
1759
|
-
this._socket.on(eventName, handler);
|
|
1760
|
-
return () => {
|
|
1761
|
-
this._socket.off(eventName, handler);
|
|
1762
|
-
};
|
|
1162
|
+
return routerRtpCapabilities;
|
|
1163
|
+
};
|
|
1164
|
+
function prioritizeRouterRtpCapabilitiesCodecs(codecs, preferredCodec) {
|
|
1165
|
+
const preferredCodecEntry = codecs.find(({ mimeType }) => mimeType.toLowerCase() === preferredCodec);
|
|
1166
|
+
if (!preferredCodecEntry) {
|
|
1167
|
+
return codecs;
|
|
1763
1168
|
}
|
|
1764
|
-
|
|
1169
|
+
return [...codecs].sort((left, right) => {
|
|
1765
1170
|
var _a;
|
|
1766
|
-
(
|
|
1767
|
-
|
|
1768
|
-
var _a;
|
|
1769
|
-
(_a = this._socket.io) === null || _a === void 0 ? void 0 : _a.off(eventName, handler);
|
|
1770
|
-
};
|
|
1771
|
-
}
|
|
1772
|
-
once(eventName, handler) {
|
|
1773
|
-
this._socket.once(eventName, handler);
|
|
1774
|
-
}
|
|
1775
|
-
off(eventName, handler) {
|
|
1776
|
-
this._socket.off(eventName, handler);
|
|
1777
|
-
}
|
|
1778
|
-
_interceptEvent(eventName, handler) {
|
|
1779
|
-
if (this._reconnectManager) {
|
|
1780
|
-
this._reconnectManager.on(eventName, handler);
|
|
1171
|
+
if (left.mimeType.toLowerCase() === preferredCodec) {
|
|
1172
|
+
return -1;
|
|
1781
1173
|
}
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1174
|
+
if (left.mimeType.toLowerCase() === "video/rtx" &&
|
|
1175
|
+
((_a = left.parameters) === null || _a === void 0 ? void 0 : _a.apt) === preferredCodecEntry.preferredPayloadType) {
|
|
1176
|
+
if (right.mimeType.toLowerCase() === preferredCodec) {
|
|
1177
|
+
return 1;
|
|
1178
|
+
}
|
|
1179
|
+
return -1;
|
|
1180
|
+
}
|
|
1181
|
+
return 0;
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
function getPreferredOrder(availableCodecs, { av1On }) {
|
|
1185
|
+
availableCodecs.unshift("video/vp9");
|
|
1186
|
+
if (av1On) {
|
|
1187
|
+
availableCodecs.unshift("video/av1");
|
|
1786
1188
|
}
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1189
|
+
return availableCodecs;
|
|
1190
|
+
}
|
|
1191
|
+
function sortCodecsByMimeType(codecs, features) {
|
|
1192
|
+
const availableCodecs = codecs
|
|
1193
|
+
.map(({ mimeType }) => mimeType)
|
|
1194
|
+
.filter((value, index, array) => array.indexOf(value) === index);
|
|
1195
|
+
const preferredOrder = getPreferredOrder(availableCodecs, features);
|
|
1196
|
+
return codecs.sort((a, b) => {
|
|
1197
|
+
const indexA = preferredOrder.indexOf(a.mimeType.toLowerCase());
|
|
1198
|
+
const indexB = preferredOrder.indexOf(b.mimeType.toLowerCase());
|
|
1199
|
+
const orderA = indexA >= 0 ? indexA : Number.MAX_VALUE;
|
|
1200
|
+
const orderB = indexB >= 0 ? indexB : Number.MAX_VALUE;
|
|
1201
|
+
return orderA - orderB;
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
function getIsCodecDecodingPowerEfficient(codec) {
|
|
1205
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1206
|
+
const { powerEfficient } = yield navigator.mediaCapabilities.decodingInfo({
|
|
1207
|
+
type: "webrtc",
|
|
1208
|
+
video: {
|
|
1209
|
+
width: 1280,
|
|
1210
|
+
height: 720,
|
|
1211
|
+
bitrate: 2580,
|
|
1212
|
+
framerate: 24,
|
|
1213
|
+
contentType: codec,
|
|
1214
|
+
},
|
|
1215
|
+
});
|
|
1216
|
+
return powerEfficient;
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
function sortCodecsByPowerEfficiency(codecs) {
|
|
1220
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1221
|
+
let codecPowerEfficiencyEntries;
|
|
1222
|
+
try {
|
|
1223
|
+
codecPowerEfficiencyEntries = yield Promise.all(codecs.map(({ mimeType }) => getIsCodecDecodingPowerEfficient(mimeType).then((val) => [mimeType, val])));
|
|
1224
|
+
}
|
|
1225
|
+
catch (error) {
|
|
1226
|
+
logger$8.error(error);
|
|
1227
|
+
return codecs;
|
|
1228
|
+
}
|
|
1229
|
+
const codecPowerEfficiencies = Object.fromEntries(codecPowerEfficiencyEntries);
|
|
1230
|
+
const sorted = codecs.sort((a, b) => {
|
|
1231
|
+
const aPowerEfficient = codecPowerEfficiencies[a.mimeType];
|
|
1232
|
+
const bPowerEfficient = codecPowerEfficiencies[b.mimeType];
|
|
1233
|
+
return aPowerEfficient === bPowerEfficient ? 0 : aPowerEfficient ? -1 : 1;
|
|
1234
|
+
});
|
|
1235
|
+
return sorted;
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
function sortCodecs(codecs, features) {
|
|
1239
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1240
|
+
let sortedCodecs = sortCodecsByMimeType(codecs, features);
|
|
1241
|
+
sortedCodecs = yield sortCodecsByPowerEfficiency(codecs);
|
|
1242
|
+
return sortedCodecs;
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
function captureCandidatePairInfoMetrics(cpMetrics, currentCptats, prevCptats, timeDiff, report) {
|
|
1247
|
+
const bytesReceivedDiff = currentCptats.bytesReceived - ((prevCptats === null || prevCptats === void 0 ? void 0 : prevCptats.bytesReceived) || 0);
|
|
1248
|
+
const bytesSentDiff = currentCptats.bytesSent - ((prevCptats === null || prevCptats === void 0 ? void 0 : prevCptats.bytesSent) || 0);
|
|
1249
|
+
cpMetrics.bitrateIn = (8000 * bytesReceivedDiff) / timeDiff;
|
|
1250
|
+
cpMetrics.bitrateOut = (8000 * bytesSentDiff) / timeDiff;
|
|
1251
|
+
cpMetrics.state = currentCptats.state;
|
|
1252
|
+
cpMetrics.roundTripTime = currentCptats.currentRoundTripTime;
|
|
1253
|
+
cpMetrics.requestsSent = currentCptats.requestsSent;
|
|
1254
|
+
cpMetrics.responsesReceived = currentCptats.responsesReceived;
|
|
1255
|
+
cpMetrics.requestsReceived = currentCptats.requestsReceived;
|
|
1256
|
+
cpMetrics.responsesSent = currentCptats.responsesSent;
|
|
1257
|
+
cpMetrics.availableOutgoingBitrate = currentCptats.availableOutgoingBitrate;
|
|
1258
|
+
cpMetrics.availableIncomingBitrate = currentCptats.availableIncomingBitrate;
|
|
1259
|
+
const remote = report.get(currentCptats.remoteCandidateId);
|
|
1260
|
+
const local = report.get(currentCptats.localCandidateId);
|
|
1261
|
+
cpMetrics.usingTurn = false;
|
|
1262
|
+
if (local) {
|
|
1263
|
+
if (/relay/i.test(local.candidateType || "")) {
|
|
1264
|
+
cpMetrics.usingTurn = true;
|
|
1265
|
+
cpMetrics.turnProtocol = local.relayProtocol;
|
|
1266
|
+
}
|
|
1790
1267
|
}
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1268
|
+
if (remote && local) {
|
|
1269
|
+
cpMetrics.localEp = `${local.protocol}:${local.address || local.ip}:${local.port} ${local.candidateType} (${local.networkType})`;
|
|
1270
|
+
cpMetrics.remoteEp = `${remote.protocol}:${remote.address || remote.ip}:${remote.port} ${remote.candidateType}`;
|
|
1794
1271
|
}
|
|
1795
1272
|
}
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1273
|
+
function captureSsrcInfo(ssrcMetrics, currentSsrcStats, prevSsrcStats, timeDiff, report) {
|
|
1274
|
+
if (ssrcMetrics.codec)
|
|
1275
|
+
return;
|
|
1276
|
+
ssrcMetrics.kind = currentSsrcStats.kind || currentSsrcStats.mediaType;
|
|
1277
|
+
ssrcMetrics.ssrc = currentSsrcStats.ssrc;
|
|
1278
|
+
ssrcMetrics.direction = currentSsrcStats.type === "inbound-rtp" ? "in" : "out";
|
|
1279
|
+
const codecStats = currentSsrcStats.codecId && report.get(currentSsrcStats.codecId);
|
|
1280
|
+
ssrcMetrics.codec =
|
|
1281
|
+
codecStats &&
|
|
1282
|
+
[
|
|
1283
|
+
codecStats.mimeType,
|
|
1284
|
+
codecStats.channels && `${codecStats.channels}ch`,
|
|
1285
|
+
codecStats.clockRate,
|
|
1286
|
+
codecStats.payloadType,
|
|
1287
|
+
currentSsrcStats.encoderImplementation || currentSsrcStats.decoderImplementation,
|
|
1288
|
+
codecStats.sdpFmtpLine,
|
|
1289
|
+
]
|
|
1290
|
+
.filter(Boolean)
|
|
1291
|
+
.join(" ");
|
|
1292
|
+
ssrcMetrics.mid = currentSsrcStats.mid;
|
|
1293
|
+
ssrcMetrics.rid = currentSsrcStats.rid;
|
|
1294
|
+
}
|
|
1295
|
+
function captureCommonSsrcMetrics(ssrcMetrics, currentSsrcStats, prevSsrcStats, timeDiff, report) {
|
|
1296
|
+
const nackCountDiff = (currentSsrcStats.nackCount || 0) - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.nackCount) || 0);
|
|
1297
|
+
ssrcMetrics.nackCount = (ssrcMetrics.nackCount || 0) + nackCountDiff;
|
|
1298
|
+
ssrcMetrics.nackRate = (1000 * nackCountDiff) / timeDiff;
|
|
1299
|
+
if (ssrcMetrics.direction === "in") {
|
|
1300
|
+
const packetCountDiff = currentSsrcStats.packetsReceived - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.packetsReceived) || 0);
|
|
1301
|
+
ssrcMetrics.packetCount = (ssrcMetrics.packetCount || 0) + packetCountDiff;
|
|
1302
|
+
ssrcMetrics.packetRate = (1000 * packetCountDiff) / timeDiff;
|
|
1303
|
+
const packetLossCountDiff = currentSsrcStats.packetsLost - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.packetsLost) || 0);
|
|
1304
|
+
ssrcMetrics.packetLossCount = (ssrcMetrics.packetLossCount || 0) + packetLossCountDiff;
|
|
1305
|
+
ssrcMetrics.packetLossRate = (1000 * packetLossCountDiff) / timeDiff;
|
|
1306
|
+
ssrcMetrics.lossRatio = (1000 * (packetLossCountDiff / (packetLossCountDiff + packetCountDiff))) / timeDiff;
|
|
1307
|
+
const byteCountDiff = currentSsrcStats.bytesReceived - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.bytesReceived) || 0);
|
|
1308
|
+
ssrcMetrics.byteCount = (ssrcMetrics.byteCount || 0) + byteCountDiff;
|
|
1309
|
+
let headerByteCountDiff = 0;
|
|
1310
|
+
if (currentSsrcStats.headerBytesReceived) {
|
|
1311
|
+
headerByteCountDiff = currentSsrcStats.headerBytesReceived - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.headerBytesReceived) || 0);
|
|
1312
|
+
ssrcMetrics.headerByteCount = (ssrcMetrics.headerByteCount || 0) + headerByteCountDiff;
|
|
1313
|
+
}
|
|
1314
|
+
const totalBytesDiff = byteCountDiff + headerByteCountDiff;
|
|
1315
|
+
ssrcMetrics.bitrate = (8000 * totalBytesDiff) / timeDiff;
|
|
1316
|
+
ssrcMetrics.mediaRatio = byteCountDiff / totalBytesDiff;
|
|
1317
|
+
if (currentSsrcStats.kind === "audio") {
|
|
1318
|
+
const fecBytesDiff = (currentSsrcStats.fecBytesReceived || 0) - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.fecBytesReceived) || 0);
|
|
1319
|
+
ssrcMetrics.fecRatio = fecBytesDiff / byteCountDiff;
|
|
1320
|
+
}
|
|
1321
|
+
const jitterBufferDelayDiff = (currentSsrcStats.jitterBufferDelay || 0) - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.jitterBufferDelay) || 0);
|
|
1322
|
+
const jitterBufferEmittedDiff = (currentSsrcStats.jitterBufferEmittedCount || 0) - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.jitterBufferEmittedCount) || 0);
|
|
1323
|
+
ssrcMetrics.jitter = jitterBufferEmittedDiff ? jitterBufferDelayDiff / jitterBufferEmittedDiff : 0;
|
|
1800
1324
|
}
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1325
|
+
else {
|
|
1326
|
+
const packetCountDiff = currentSsrcStats.packetsSent - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.packetsSent) || 0);
|
|
1327
|
+
ssrcMetrics.packetCount = (ssrcMetrics.packetCount || 0) + packetCountDiff;
|
|
1328
|
+
ssrcMetrics.packetRate = (1000 * packetCountDiff) / timeDiff;
|
|
1329
|
+
const byteCountDiff = currentSsrcStats.bytesSent - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.bytesSent) || 0);
|
|
1330
|
+
ssrcMetrics.byteCount = (ssrcMetrics.byteCount || 0) + byteCountDiff;
|
|
1331
|
+
let headerByteCountDiff = 0;
|
|
1332
|
+
if (currentSsrcStats.headerBytesSent) {
|
|
1333
|
+
headerByteCountDiff = currentSsrcStats.headerBytesSent - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.headerBytesSent) || 0);
|
|
1334
|
+
ssrcMetrics.headerByteCount = (ssrcMetrics.headerByteCount || 0) + headerByteCountDiff;
|
|
1335
|
+
}
|
|
1336
|
+
const totalBytesDiff = byteCountDiff + headerByteCountDiff;
|
|
1337
|
+
ssrcMetrics.bitrate = (8000 * totalBytesDiff) / timeDiff;
|
|
1338
|
+
ssrcMetrics.mediaRatio = byteCountDiff / totalBytesDiff;
|
|
1339
|
+
const sendDelayDiff = currentSsrcStats.totalPacketSendDelay - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.totalPacketSendDelay) || 0);
|
|
1340
|
+
ssrcMetrics.sendDelay = sendDelayDiff / packetCountDiff;
|
|
1341
|
+
const retransDiff = currentSsrcStats.retransmittedPacketsSent - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.retransmittedPacketsSent) || 0);
|
|
1342
|
+
ssrcMetrics.retransRatio = (1000 * (retransDiff / packetCountDiff)) / timeDiff;
|
|
1343
|
+
if (currentSsrcStats.remoteId) {
|
|
1344
|
+
const remoteReport = report.get(currentSsrcStats.remoteId);
|
|
1345
|
+
if (remoteReport) {
|
|
1346
|
+
ssrcMetrics.roundTripTime = remoteReport.roundTripTime || 0;
|
|
1347
|
+
ssrcMetrics.jitter = remoteReport.jitter || 0;
|
|
1348
|
+
ssrcMetrics.fractionLost = remoteReport.fractionLost || 0;
|
|
1815
1349
|
}
|
|
1816
|
-
}
|
|
1817
|
-
}
|
|
1818
|
-
};
|
|
1819
|
-
const external_stun_servers = (iceConfig, features) => {
|
|
1820
|
-
if (features.addGoogleStunServers) {
|
|
1821
|
-
iceConfig.iceServers = [
|
|
1822
|
-
{ urls: "stun:stun.l.google.com:19302" },
|
|
1823
|
-
{ urls: "stun:stun2.l.google.com:19302" },
|
|
1824
|
-
...iceConfig.iceServers,
|
|
1825
|
-
];
|
|
1350
|
+
}
|
|
1826
1351
|
}
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1352
|
+
}
|
|
1353
|
+
function captureAudioSsrcMetrics(ssrcMetrics, currentSsrcStats, prevSsrcStats, timeDiff, report) {
|
|
1354
|
+
const packetsDiscardedDiff = currentSsrcStats.packetsDiscarded - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.packetsDiscarded) || 0);
|
|
1355
|
+
ssrcMetrics.packetsDiscarded = (ssrcMetrics.packetsDiscarded || 0) + packetsDiscardedDiff;
|
|
1356
|
+
if (ssrcMetrics.direction === "in") {
|
|
1357
|
+
const totalAudioEnergyDiff = currentSsrcStats.totalAudioEnergy - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.totalAudioEnergy) || 0);
|
|
1358
|
+
const totalSamplesDurationDiff = currentSsrcStats.totalSamplesDuration - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.totalSamplesDuration) || 0);
|
|
1359
|
+
ssrcMetrics.audioLevel = Math.sqrt(totalAudioEnergyDiff / totalSamplesDurationDiff);
|
|
1360
|
+
const samples = currentSsrcStats.totalSamplesReceived || 0;
|
|
1361
|
+
const concealmentEvents = currentSsrcStats.concealmentEvents || 0;
|
|
1362
|
+
const samplesDiff = samples - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.totalSamplesReceived) || 0);
|
|
1363
|
+
const concealedSamples = currentSsrcStats.concealedSamples || 0;
|
|
1364
|
+
const concealedDiff = concealedSamples - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.concealedSamples) || 0);
|
|
1365
|
+
const silentConcealedDiff = (currentSsrcStats.silentConcealedSamples || 0) - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.silentConcealedSamples) || 0);
|
|
1366
|
+
const insDiff = (currentSsrcStats.insertedSamplesForDeceleration || 0) -
|
|
1367
|
+
((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.insertedSamplesForDeceleration) || 0);
|
|
1368
|
+
const remDiff = (currentSsrcStats.removedSamplesForAcceleration || 0) - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.removedSamplesForAcceleration) || 0);
|
|
1369
|
+
ssrcMetrics.audioSamples = samples;
|
|
1370
|
+
ssrcMetrics.audioConcealmentEvents = concealmentEvents;
|
|
1371
|
+
ssrcMetrics.audioConcealedSamples = concealedSamples;
|
|
1372
|
+
ssrcMetrics.audioConcealment = concealedDiff ? concealedDiff / samplesDiff : 0;
|
|
1373
|
+
ssrcMetrics.audioSilentConcealment = silentConcealedDiff ? silentConcealedDiff / samplesDiff : 0;
|
|
1374
|
+
ssrcMetrics.audioAcceleration = remDiff ? remDiff / samplesDiff : 0;
|
|
1375
|
+
ssrcMetrics.audioDeceleration = insDiff ? insDiff / samplesDiff : 0;
|
|
1833
1376
|
}
|
|
1834
|
-
}
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1377
|
+
}
|
|
1378
|
+
function captureVideoSsrcMetrics(ssrcMetrics, currentSsrcStats, prevSsrcStats, timeDiff, report) {
|
|
1379
|
+
ssrcMetrics.width = currentSsrcStats.frameWidth;
|
|
1380
|
+
ssrcMetrics.height = currentSsrcStats.frameHeight;
|
|
1381
|
+
ssrcMetrics.qualityLimitationReason = currentSsrcStats.qualityLimitationReason || "";
|
|
1382
|
+
const pliCountDiff = currentSsrcStats.pliCount - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.pliCount) || 0);
|
|
1383
|
+
ssrcMetrics.pliCount = (ssrcMetrics.pliCount || 0) + pliCountDiff;
|
|
1384
|
+
ssrcMetrics.pliRate = (1000 * pliCountDiff) / timeDiff;
|
|
1385
|
+
const firCountDiff = currentSsrcStats.firCount - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.firCount) || 0);
|
|
1386
|
+
ssrcMetrics.firCount = (ssrcMetrics.firCount || 0) + firCountDiff;
|
|
1387
|
+
ssrcMetrics.firRate = (1000 * firCountDiff) / timeDiff;
|
|
1388
|
+
if (ssrcMetrics.direction === "in") {
|
|
1389
|
+
const kfCountDiff = currentSsrcStats.keyFramesDecoded - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.keyFramesDecoded) || 0);
|
|
1390
|
+
ssrcMetrics.kfCount = (ssrcMetrics.kfCount || 0) + kfCountDiff;
|
|
1391
|
+
ssrcMetrics.kfRate = (1000 * kfCountDiff) / timeDiff;
|
|
1392
|
+
const frameCountDiff = currentSsrcStats.framesDecoded - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.framesDecoded) || 0);
|
|
1393
|
+
ssrcMetrics.frameCount = (ssrcMetrics.frameCount || 0) + frameCountDiff;
|
|
1394
|
+
const qpsumDiff = currentSsrcStats.qpSum - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.qpSum) || 0);
|
|
1395
|
+
ssrcMetrics.qpf = qpsumDiff / frameCountDiff;
|
|
1396
|
+
ssrcMetrics.fps = (frameCountDiff * 1000) / timeDiff;
|
|
1850
1397
|
}
|
|
1851
1398
|
else {
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
const
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
const
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
let subdomain = "";
|
|
1870
|
-
let domain = host;
|
|
1871
|
-
let subdomainSeparator = ".";
|
|
1872
|
-
for (const { separator, pattern } of subdomainPatterns) {
|
|
1873
|
-
const match = pattern.exec(host);
|
|
1874
|
-
if (match) {
|
|
1875
|
-
subdomain = match[1] || "";
|
|
1876
|
-
domain = match[2];
|
|
1877
|
-
subdomainSeparator = separator;
|
|
1878
|
-
break;
|
|
1399
|
+
const kfCountDiff = currentSsrcStats.keyFramesEncoded - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.keyFramesEncoded) || 0);
|
|
1400
|
+
ssrcMetrics.kfCount = (ssrcMetrics.kfCount || 0) + kfCountDiff;
|
|
1401
|
+
ssrcMetrics.kfRate = (1000 * kfCountDiff) / timeDiff;
|
|
1402
|
+
const frameCountDiff = currentSsrcStats.framesEncoded - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.framesEncoded) || 0);
|
|
1403
|
+
ssrcMetrics.frameCount = (ssrcMetrics.frameCount || 0) + frameCountDiff;
|
|
1404
|
+
const qpsumDiff = currentSsrcStats.qpSum - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.qpSum) || 0);
|
|
1405
|
+
ssrcMetrics.qpf = qpsumDiff / frameCountDiff;
|
|
1406
|
+
ssrcMetrics.fps = (frameCountDiff * 1000) / timeDiff;
|
|
1407
|
+
const encodeTimeDiff = currentSsrcStats.totalEncodeTime - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.totalEncodeTime) || 0);
|
|
1408
|
+
ssrcMetrics.encodeTime = encodeTimeDiff / frameCountDiff;
|
|
1409
|
+
if (currentSsrcStats.mediaSourceId) {
|
|
1410
|
+
const mediaSourceReport = report.get(currentSsrcStats.mediaSourceId);
|
|
1411
|
+
if (mediaSourceReport) {
|
|
1412
|
+
ssrcMetrics.sourceWidth = mediaSourceReport.width || 0;
|
|
1413
|
+
ssrcMetrics.sourceHeight = mediaSourceReport.height || 0;
|
|
1414
|
+
ssrcMetrics.sourceFps = mediaSourceReport.framesPerSecond || 0;
|
|
1415
|
+
}
|
|
1879
1416
|
}
|
|
1880
1417
|
}
|
|
1881
|
-
const organizationDomain = !subdomain ? domain : `${subdomain}${subdomainSeparator}${domain}`;
|
|
1882
|
-
return {
|
|
1883
|
-
domain,
|
|
1884
|
-
domainWithSeparator: `${subdomainSeparator}${domain}`,
|
|
1885
|
-
organizationDomain,
|
|
1886
|
-
organization: `${protocol}//${organizationDomain}`,
|
|
1887
|
-
service: `${protocol}//${domain}`,
|
|
1888
|
-
subdomain,
|
|
1889
|
-
};
|
|
1890
1418
|
}
|
|
1891
|
-
fromLocation(window && window.location);
|
|
1892
1419
|
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1420
|
+
let peerConnections = [];
|
|
1421
|
+
let peerConnectionCounter = 0;
|
|
1422
|
+
const peerConnectionData = new WeakMap();
|
|
1423
|
+
const removePeerConnection = (pc) => {
|
|
1424
|
+
peerConnections = peerConnections.filter((old) => old !== pc);
|
|
1425
|
+
};
|
|
1426
|
+
if (window.RTCPeerConnection) {
|
|
1427
|
+
const OriginalRTCPeerConnection = window.RTCPeerConnection;
|
|
1428
|
+
function PatchedRTCPeerConnection(rtcConfig) {
|
|
1429
|
+
const pc = new OriginalRTCPeerConnection(rtcConfig);
|
|
1430
|
+
peerConnections.push(pc);
|
|
1431
|
+
peerConnectionData.set(pc, { index: peerConnectionCounter++ });
|
|
1432
|
+
const onConnectionStateChange = () => {
|
|
1433
|
+
if (pc.connectionState === "closed") {
|
|
1434
|
+
removePeerConnection(pc);
|
|
1435
|
+
pc.removeEventListener("connectionstatechange", onConnectionStateChange);
|
|
1436
|
+
}
|
|
1437
|
+
};
|
|
1438
|
+
pc.addEventListener("connectionstatechange", onConnectionStateChange);
|
|
1439
|
+
return pc;
|
|
1899
1440
|
}
|
|
1900
|
-
|
|
1441
|
+
PatchedRTCPeerConnection.prototype = OriginalRTCPeerConnection.prototype;
|
|
1442
|
+
window.RTCPeerConnection = PatchedRTCPeerConnection;
|
|
1901
1443
|
}
|
|
1444
|
+
const getCurrentPeerConnections = () => peerConnections;
|
|
1445
|
+
const getPeerConnectionIndex = (pc) => { var _a; return (_a = peerConnectionData.get(pc)) === null || _a === void 0 ? void 0 : _a.index; };
|
|
1446
|
+
const setPeerConnectionsForTests = (pcs) => (peerConnections = pcs);
|
|
1902
1447
|
|
|
1903
|
-
const
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1448
|
+
const PC_DATA_BY_PC = new WeakMap();
|
|
1449
|
+
let numMissingTrackSsrcLookups = 0;
|
|
1450
|
+
let numFailedTrackSsrcLookups = 0;
|
|
1451
|
+
const getPeerConnectionsWithStatsReports = (pcDataByPc = PC_DATA_BY_PC) => Promise.all(getCurrentPeerConnections().map((pc) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1452
|
+
let pcData = pcDataByPc.get(pc);
|
|
1453
|
+
if (!pcData) {
|
|
1454
|
+
pcData = { ssrcToTrackId: {} };
|
|
1455
|
+
pcDataByPc.set(pc, pcData);
|
|
1456
|
+
}
|
|
1457
|
+
try {
|
|
1458
|
+
const report = yield pc.getStats();
|
|
1459
|
+
let missingSsrcs = null;
|
|
1460
|
+
report.forEach((stats) => {
|
|
1461
|
+
if (stats.type === "inbound-rtp" || stats.type === "outbound-rtp") {
|
|
1462
|
+
if (!stats.trackIdentifier && !pcData.ssrcToTrackId[stats.ssrc]) {
|
|
1463
|
+
if (stats.mediaSourceId) {
|
|
1464
|
+
const mediaSourceStats = report.get(stats.mediaSourceId);
|
|
1465
|
+
if (mediaSourceStats) {
|
|
1466
|
+
if (mediaSourceStats.trackIdentifier) {
|
|
1467
|
+
pcData.ssrcToTrackId[stats.ssrc] = mediaSourceStats.trackIdentifier;
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
if (!pcData.ssrcToTrackId[stats.ssrc] && stats.trackId) {
|
|
1472
|
+
const deprecatedTrackStats = report.get(stats.trackId);
|
|
1473
|
+
if (deprecatedTrackStats) {
|
|
1474
|
+
if (deprecatedTrackStats.trackIdentifier) {
|
|
1475
|
+
pcData.ssrcToTrackId[stats.ssrc] = deprecatedTrackStats.trackIdentifier;
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
if (!pcData.ssrcToTrackId[stats.ssrc]) {
|
|
1480
|
+
if (!missingSsrcs)
|
|
1481
|
+
missingSsrcs = [];
|
|
1482
|
+
missingSsrcs.push(stats.ssrc);
|
|
1483
|
+
}
|
|
1937
1484
|
}
|
|
1938
1485
|
}
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1486
|
+
});
|
|
1487
|
+
if (missingSsrcs) {
|
|
1488
|
+
const sendersAndReceivers = [...pc.getSenders(), ...pc.getReceivers()];
|
|
1489
|
+
const reports = yield Promise.all(sendersAndReceivers.map((o) => o.getStats()));
|
|
1490
|
+
reports.forEach((tReport, index) => {
|
|
1491
|
+
tReport.forEach((stats) => {
|
|
1492
|
+
if (stats.type === "inbound-rtp" || stats.type === "outbound-rtp") {
|
|
1493
|
+
pcData.ssrcToTrackId[stats.ssrc] = sendersAndReceivers[index].track.id;
|
|
1494
|
+
}
|
|
1495
|
+
});
|
|
1496
|
+
});
|
|
1497
|
+
missingSsrcs.forEach((ssrc) => {
|
|
1498
|
+
numMissingTrackSsrcLookups++;
|
|
1499
|
+
if (!pcData.ssrcToTrackId[ssrc]) {
|
|
1500
|
+
pcData.ssrcToTrackId[ssrc] = "?" + ssrc;
|
|
1501
|
+
}
|
|
1502
|
+
});
|
|
1946
1503
|
}
|
|
1504
|
+
return [pc, report, pcData];
|
|
1947
1505
|
}
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
}
|
|
1954
|
-
|
|
1506
|
+
catch (e) {
|
|
1507
|
+
rtcStats.sendEvent("trackSsrcLookupFailed", {
|
|
1508
|
+
name: e === null || e === void 0 ? void 0 : e.name,
|
|
1509
|
+
cause: e === null || e === void 0 ? void 0 : e.cause,
|
|
1510
|
+
message: e === null || e === void 0 ? void 0 : e.message,
|
|
1511
|
+
});
|
|
1512
|
+
numFailedTrackSsrcLookups++;
|
|
1513
|
+
return [pc, [], pcData];
|
|
1955
1514
|
}
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
return false;
|
|
1515
|
+
})));
|
|
1516
|
+
|
|
1517
|
+
const getOrCreateSsrcMetricsContainer = (statsByView, time, pcIndex, clientId, trackId, ssrc) => {
|
|
1518
|
+
let viewStats = statsByView[clientId];
|
|
1519
|
+
if (!viewStats) {
|
|
1520
|
+
viewStats = { candidatePairs: {}, tracks: {}, startTime: time, updated: time };
|
|
1521
|
+
statsByView[clientId] = viewStats;
|
|
1964
1522
|
}
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1523
|
+
viewStats.updated = time;
|
|
1524
|
+
let trackStats = viewStats.tracks[trackId];
|
|
1525
|
+
if (!trackStats) {
|
|
1526
|
+
trackStats = { ssrcs: {}, startTime: time, updated: time };
|
|
1527
|
+
viewStats.tracks[trackId] = trackStats;
|
|
1528
|
+
}
|
|
1529
|
+
trackStats.updated = time;
|
|
1530
|
+
let ssrcStats = trackStats.ssrcs[ssrc];
|
|
1531
|
+
if (!ssrcStats) {
|
|
1532
|
+
ssrcStats = {
|
|
1533
|
+
startTime: time,
|
|
1534
|
+
updated: time,
|
|
1535
|
+
pcIndex,
|
|
1536
|
+
};
|
|
1537
|
+
trackStats.ssrcs[ssrc] = ssrcStats;
|
|
1974
1538
|
}
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1539
|
+
ssrcStats.updated = time;
|
|
1540
|
+
return ssrcStats;
|
|
1541
|
+
};
|
|
1542
|
+
const removeNonUpdatedStats = (statsByView, time) => {
|
|
1543
|
+
Object.entries(statsByView).forEach(([viewId, viewStats]) => {
|
|
1544
|
+
if (viewStats.updated !== undefined && viewStats.updated < time) {
|
|
1545
|
+
delete statsByView[viewId];
|
|
1981
1546
|
}
|
|
1982
1547
|
else {
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
if (!history.currPeriod || !history.prevPeriod)
|
|
1992
|
-
throw new Error("missing period timestamps");
|
|
1993
|
-
const prevPeriodCenter = this.calculatePeriodCenterTimestamp(history.prevPeriod);
|
|
1994
|
-
const currPeriodCenter = this.calculatePeriodCenterTimestamp(history.currPeriod);
|
|
1995
|
-
const currIntervalInMs = currPeriodCenter - prevPeriodCenter;
|
|
1996
|
-
if (history.prevIntervalInMs) {
|
|
1997
|
-
const intervalDiffInMs = Math.abs(history.prevIntervalInMs - currIntervalInMs);
|
|
1998
|
-
history.hasPeriodicPacketLoss = intervalDiffInMs < this.INTERVAL_DIFF_THRESHOLD_MS;
|
|
1999
|
-
logger$9.debug("addNewPacketLossInterval() [hasPeriodicPacketLoss: %s, intervalDiffInMs: %s]", intervalDiffInMs < this.INTERVAL_DIFF_THRESHOLD_MS, intervalDiffInMs);
|
|
2000
|
-
}
|
|
2001
|
-
history.prevIntervalInMs = currIntervalInMs;
|
|
2002
|
-
history.prevPeriod = history.currPeriod;
|
|
2003
|
-
}
|
|
2004
|
-
calculatePeriodCenterTimestamp(period) {
|
|
2005
|
-
if (!period.end)
|
|
2006
|
-
throw new Error("Missing period end timestamp");
|
|
2007
|
-
return period.begin + (period.end - period.begin) / 2;
|
|
2008
|
-
}
|
|
2009
|
-
}
|
|
2010
|
-
|
|
2011
|
-
var _a$5, _b$2;
|
|
2012
|
-
const adapter$5 = (_a$5 = adapterRaw.default) !== null && _a$5 !== void 0 ? _a$5 : adapterRaw;
|
|
2013
|
-
const logger$8 = new Logger();
|
|
2014
|
-
const browserName$2 = (_b$2 = adapter$5.browserDetails) === null || _b$2 === void 0 ? void 0 : _b$2.browser;
|
|
2015
|
-
const browserVersion$1 = adapter$5.browserDetails.version;
|
|
2016
|
-
function setCodecPreferenceSDP({ sdp, redOn, incrementAnalyticMetric }) {
|
|
2017
|
-
var _a, _b;
|
|
2018
|
-
try {
|
|
2019
|
-
const sdpObject = sdpTransform.parse(sdp);
|
|
2020
|
-
if (Array.isArray(sdpObject === null || sdpObject === void 0 ? void 0 : sdpObject.media)) {
|
|
2021
|
-
const mediaAudio = sdpObject.media.find((m) => m.type === "audio");
|
|
2022
|
-
if (Array.isArray(mediaAudio === null || mediaAudio === void 0 ? void 0 : mediaAudio.rtp)) {
|
|
2023
|
-
const rtp = mediaAudio.rtp;
|
|
2024
|
-
for (let i = 0; i < rtp.length; i++) {
|
|
2025
|
-
if (redOn && rtp[i].codec === "red") {
|
|
2026
|
-
const payloads = (_a = mediaAudio.payloads) === null || _a === void 0 ? void 0 : _a.split(" ");
|
|
2027
|
-
const pt = payloads === null || payloads === void 0 ? void 0 : payloads.indexOf("" + rtp[i].payload);
|
|
2028
|
-
if (pt && pt !== -1 && pt >= 0) {
|
|
2029
|
-
payloads === null || payloads === void 0 ? void 0 : payloads.unshift(payloads.splice(pt, 1)[0]);
|
|
2030
|
-
mediaAudio.payloads = payloads === null || payloads === void 0 ? void 0 : payloads.join(" ");
|
|
1548
|
+
Object.entries(viewStats.tracks).forEach(([trackId, trackStats]) => {
|
|
1549
|
+
if (trackStats.updated < time) {
|
|
1550
|
+
delete viewStats.tracks[trackId];
|
|
1551
|
+
}
|
|
1552
|
+
else {
|
|
1553
|
+
Object.entries(trackStats.ssrcs).forEach(([ssrc, ssrcStats]) => {
|
|
1554
|
+
if (ssrcStats.updated < time) {
|
|
1555
|
+
delete trackStats.ssrcs[ssrc];
|
|
2031
1556
|
}
|
|
2032
|
-
}
|
|
1557
|
+
});
|
|
2033
1558
|
}
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1561
|
+
});
|
|
1562
|
+
};
|
|
1563
|
+
const DEFAULT_CLIENT = {
|
|
1564
|
+
id: "unknown",
|
|
1565
|
+
clientId: "unknown",
|
|
1566
|
+
audio: { enabled: false, track: undefined },
|
|
1567
|
+
video: { enabled: false, track: undefined },
|
|
1568
|
+
isAudioOnlyModeEnabled: false,
|
|
1569
|
+
isLocalClient: true,
|
|
1570
|
+
isPresentation: false,
|
|
1571
|
+
};
|
|
1572
|
+
function collectStats(state_1, _a, immediate_1) {
|
|
1573
|
+
return __awaiter(this, arguments, void 0, function* (state, { logger, interval }, immediate) {
|
|
1574
|
+
const collectStatsBound = collectStats.bind(null, state, { interval, logger });
|
|
1575
|
+
try {
|
|
1576
|
+
const clients = state.getClients();
|
|
1577
|
+
const defaultClient = clients.find((c) => c.isLocalClient && !c.isPresentation) || DEFAULT_CLIENT;
|
|
1578
|
+
let defaultViewStats = state.statsByView[defaultClient.id];
|
|
1579
|
+
if (!defaultViewStats) {
|
|
1580
|
+
defaultViewStats = { tracks: {}, candidatePairs: {}, pressure: null };
|
|
1581
|
+
state.statsByView[defaultClient.id] = defaultViewStats;
|
|
2034
1582
|
}
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
1583
|
+
defaultViewStats.pressure = state.lastPressureObserverRecord;
|
|
1584
|
+
const timeSinceLastUpdate = Date.now() - state.lastUpdateTime;
|
|
1585
|
+
if (timeSinceLastUpdate < 400) {
|
|
1586
|
+
if (immediate)
|
|
1587
|
+
return state.statsByView;
|
|
1588
|
+
state.subscriptions.forEach((subscription) => { var _a; return (_a = subscription.onUpdatedStats) === null || _a === void 0 ? void 0 : _a.call(subscription, state.statsByView, clients); });
|
|
1589
|
+
state.nextTimeout = setTimeout(collectStatsBound, interval);
|
|
1590
|
+
return;
|
|
1591
|
+
}
|
|
1592
|
+
state.lastUpdateTime = Date.now();
|
|
1593
|
+
(yield getPeerConnectionsWithStatsReports()).forEach(([pc, report, pcData]) => {
|
|
1594
|
+
const pcIndex = getPeerConnectionIndex(pc);
|
|
1595
|
+
if (pcIndex === undefined) {
|
|
1596
|
+
logger.warn("Could not find index for PeerConnection");
|
|
1597
|
+
}
|
|
1598
|
+
if (pc.connectionState === "closed") {
|
|
1599
|
+
report = new Map();
|
|
1600
|
+
removePeerConnection(pc);
|
|
1601
|
+
}
|
|
1602
|
+
pcData.previousSSRCs = pcData.currentSSRCs || {};
|
|
1603
|
+
pcData.currentSSRCs = {};
|
|
1604
|
+
report.forEach((currentRtcStats) => {
|
|
1605
|
+
var _a, _b;
|
|
1606
|
+
if (currentRtcStats.type === "candidate-pair" && /inprogress|succeeded/.test(currentRtcStats.state)) {
|
|
1607
|
+
const prevRtcStats = (_a = pcData._oldReport) === null || _a === void 0 ? void 0 : _a.get(currentRtcStats.id);
|
|
1608
|
+
const timeDiff = prevRtcStats ? currentRtcStats.timestamp - prevRtcStats.timestamp : interval;
|
|
1609
|
+
const cpId = pcIndex + ":" + currentRtcStats.id;
|
|
1610
|
+
let cpMetrics = defaultViewStats.candidatePairs[cpId];
|
|
1611
|
+
if (!cpMetrics) {
|
|
1612
|
+
cpMetrics = { startTime: state.lastUpdateTime, id: cpId };
|
|
1613
|
+
defaultViewStats.candidatePairs[cpId] = cpMetrics;
|
|
1614
|
+
}
|
|
1615
|
+
captureCandidatePairInfoMetrics(cpMetrics, currentRtcStats, prevRtcStats, timeDiff, report);
|
|
1616
|
+
cpMetrics.lastRtcStatsTime = state.lastUpdateTime;
|
|
1617
|
+
}
|
|
1618
|
+
if (currentRtcStats.type === "inbound-rtp" || currentRtcStats.type === "outbound-rtp") {
|
|
1619
|
+
const kind = (currentRtcStats.mediaType || currentRtcStats.kind);
|
|
1620
|
+
const ssrc = currentRtcStats.ssrc;
|
|
1621
|
+
let trackId = currentRtcStats.trackIdentifier || pcData.ssrcToTrackId[ssrc];
|
|
1622
|
+
let prevRtcStats = (_b = pcData._oldReport) === null || _b === void 0 ? void 0 : _b.get(currentRtcStats.id);
|
|
1623
|
+
if (prevRtcStats && prevRtcStats.mediaSourceId !== currentRtcStats.mediaSourceId) {
|
|
1624
|
+
const mediaSourceStats = report.get(currentRtcStats.mediaSourceId);
|
|
1625
|
+
if (mediaSourceStats && mediaSourceStats.trackIdentifier) {
|
|
1626
|
+
trackId = mediaSourceStats.trackIdentifier;
|
|
1627
|
+
pcData.ssrcToTrackId[ssrc] = trackId;
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
const client = clients.find((c) => { var _a; return ((_a = c[kind].track) === null || _a === void 0 ? void 0 : _a.id) === trackId; }) || defaultClient;
|
|
1631
|
+
const clientTrack = client[kind].track;
|
|
1632
|
+
if (!currentRtcStats.trackIdentifier &&
|
|
1633
|
+
pcData.ssrcToTrackId[ssrc] &&
|
|
1634
|
+
(clientTrack === null || clientTrack === void 0 ? void 0 : clientTrack.id) &&
|
|
1635
|
+
clientTrack.id !== pcData.ssrcToTrackId[ssrc]) {
|
|
1636
|
+
trackId = clientTrack.id;
|
|
1637
|
+
pcData.ssrcToTrackId[ssrc] = clientTrack.id;
|
|
1638
|
+
}
|
|
1639
|
+
pcData.currentSSRCs[ssrc] = client.id;
|
|
1640
|
+
if (prevRtcStats) {
|
|
1641
|
+
const newTransport = report.get(currentRtcStats.transportId);
|
|
1642
|
+
const oldTransport = pcData._oldReport.get(prevRtcStats.transportId);
|
|
1643
|
+
if (oldTransport &&
|
|
1644
|
+
(newTransport === null || newTransport === void 0 ? void 0 : newTransport.selectedCandidatePairId) !== oldTransport.selectedCandidatePairId) {
|
|
1645
|
+
prevRtcStats = null;
|
|
1646
|
+
}
|
|
1647
|
+
else if (currentRtcStats.bytesReceived < prevRtcStats.bytesReceived ||
|
|
1648
|
+
currentRtcStats.bytesSent < prevRtcStats.bytesSent) {
|
|
1649
|
+
prevRtcStats = null;
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
const timeDiff = prevRtcStats ? currentRtcStats.timestamp - prevRtcStats.timestamp : interval;
|
|
1653
|
+
const ssrcMetrics = getOrCreateSsrcMetricsContainer(state.statsByView, state.lastUpdateTime, pcIndex, client.id, trackId, ssrc);
|
|
1654
|
+
captureSsrcInfo(ssrcMetrics, currentRtcStats, prevRtcStats, timeDiff, report);
|
|
1655
|
+
captureCommonSsrcMetrics(ssrcMetrics, currentRtcStats, prevRtcStats, timeDiff, report);
|
|
1656
|
+
if (kind === "video") {
|
|
1657
|
+
captureVideoSsrcMetrics(ssrcMetrics, currentRtcStats, prevRtcStats, timeDiff, report);
|
|
1658
|
+
}
|
|
1659
|
+
if (kind === "audio") {
|
|
1660
|
+
captureAudioSsrcMetrics(ssrcMetrics, currentRtcStats, prevRtcStats, timeDiff, report);
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
});
|
|
1664
|
+
pcData._oldReport = report;
|
|
1665
|
+
Object.keys(pcData.previousSSRCs)
|
|
1666
|
+
.filter((ssrc) => !pcData.currentSSRCs[ssrc])
|
|
1667
|
+
.forEach((ssrc) => {
|
|
1668
|
+
const clientId = pcData.previousSSRCs[ssrc];
|
|
1669
|
+
if (clientId) {
|
|
1670
|
+
const clientView = state.statsByView[clientId];
|
|
1671
|
+
if (clientView) {
|
|
1672
|
+
Object.values(clientView.tracks).forEach((trackStats) => {
|
|
1673
|
+
if (trackStats.ssrcs[ssrc]) {
|
|
1674
|
+
delete trackStats.ssrcs[ssrc];
|
|
1675
|
+
}
|
|
1676
|
+
});
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
});
|
|
1680
|
+
});
|
|
1681
|
+
removeNonUpdatedStats(state.statsByView, state.lastUpdateTime);
|
|
1682
|
+
Object.entries((defaultViewStats === null || defaultViewStats === void 0 ? void 0 : defaultViewStats.candidatePairs) || {}).forEach(([cpKey, cp]) => {
|
|
1683
|
+
const active = cp.lastRtcStatsTime === state.lastUpdateTime;
|
|
1684
|
+
cp.active = active;
|
|
1685
|
+
if (!active) {
|
|
1686
|
+
cp.state = "old/inactive";
|
|
1687
|
+
if (!cp.inactiveFromTime)
|
|
1688
|
+
cp.inactiveFromTime = state.lastUpdateTime;
|
|
1689
|
+
else {
|
|
1690
|
+
if (state.lastUpdateTime - cp.inactiveFromTime > 4000) {
|
|
1691
|
+
delete defaultViewStats.candidatePairs[cpKey];
|
|
2045
1692
|
}
|
|
2046
1693
|
}
|
|
2047
1694
|
}
|
|
1695
|
+
});
|
|
1696
|
+
if (immediate) {
|
|
1697
|
+
return state.statsByView;
|
|
1698
|
+
}
|
|
1699
|
+
else {
|
|
1700
|
+
state.subscriptions.forEach((subscription) => { var _a; return (_a = subscription.onUpdatedStats) === null || _a === void 0 ? void 0 : _a.call(subscription, state.statsByView, clients); });
|
|
2048
1701
|
}
|
|
2049
1702
|
}
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
1703
|
+
catch (e) {
|
|
1704
|
+
logger.warn(e);
|
|
1705
|
+
state.numFailedStatsReports++;
|
|
1706
|
+
rtcStats.sendEvent("collectStatsFailed", {
|
|
1707
|
+
name: e === null || e === void 0 ? void 0 : e.name,
|
|
1708
|
+
cause: e === null || e === void 0 ? void 0 : e.cause,
|
|
1709
|
+
message: e === null || e === void 0 ? void 0 : e.message,
|
|
1710
|
+
});
|
|
1711
|
+
}
|
|
1712
|
+
state.nextTimeout = setTimeout(collectStatsBound, interval);
|
|
1713
|
+
});
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
const REGISTERED_TRIALS = {};
|
|
1717
|
+
function registerOriginTrials(trials, registeredTrials = REGISTERED_TRIALS, document = window.document) {
|
|
1718
|
+
trials.forEach(({ hostnamePattern, token }) => {
|
|
1719
|
+
const key = `${hostnamePattern}-${token}`;
|
|
1720
|
+
if (registeredTrials[key]) {
|
|
1721
|
+
return;
|
|
1722
|
+
}
|
|
1723
|
+
if (hostnamePattern.test(document.location.hostname)) {
|
|
1724
|
+
const otMeta = document.createElement("meta");
|
|
1725
|
+
otMeta.httpEquiv = "origin-trial";
|
|
1726
|
+
otMeta.content = token;
|
|
1727
|
+
document.head.append(otMeta);
|
|
1728
|
+
registeredTrials[key] = true;
|
|
1729
|
+
}
|
|
1730
|
+
});
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
const CPU_OBSERVER_OPTIONS = {
|
|
1734
|
+
sampleRate: 1,
|
|
1735
|
+
originTrials: [
|
|
1736
|
+
{
|
|
1737
|
+
hostnamePattern: /hereby\.dev/,
|
|
1738
|
+
token: "AkSNPHJw6EK08X0QU7kORnK9NABzRLAC7dqfXOwk5JwFAQG4Ey7WxLXxsnhieCgC1QHUdevE2EFICy7uBGDANwUAAABqeyJvcmlnaW4iOiJodHRwczovL2hlcmVieS5kZXY6NDQ0MyIsImZlYXR1cmUiOiJDb21wdXRlUHJlc3N1cmVfdjIiLCJleHBpcnkiOjE3MTY5NDA3OTksImlzU3ViZG9tYWluIjp0cnVlfQ==",
|
|
1739
|
+
},
|
|
1740
|
+
{
|
|
1741
|
+
hostnamePattern: /whereby\.com/,
|
|
1742
|
+
token: "Asc2wu8KpSx648i932NICteQDFcB05yl2QUUSHD7AQo8JGP2Fp6FF91TvYVJBsKGzLMH349rysPw5q9tqPC/PAUAAABqeyJvcmlnaW4iOiJodHRwczovL3doZXJlYnkuY29tOjQ0MyIsImZlYXR1cmUiOiJDb21wdXRlUHJlc3N1cmVfdjIiLCJleHBpcnkiOjE3MTY5NDA3OTksImlzU3ViZG9tYWluIjp0cnVlfQ==",
|
|
1743
|
+
},
|
|
1744
|
+
],
|
|
1745
|
+
};
|
|
1746
|
+
function startCpuObserver(cb, { sampleRate, originTrials } = CPU_OBSERVER_OPTIONS, window = globalThis.window) {
|
|
1747
|
+
registerOriginTrials(originTrials);
|
|
1748
|
+
let pressureObserver;
|
|
1749
|
+
if ("PressureObserver" in window) {
|
|
1750
|
+
pressureObserver = new window.PressureObserver(cb, { sampleRate });
|
|
1751
|
+
pressureObserver.observe("cpu", { sampleInterval: sampleRate * 1000 });
|
|
1752
|
+
return {
|
|
1753
|
+
stop: () => {
|
|
1754
|
+
pressureObserver.unobserve("cpu");
|
|
1755
|
+
},
|
|
1756
|
+
};
|
|
2058
1757
|
}
|
|
2059
1758
|
}
|
|
2060
|
-
|
|
1759
|
+
|
|
1760
|
+
const STATE = {
|
|
1761
|
+
currentMonitor: null,
|
|
1762
|
+
getClients: () => [],
|
|
1763
|
+
lastUpdateTime: 0,
|
|
1764
|
+
statsByView: {},
|
|
1765
|
+
subscriptions: [],
|
|
1766
|
+
numFailedStatsReports: 0,
|
|
1767
|
+
};
|
|
1768
|
+
const OPTIONS = {
|
|
1769
|
+
interval: 2000,
|
|
1770
|
+
logger: new Logger(),
|
|
1771
|
+
};
|
|
1772
|
+
const getStats = () => {
|
|
1773
|
+
return Object.assign({}, STATE.statsByView);
|
|
1774
|
+
};
|
|
1775
|
+
const getNumFailedStatsReports = () => {
|
|
1776
|
+
return STATE.numFailedStatsReports;
|
|
1777
|
+
};
|
|
1778
|
+
const getNumMissingTrackSsrcLookups = () => numMissingTrackSsrcLookups;
|
|
1779
|
+
const getNumFailedTrackSsrcLookups = () => numFailedTrackSsrcLookups;
|
|
1780
|
+
const getUpdatedStats = () => { var _a; return (_a = STATE.currentMonitor) === null || _a === void 0 ? void 0 : _a.getUpdatedStats(); };
|
|
1781
|
+
const setClientProvider = (provider) => (STATE.getClients = provider);
|
|
1782
|
+
function startStatsMonitor(state, { interval, logger }) {
|
|
1783
|
+
const collectStatsBound = collectStats.bind(null, state, { interval, logger });
|
|
1784
|
+
let cpuObserver;
|
|
2061
1785
|
try {
|
|
2062
|
-
|
|
2063
|
-
sdpObject.media.forEach((mediaObject) => {
|
|
2064
|
-
const usedPayloads = {};
|
|
2065
|
-
if (mediaObject.payloads)
|
|
2066
|
-
mediaObject.payloads = ("" + mediaObject.payloads)
|
|
2067
|
-
.split(" ")
|
|
2068
|
-
.filter((p) => !usedPayloads[p] && (usedPayloads[p] = true))
|
|
2069
|
-
.join(" ");
|
|
2070
|
-
const usedRtps = {};
|
|
2071
|
-
mediaObject.rtp = mediaObject.rtp.filter((p) => !p.payload || (usedPayloads[p.payload] && !usedRtps[p.payload] && (usedRtps[p.payload] = true)));
|
|
2072
|
-
const usedFmtps = {};
|
|
2073
|
-
if (mediaObject.fmtp)
|
|
2074
|
-
mediaObject.fmtp = mediaObject.fmtp.filter((p) => !p.payload ||
|
|
2075
|
-
(usedPayloads[p.payload] && !usedFmtps[p.payload] && (usedFmtps[p.payload] = true)));
|
|
2076
|
-
const usedRtcpFb = {};
|
|
2077
|
-
if (mediaObject.rtcpFb)
|
|
2078
|
-
mediaObject.rtcpFb = mediaObject.rtcpFb.filter((p) => !p.payload ||
|
|
2079
|
-
(usedPayloads[p.payload] &&
|
|
2080
|
-
!usedRtcpFb[p.payload + p.type + p.subtype] &&
|
|
2081
|
-
(usedRtcpFb[p.payload + p.type + p.subtype] = true)));
|
|
2082
|
-
});
|
|
2083
|
-
return sdpTransform.write(sdpObject);
|
|
1786
|
+
cpuObserver = startCpuObserver((records) => (state.lastPressureObserverRecord = records.pop()));
|
|
2084
1787
|
}
|
|
2085
|
-
catch (
|
|
2086
|
-
|
|
2087
|
-
}
|
|
2088
|
-
function deprioritizeH264(sdp) {
|
|
2089
|
-
return SDPUtils.splitSections(sdp)
|
|
2090
|
-
.map((section) => {
|
|
2091
|
-
if (SDPUtils.getKind(section) !== "video")
|
|
2092
|
-
return section;
|
|
2093
|
-
const h264payloadTypes = SDPUtils.matchPrefix(section, "a=rtpmap:")
|
|
2094
|
-
.map((line) => SDPUtils.parseRtpMap(line))
|
|
2095
|
-
.filter((codec) => /h264/i.test(codec.name))
|
|
2096
|
-
.map((codec) => "" + codec.payloadType);
|
|
2097
|
-
if (!h264payloadTypes.length)
|
|
2098
|
-
return section;
|
|
2099
|
-
const mline = SDPUtils.matchPrefix(section, "m=video")[0];
|
|
2100
|
-
const mlinePayloadsSectionExec = /(\s\d+)+$/i.exec(mline);
|
|
2101
|
-
const mlinePayloadsSection = mlinePayloadsSectionExec ? mlinePayloadsSectionExec[0] : "";
|
|
2102
|
-
const mlinePayloadsNonH264 = mlinePayloadsSection
|
|
2103
|
-
.split(" ")
|
|
2104
|
-
.filter((payloadType) => payloadType && !h264payloadTypes.includes(payloadType));
|
|
2105
|
-
const reorderedPayloads = [...mlinePayloadsNonH264, ...h264payloadTypes].join(" ");
|
|
2106
|
-
const newmline = mline.replace(mlinePayloadsSection, " " + reorderedPayloads);
|
|
2107
|
-
return section.replace(mline, newmline);
|
|
2108
|
-
})
|
|
2109
|
-
.join("");
|
|
2110
|
-
}
|
|
2111
|
-
function filterMidExtension(sdp) {
|
|
2112
|
-
if (browserName$2 !== "firefox" || (browserVersion$1 && browserVersion$1 >= 63) || browserVersion$1 === 60) {
|
|
2113
|
-
return sdp;
|
|
1788
|
+
catch (ex) {
|
|
1789
|
+
logger.warn("Failed to observe CPU pressure", ex);
|
|
2114
1790
|
}
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
return true;
|
|
2119
|
-
}
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
1791
|
+
setTimeout(collectStatsBound, interval);
|
|
1792
|
+
return {
|
|
1793
|
+
getUpdatedStats: () => {
|
|
1794
|
+
return collectStatsBound(true);
|
|
1795
|
+
},
|
|
1796
|
+
stop: () => {
|
|
1797
|
+
clearTimeout(state.nextTimeout);
|
|
1798
|
+
cpuObserver === null || cpuObserver === void 0 ? void 0 : cpuObserver.stop();
|
|
1799
|
+
},
|
|
1800
|
+
};
|
|
2124
1801
|
}
|
|
2125
|
-
function
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
return
|
|
2130
|
-
|
|
2131
|
-
|
|
1802
|
+
function subscribeStats(subscription, options = OPTIONS, state = STATE) {
|
|
1803
|
+
state.subscriptions.push(subscription);
|
|
1804
|
+
if (!state.currentMonitor)
|
|
1805
|
+
state.currentMonitor = startStatsMonitor(state, options);
|
|
1806
|
+
return {
|
|
1807
|
+
stop() {
|
|
1808
|
+
var _a;
|
|
1809
|
+
state.subscriptions = state.subscriptions.filter((s) => s !== subscription);
|
|
1810
|
+
if (!state.subscriptions.length) {
|
|
1811
|
+
(_a = state.currentMonitor) === null || _a === void 0 ? void 0 : _a.stop();
|
|
1812
|
+
state.currentMonitor = null;
|
|
1813
|
+
}
|
|
1814
|
+
},
|
|
1815
|
+
};
|
|
2132
1816
|
}
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
1817
|
+
|
|
1818
|
+
const logger$7 = new Logger();
|
|
1819
|
+
class ReconnectManager extends EventEmitter {
|
|
1820
|
+
constructor(socket) {
|
|
1821
|
+
super();
|
|
1822
|
+
this.reconnectThresholdInMs = 0;
|
|
1823
|
+
this._socket = socket;
|
|
1824
|
+
this._clients = {};
|
|
1825
|
+
this._signalDisconnectTime = undefined;
|
|
1826
|
+
this.rtcManager = undefined;
|
|
1827
|
+
this.metrics = {
|
|
1828
|
+
roomJoinedLate: 0,
|
|
1829
|
+
pendingClientCanceled: 0,
|
|
1830
|
+
evaluationFailed: 0,
|
|
1831
|
+
roomJoined: 0,
|
|
1832
|
+
};
|
|
1833
|
+
socket.on("disconnect", () => {
|
|
1834
|
+
this._signalDisconnectTime = Date.now();
|
|
1835
|
+
});
|
|
1836
|
+
socket.on(PROTOCOL_RESPONSES.ROOM_JOINED, (payload) => this._onRoomJoined(payload));
|
|
1837
|
+
socket.on(PROTOCOL_RESPONSES.NEW_CLIENT, (payload) => this._onNewClient(payload));
|
|
1838
|
+
socket.on(PROTOCOL_RESPONSES.CLIENT_LEFT, (payload) => this._onClientLeft(payload));
|
|
1839
|
+
socket.on(PROTOCOL_EVENTS.PENDING_CLIENT_LEFT, (payload) => this._onPendingClientLeft(payload));
|
|
1840
|
+
socket.on(PROTOCOL_RESPONSES.AUDIO_ENABLED, (payload) => this._onAudioEnabled(payload));
|
|
1841
|
+
socket.on(PROTOCOL_RESPONSES.VIDEO_ENABLED, (payload) => this._onVideoEnabled(payload));
|
|
1842
|
+
socket.on(PROTOCOL_RESPONSES.SCREENSHARE_STARTED, (payload) => this._onScreenshareChanged(payload, true));
|
|
1843
|
+
socket.on(PROTOCOL_RESPONSES.SCREENSHARE_STOPPED, (payload) => this._onScreenshareChanged(payload, false));
|
|
1844
|
+
}
|
|
1845
|
+
_onRoomJoined(payload) {
|
|
1846
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2148
1847
|
var _a;
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
1848
|
+
this.reconnectThresholdInMs = (payload.disconnectTimeout || 0) * 0.8;
|
|
1849
|
+
if (payload === null || payload === void 0 ? void 0 : payload.error) {
|
|
1850
|
+
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1851
|
+
return;
|
|
1852
|
+
}
|
|
1853
|
+
if (!payload.selfId) {
|
|
1854
|
+
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1855
|
+
return;
|
|
1856
|
+
}
|
|
1857
|
+
const myDeviceId = (_a = payload.room.clients.find((c) => payload.selfId === c.id)) === null || _a === void 0 ? void 0 : _a.deviceId;
|
|
1858
|
+
if (!myDeviceId) {
|
|
1859
|
+
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1860
|
+
return;
|
|
1861
|
+
}
|
|
1862
|
+
if (!this._signalDisconnectTime) {
|
|
1863
|
+
this._resetClientState(payload);
|
|
1864
|
+
payload.room.clients = payload.room.clients.filter((c) => !(c.deviceId === myDeviceId && c.isPendingToLeave));
|
|
1865
|
+
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1866
|
+
return;
|
|
1867
|
+
}
|
|
1868
|
+
const RECONNECT_THRESHOLD = payload.disconnectTimeout * 0.8;
|
|
1869
|
+
const timeSinceDisconnect = Date.now() - this._signalDisconnectTime;
|
|
1870
|
+
if (timeSinceDisconnect > RECONNECT_THRESHOLD) {
|
|
1871
|
+
this._resetClientState(payload);
|
|
1872
|
+
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
1873
|
+
this.metrics.roomJoinedLate++;
|
|
1874
|
+
return;
|
|
1875
|
+
}
|
|
1876
|
+
payload.room.clients = payload.room.clients.filter((c) => !(c.deviceId === myDeviceId && c.isPendingToLeave));
|
|
1877
|
+
const allStats = yield getUpdatedStats();
|
|
1878
|
+
payload.room.clients.forEach((client) => {
|
|
1879
|
+
var _a;
|
|
1880
|
+
try {
|
|
1881
|
+
if (client.id === payload.selfId)
|
|
1882
|
+
return;
|
|
1883
|
+
if (!this._clients[client.id]) {
|
|
1884
|
+
this._addClientToState(client);
|
|
1885
|
+
return;
|
|
2153
1886
|
}
|
|
2154
|
-
|
|
2155
|
-
|
|
1887
|
+
if (!((_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.hasClient(client.id))) {
|
|
1888
|
+
return;
|
|
1889
|
+
}
|
|
1890
|
+
if (this._hasClientStateChanged({
|
|
1891
|
+
clientId: client.id,
|
|
1892
|
+
webcam: client.isVideoEnabled,
|
|
1893
|
+
mic: client.isAudioEnabled,
|
|
1894
|
+
screenShare: client.streams.length > 1,
|
|
1895
|
+
})) {
|
|
1896
|
+
return;
|
|
1897
|
+
}
|
|
1898
|
+
if (this._wasClientSendingMedia(client.id)) {
|
|
1899
|
+
if (!this._isClientMediaActive(allStats, client.id)) {
|
|
1900
|
+
return;
|
|
1901
|
+
}
|
|
2156
1902
|
}
|
|
1903
|
+
client.mergeWithOldClientState = true;
|
|
2157
1904
|
}
|
|
2158
|
-
|
|
1905
|
+
catch (error) {
|
|
1906
|
+
logger$7.error("Failed to evaluate if we should merge client state %o", error);
|
|
1907
|
+
this.metrics.evaluationFailed++;
|
|
1908
|
+
}
|
|
1909
|
+
});
|
|
1910
|
+
payload.room.clients.forEach((c) => {
|
|
1911
|
+
if (c.isPendingToLeave) {
|
|
1912
|
+
this._onPendingClientLeft({ clientId: c.id });
|
|
1913
|
+
}
|
|
1914
|
+
});
|
|
1915
|
+
this.metrics.roomJoined++;
|
|
1916
|
+
this.emit(PROTOCOL_RESPONSES.ROOM_JOINED, payload);
|
|
2159
1917
|
});
|
|
2160
|
-
return sdpTransform.write(sdpObj);
|
|
2161
|
-
}
|
|
2162
|
-
catch (error) {
|
|
2163
|
-
console.error("Error during addAbsCaptureTimeExtMap: ", error);
|
|
2164
|
-
}
|
|
2165
|
-
return sdp;
|
|
2166
|
-
}
|
|
2167
|
-
function addAbsCaptureTimeExtMap(sdp) {
|
|
2168
|
-
const absCaptureTimeUri = "http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time";
|
|
2169
|
-
return addExtMap(sdp, absCaptureTimeUri, true, true);
|
|
2170
|
-
}
|
|
2171
|
-
|
|
2172
|
-
function setVideoBandwidthUsingSetParameters(pc, bandwidth, logger = console) {
|
|
2173
|
-
const sender = pc.getSenders().find((s) => s.track && s.track.kind === "video");
|
|
2174
|
-
if (!sender) {
|
|
2175
|
-
return Promise.resolve();
|
|
2176
|
-
}
|
|
2177
|
-
const parameters = sender.getParameters();
|
|
2178
|
-
if (parameters.encodings && parameters.encodings.length === 0) {
|
|
2179
|
-
return Promise.resolve();
|
|
2180
1918
|
}
|
|
2181
|
-
|
|
2182
|
-
|
|
1919
|
+
_onClientLeft(payload) {
|
|
1920
|
+
var _a;
|
|
1921
|
+
const { clientId } = payload;
|
|
1922
|
+
const client = this._clients[clientId];
|
|
1923
|
+
if (client) {
|
|
1924
|
+
clearTimeout(client.timeout);
|
|
1925
|
+
delete this._clients[clientId];
|
|
1926
|
+
}
|
|
1927
|
+
(_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.disconnect(clientId, payload.eventClaim);
|
|
1928
|
+
this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, payload);
|
|
2183
1929
|
}
|
|
2184
|
-
|
|
2185
|
-
|
|
1930
|
+
_onPendingClientLeft(payload) {
|
|
1931
|
+
const { clientId } = payload;
|
|
1932
|
+
const client = this._clients[clientId];
|
|
1933
|
+
if (!client) {
|
|
1934
|
+
logger$7.warn(`client ${clientId} not found`);
|
|
1935
|
+
return;
|
|
1936
|
+
}
|
|
1937
|
+
if (client.isPendingToLeave) {
|
|
1938
|
+
return;
|
|
1939
|
+
}
|
|
1940
|
+
client.isPendingToLeave = true;
|
|
1941
|
+
if (this._wasClientSendingMedia(clientId)) {
|
|
1942
|
+
client.checkActiveMediaAttempts = 0;
|
|
1943
|
+
this._abortIfNotActive(payload);
|
|
1944
|
+
}
|
|
2186
1945
|
}
|
|
2187
|
-
|
|
2188
|
-
|
|
1946
|
+
_onNewClient(payload) {
|
|
1947
|
+
const { client: { id: clientId, deviceId }, } = payload;
|
|
1948
|
+
const client = this._clients[clientId];
|
|
1949
|
+
if (client && client.isPendingToLeave) {
|
|
1950
|
+
clearTimeout(client.timeoutHandler);
|
|
1951
|
+
client.isPendingToLeave = false;
|
|
1952
|
+
this.metrics.pendingClientCanceled++;
|
|
1953
|
+
return;
|
|
1954
|
+
}
|
|
1955
|
+
this._getPendingClientsByDeviceId(deviceId).forEach((client) => {
|
|
1956
|
+
clearTimeout(client.timeoutHandler);
|
|
1957
|
+
client.isPendingToLeave = undefined;
|
|
1958
|
+
this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, { clientId: client.clientId });
|
|
1959
|
+
});
|
|
1960
|
+
this._addClientToState(payload.client);
|
|
1961
|
+
this.emit(PROTOCOL_RESPONSES.NEW_CLIENT, payload);
|
|
2189
1962
|
}
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
class Session {
|
|
2199
|
-
constructor({ clientId, bandwidth, peerConnectionConfig, deprioritizeH264Encoding, incrementAnalyticMetric, }) {
|
|
2200
|
-
this.relayCandidateSeen = false;
|
|
2201
|
-
this.serverReflexiveCandidateSeen = false;
|
|
2202
|
-
this.publicHostCandidateSeen = false;
|
|
2203
|
-
this.ipv6HostCandidateSeen = false;
|
|
2204
|
-
this.ipv6HostCandidateTeredoSeen = false;
|
|
2205
|
-
this.ipv6HostCandidate6to4Seen = false;
|
|
2206
|
-
this.mdnsHostCandidateSeen = false;
|
|
2207
|
-
this.pendingReplaceTrackActions = [];
|
|
2208
|
-
this.peerConnectionConfig = peerConnectionConfig;
|
|
2209
|
-
this.clientId = clientId;
|
|
2210
|
-
this.pc = new RTCPeerConnection(this.peerConnectionConfig);
|
|
2211
|
-
this.signalingState = this.pc.signalingState;
|
|
2212
|
-
this.pc.addEventListener("signalingstatechange", () => {
|
|
2213
|
-
if (this.signalingState === this.pc.signalingState) {
|
|
1963
|
+
_abortIfNotActive(payload) {
|
|
1964
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1965
|
+
const { clientId } = payload;
|
|
1966
|
+
let client = this._clients[clientId];
|
|
1967
|
+
if (!(client === null || client === void 0 ? void 0 : client.isPendingToLeave))
|
|
1968
|
+
return;
|
|
1969
|
+
client.checkActiveMediaAttempts++;
|
|
1970
|
+
if (client.checkActiveMediaAttempts > 3) {
|
|
2214
1971
|
return;
|
|
2215
1972
|
}
|
|
2216
|
-
|
|
2217
|
-
if (
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
1973
|
+
const stillActive = yield this._checkIsActive(clientId);
|
|
1974
|
+
if (stillActive) {
|
|
1975
|
+
client.timeoutHandler = setTimeout(() => this._abortIfNotActive(payload), 500);
|
|
1976
|
+
return;
|
|
1977
|
+
}
|
|
1978
|
+
client = this._clients[clientId];
|
|
1979
|
+
if (client === null || client === void 0 ? void 0 : client.isPendingToLeave) {
|
|
1980
|
+
clearTimeout(client.timeoutHandler);
|
|
1981
|
+
delete this._clients[clientId];
|
|
1982
|
+
this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, payload);
|
|
2223
1983
|
}
|
|
2224
1984
|
});
|
|
2225
|
-
this.wasEverConnected = false;
|
|
2226
|
-
this.connectionStatus = null;
|
|
2227
|
-
this.bandwidth = bandwidth || 0;
|
|
2228
|
-
this.pending = [];
|
|
2229
|
-
this.isOperationPending = false;
|
|
2230
|
-
this.streamIds = [];
|
|
2231
|
-
this.streams = [];
|
|
2232
|
-
this.earlyIceCandidates = [];
|
|
2233
|
-
this.afterConnected = new Promise((resolve) => {
|
|
2234
|
-
this.registerConnected = resolve;
|
|
2235
|
-
});
|
|
2236
|
-
this._deprioritizeH264Encoding = deprioritizeH264Encoding;
|
|
2237
|
-
this._incrementAnalyticMetric = incrementAnalyticMetric;
|
|
2238
1985
|
}
|
|
2239
|
-
|
|
2240
|
-
this
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
this.pc.addTrack(track, stream);
|
|
2244
|
-
});
|
|
2245
|
-
stream.getVideoTracks().forEach((track) => {
|
|
2246
|
-
this.pc.addTrack(track, stream);
|
|
1986
|
+
_checkIsActive(clientId) {
|
|
1987
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1988
|
+
const allStats = yield getUpdatedStats();
|
|
1989
|
+
return this._isClientMediaActive(allStats, clientId);
|
|
2247
1990
|
});
|
|
2248
1991
|
}
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
1992
|
+
_isClientMediaActive(stats, clientId) {
|
|
1993
|
+
const clientStats = stats === null || stats === void 0 ? void 0 : stats[clientId];
|
|
1994
|
+
let isActive = false;
|
|
1995
|
+
if (clientStats) {
|
|
1996
|
+
Object.entries(clientStats.tracks).forEach(([trackId, trackStats]) => {
|
|
1997
|
+
if (trackId !== "probator")
|
|
1998
|
+
Object.values(trackStats.ssrcs).forEach((ssrcStats) => {
|
|
1999
|
+
if ((ssrcStats.bitrate || 0) > 0)
|
|
2000
|
+
isActive = true;
|
|
2001
|
+
});
|
|
2002
|
+
});
|
|
2252
2003
|
}
|
|
2253
|
-
|
|
2254
|
-
this.pc.addTrack(track, stream);
|
|
2004
|
+
return isActive;
|
|
2255
2005
|
}
|
|
2256
|
-
|
|
2257
|
-
const
|
|
2258
|
-
|
|
2259
|
-
const sender = this.pc.getSenders().find((sender) => sender.track === track);
|
|
2260
|
-
if (sender) {
|
|
2261
|
-
this.pc.removeTrack(sender);
|
|
2262
|
-
}
|
|
2006
|
+
_onAudioEnabled(payload) {
|
|
2007
|
+
const { clientId, isAudioEnabled } = payload;
|
|
2008
|
+
this._clients[clientId] = Object.assign(Object.assign({}, (this._clients[clientId] || {})), { isAudioEnabled });
|
|
2263
2009
|
}
|
|
2264
|
-
|
|
2265
|
-
const
|
|
2266
|
-
|
|
2267
|
-
|
|
2010
|
+
_onVideoEnabled(payload) {
|
|
2011
|
+
const { clientId, isVideoEnabled } = payload;
|
|
2012
|
+
this._clients[clientId] = Object.assign(Object.assign({}, (this._clients[clientId] || {})), { isVideoEnabled });
|
|
2013
|
+
}
|
|
2014
|
+
_onScreenshareChanged(payload, action) {
|
|
2015
|
+
const { clientId } = payload;
|
|
2016
|
+
this._clients[clientId] = Object.assign(Object.assign({}, (this._clients[clientId] || {})), { isScreenshareEnabled: action });
|
|
2017
|
+
}
|
|
2018
|
+
_hasClientStateChanged({ clientId, webcam, mic, screenShare, }) {
|
|
2019
|
+
const state = this._clients[clientId];
|
|
2020
|
+
if (!state) {
|
|
2021
|
+
throw new Error(`Client ${clientId} not found in ReconnectManager state`);
|
|
2268
2022
|
}
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2023
|
+
if (webcam !== state.isVideoEnabled) {
|
|
2024
|
+
return true;
|
|
2025
|
+
}
|
|
2026
|
+
if (mic !== state.isAudioEnabled) {
|
|
2027
|
+
return true;
|
|
2028
|
+
}
|
|
2029
|
+
if (screenShare !== state.isScreenshareEnabled) {
|
|
2030
|
+
return true;
|
|
2031
|
+
}
|
|
2032
|
+
return false;
|
|
2033
|
+
}
|
|
2034
|
+
_addClientToState(newClient) {
|
|
2035
|
+
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 });
|
|
2036
|
+
}
|
|
2037
|
+
_wasClientSendingMedia(clientId) {
|
|
2038
|
+
const client = this._clients[clientId];
|
|
2039
|
+
if (!client) {
|
|
2040
|
+
throw new Error(`Client ${clientId} not found in ReconnectManager state`);
|
|
2272
2041
|
}
|
|
2273
|
-
|
|
2274
|
-
const sender = this.pc.getSenders().find((sender) => sender.track === track);
|
|
2275
|
-
if (sender) {
|
|
2276
|
-
this.pc.removeTrack(sender);
|
|
2277
|
-
}
|
|
2278
|
-
});
|
|
2042
|
+
return client.isAudioEnabled || client.isVideoEnabled || client.isScreenshareEnabled;
|
|
2279
2043
|
}
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
this.srdComplete = this.pc.setRemoteDescription(desc);
|
|
2284
|
-
return this.srdComplete.then(() => {
|
|
2285
|
-
this.earlyIceCandidates.forEach((candidate) => this.pc.addIceCandidate(candidate));
|
|
2286
|
-
this.earlyIceCandidates = [];
|
|
2044
|
+
_getPendingClientsByDeviceId(deviceId) {
|
|
2045
|
+
return Object.values(this._clients).filter((clientState) => {
|
|
2046
|
+
return clientState.deviceId === deviceId && clientState.isPendingToLeave;
|
|
2287
2047
|
});
|
|
2288
2048
|
}
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
}
|
|
2295
|
-
this.isOperationPending = true;
|
|
2296
|
-
let sdp = offer.sdp;
|
|
2297
|
-
sdp = filterMidExtension(sdp);
|
|
2298
|
-
sdp = filterMsidSemantic(sdp);
|
|
2299
|
-
const desc = { type: offer.type, sdp };
|
|
2300
|
-
let answerToSignal;
|
|
2301
|
-
return this._setRemoteDescription(desc)
|
|
2302
|
-
.then(() => {
|
|
2303
|
-
return this.pc.createAnswer();
|
|
2304
|
-
})
|
|
2305
|
-
.then((answer) => {
|
|
2306
|
-
if (!answer.sdp) {
|
|
2307
|
-
this._incrementAnalyticMetric("P2PCreateAnswerNoSDP");
|
|
2308
|
-
rtcStats.sendEvent("P2PCreateAnswerNoSDP", {});
|
|
2309
|
-
throw new Error("SDP undefined while creating answer");
|
|
2049
|
+
_resetClientState(payload) {
|
|
2050
|
+
this._clients = {};
|
|
2051
|
+
payload.room.clients.forEach((client) => {
|
|
2052
|
+
if (client.id === payload.selfId) {
|
|
2053
|
+
return;
|
|
2310
2054
|
}
|
|
2311
2055
|
else {
|
|
2312
|
-
|
|
2313
|
-
sdp: answer.sdp,
|
|
2314
|
-
sdpU: answer.sdp,
|
|
2315
|
-
type: answer.type,
|
|
2316
|
-
};
|
|
2317
|
-
return this.pc.setLocalDescription(answer);
|
|
2056
|
+
this._addClientToState(client);
|
|
2318
2057
|
}
|
|
2319
|
-
})
|
|
2320
|
-
.then(() => {
|
|
2321
|
-
return setVideoBandwidthUsingSetParameters(this.pc, this.bandwidth);
|
|
2322
|
-
})
|
|
2323
|
-
.then(() => {
|
|
2324
|
-
return answerToSignal;
|
|
2325
2058
|
});
|
|
2326
2059
|
}
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
const DISCONNECT_DURATION_LIMIT_MS$1 = 60000;
|
|
2063
|
+
const SIGNAL_PING_INTERVAL = 2000;
|
|
2064
|
+
const SIGNAL_PING_MAX_LATENCY = 1000;
|
|
2065
|
+
class KeepAliveManager {
|
|
2066
|
+
constructor(serverSocket) {
|
|
2067
|
+
this.lastPingTimestamp = Date.now();
|
|
2068
|
+
this._disconnectDurationLimitEnabled = false;
|
|
2069
|
+
this.disconnectDurationLimitExceeded = false;
|
|
2070
|
+
this.serverSocket = serverSocket;
|
|
2071
|
+
this.serverSocket.on("connect", () => this.onConnect());
|
|
2072
|
+
this.serverSocket.onEngineEvent("ping", () => this.onPing());
|
|
2073
|
+
this.serverSocket.on("disconnect", () => this.onDisconnect());
|
|
2074
|
+
this.serverSocket.onEngineEvent("reconnect_attempt", () => this.onReconnectAttempt());
|
|
2333
2075
|
}
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
this.earlyIceCandidates.push(candidate);
|
|
2337
|
-
return;
|
|
2338
|
-
}
|
|
2339
|
-
this.srdComplete.then(() => {
|
|
2340
|
-
var _a;
|
|
2341
|
-
if (this.pc.signalingState === "closed") {
|
|
2342
|
-
return;
|
|
2343
|
-
}
|
|
2344
|
-
if (((_a = adapter$4.browserDetails) === null || _a === void 0 ? void 0 : _a.browser) === "safari" && candidate && candidate.candidate === "") {
|
|
2345
|
-
return;
|
|
2346
|
-
}
|
|
2347
|
-
this.pc.addIceCandidate(candidate).catch((e) => {
|
|
2348
|
-
logger$7.warn("Failed to add ICE candidate ('%s'): %s", candidate ? candidate.candidate : null, e);
|
|
2349
|
-
});
|
|
2350
|
-
});
|
|
2076
|
+
enableDisconnectDurationLimit() {
|
|
2077
|
+
this._disconnectDurationLimitEnabled = true;
|
|
2351
2078
|
}
|
|
2352
|
-
|
|
2353
|
-
|
|
2079
|
+
pingHeartbeat() {
|
|
2080
|
+
clearTimeout(this.pingTimer);
|
|
2081
|
+
this.pingTimer = setTimeout(() => {
|
|
2082
|
+
this.serverSocket._socket.io.engine.close();
|
|
2083
|
+
}, SIGNAL_PING_INTERVAL + SIGNAL_PING_MAX_LATENCY);
|
|
2084
|
+
this.lastPingTimestamp = Date.now();
|
|
2354
2085
|
}
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
if (!pc) {
|
|
2358
|
-
return;
|
|
2359
|
-
}
|
|
2360
|
-
pc.oniceconnectionstatechange = null;
|
|
2361
|
-
pc.onicecandidate = null;
|
|
2362
|
-
pc.ontrack = null;
|
|
2363
|
-
try {
|
|
2364
|
-
pc.close();
|
|
2365
|
-
}
|
|
2366
|
-
catch (e) {
|
|
2367
|
-
logger$7.warn("failures during close of session", e);
|
|
2368
|
-
}
|
|
2086
|
+
onConnect() {
|
|
2087
|
+
this.pingHeartbeat();
|
|
2369
2088
|
}
|
|
2370
|
-
|
|
2371
|
-
|
|
2089
|
+
onPing() {
|
|
2090
|
+
this.pingHeartbeat();
|
|
2372
2091
|
}
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2092
|
+
onDisconnect() {
|
|
2093
|
+
clearTimeout(this.pingTimer);
|
|
2094
|
+
}
|
|
2095
|
+
onReconnectAttempt() {
|
|
2096
|
+
if (this._disconnectDurationLimitEnabled) {
|
|
2097
|
+
this.disconnectDurationLimitExceeded = Boolean(Date.now() - this.lastPingTimestamp > DISCONNECT_DURATION_LIMIT_MS$1);
|
|
2098
|
+
if (this.disconnectDurationLimitExceeded) {
|
|
2099
|
+
this.serverSocket.disconnect();
|
|
2378
2100
|
}
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
var _a$3;
|
|
2106
|
+
const adapter$3 = (_a$3 = adapterRaw.default) !== null && _a$3 !== void 0 ? _a$3 : adapterRaw;
|
|
2107
|
+
const DEFAULT_SOCKET_PATH = "/protocol/socket.io/v4";
|
|
2108
|
+
const NOOP_KEEPALIVE_INTERVAL = 2000;
|
|
2109
|
+
const DISCONNECT_DURATION_LIMIT_MS = 60000;
|
|
2110
|
+
class ServerSocket {
|
|
2111
|
+
constructor(hostName, optionsOverrides, glitchFree = false, disconnectDurationLimitOn = false, serverSideDisconnectDurationLimitOn = false) {
|
|
2112
|
+
this._wasConnectedUsingWebsocket = false;
|
|
2113
|
+
this._disconnectDurationLimitOn = disconnectDurationLimitOn && !serverSideDisconnectDurationLimitOn;
|
|
2114
|
+
this._serverSideDisconnectDurationLimitOn = serverSideDisconnectDurationLimitOn;
|
|
2115
|
+
this._disconnectDurationLimitExceeded = false;
|
|
2116
|
+
this._reconnectManager = null;
|
|
2117
|
+
this._socket = io(hostName, Object.assign({ path: DEFAULT_SOCKET_PATH, randomizationFactor: 0.5, reconnectionDelay: 250, reconnectionDelayMax: 5000, timeout: 5000, transports: ["websocket"], withCredentials: true }, optionsOverrides));
|
|
2118
|
+
this._disconnectDurationLimitEnabled = false;
|
|
2119
|
+
this.joinRoomFinished = false;
|
|
2120
|
+
this._socket.io.on("reconnect", () => {
|
|
2121
|
+
if (this._disconnectDurationLimitOn &&
|
|
2122
|
+
this._didExceedDisconnectDurationLimit(this._disconnectDurationLimitLatestTimestamp)) {
|
|
2123
|
+
this._socket.close();
|
|
2124
|
+
this._disconnectDurationLimitExceeded = true;
|
|
2125
|
+
}
|
|
2126
|
+
this._socket.sendBuffer = [];
|
|
2127
|
+
});
|
|
2128
|
+
this._socket.io.on("reconnect_attempt", () => {
|
|
2129
|
+
var _a;
|
|
2130
|
+
if (this._disconnectDurationLimitOn &&
|
|
2131
|
+
this._didExceedDisconnectDurationLimit(this._disconnectDurationLimitLatestTimestamp)) {
|
|
2132
|
+
this._socket.close();
|
|
2133
|
+
this._disconnectDurationLimitExceeded = true;
|
|
2134
|
+
}
|
|
2135
|
+
if (this._wasConnectedUsingWebsocket) {
|
|
2136
|
+
this._socket.io.opts.transports = ["websocket"];
|
|
2137
|
+
if (((_a = adapter$3.browserDetails) === null || _a === void 0 ? void 0 : _a.browser) !== "safari") {
|
|
2138
|
+
delete this._wasConnectedUsingWebsocket;
|
|
2384
2139
|
}
|
|
2385
2140
|
}
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
return (track === null || track === void 0 ? void 0 : track.kind) === newTrack.kind && !trackAnnotations(track).fromGetDisplayMedia;
|
|
2389
|
-
});
|
|
2390
|
-
if (sender) {
|
|
2391
|
-
return yield sender.replaceTrack(newTrack);
|
|
2141
|
+
else {
|
|
2142
|
+
this._socket.io.opts.transports = ["websocket", "polling"];
|
|
2392
2143
|
}
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
newTrackIsEffect: trackAnnotations(newTrack).isEffectTrack,
|
|
2402
|
-
});
|
|
2403
|
-
this._incrementAnalyticMetric("P2PReplaceTrackNewTrackNotInStream");
|
|
2144
|
+
});
|
|
2145
|
+
if (glitchFree)
|
|
2146
|
+
this._reconnectManager = new ReconnectManager(this._socket);
|
|
2147
|
+
if (this._serverSideDisconnectDurationLimitOn)
|
|
2148
|
+
this._keepAliveManager = new KeepAliveManager(this);
|
|
2149
|
+
this._socket.on("room_joined", (payload) => {
|
|
2150
|
+
if (!("error" in payload)) {
|
|
2151
|
+
this.joinRoomFinished = true;
|
|
2404
2152
|
}
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2153
|
+
});
|
|
2154
|
+
this._socket.on("connect", () => {
|
|
2155
|
+
const transport = this.getTransport();
|
|
2156
|
+
if (transport === "websocket") {
|
|
2157
|
+
this._wasConnectedUsingWebsocket = true;
|
|
2158
|
+
if (this._serverSideDisconnectDurationLimitOn)
|
|
2159
|
+
return;
|
|
2160
|
+
if (!this.noopKeepaliveInterval) {
|
|
2161
|
+
let disconnectDurationLimitTimestampCandidate = Date.now();
|
|
2162
|
+
this.noopKeepaliveInterval = setInterval(() => {
|
|
2163
|
+
try {
|
|
2164
|
+
if (this._socket.connected) {
|
|
2165
|
+
if (this._disconnectDurationLimitOn &&
|
|
2166
|
+
!this._didExceedDisconnectDurationLimit(disconnectDurationLimitTimestampCandidate)) {
|
|
2167
|
+
this._disconnectDurationLimitLatestTimestamp =
|
|
2168
|
+
disconnectDurationLimitTimestampCandidate;
|
|
2169
|
+
disconnectDurationLimitTimestampCandidate = Date.now();
|
|
2170
|
+
}
|
|
2171
|
+
this._socket.io.engine.sendPacket("noop");
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
catch (ex) { }
|
|
2175
|
+
}, NOOP_KEEPALIVE_INTERVAL);
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
});
|
|
2179
|
+
this._socket.on("disconnect", () => {
|
|
2180
|
+
this.joinRoomFinished = false;
|
|
2181
|
+
this.disconnectTimestamp = Date.now();
|
|
2182
|
+
if (this._serverSideDisconnectDurationLimitOn)
|
|
2183
|
+
return;
|
|
2184
|
+
if (this._disconnectDurationLimitOn &&
|
|
2185
|
+
this._didExceedDisconnectDurationLimit(this._disconnectDurationLimitLatestTimestamp)) {
|
|
2186
|
+
this._socket.close();
|
|
2187
|
+
this._disconnectDurationLimitExceeded = true;
|
|
2188
|
+
}
|
|
2189
|
+
if (this.noopKeepaliveInterval) {
|
|
2190
|
+
clearInterval(this.noopKeepaliveInterval);
|
|
2191
|
+
this.noopKeepaliveInterval = null;
|
|
2410
2192
|
}
|
|
2411
|
-
pc.addTrack(newTrack, stream);
|
|
2412
2193
|
});
|
|
2413
2194
|
}
|
|
2414
|
-
|
|
2195
|
+
_didExceedDisconnectDurationLimit(timestamp) {
|
|
2196
|
+
if (!timestamp || !this._disconnectDurationLimitOn || !this._disconnectDurationLimitEnabled)
|
|
2197
|
+
return false;
|
|
2198
|
+
const disconnectedDuration = Date.now() - timestamp;
|
|
2199
|
+
if (disconnectedDuration > DISCONNECT_DURATION_LIMIT_MS) {
|
|
2200
|
+
return true;
|
|
2201
|
+
}
|
|
2202
|
+
return false;
|
|
2203
|
+
}
|
|
2204
|
+
get disconnectDurationLimitExceeded() {
|
|
2205
|
+
var _a, _b;
|
|
2206
|
+
if (this._serverSideDisconnectDurationLimitOn) {
|
|
2207
|
+
return (_b = (_a = this._keepAliveManager) === null || _a === void 0 ? void 0 : _a.disconnectDurationLimitExceeded) !== null && _b !== void 0 ? _b : false;
|
|
2208
|
+
}
|
|
2209
|
+
else if (this._disconnectDurationLimitOn) {
|
|
2210
|
+
return this._disconnectDurationLimitExceeded;
|
|
2211
|
+
}
|
|
2212
|
+
return false;
|
|
2213
|
+
}
|
|
2214
|
+
enableDisconnectDurationLimit() {
|
|
2415
2215
|
var _a;
|
|
2416
|
-
if (
|
|
2417
|
-
|
|
2216
|
+
if (this._serverSideDisconnectDurationLimitOn) {
|
|
2217
|
+
(_a = this._keepAliveManager) === null || _a === void 0 ? void 0 : _a.enableDisconnectDurationLimit();
|
|
2418
2218
|
}
|
|
2419
|
-
if (
|
|
2420
|
-
this.
|
|
2421
|
-
return;
|
|
2219
|
+
else if (this._disconnectDurationLimitOn) {
|
|
2220
|
+
this._disconnectDurationLimitEnabled = true;
|
|
2422
2221
|
}
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2222
|
+
}
|
|
2223
|
+
setRtcManager(rtcManager) {
|
|
2224
|
+
if (this._reconnectManager) {
|
|
2225
|
+
this._reconnectManager.rtcManager = rtcManager;
|
|
2427
2226
|
}
|
|
2428
|
-
|
|
2227
|
+
}
|
|
2228
|
+
connect() {
|
|
2229
|
+
if (this.isConnected() || this.isConnecting()) {
|
|
2429
2230
|
return;
|
|
2430
2231
|
}
|
|
2431
|
-
|
|
2232
|
+
this._socket.open();
|
|
2432
2233
|
}
|
|
2433
|
-
|
|
2234
|
+
disconnect() {
|
|
2235
|
+
this._socket.disconnect();
|
|
2236
|
+
}
|
|
2237
|
+
emit(eventName, ...args) {
|
|
2238
|
+
this._socket.emit.apply(this._socket, arguments);
|
|
2239
|
+
}
|
|
2240
|
+
getTransport() {
|
|
2241
|
+
var _a, _b, _c, _d;
|
|
2242
|
+
return (_d = (_c = (_b = (_a = this._socket) === null || _a === void 0 ? void 0 : _a.io) === null || _b === void 0 ? void 0 : _b.engine) === null || _c === void 0 ? void 0 : _c.transport) === null || _d === void 0 ? void 0 : _d.name;
|
|
2243
|
+
}
|
|
2244
|
+
getManager() {
|
|
2245
|
+
return this._socket.io;
|
|
2246
|
+
}
|
|
2247
|
+
isConnecting() {
|
|
2248
|
+
return this._socket && this._socket.connecting;
|
|
2249
|
+
}
|
|
2250
|
+
isConnected() {
|
|
2251
|
+
return this._socket && this._socket.connected;
|
|
2252
|
+
}
|
|
2253
|
+
on(eventName, handler) {
|
|
2254
|
+
const relayableEvents = [
|
|
2255
|
+
PROTOCOL_RESPONSES.ROOM_JOINED,
|
|
2256
|
+
PROTOCOL_RESPONSES.CLIENT_LEFT,
|
|
2257
|
+
PROTOCOL_RESPONSES.NEW_CLIENT,
|
|
2258
|
+
];
|
|
2259
|
+
if (this._reconnectManager && relayableEvents.includes(eventName)) {
|
|
2260
|
+
return this._interceptEvent(eventName, handler);
|
|
2261
|
+
}
|
|
2262
|
+
this._socket.on(eventName, handler);
|
|
2263
|
+
return () => {
|
|
2264
|
+
this._socket.off(eventName, handler);
|
|
2265
|
+
};
|
|
2266
|
+
}
|
|
2267
|
+
onEngineEvent(eventName, handler) {
|
|
2434
2268
|
var _a;
|
|
2435
|
-
(_a = this.
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2269
|
+
(_a = this._socket.io) === null || _a === void 0 ? void 0 : _a.on(eventName, handler);
|
|
2270
|
+
return () => {
|
|
2271
|
+
var _a;
|
|
2272
|
+
(_a = this._socket.io) === null || _a === void 0 ? void 0 : _a.off(eventName, handler);
|
|
2273
|
+
};
|
|
2274
|
+
}
|
|
2275
|
+
once(eventName, handler) {
|
|
2276
|
+
this._socket.once(eventName, handler);
|
|
2277
|
+
}
|
|
2278
|
+
off(eventName, handler) {
|
|
2279
|
+
this._socket.off(eventName, handler);
|
|
2280
|
+
}
|
|
2281
|
+
_interceptEvent(eventName, handler) {
|
|
2282
|
+
if (this._reconnectManager) {
|
|
2283
|
+
this._reconnectManager.on(eventName, handler);
|
|
2284
|
+
}
|
|
2285
|
+
return () => {
|
|
2286
|
+
if (this._reconnectManager)
|
|
2287
|
+
this._reconnectManager.removeListener(eventName, handler);
|
|
2288
|
+
};
|
|
2289
|
+
}
|
|
2290
|
+
getGlitchFreeMetrics() {
|
|
2291
|
+
var _a;
|
|
2292
|
+
return (_a = this._reconnectManager) === null || _a === void 0 ? void 0 : _a.metrics;
|
|
2293
|
+
}
|
|
2294
|
+
getReconnectThreshold() {
|
|
2295
|
+
var _a;
|
|
2296
|
+
return (_a = this._reconnectManager) === null || _a === void 0 ? void 0 : _a.reconnectThresholdInMs;
|
|
2444
2297
|
}
|
|
2445
2298
|
}
|
|
2446
2299
|
|
|
2447
|
-
const
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
const adapter$3 = (_a$3 = adapterRaw.default) !== null && _a$3 !== void 0 ? _a$3 : adapterRaw;
|
|
2451
|
-
function detectMicrophoneNotWorking(pc) {
|
|
2452
|
-
var _a, _b;
|
|
2453
|
-
if (((_a = adapter$3.browserDetails) === null || _a === void 0 ? void 0 : _a.browser) !== "chrome" ||
|
|
2454
|
-
((_b = adapter$3.browserDetails) === null || _b === void 0 ? void 0 : _b.browser) < 58 ||
|
|
2455
|
-
pc.signalingState === "closed") {
|
|
2456
|
-
return Promise.resolve("");
|
|
2300
|
+
const maybeTurnOnly = (iceConfig, features) => {
|
|
2301
|
+
if (!features.useOnlyTURN) {
|
|
2302
|
+
return;
|
|
2457
2303
|
}
|
|
2458
|
-
|
|
2459
|
-
const
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
receivingAudio) {
|
|
2473
|
-
if (report.bytesReceived === 0) {
|
|
2474
|
-
microphoneFailed = "inbound";
|
|
2475
|
-
}
|
|
2304
|
+
iceConfig.iceTransportPolicy = "relay";
|
|
2305
|
+
const filter = {
|
|
2306
|
+
onlyudp: /^turn:.*transport=udp$/,
|
|
2307
|
+
onlytcp: /^turn:.*transport=tcp$/,
|
|
2308
|
+
onlytls: /^turns:.*transport=tcp$/,
|
|
2309
|
+
}[features.useOnlyTURN];
|
|
2310
|
+
if (filter) {
|
|
2311
|
+
iceConfig.iceServers = iceConfig.iceServers.filter((entry) => {
|
|
2312
|
+
if (entry.url && entry.url.match(filter))
|
|
2313
|
+
return entry;
|
|
2314
|
+
if (entry.urls) {
|
|
2315
|
+
entry.urls = (entry.urls.some ? entry.urls : [entry.urls]).filter((url) => url.match(filter));
|
|
2316
|
+
if (entry.urls.length > 0)
|
|
2317
|
+
return entry;
|
|
2476
2318
|
}
|
|
2477
2319
|
});
|
|
2478
|
-
|
|
2479
|
-
});
|
|
2480
|
-
}
|
|
2481
|
-
|
|
2482
|
-
const EVENTS = {
|
|
2483
|
-
CLIENT_CONNECTION_STATUS_CHANGED: "client_connection_status_changed",
|
|
2484
|
-
STREAM_ADDED: "stream_added",
|
|
2485
|
-
RTC_MANAGER_CREATED: "rtc_manager_created",
|
|
2486
|
-
RTC_MANAGER_DESTROYED: "rtc_manager_destroyed",
|
|
2487
|
-
LOCAL_STREAM_TRACK_ADDED: "local_stream_track_added",
|
|
2488
|
-
LOCAL_STREAM_TRACK_REMOVED: "local_stream_track_removed",
|
|
2489
|
-
REMOTE_STREAM_TRACK_ADDED: "remote_stream_track_added",
|
|
2490
|
-
REMOTE_STREAM_TRACK_REMOVED: "remote_stream_track_removed",
|
|
2320
|
+
}
|
|
2491
2321
|
};
|
|
2492
|
-
const
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2322
|
+
const external_stun_servers = (iceConfig, features) => {
|
|
2323
|
+
if (features.addGoogleStunServers) {
|
|
2324
|
+
iceConfig.iceServers = [
|
|
2325
|
+
{ urls: "stun:stun.l.google.com:19302" },
|
|
2326
|
+
{ urls: "stun:stun2.l.google.com:19302" },
|
|
2327
|
+
...iceConfig.iceServers,
|
|
2328
|
+
];
|
|
2329
|
+
}
|
|
2330
|
+
if (features.addCloudflareStunServers) {
|
|
2331
|
+
iceConfig.iceServers = [
|
|
2332
|
+
{ urls: "stun:stun.cloudflare.com:3478" },
|
|
2333
|
+
{ urls: "stun:stun.cloudflare.com:53" },
|
|
2334
|
+
...iceConfig.iceServers,
|
|
2335
|
+
];
|
|
2336
|
+
}
|
|
2497
2337
|
};
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2338
|
+
const turnServerOverride = (iceServers, overrideHost) => {
|
|
2339
|
+
if (overrideHost && iceServers) {
|
|
2340
|
+
const host = overrideHost;
|
|
2341
|
+
const port = host.indexOf(":") > 0 ? "" : ":443";
|
|
2342
|
+
const override = ":" + host + port;
|
|
2343
|
+
return iceServers.map((original) => {
|
|
2344
|
+
const entry = Object.assign({}, original);
|
|
2345
|
+
if (entry.url) {
|
|
2346
|
+
entry.url = entry.url.replace(/:[^?]*/, override);
|
|
2347
|
+
}
|
|
2348
|
+
if (entry.urls) {
|
|
2349
|
+
entry.urls = entry.urls.map((url) => url.replace(/:[^?]*/, override));
|
|
2350
|
+
}
|
|
2351
|
+
return entry;
|
|
2352
|
+
});
|
|
2353
|
+
}
|
|
2354
|
+
else {
|
|
2355
|
+
return iceServers;
|
|
2356
|
+
}
|
|
2511
2357
|
};
|
|
2512
2358
|
|
|
2359
|
+
const defaultSubdomainPattern = /^(?:([^.]+)[.])?((:?[^.]+[.]){1,}[^.]+)$/;
|
|
2360
|
+
const localstackPattern = /^(?:([^.]+)-)?(ip-[^.]*[.](?:hereby[.]dev|rfc1918[.]disappear[.]at)(?::\d+|))$/;
|
|
2361
|
+
const localhostPattern = /^(?:([^.]+)[.])?(localhost:?\d*)/;
|
|
2362
|
+
const serverPattern = /^(?:([^.]+)[.])?(server:?\d*)/;
|
|
2363
|
+
const ipv4Pattern = /^(?:([^.]+)[.])?((\d+[.]){3}:?\d*)$/;
|
|
2364
|
+
const subdomainPatterns = [
|
|
2365
|
+
{ pattern: serverPattern, separator: "." },
|
|
2366
|
+
{ pattern: localhostPattern, separator: "." },
|
|
2367
|
+
{ pattern: ipv4Pattern, separator: "." },
|
|
2368
|
+
{ pattern: localstackPattern, separator: "-" },
|
|
2369
|
+
{ pattern: defaultSubdomainPattern, separator: "." },
|
|
2370
|
+
];
|
|
2371
|
+
function fromLocation({ host = "whereby.com", protocol = "https:" } = {}) {
|
|
2372
|
+
let subdomain = "";
|
|
2373
|
+
let domain = host;
|
|
2374
|
+
let subdomainSeparator = ".";
|
|
2375
|
+
for (const { separator, pattern } of subdomainPatterns) {
|
|
2376
|
+
const match = pattern.exec(host);
|
|
2377
|
+
if (match) {
|
|
2378
|
+
subdomain = match[1] || "";
|
|
2379
|
+
domain = match[2];
|
|
2380
|
+
subdomainSeparator = separator;
|
|
2381
|
+
break;
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
const organizationDomain = !subdomain ? domain : `${subdomain}${subdomainSeparator}${domain}`;
|
|
2385
|
+
return {
|
|
2386
|
+
domain,
|
|
2387
|
+
domainWithSeparator: `${subdomainSeparator}${domain}`,
|
|
2388
|
+
organizationDomain,
|
|
2389
|
+
organization: `${protocol}//${organizationDomain}`,
|
|
2390
|
+
service: `${protocol}//${domain}`,
|
|
2391
|
+
subdomain,
|
|
2392
|
+
};
|
|
2393
|
+
}
|
|
2394
|
+
fromLocation(window && window.location);
|
|
2395
|
+
|
|
2513
2396
|
var _a$2, _b$1;
|
|
2514
2397
|
const adapter$2 = (_a$2 = adapterRaw.default) !== null && _a$2 !== void 0 ? _a$2 : adapterRaw;
|
|
2515
2398
|
const isSafari = ((_b$1 = adapter$2.browserDetails) === null || _b$1 === void 0 ? void 0 : _b$1.browser) === "safari";
|
|
@@ -2642,17 +2525,12 @@ class P2pRtcManager {
|
|
|
2642
2525
|
numPcSldFailure: 0,
|
|
2643
2526
|
numPcOnAnswerFailure: 0,
|
|
2644
2527
|
numPcOnOfferFailure: 0,
|
|
2645
|
-
P2PChangeBandwidthEmptySDPType: 0,
|
|
2646
2528
|
P2PReplaceTrackNoStream: 0,
|
|
2647
2529
|
P2PReplaceTrackNewTrackNotInStream: 0,
|
|
2648
2530
|
P2POnTrackNoStream: 0,
|
|
2649
|
-
P2PSetCodecPreferenceError: 0,
|
|
2650
|
-
P2PCreateOfferNoSDP: 0,
|
|
2651
|
-
P2PCreateAnswerNoSDP: 0,
|
|
2652
2531
|
P2PMicNotWorking: 0,
|
|
2653
2532
|
P2PLocalNetworkFailed: 0,
|
|
2654
2533
|
P2PRelayedIceCandidate: 0,
|
|
2655
|
-
P2PStartScreenshareNoStream: 0,
|
|
2656
2534
|
};
|
|
2657
2535
|
}
|
|
2658
2536
|
numberOfPeerconnections() {
|
|
@@ -3193,10 +3071,6 @@ class P2pRtcManager {
|
|
|
3193
3071
|
if (this._localScreenshareStream) {
|
|
3194
3072
|
session.addStream(this._localScreenshareStream);
|
|
3195
3073
|
}
|
|
3196
|
-
else {
|
|
3197
|
-
this.analytics.P2PStartScreenshareNoStream++;
|
|
3198
|
-
rtcStats.sendEvent("P2PStartScreenshareNoStream", {});
|
|
3199
|
-
}
|
|
3200
3074
|
});
|
|
3201
3075
|
});
|
|
3202
3076
|
}
|
|
@@ -3404,8 +3278,6 @@ class P2pRtcManager {
|
|
|
3404
3278
|
.createOffer(constraints || this.offerOptions)
|
|
3405
3279
|
.then((offer) => {
|
|
3406
3280
|
if (!offer.sdp) {
|
|
3407
|
-
this.analytics.P2PCreateOfferNoSDP++;
|
|
3408
|
-
rtcStats.sendEvent("P2PCreateOfferNoSDP", {});
|
|
3409
3281
|
throw new Error("SDP undefined while creating offer");
|
|
3410
3282
|
}
|
|
3411
3283
|
if (rtpAbsCaptureTimeOn)
|
|
@@ -3414,7 +3286,6 @@ class P2pRtcManager {
|
|
|
3414
3286
|
offer.sdp = setCodecPreferenceSDP({
|
|
3415
3287
|
sdp: offer.sdp,
|
|
3416
3288
|
redOn,
|
|
3417
|
-
incrementAnalyticMetric: (metric) => this.analytics[metric]++,
|
|
3418
3289
|
});
|
|
3419
3290
|
}
|
|
3420
3291
|
if (cleanSdpOn)
|
|
@@ -5387,6 +5258,11 @@ class VegaRtcManager {
|
|
|
5387
5258
|
}
|
|
5388
5259
|
}
|
|
5389
5260
|
replaceTrack(_, track) {
|
|
5261
|
+
logger$2.info("replaceTrack() [kind: %s, id: %s, readyState: %s]", track.kind, track.id, track.readyState);
|
|
5262
|
+
if (track.readyState === "ended") {
|
|
5263
|
+
logger$2.error(`refusing to use ended track with id: ${track.id}, kind: ${track.kind}`);
|
|
5264
|
+
return;
|
|
5265
|
+
}
|
|
5390
5266
|
if (track.kind === "audio") {
|
|
5391
5267
|
if (!trackAnnotations(track).isEffectTrack) {
|
|
5392
5268
|
this._monitorAudioTrack(track);
|
|
@@ -5990,23 +5866,6 @@ const getRoomMode = () => {
|
|
|
5990
5866
|
return roomMode;
|
|
5991
5867
|
};
|
|
5992
5868
|
|
|
5993
|
-
const packetLossAnalyser = new PacketLossAnalyser();
|
|
5994
|
-
const periodicPacketLossDetector = {
|
|
5995
|
-
id: "periodic-packet-loss",
|
|
5996
|
-
enabled: ({ client, hasLiveTrack, ssrc0 }) => {
|
|
5997
|
-
return (!!client.isLocalClient &&
|
|
5998
|
-
hasLiveTrack &&
|
|
5999
|
-
!!(ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.ssrc) &&
|
|
6000
|
-
(ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.direction) === "out" &&
|
|
6001
|
-
((ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.bitrate) || 0) > 0);
|
|
6002
|
-
},
|
|
6003
|
-
check: ({ ssrc0 }) => {
|
|
6004
|
-
if (!ssrc0 || !ssrc0.ssrc)
|
|
6005
|
-
return false;
|
|
6006
|
-
packetLossAnalyser.addPacketLossMeasurement(ssrc0.ssrc, ssrc0.fractionLost || 0, Date.now());
|
|
6007
|
-
return packetLossAnalyser.hasPeriodicPacketLoss(ssrc0.ssrc, Date.now());
|
|
6008
|
-
},
|
|
6009
|
-
};
|
|
6010
5869
|
const badNetworkIssueDetector = {
|
|
6011
5870
|
id: "bad-network",
|
|
6012
5871
|
enabled: ({ hasLiveTrack, ssrcs }) => hasLiveTrack && ssrcs.length > 0,
|
|
@@ -6194,7 +6053,6 @@ const issueDetectors = [
|
|
|
6194
6053
|
check: ({ ssrc0 }) => ((ssrc0 === null || ssrc0 === void 0 ? void 0 : ssrc0.fps) || 0) < 10,
|
|
6195
6054
|
},
|
|
6196
6055
|
badNetworkIssueDetector,
|
|
6197
|
-
periodicPacketLossDetector,
|
|
6198
6056
|
{
|
|
6199
6057
|
id: "cpu-pressure-serious",
|
|
6200
6058
|
global: true,
|