@whereby.com/media 2.0.0 → 2.1.1

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