@whereby.com/media 2.0.0 → 2.1.0

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