@whereby.com/media 1.17.16 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1741,6 +1741,7 @@ var rtcManagerEvents = {
1741
1741
  NEW_PC: "new_pc",
1742
1742
  SFU_CONNECTION_OPEN: "sfu_connection_open",
1743
1743
  SFU_CONNECTION_CLOSED: "sfu_connection_closed",
1744
+ SFU_CONNECTION_INFO: "sfu_connection_info",
1744
1745
  COLOCATION_SPEAKER: "colocation_speaker",
1745
1746
  DOMINANT_SPEAKER: "dominant_speaker",
1746
1747
  PC_SLD_FAILURE: "pc_sld_failure",
@@ -4249,6 +4250,167 @@ function getNumberOfTemporalLayers(consumer) {
4249
4250
  return /T3/.test(((_c = (_b = (_a = consumer._rtpParameters) === null || _a === void 0 ? void 0 : _a.encodings) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.scalabilityMode) || "") ? 3 : 2;
4250
4251
  }
4251
4252
 
4253
+ const timeNextServer = 500;
4254
+ const minTimeNextServerSameDC = 2000;
4255
+ const timeToWaitForEarlyServerClose = 100;
4256
+ function convertToProperHostList(hostList) {
4257
+ if (typeof hostList === "string") {
4258
+ return hostList
4259
+ .split(",")
4260
+ .filter(Boolean)
4261
+ .map((hostString) => {
4262
+ const [dc, host] = /\|/.test(hostString) ? hostString.split("|") : ["", hostString];
4263
+ return { host, dc };
4264
+ });
4265
+ }
4266
+ return hostList.filter((item) => item.host).map((item) => ({ host: item.host, dc: item.dc || "" }));
4267
+ }
4268
+ function createVegaConnectionManager(config) {
4269
+ let connectionInfo;
4270
+ let lastDisconnectTime;
4271
+ let lastNetworkUpTime;
4272
+ let lastNetworkPossiblyDownTime;
4273
+ let hostList = [];
4274
+ const updateHostList = (updatedHostList) => {
4275
+ hostList = convertToProperHostList(updatedHostList);
4276
+ };
4277
+ let connectionAttemptInProgress = false;
4278
+ let hasPendingConnectionAttempt = false;
4279
+ const connect = () => {
4280
+ if (connectionAttemptInProgress) {
4281
+ hasPendingConnectionAttempt = true;
4282
+ return;
4283
+ }
4284
+ connectionAttemptInProgress = true;
4285
+ hasPendingConnectionAttempt = false;
4286
+ let targetHostList = hostList;
4287
+ if (connectionInfo) {
4288
+ const now = Date.now();
4289
+ const isLongEnoughSinceDisconnect = now - 3000 > (lastDisconnectTime || 0);
4290
+ const isNetworkUp = !lastNetworkPossiblyDownTime || (lastNetworkUpTime || 0) > lastNetworkPossiblyDownTime;
4291
+ const hasNetworkBeenUpLongEnough = isNetworkUp && now - 3000 > (lastNetworkUpTime || 0);
4292
+ if (!isLongEnoughSinceDisconnect || !hasNetworkBeenUpLongEnough) {
4293
+ targetHostList = [{ host: connectionInfo.host, dc: connectionInfo.dc }];
4294
+ }
4295
+ }
4296
+ const dcIndexByDC = {};
4297
+ let currentDCIndex = 0;
4298
+ targetHostList.forEach(({ dc }) => {
4299
+ if (typeof dcIndexByDC[dc] === "undefined")
4300
+ dcIndexByDC[dc] = currentDCIndex++;
4301
+ });
4302
+ let timeBeforeConnect = 0;
4303
+ const prevTimeBeforeConnectByDC = {};
4304
+ let nominatedConnection;
4305
+ let connectionsToResolve = targetHostList.length;
4306
+ let hasNotifiedDisconnect = false;
4307
+ let wasConnected = false;
4308
+ targetHostList.forEach(({ host, dc }, index) => {
4309
+ if (index > 0) {
4310
+ timeBeforeConnect += timeNextServer;
4311
+ const minTimeBeforeConnect = (prevTimeBeforeConnectByDC[dc] || 0) + minTimeNextServerSameDC;
4312
+ timeBeforeConnect = Math.max(timeBeforeConnect, minTimeBeforeConnect);
4313
+ }
4314
+ prevTimeBeforeConnectByDC[dc] = timeBeforeConnect;
4315
+ setTimeout(() => {
4316
+ var _a;
4317
+ if (wasConnected)
4318
+ return;
4319
+ const vegaConnection = new VegaConnection(((_a = config.getUrlForHost) === null || _a === void 0 ? void 0 : _a.call(config, host)) || host);
4320
+ let wasClosed = false;
4321
+ vegaConnection.on("open", () => {
4322
+ setTimeout(() => {
4323
+ var _a;
4324
+ if (wasClosed)
4325
+ return;
4326
+ if (!nominatedConnection && !wasConnected) {
4327
+ nominatedConnection = vegaConnection;
4328
+ wasConnected = true;
4329
+ const thisRoundFailedHosts = [
4330
+ ...new Set(targetHostList
4331
+ .slice(0, index)
4332
+ .filter((o) => o.host !== host)
4333
+ .map((o) => o.host)),
4334
+ ];
4335
+ const thisRoundFailedDCs = [
4336
+ ...new Set(targetHostList
4337
+ .slice(0, index)
4338
+ .filter((o) => o.dc !== dc)
4339
+ .map((o) => o.dc)),
4340
+ ];
4341
+ if (!connectionInfo) {
4342
+ connectionInfo = {
4343
+ host,
4344
+ dc,
4345
+ initialHost: host,
4346
+ initialDC: dc,
4347
+ initialHostIndex: index,
4348
+ initialDCIndex: dcIndexByDC[dc],
4349
+ failedHosts: thisRoundFailedHosts,
4350
+ failedDCs: thisRoundFailedDCs,
4351
+ usedHosts: [host],
4352
+ usedDCs: [dc],
4353
+ numConnections: 1,
4354
+ numUsedDCs: 1,
4355
+ numUsedHosts: 1,
4356
+ numFailedDCs: 0,
4357
+ numFailedHosts: 0,
4358
+ };
4359
+ }
4360
+ else {
4361
+ connectionInfo = Object.assign(Object.assign({}, connectionInfo), { host,
4362
+ dc, failedHosts: [
4363
+ ...new Set([...thisRoundFailedHosts, ...connectionInfo.failedHosts]),
4364
+ ].filter((failedHost) => failedHost !== host && !connectionInfo.usedHosts.includes(failedHost)), failedDCs: [
4365
+ ...new Set([...thisRoundFailedDCs, ...connectionInfo.failedDCs]),
4366
+ ].filter((failedDC) => failedDC !== dc && !connectionInfo.usedDCs.includes(failedDC)), usedHosts: [...new Set([...connectionInfo.usedHosts, host])], usedDCs: [...new Set([...connectionInfo.usedDCs, dc])], numConnections: connectionInfo.numConnections + 1 });
4367
+ }
4368
+ connectionInfo.numUsedDCs = connectionInfo.usedDCs.length;
4369
+ connectionInfo.numUsedHosts = connectionInfo.usedHosts.length;
4370
+ connectionInfo.numFailedDCs = connectionInfo.failedDCs.length;
4371
+ connectionInfo.numFailedHosts = connectionInfo.failedHosts.length;
4372
+ hasPendingConnectionAttempt = false;
4373
+ connectionAttemptInProgress = false;
4374
+ (_a = config.onConnected) === null || _a === void 0 ? void 0 : _a.call(config, vegaConnection, connectionInfo);
4375
+ }
4376
+ else {
4377
+ vegaConnection.close();
4378
+ }
4379
+ }, timeToWaitForEarlyServerClose);
4380
+ });
4381
+ vegaConnection.on("close", () => {
4382
+ var _a, _b;
4383
+ wasClosed = true;
4384
+ if (vegaConnection === nominatedConnection) {
4385
+ nominatedConnection = undefined;
4386
+ lastDisconnectTime = Date.now();
4387
+ hasNotifiedDisconnect = true;
4388
+ (_a = config.onDisconnected) === null || _a === void 0 ? void 0 : _a.call(config);
4389
+ }
4390
+ connectionsToResolve--;
4391
+ if (connectionsToResolve === 0 && !hasNotifiedDisconnect) {
4392
+ connectionAttemptInProgress = false;
4393
+ if (hasPendingConnectionAttempt) {
4394
+ setTimeout(connect, 0);
4395
+ }
4396
+ else {
4397
+ (_b = config.onFailed) === null || _b === void 0 ? void 0 : _b.call(config);
4398
+ }
4399
+ }
4400
+ });
4401
+ }, timeBeforeConnect);
4402
+ });
4403
+ };
4404
+ updateHostList(config.initialHostList);
4405
+ const networkIsUp = () => {
4406
+ lastNetworkUpTime = Math.max(Date.now(), lastNetworkUpTime || 0);
4407
+ };
4408
+ const networkIsPossiblyDown = () => {
4409
+ lastNetworkPossiblyDownTime = Date.now();
4410
+ };
4411
+ return { connect, updateHostList, networkIsUp, networkIsPossiblyDown };
4412
+ }
4413
+
4252
4414
  var _a$2;
4253
4415
  const adapter$2 = (_a$2 = adapterRaw.default) !== null && _a$2 !== void 0 ? _a$2 : adapterRaw;
4254
4416
  const logger$4 = new Logger();
@@ -4262,7 +4424,7 @@ if (browserName === "chrome")
4262
4424
  window.document.addEventListener("beforeunload", () => (unloading = true));
4263
4425
  class VegaRtcManager {
4264
4426
  constructor({ selfId, room, emitter, serverSocket, webrtcProvider, features, eventClaim, }) {
4265
- const { session, iceServers, sfuServer, mediaserverConfigTtlSeconds } = room;
4427
+ const { session, iceServers, sfuServer, sfuServers, mediaserverConfigTtlSeconds } = room;
4266
4428
  this._selfId = selfId;
4267
4429
  this._room = room;
4268
4430
  this._roomSessionId = session === null || session === void 0 ? void 0 : session.id;
@@ -4314,6 +4476,7 @@ class VegaRtcManager {
4314
4476
  };
4315
4477
  this._updateAndScheduleMediaServersRefresh({
4316
4478
  sfuServer,
4479
+ sfuServers,
4317
4480
  iceServers: iceServers.iceServers || [],
4318
4481
  mediaserverConfigTtlSeconds,
4319
4482
  });
@@ -4321,18 +4484,31 @@ class VegaRtcManager {
4321
4484
  this._reconnect = true;
4322
4485
  this._reconnectTimeOut = null;
4323
4486
  this._hasVegaConnection = false;
4487
+ this._isConnectingOrConnected = false;
4324
4488
  this._qualityMonitor = new VegaMediaQualityMonitor();
4325
4489
  this._qualityMonitor.on(PROTOCOL_EVENTS.MEDIA_QUALITY_CHANGED, (payload) => {
4326
4490
  this._emitToPWA(PROTOCOL_EVENTS.MEDIA_QUALITY_CHANGED, payload);
4327
4491
  });
4492
+ this._networkIsDetectedUpBySignal = false;
4328
4493
  }
4329
- _updateAndScheduleMediaServersRefresh({ iceServers, sfuServer, mediaserverConfigTtlSeconds, }) {
4330
- var _a, _b;
4494
+ _updateAndScheduleMediaServersRefresh({ iceServers, sfuServer, sfuServers, mediaserverConfigTtlSeconds, }) {
4495
+ var _a, _b, _c;
4331
4496
  this._iceServers = iceServers;
4332
4497
  this._sfuServer = sfuServer;
4498
+ this._sfuServers = sfuServers;
4499
+ if (!sfuServers && (sfuServer === null || sfuServer === void 0 ? void 0 : sfuServer.fallbackServers)) {
4500
+ this._sfuServers = sfuServer.fallbackServers.map((entry) => ({
4501
+ host: entry.host || entry.fqdn,
4502
+ dc: entry.dc,
4503
+ }));
4504
+ }
4333
4505
  this._mediaserverConfigTtlSeconds = mediaserverConfigTtlSeconds;
4334
- (_a = this._sendTransport) === null || _a === void 0 ? void 0 : _a.updateIceServers({ iceServers: this._iceServers });
4335
- (_b = this._receiveTransport) === null || _b === void 0 ? void 0 : _b.updateIceServers({ iceServers: this._iceServers });
4506
+ (_a = this._vegaConnectionManager) === null || _a === void 0 ? void 0 : _a.updateHostList(this._features.sfuServersOverride ||
4507
+ this._sfuServers ||
4508
+ this._features.sfuServerOverrideHost ||
4509
+ sfuServer.url);
4510
+ (_b = this._sendTransport) === null || _b === void 0 ? void 0 : _b.updateIceServers({ iceServers: this._iceServers });
4511
+ (_c = this._receiveTransport) === null || _c === void 0 ? void 0 : _c.updateIceServers({ iceServers: this._iceServers });
4336
4512
  this._clearMediaServersRefresh();
4337
4513
  if (!mediaserverConfigTtlSeconds) {
4338
4514
  return;
@@ -4345,6 +4521,20 @@ class VegaRtcManager {
4345
4521
  clearTimeout(this._fetchMediaServersTimer);
4346
4522
  this._fetchMediaServersTimer = null;
4347
4523
  }
4524
+ _onNetworkIsDetectedUpBySignal() {
4525
+ var _a;
4526
+ if (!this._networkIsDetectedUpBySignal) {
4527
+ this._networkIsDetectedUpBySignal = true;
4528
+ (_a = this._vegaConnectionManager) === null || _a === void 0 ? void 0 : _a.networkIsUp();
4529
+ }
4530
+ }
4531
+ _onNetworkIsDetectedPossiblyDownBySignal() {
4532
+ var _a;
4533
+ if (this._networkIsDetectedUpBySignal) {
4534
+ this._networkIsDetectedUpBySignal = false;
4535
+ (_a = this._vegaConnectionManager) === null || _a === void 0 ? void 0 : _a.networkIsPossiblyDown();
4536
+ }
4537
+ }
4348
4538
  setupSocketListeners() {
4349
4539
  this._socketListenerDeregisterFunctions.push(() => this._clearMediaServersRefresh(), this._serverSocket.on(PROTOCOL_RESPONSES.MEDIASERVER_CONFIG, (data) => {
4350
4540
  if (data.error) {
@@ -4358,7 +4548,7 @@ class VegaRtcManager {
4358
4548
  if (this._features.sfuReconnectV2On && !this._hasVegaConnection && this._reconnect) {
4359
4549
  this._connect();
4360
4550
  }
4361
- }));
4551
+ }), this._serverSocket.on("connect", () => this._onNetworkIsDetectedUpBySignal()), this._serverSocket.onEngineEvent("packet", () => this._onNetworkIsDetectedUpBySignal()), this._serverSocket.on("disconnect", () => this._onNetworkIsDetectedPossiblyDownBySignal()));
4362
4552
  this._connect();
4363
4553
  }
4364
4554
  _emitScreenshareStarted() {
@@ -4368,6 +4558,8 @@ class VegaRtcManager {
4368
4558
  });
4369
4559
  }
4370
4560
  _connect() {
4561
+ if (this._features.sfuConnectionManagerOn)
4562
+ return this._connect_v2();
4371
4563
  if (this._features.sfuReconnectV2On) {
4372
4564
  if (this._hasVegaConnection)
4373
4565
  return;
@@ -4393,6 +4585,56 @@ class VegaRtcManager {
4393
4585
  this._vegaConnection.on("close", () => this._onClose());
4394
4586
  this._vegaConnection.on("message", (message) => this._onMessage(message));
4395
4587
  }
4588
+ _connect_v2() {
4589
+ if (this._features.sfuReconnectV2On) {
4590
+ if (this._isConnectingOrConnected)
4591
+ return;
4592
+ if (!this._serverSocket.isConnected()) {
4593
+ const reconnectThresholdInMs = this._serverSocket.getReconnectThreshold();
4594
+ if (!reconnectThresholdInMs)
4595
+ return;
4596
+ if (Date.now() > (this._serverSocket.disconnectTimestamp || 0) + reconnectThresholdInMs)
4597
+ return;
4598
+ }
4599
+ if (this._reconnectTimeOut)
4600
+ clearTimeout(this._reconnectTimeOut);
4601
+ }
4602
+ if (!this._vegaConnectionManager) {
4603
+ const hostList = this._features.sfuServersOverride ||
4604
+ this._sfuServers ||
4605
+ this._features.sfuServerOverrideHost ||
4606
+ this._sfuServer.url;
4607
+ this._vegaConnectionManager = createVegaConnectionManager({
4608
+ initialHostList: hostList,
4609
+ getUrlForHost: (host) => {
4610
+ const searchParams = new URLSearchParams(Object.assign({ clientId: this._selfId, organizationId: this._room.organizationId, roomName: this._room.name, eventClaim: this._room.isClaimed ? this._eventClaim : null, lowBw: "true" }, Object.keys(this._features || {})
4611
+ .filter((featureKey) => this._features[featureKey] && /^sfu/.test(featureKey))
4612
+ .reduce((prev, current) => (Object.assign(Object.assign({}, prev), { [current]: this._features[current] })), {})));
4613
+ const queryString = searchParams.toString();
4614
+ const wsUrl = `wss://${host}?${queryString}`;
4615
+ return wsUrl;
4616
+ },
4617
+ onConnected: (vegaConnection, info) => {
4618
+ this._vegaConnection = vegaConnection;
4619
+ this._vegaConnection.on("message", (message) => this._onMessage(message));
4620
+ this._emitToPWA(rtcManagerEvents.SFU_CONNECTION_INFO, info);
4621
+ this._join();
4622
+ },
4623
+ onDisconnected: () => {
4624
+ this._vegaConnection = null;
4625
+ this._isConnectingOrConnected = false;
4626
+ this._onClose();
4627
+ },
4628
+ onFailed: () => {
4629
+ this._vegaConnection = null;
4630
+ this._isConnectingOrConnected = false;
4631
+ this._onClose();
4632
+ },
4633
+ });
4634
+ }
4635
+ this._vegaConnectionManager.connect();
4636
+ this._isConnectingOrConnected = true;
4637
+ }
4396
4638
  _onClose() {
4397
4639
  var _a, _b;
4398
4640
  logger$4.info("_onClose()");
@@ -6086,6 +6328,14 @@ class ServerSocket {
6086
6328
  this._socket.off(eventName, handler);
6087
6329
  };
6088
6330
  }
6331
+ onEngineEvent(eventName, handler) {
6332
+ var _a;
6333
+ (_a = this._socket.io) === null || _a === void 0 ? void 0 : _a.on(eventName, handler);
6334
+ return () => {
6335
+ var _a;
6336
+ (_a = this._socket.io) === null || _a === void 0 ? void 0 : _a.off(eventName, handler);
6337
+ };
6338
+ }
6089
6339
  once(eventName, handler) {
6090
6340
  this._socket.once(eventName, handler);
6091
6341
  }
package/dist/index.d.cts CHANGED
@@ -655,6 +655,7 @@ declare class ServerSocket {
655
655
  isConnecting(): any;
656
656
  isConnected(): any;
657
657
  on(eventName: string, handler: Function): () => void;
658
+ onEngineEvent(eventName: string, handler: Function): () => void;
658
659
  once(eventName: string, handler: Function): void;
659
660
  off(eventName: string, handler: Function): void;
660
661
  _interceptEvent(eventName: string, handler: any): () => void;
@@ -1045,6 +1046,7 @@ declare const _default: {
1045
1046
  NEW_PC: string;
1046
1047
  SFU_CONNECTION_OPEN: string;
1047
1048
  SFU_CONNECTION_CLOSED: string;
1049
+ SFU_CONNECTION_INFO: string;
1048
1050
  COLOCATION_SPEAKER: string;
1049
1051
  DOMINANT_SPEAKER: string;
1050
1052
  PC_SLD_FAILURE: string;
@@ -1252,6 +1254,40 @@ declare const standardDeviation: (arr: any[]) => {
1252
1254
  };
1253
1255
  declare const variance: (arr: any[], usePopulation?: boolean) => number;
1254
1256
 
1257
+ type ConnectionInfo = {
1258
+ host: string;
1259
+ dc: string;
1260
+ initialHost: string;
1261
+ initialDC: string;
1262
+ initialHostIndex: number;
1263
+ initialDCIndex: number;
1264
+ failedDCs: string[];
1265
+ numFailedDCs: number;
1266
+ failedHosts: string[];
1267
+ numFailedHosts: number;
1268
+ usedDCs: string[];
1269
+ numUsedDCs: number;
1270
+ usedHosts: string[];
1271
+ numUsedHosts: number;
1272
+ numConnections: number;
1273
+ };
1274
+ type HostListEntryOptionalDC = {
1275
+ host: string;
1276
+ dc?: string;
1277
+ };
1278
+ declare function createVegaConnectionManager(config: {
1279
+ initialHostList: string | any[];
1280
+ getUrlForHost?: (host: string) => string;
1281
+ onConnected?: (vegaConnection: VegaConnection, info: ConnectionInfo) => void;
1282
+ onDisconnected?: () => void;
1283
+ onFailed?: () => void;
1284
+ }): {
1285
+ connect: () => void;
1286
+ updateHostList: (updatedHostList: string | HostListEntryOptionalDC[]) => void;
1287
+ networkIsUp: () => void;
1288
+ networkIsPossiblyDown: () => void;
1289
+ };
1290
+
1255
1291
  declare class VegaRtcManager implements RtcManager {
1256
1292
  _selfId: any;
1257
1293
  _room: any;
@@ -1306,10 +1342,14 @@ declare class VegaRtcManager implements RtcManager {
1306
1342
  _fetchMediaServersTimer: any;
1307
1343
  _iceServers: any;
1308
1344
  _sfuServer: any;
1345
+ _sfuServers?: HostListEntryOptionalDC[];
1309
1346
  _mediaserverConfigTtlSeconds: any;
1310
1347
  _videoTrackBeingMonitored?: CustomMediaStreamTrack;
1311
1348
  _audioTrackBeingMonitored?: CustomMediaStreamTrack;
1312
1349
  _hasVegaConnection: boolean;
1350
+ _isConnectingOrConnected: boolean;
1351
+ _vegaConnectionManager?: ReturnType<typeof createVegaConnectionManager>;
1352
+ _networkIsDetectedUpBySignal: boolean;
1313
1353
  constructor({ selfId, room, emitter, serverSocket, webrtcProvider, features, eventClaim, }: {
1314
1354
  selfId: any;
1315
1355
  room: any;
@@ -1319,15 +1359,19 @@ declare class VegaRtcManager implements RtcManager {
1319
1359
  features?: any;
1320
1360
  eventClaim?: string;
1321
1361
  });
1322
- _updateAndScheduleMediaServersRefresh({ iceServers, sfuServer, mediaserverConfigTtlSeconds, }: {
1362
+ _updateAndScheduleMediaServersRefresh({ iceServers, sfuServer, sfuServers, mediaserverConfigTtlSeconds, }: {
1323
1363
  iceServers: any;
1324
1364
  sfuServer: any;
1365
+ sfuServers: any;
1325
1366
  mediaserverConfigTtlSeconds: any;
1326
1367
  }): void;
1327
1368
  _clearMediaServersRefresh(): void;
1369
+ _onNetworkIsDetectedUpBySignal(): void;
1370
+ _onNetworkIsDetectedPossiblyDownBySignal(): void;
1328
1371
  setupSocketListeners(): void;
1329
1372
  _emitScreenshareStarted(): void;
1330
1373
  _connect(): void;
1374
+ _connect_v2(): void;
1331
1375
  _onClose(): void;
1332
1376
  _join(): Promise<void>;
1333
1377
  _createTransport(send: any): Promise<void>;
package/dist/index.d.mts CHANGED
@@ -655,6 +655,7 @@ declare class ServerSocket {
655
655
  isConnecting(): any;
656
656
  isConnected(): any;
657
657
  on(eventName: string, handler: Function): () => void;
658
+ onEngineEvent(eventName: string, handler: Function): () => void;
658
659
  once(eventName: string, handler: Function): void;
659
660
  off(eventName: string, handler: Function): void;
660
661
  _interceptEvent(eventName: string, handler: any): () => void;
@@ -1045,6 +1046,7 @@ declare const _default: {
1045
1046
  NEW_PC: string;
1046
1047
  SFU_CONNECTION_OPEN: string;
1047
1048
  SFU_CONNECTION_CLOSED: string;
1049
+ SFU_CONNECTION_INFO: string;
1048
1050
  COLOCATION_SPEAKER: string;
1049
1051
  DOMINANT_SPEAKER: string;
1050
1052
  PC_SLD_FAILURE: string;
@@ -1252,6 +1254,40 @@ declare const standardDeviation: (arr: any[]) => {
1252
1254
  };
1253
1255
  declare const variance: (arr: any[], usePopulation?: boolean) => number;
1254
1256
 
1257
+ type ConnectionInfo = {
1258
+ host: string;
1259
+ dc: string;
1260
+ initialHost: string;
1261
+ initialDC: string;
1262
+ initialHostIndex: number;
1263
+ initialDCIndex: number;
1264
+ failedDCs: string[];
1265
+ numFailedDCs: number;
1266
+ failedHosts: string[];
1267
+ numFailedHosts: number;
1268
+ usedDCs: string[];
1269
+ numUsedDCs: number;
1270
+ usedHosts: string[];
1271
+ numUsedHosts: number;
1272
+ numConnections: number;
1273
+ };
1274
+ type HostListEntryOptionalDC = {
1275
+ host: string;
1276
+ dc?: string;
1277
+ };
1278
+ declare function createVegaConnectionManager(config: {
1279
+ initialHostList: string | any[];
1280
+ getUrlForHost?: (host: string) => string;
1281
+ onConnected?: (vegaConnection: VegaConnection, info: ConnectionInfo) => void;
1282
+ onDisconnected?: () => void;
1283
+ onFailed?: () => void;
1284
+ }): {
1285
+ connect: () => void;
1286
+ updateHostList: (updatedHostList: string | HostListEntryOptionalDC[]) => void;
1287
+ networkIsUp: () => void;
1288
+ networkIsPossiblyDown: () => void;
1289
+ };
1290
+
1255
1291
  declare class VegaRtcManager implements RtcManager {
1256
1292
  _selfId: any;
1257
1293
  _room: any;
@@ -1306,10 +1342,14 @@ declare class VegaRtcManager implements RtcManager {
1306
1342
  _fetchMediaServersTimer: any;
1307
1343
  _iceServers: any;
1308
1344
  _sfuServer: any;
1345
+ _sfuServers?: HostListEntryOptionalDC[];
1309
1346
  _mediaserverConfigTtlSeconds: any;
1310
1347
  _videoTrackBeingMonitored?: CustomMediaStreamTrack;
1311
1348
  _audioTrackBeingMonitored?: CustomMediaStreamTrack;
1312
1349
  _hasVegaConnection: boolean;
1350
+ _isConnectingOrConnected: boolean;
1351
+ _vegaConnectionManager?: ReturnType<typeof createVegaConnectionManager>;
1352
+ _networkIsDetectedUpBySignal: boolean;
1313
1353
  constructor({ selfId, room, emitter, serverSocket, webrtcProvider, features, eventClaim, }: {
1314
1354
  selfId: any;
1315
1355
  room: any;
@@ -1319,15 +1359,19 @@ declare class VegaRtcManager implements RtcManager {
1319
1359
  features?: any;
1320
1360
  eventClaim?: string;
1321
1361
  });
1322
- _updateAndScheduleMediaServersRefresh({ iceServers, sfuServer, mediaserverConfigTtlSeconds, }: {
1362
+ _updateAndScheduleMediaServersRefresh({ iceServers, sfuServer, sfuServers, mediaserverConfigTtlSeconds, }: {
1323
1363
  iceServers: any;
1324
1364
  sfuServer: any;
1365
+ sfuServers: any;
1325
1366
  mediaserverConfigTtlSeconds: any;
1326
1367
  }): void;
1327
1368
  _clearMediaServersRefresh(): void;
1369
+ _onNetworkIsDetectedUpBySignal(): void;
1370
+ _onNetworkIsDetectedPossiblyDownBySignal(): void;
1328
1371
  setupSocketListeners(): void;
1329
1372
  _emitScreenshareStarted(): void;
1330
1373
  _connect(): void;
1374
+ _connect_v2(): void;
1331
1375
  _onClose(): void;
1332
1376
  _join(): Promise<void>;
1333
1377
  _createTransport(send: any): Promise<void>;
package/dist/index.d.ts CHANGED
@@ -655,6 +655,7 @@ declare class ServerSocket {
655
655
  isConnecting(): any;
656
656
  isConnected(): any;
657
657
  on(eventName: string, handler: Function): () => void;
658
+ onEngineEvent(eventName: string, handler: Function): () => void;
658
659
  once(eventName: string, handler: Function): void;
659
660
  off(eventName: string, handler: Function): void;
660
661
  _interceptEvent(eventName: string, handler: any): () => void;
@@ -1045,6 +1046,7 @@ declare const _default: {
1045
1046
  NEW_PC: string;
1046
1047
  SFU_CONNECTION_OPEN: string;
1047
1048
  SFU_CONNECTION_CLOSED: string;
1049
+ SFU_CONNECTION_INFO: string;
1048
1050
  COLOCATION_SPEAKER: string;
1049
1051
  DOMINANT_SPEAKER: string;
1050
1052
  PC_SLD_FAILURE: string;
@@ -1252,6 +1254,40 @@ declare const standardDeviation: (arr: any[]) => {
1252
1254
  };
1253
1255
  declare const variance: (arr: any[], usePopulation?: boolean) => number;
1254
1256
 
1257
+ type ConnectionInfo = {
1258
+ host: string;
1259
+ dc: string;
1260
+ initialHost: string;
1261
+ initialDC: string;
1262
+ initialHostIndex: number;
1263
+ initialDCIndex: number;
1264
+ failedDCs: string[];
1265
+ numFailedDCs: number;
1266
+ failedHosts: string[];
1267
+ numFailedHosts: number;
1268
+ usedDCs: string[];
1269
+ numUsedDCs: number;
1270
+ usedHosts: string[];
1271
+ numUsedHosts: number;
1272
+ numConnections: number;
1273
+ };
1274
+ type HostListEntryOptionalDC = {
1275
+ host: string;
1276
+ dc?: string;
1277
+ };
1278
+ declare function createVegaConnectionManager(config: {
1279
+ initialHostList: string | any[];
1280
+ getUrlForHost?: (host: string) => string;
1281
+ onConnected?: (vegaConnection: VegaConnection, info: ConnectionInfo) => void;
1282
+ onDisconnected?: () => void;
1283
+ onFailed?: () => void;
1284
+ }): {
1285
+ connect: () => void;
1286
+ updateHostList: (updatedHostList: string | HostListEntryOptionalDC[]) => void;
1287
+ networkIsUp: () => void;
1288
+ networkIsPossiblyDown: () => void;
1289
+ };
1290
+
1255
1291
  declare class VegaRtcManager implements RtcManager {
1256
1292
  _selfId: any;
1257
1293
  _room: any;
@@ -1306,10 +1342,14 @@ declare class VegaRtcManager implements RtcManager {
1306
1342
  _fetchMediaServersTimer: any;
1307
1343
  _iceServers: any;
1308
1344
  _sfuServer: any;
1345
+ _sfuServers?: HostListEntryOptionalDC[];
1309
1346
  _mediaserverConfigTtlSeconds: any;
1310
1347
  _videoTrackBeingMonitored?: CustomMediaStreamTrack;
1311
1348
  _audioTrackBeingMonitored?: CustomMediaStreamTrack;
1312
1349
  _hasVegaConnection: boolean;
1350
+ _isConnectingOrConnected: boolean;
1351
+ _vegaConnectionManager?: ReturnType<typeof createVegaConnectionManager>;
1352
+ _networkIsDetectedUpBySignal: boolean;
1313
1353
  constructor({ selfId, room, emitter, serverSocket, webrtcProvider, features, eventClaim, }: {
1314
1354
  selfId: any;
1315
1355
  room: any;
@@ -1319,15 +1359,19 @@ declare class VegaRtcManager implements RtcManager {
1319
1359
  features?: any;
1320
1360
  eventClaim?: string;
1321
1361
  });
1322
- _updateAndScheduleMediaServersRefresh({ iceServers, sfuServer, mediaserverConfigTtlSeconds, }: {
1362
+ _updateAndScheduleMediaServersRefresh({ iceServers, sfuServer, sfuServers, mediaserverConfigTtlSeconds, }: {
1323
1363
  iceServers: any;
1324
1364
  sfuServer: any;
1365
+ sfuServers: any;
1325
1366
  mediaserverConfigTtlSeconds: any;
1326
1367
  }): void;
1327
1368
  _clearMediaServersRefresh(): void;
1369
+ _onNetworkIsDetectedUpBySignal(): void;
1370
+ _onNetworkIsDetectedPossiblyDownBySignal(): void;
1328
1371
  setupSocketListeners(): void;
1329
1372
  _emitScreenshareStarted(): void;
1330
1373
  _connect(): void;
1374
+ _connect_v2(): void;
1331
1375
  _onClose(): void;
1332
1376
  _join(): Promise<void>;
1333
1377
  _createTransport(send: any): Promise<void>;
package/dist/index.mjs CHANGED
@@ -1716,6 +1716,7 @@ var rtcManagerEvents = {
1716
1716
  NEW_PC: "new_pc",
1717
1717
  SFU_CONNECTION_OPEN: "sfu_connection_open",
1718
1718
  SFU_CONNECTION_CLOSED: "sfu_connection_closed",
1719
+ SFU_CONNECTION_INFO: "sfu_connection_info",
1719
1720
  COLOCATION_SPEAKER: "colocation_speaker",
1720
1721
  DOMINANT_SPEAKER: "dominant_speaker",
1721
1722
  PC_SLD_FAILURE: "pc_sld_failure",
@@ -4224,6 +4225,167 @@ function getNumberOfTemporalLayers(consumer) {
4224
4225
  return /T3/.test(((_c = (_b = (_a = consumer._rtpParameters) === null || _a === void 0 ? void 0 : _a.encodings) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.scalabilityMode) || "") ? 3 : 2;
4225
4226
  }
4226
4227
 
4228
+ const timeNextServer = 500;
4229
+ const minTimeNextServerSameDC = 2000;
4230
+ const timeToWaitForEarlyServerClose = 100;
4231
+ function convertToProperHostList(hostList) {
4232
+ if (typeof hostList === "string") {
4233
+ return hostList
4234
+ .split(",")
4235
+ .filter(Boolean)
4236
+ .map((hostString) => {
4237
+ const [dc, host] = /\|/.test(hostString) ? hostString.split("|") : ["", hostString];
4238
+ return { host, dc };
4239
+ });
4240
+ }
4241
+ return hostList.filter((item) => item.host).map((item) => ({ host: item.host, dc: item.dc || "" }));
4242
+ }
4243
+ function createVegaConnectionManager(config) {
4244
+ let connectionInfo;
4245
+ let lastDisconnectTime;
4246
+ let lastNetworkUpTime;
4247
+ let lastNetworkPossiblyDownTime;
4248
+ let hostList = [];
4249
+ const updateHostList = (updatedHostList) => {
4250
+ hostList = convertToProperHostList(updatedHostList);
4251
+ };
4252
+ let connectionAttemptInProgress = false;
4253
+ let hasPendingConnectionAttempt = false;
4254
+ const connect = () => {
4255
+ if (connectionAttemptInProgress) {
4256
+ hasPendingConnectionAttempt = true;
4257
+ return;
4258
+ }
4259
+ connectionAttemptInProgress = true;
4260
+ hasPendingConnectionAttempt = false;
4261
+ let targetHostList = hostList;
4262
+ if (connectionInfo) {
4263
+ const now = Date.now();
4264
+ const isLongEnoughSinceDisconnect = now - 3000 > (lastDisconnectTime || 0);
4265
+ const isNetworkUp = !lastNetworkPossiblyDownTime || (lastNetworkUpTime || 0) > lastNetworkPossiblyDownTime;
4266
+ const hasNetworkBeenUpLongEnough = isNetworkUp && now - 3000 > (lastNetworkUpTime || 0);
4267
+ if (!isLongEnoughSinceDisconnect || !hasNetworkBeenUpLongEnough) {
4268
+ targetHostList = [{ host: connectionInfo.host, dc: connectionInfo.dc }];
4269
+ }
4270
+ }
4271
+ const dcIndexByDC = {};
4272
+ let currentDCIndex = 0;
4273
+ targetHostList.forEach(({ dc }) => {
4274
+ if (typeof dcIndexByDC[dc] === "undefined")
4275
+ dcIndexByDC[dc] = currentDCIndex++;
4276
+ });
4277
+ let timeBeforeConnect = 0;
4278
+ const prevTimeBeforeConnectByDC = {};
4279
+ let nominatedConnection;
4280
+ let connectionsToResolve = targetHostList.length;
4281
+ let hasNotifiedDisconnect = false;
4282
+ let wasConnected = false;
4283
+ targetHostList.forEach(({ host, dc }, index) => {
4284
+ if (index > 0) {
4285
+ timeBeforeConnect += timeNextServer;
4286
+ const minTimeBeforeConnect = (prevTimeBeforeConnectByDC[dc] || 0) + minTimeNextServerSameDC;
4287
+ timeBeforeConnect = Math.max(timeBeforeConnect, minTimeBeforeConnect);
4288
+ }
4289
+ prevTimeBeforeConnectByDC[dc] = timeBeforeConnect;
4290
+ setTimeout(() => {
4291
+ var _a;
4292
+ if (wasConnected)
4293
+ return;
4294
+ const vegaConnection = new VegaConnection(((_a = config.getUrlForHost) === null || _a === void 0 ? void 0 : _a.call(config, host)) || host);
4295
+ let wasClosed = false;
4296
+ vegaConnection.on("open", () => {
4297
+ setTimeout(() => {
4298
+ var _a;
4299
+ if (wasClosed)
4300
+ return;
4301
+ if (!nominatedConnection && !wasConnected) {
4302
+ nominatedConnection = vegaConnection;
4303
+ wasConnected = true;
4304
+ const thisRoundFailedHosts = [
4305
+ ...new Set(targetHostList
4306
+ .slice(0, index)
4307
+ .filter((o) => o.host !== host)
4308
+ .map((o) => o.host)),
4309
+ ];
4310
+ const thisRoundFailedDCs = [
4311
+ ...new Set(targetHostList
4312
+ .slice(0, index)
4313
+ .filter((o) => o.dc !== dc)
4314
+ .map((o) => o.dc)),
4315
+ ];
4316
+ if (!connectionInfo) {
4317
+ connectionInfo = {
4318
+ host,
4319
+ dc,
4320
+ initialHost: host,
4321
+ initialDC: dc,
4322
+ initialHostIndex: index,
4323
+ initialDCIndex: dcIndexByDC[dc],
4324
+ failedHosts: thisRoundFailedHosts,
4325
+ failedDCs: thisRoundFailedDCs,
4326
+ usedHosts: [host],
4327
+ usedDCs: [dc],
4328
+ numConnections: 1,
4329
+ numUsedDCs: 1,
4330
+ numUsedHosts: 1,
4331
+ numFailedDCs: 0,
4332
+ numFailedHosts: 0,
4333
+ };
4334
+ }
4335
+ else {
4336
+ connectionInfo = Object.assign(Object.assign({}, connectionInfo), { host,
4337
+ dc, failedHosts: [
4338
+ ...new Set([...thisRoundFailedHosts, ...connectionInfo.failedHosts]),
4339
+ ].filter((failedHost) => failedHost !== host && !connectionInfo.usedHosts.includes(failedHost)), failedDCs: [
4340
+ ...new Set([...thisRoundFailedDCs, ...connectionInfo.failedDCs]),
4341
+ ].filter((failedDC) => failedDC !== dc && !connectionInfo.usedDCs.includes(failedDC)), usedHosts: [...new Set([...connectionInfo.usedHosts, host])], usedDCs: [...new Set([...connectionInfo.usedDCs, dc])], numConnections: connectionInfo.numConnections + 1 });
4342
+ }
4343
+ connectionInfo.numUsedDCs = connectionInfo.usedDCs.length;
4344
+ connectionInfo.numUsedHosts = connectionInfo.usedHosts.length;
4345
+ connectionInfo.numFailedDCs = connectionInfo.failedDCs.length;
4346
+ connectionInfo.numFailedHosts = connectionInfo.failedHosts.length;
4347
+ hasPendingConnectionAttempt = false;
4348
+ connectionAttemptInProgress = false;
4349
+ (_a = config.onConnected) === null || _a === void 0 ? void 0 : _a.call(config, vegaConnection, connectionInfo);
4350
+ }
4351
+ else {
4352
+ vegaConnection.close();
4353
+ }
4354
+ }, timeToWaitForEarlyServerClose);
4355
+ });
4356
+ vegaConnection.on("close", () => {
4357
+ var _a, _b;
4358
+ wasClosed = true;
4359
+ if (vegaConnection === nominatedConnection) {
4360
+ nominatedConnection = undefined;
4361
+ lastDisconnectTime = Date.now();
4362
+ hasNotifiedDisconnect = true;
4363
+ (_a = config.onDisconnected) === null || _a === void 0 ? void 0 : _a.call(config);
4364
+ }
4365
+ connectionsToResolve--;
4366
+ if (connectionsToResolve === 0 && !hasNotifiedDisconnect) {
4367
+ connectionAttemptInProgress = false;
4368
+ if (hasPendingConnectionAttempt) {
4369
+ setTimeout(connect, 0);
4370
+ }
4371
+ else {
4372
+ (_b = config.onFailed) === null || _b === void 0 ? void 0 : _b.call(config);
4373
+ }
4374
+ }
4375
+ });
4376
+ }, timeBeforeConnect);
4377
+ });
4378
+ };
4379
+ updateHostList(config.initialHostList);
4380
+ const networkIsUp = () => {
4381
+ lastNetworkUpTime = Math.max(Date.now(), lastNetworkUpTime || 0);
4382
+ };
4383
+ const networkIsPossiblyDown = () => {
4384
+ lastNetworkPossiblyDownTime = Date.now();
4385
+ };
4386
+ return { connect, updateHostList, networkIsUp, networkIsPossiblyDown };
4387
+ }
4388
+
4227
4389
  var _a$2;
4228
4390
  const adapter$2 = (_a$2 = adapterRaw.default) !== null && _a$2 !== void 0 ? _a$2 : adapterRaw;
4229
4391
  const logger$4 = new Logger();
@@ -4237,7 +4399,7 @@ if (browserName === "chrome")
4237
4399
  window.document.addEventListener("beforeunload", () => (unloading = true));
4238
4400
  class VegaRtcManager {
4239
4401
  constructor({ selfId, room, emitter, serverSocket, webrtcProvider, features, eventClaim, }) {
4240
- const { session, iceServers, sfuServer, mediaserverConfigTtlSeconds } = room;
4402
+ const { session, iceServers, sfuServer, sfuServers, mediaserverConfigTtlSeconds } = room;
4241
4403
  this._selfId = selfId;
4242
4404
  this._room = room;
4243
4405
  this._roomSessionId = session === null || session === void 0 ? void 0 : session.id;
@@ -4289,6 +4451,7 @@ class VegaRtcManager {
4289
4451
  };
4290
4452
  this._updateAndScheduleMediaServersRefresh({
4291
4453
  sfuServer,
4454
+ sfuServers,
4292
4455
  iceServers: iceServers.iceServers || [],
4293
4456
  mediaserverConfigTtlSeconds,
4294
4457
  });
@@ -4296,18 +4459,31 @@ class VegaRtcManager {
4296
4459
  this._reconnect = true;
4297
4460
  this._reconnectTimeOut = null;
4298
4461
  this._hasVegaConnection = false;
4462
+ this._isConnectingOrConnected = false;
4299
4463
  this._qualityMonitor = new VegaMediaQualityMonitor();
4300
4464
  this._qualityMonitor.on(PROTOCOL_EVENTS.MEDIA_QUALITY_CHANGED, (payload) => {
4301
4465
  this._emitToPWA(PROTOCOL_EVENTS.MEDIA_QUALITY_CHANGED, payload);
4302
4466
  });
4467
+ this._networkIsDetectedUpBySignal = false;
4303
4468
  }
4304
- _updateAndScheduleMediaServersRefresh({ iceServers, sfuServer, mediaserverConfigTtlSeconds, }) {
4305
- var _a, _b;
4469
+ _updateAndScheduleMediaServersRefresh({ iceServers, sfuServer, sfuServers, mediaserverConfigTtlSeconds, }) {
4470
+ var _a, _b, _c;
4306
4471
  this._iceServers = iceServers;
4307
4472
  this._sfuServer = sfuServer;
4473
+ this._sfuServers = sfuServers;
4474
+ if (!sfuServers && (sfuServer === null || sfuServer === void 0 ? void 0 : sfuServer.fallbackServers)) {
4475
+ this._sfuServers = sfuServer.fallbackServers.map((entry) => ({
4476
+ host: entry.host || entry.fqdn,
4477
+ dc: entry.dc,
4478
+ }));
4479
+ }
4308
4480
  this._mediaserverConfigTtlSeconds = mediaserverConfigTtlSeconds;
4309
- (_a = this._sendTransport) === null || _a === void 0 ? void 0 : _a.updateIceServers({ iceServers: this._iceServers });
4310
- (_b = this._receiveTransport) === null || _b === void 0 ? void 0 : _b.updateIceServers({ iceServers: this._iceServers });
4481
+ (_a = this._vegaConnectionManager) === null || _a === void 0 ? void 0 : _a.updateHostList(this._features.sfuServersOverride ||
4482
+ this._sfuServers ||
4483
+ this._features.sfuServerOverrideHost ||
4484
+ sfuServer.url);
4485
+ (_b = this._sendTransport) === null || _b === void 0 ? void 0 : _b.updateIceServers({ iceServers: this._iceServers });
4486
+ (_c = this._receiveTransport) === null || _c === void 0 ? void 0 : _c.updateIceServers({ iceServers: this._iceServers });
4311
4487
  this._clearMediaServersRefresh();
4312
4488
  if (!mediaserverConfigTtlSeconds) {
4313
4489
  return;
@@ -4320,6 +4496,20 @@ class VegaRtcManager {
4320
4496
  clearTimeout(this._fetchMediaServersTimer);
4321
4497
  this._fetchMediaServersTimer = null;
4322
4498
  }
4499
+ _onNetworkIsDetectedUpBySignal() {
4500
+ var _a;
4501
+ if (!this._networkIsDetectedUpBySignal) {
4502
+ this._networkIsDetectedUpBySignal = true;
4503
+ (_a = this._vegaConnectionManager) === null || _a === void 0 ? void 0 : _a.networkIsUp();
4504
+ }
4505
+ }
4506
+ _onNetworkIsDetectedPossiblyDownBySignal() {
4507
+ var _a;
4508
+ if (this._networkIsDetectedUpBySignal) {
4509
+ this._networkIsDetectedUpBySignal = false;
4510
+ (_a = this._vegaConnectionManager) === null || _a === void 0 ? void 0 : _a.networkIsPossiblyDown();
4511
+ }
4512
+ }
4323
4513
  setupSocketListeners() {
4324
4514
  this._socketListenerDeregisterFunctions.push(() => this._clearMediaServersRefresh(), this._serverSocket.on(PROTOCOL_RESPONSES.MEDIASERVER_CONFIG, (data) => {
4325
4515
  if (data.error) {
@@ -4333,7 +4523,7 @@ class VegaRtcManager {
4333
4523
  if (this._features.sfuReconnectV2On && !this._hasVegaConnection && this._reconnect) {
4334
4524
  this._connect();
4335
4525
  }
4336
- }));
4526
+ }), this._serverSocket.on("connect", () => this._onNetworkIsDetectedUpBySignal()), this._serverSocket.onEngineEvent("packet", () => this._onNetworkIsDetectedUpBySignal()), this._serverSocket.on("disconnect", () => this._onNetworkIsDetectedPossiblyDownBySignal()));
4337
4527
  this._connect();
4338
4528
  }
4339
4529
  _emitScreenshareStarted() {
@@ -4343,6 +4533,8 @@ class VegaRtcManager {
4343
4533
  });
4344
4534
  }
4345
4535
  _connect() {
4536
+ if (this._features.sfuConnectionManagerOn)
4537
+ return this._connect_v2();
4346
4538
  if (this._features.sfuReconnectV2On) {
4347
4539
  if (this._hasVegaConnection)
4348
4540
  return;
@@ -4368,6 +4560,56 @@ class VegaRtcManager {
4368
4560
  this._vegaConnection.on("close", () => this._onClose());
4369
4561
  this._vegaConnection.on("message", (message) => this._onMessage(message));
4370
4562
  }
4563
+ _connect_v2() {
4564
+ if (this._features.sfuReconnectV2On) {
4565
+ if (this._isConnectingOrConnected)
4566
+ return;
4567
+ if (!this._serverSocket.isConnected()) {
4568
+ const reconnectThresholdInMs = this._serverSocket.getReconnectThreshold();
4569
+ if (!reconnectThresholdInMs)
4570
+ return;
4571
+ if (Date.now() > (this._serverSocket.disconnectTimestamp || 0) + reconnectThresholdInMs)
4572
+ return;
4573
+ }
4574
+ if (this._reconnectTimeOut)
4575
+ clearTimeout(this._reconnectTimeOut);
4576
+ }
4577
+ if (!this._vegaConnectionManager) {
4578
+ const hostList = this._features.sfuServersOverride ||
4579
+ this._sfuServers ||
4580
+ this._features.sfuServerOverrideHost ||
4581
+ this._sfuServer.url;
4582
+ this._vegaConnectionManager = createVegaConnectionManager({
4583
+ initialHostList: hostList,
4584
+ getUrlForHost: (host) => {
4585
+ const searchParams = new URLSearchParams(Object.assign({ clientId: this._selfId, organizationId: this._room.organizationId, roomName: this._room.name, eventClaim: this._room.isClaimed ? this._eventClaim : null, lowBw: "true" }, Object.keys(this._features || {})
4586
+ .filter((featureKey) => this._features[featureKey] && /^sfu/.test(featureKey))
4587
+ .reduce((prev, current) => (Object.assign(Object.assign({}, prev), { [current]: this._features[current] })), {})));
4588
+ const queryString = searchParams.toString();
4589
+ const wsUrl = `wss://${host}?${queryString}`;
4590
+ return wsUrl;
4591
+ },
4592
+ onConnected: (vegaConnection, info) => {
4593
+ this._vegaConnection = vegaConnection;
4594
+ this._vegaConnection.on("message", (message) => this._onMessage(message));
4595
+ this._emitToPWA(rtcManagerEvents.SFU_CONNECTION_INFO, info);
4596
+ this._join();
4597
+ },
4598
+ onDisconnected: () => {
4599
+ this._vegaConnection = null;
4600
+ this._isConnectingOrConnected = false;
4601
+ this._onClose();
4602
+ },
4603
+ onFailed: () => {
4604
+ this._vegaConnection = null;
4605
+ this._isConnectingOrConnected = false;
4606
+ this._onClose();
4607
+ },
4608
+ });
4609
+ }
4610
+ this._vegaConnectionManager.connect();
4611
+ this._isConnectingOrConnected = true;
4612
+ }
4371
4613
  _onClose() {
4372
4614
  var _a, _b;
4373
4615
  logger$4.info("_onClose()");
@@ -6061,6 +6303,14 @@ class ServerSocket {
6061
6303
  this._socket.off(eventName, handler);
6062
6304
  };
6063
6305
  }
6306
+ onEngineEvent(eventName, handler) {
6307
+ var _a;
6308
+ (_a = this._socket.io) === null || _a === void 0 ? void 0 : _a.on(eventName, handler);
6309
+ return () => {
6310
+ var _a;
6311
+ (_a = this._socket.io) === null || _a === void 0 ? void 0 : _a.off(eventName, handler);
6312
+ };
6313
+ }
6064
6314
  once(eventName, handler) {
6065
6315
  this._socket.once(eventName, handler);
6066
6316
  }
@@ -1716,6 +1716,7 @@ var rtcManagerEvents = {
1716
1716
  NEW_PC: "new_pc",
1717
1717
  SFU_CONNECTION_OPEN: "sfu_connection_open",
1718
1718
  SFU_CONNECTION_CLOSED: "sfu_connection_closed",
1719
+ SFU_CONNECTION_INFO: "sfu_connection_info",
1719
1720
  COLOCATION_SPEAKER: "colocation_speaker",
1720
1721
  DOMINANT_SPEAKER: "dominant_speaker",
1721
1722
  PC_SLD_FAILURE: "pc_sld_failure",
@@ -4224,6 +4225,167 @@ function getNumberOfTemporalLayers(consumer) {
4224
4225
  return /T3/.test(((_c = (_b = (_a = consumer._rtpParameters) === null || _a === void 0 ? void 0 : _a.encodings) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.scalabilityMode) || "") ? 3 : 2;
4225
4226
  }
4226
4227
 
4228
+ const timeNextServer = 500;
4229
+ const minTimeNextServerSameDC = 2000;
4230
+ const timeToWaitForEarlyServerClose = 100;
4231
+ function convertToProperHostList(hostList) {
4232
+ if (typeof hostList === "string") {
4233
+ return hostList
4234
+ .split(",")
4235
+ .filter(Boolean)
4236
+ .map((hostString) => {
4237
+ const [dc, host] = /\|/.test(hostString) ? hostString.split("|") : ["", hostString];
4238
+ return { host, dc };
4239
+ });
4240
+ }
4241
+ return hostList.filter((item) => item.host).map((item) => ({ host: item.host, dc: item.dc || "" }));
4242
+ }
4243
+ function createVegaConnectionManager(config) {
4244
+ let connectionInfo;
4245
+ let lastDisconnectTime;
4246
+ let lastNetworkUpTime;
4247
+ let lastNetworkPossiblyDownTime;
4248
+ let hostList = [];
4249
+ const updateHostList = (updatedHostList) => {
4250
+ hostList = convertToProperHostList(updatedHostList);
4251
+ };
4252
+ let connectionAttemptInProgress = false;
4253
+ let hasPendingConnectionAttempt = false;
4254
+ const connect = () => {
4255
+ if (connectionAttemptInProgress) {
4256
+ hasPendingConnectionAttempt = true;
4257
+ return;
4258
+ }
4259
+ connectionAttemptInProgress = true;
4260
+ hasPendingConnectionAttempt = false;
4261
+ let targetHostList = hostList;
4262
+ if (connectionInfo) {
4263
+ const now = Date.now();
4264
+ const isLongEnoughSinceDisconnect = now - 3000 > (lastDisconnectTime || 0);
4265
+ const isNetworkUp = !lastNetworkPossiblyDownTime || (lastNetworkUpTime || 0) > lastNetworkPossiblyDownTime;
4266
+ const hasNetworkBeenUpLongEnough = isNetworkUp && now - 3000 > (lastNetworkUpTime || 0);
4267
+ if (!isLongEnoughSinceDisconnect || !hasNetworkBeenUpLongEnough) {
4268
+ targetHostList = [{ host: connectionInfo.host, dc: connectionInfo.dc }];
4269
+ }
4270
+ }
4271
+ const dcIndexByDC = {};
4272
+ let currentDCIndex = 0;
4273
+ targetHostList.forEach(({ dc }) => {
4274
+ if (typeof dcIndexByDC[dc] === "undefined")
4275
+ dcIndexByDC[dc] = currentDCIndex++;
4276
+ });
4277
+ let timeBeforeConnect = 0;
4278
+ const prevTimeBeforeConnectByDC = {};
4279
+ let nominatedConnection;
4280
+ let connectionsToResolve = targetHostList.length;
4281
+ let hasNotifiedDisconnect = false;
4282
+ let wasConnected = false;
4283
+ targetHostList.forEach(({ host, dc }, index) => {
4284
+ if (index > 0) {
4285
+ timeBeforeConnect += timeNextServer;
4286
+ const minTimeBeforeConnect = (prevTimeBeforeConnectByDC[dc] || 0) + minTimeNextServerSameDC;
4287
+ timeBeforeConnect = Math.max(timeBeforeConnect, minTimeBeforeConnect);
4288
+ }
4289
+ prevTimeBeforeConnectByDC[dc] = timeBeforeConnect;
4290
+ setTimeout(() => {
4291
+ var _a;
4292
+ if (wasConnected)
4293
+ return;
4294
+ const vegaConnection = new VegaConnection(((_a = config.getUrlForHost) === null || _a === void 0 ? void 0 : _a.call(config, host)) || host);
4295
+ let wasClosed = false;
4296
+ vegaConnection.on("open", () => {
4297
+ setTimeout(() => {
4298
+ var _a;
4299
+ if (wasClosed)
4300
+ return;
4301
+ if (!nominatedConnection && !wasConnected) {
4302
+ nominatedConnection = vegaConnection;
4303
+ wasConnected = true;
4304
+ const thisRoundFailedHosts = [
4305
+ ...new Set(targetHostList
4306
+ .slice(0, index)
4307
+ .filter((o) => o.host !== host)
4308
+ .map((o) => o.host)),
4309
+ ];
4310
+ const thisRoundFailedDCs = [
4311
+ ...new Set(targetHostList
4312
+ .slice(0, index)
4313
+ .filter((o) => o.dc !== dc)
4314
+ .map((o) => o.dc)),
4315
+ ];
4316
+ if (!connectionInfo) {
4317
+ connectionInfo = {
4318
+ host,
4319
+ dc,
4320
+ initialHost: host,
4321
+ initialDC: dc,
4322
+ initialHostIndex: index,
4323
+ initialDCIndex: dcIndexByDC[dc],
4324
+ failedHosts: thisRoundFailedHosts,
4325
+ failedDCs: thisRoundFailedDCs,
4326
+ usedHosts: [host],
4327
+ usedDCs: [dc],
4328
+ numConnections: 1,
4329
+ numUsedDCs: 1,
4330
+ numUsedHosts: 1,
4331
+ numFailedDCs: 0,
4332
+ numFailedHosts: 0,
4333
+ };
4334
+ }
4335
+ else {
4336
+ connectionInfo = Object.assign(Object.assign({}, connectionInfo), { host,
4337
+ dc, failedHosts: [
4338
+ ...new Set([...thisRoundFailedHosts, ...connectionInfo.failedHosts]),
4339
+ ].filter((failedHost) => failedHost !== host && !connectionInfo.usedHosts.includes(failedHost)), failedDCs: [
4340
+ ...new Set([...thisRoundFailedDCs, ...connectionInfo.failedDCs]),
4341
+ ].filter((failedDC) => failedDC !== dc && !connectionInfo.usedDCs.includes(failedDC)), usedHosts: [...new Set([...connectionInfo.usedHosts, host])], usedDCs: [...new Set([...connectionInfo.usedDCs, dc])], numConnections: connectionInfo.numConnections + 1 });
4342
+ }
4343
+ connectionInfo.numUsedDCs = connectionInfo.usedDCs.length;
4344
+ connectionInfo.numUsedHosts = connectionInfo.usedHosts.length;
4345
+ connectionInfo.numFailedDCs = connectionInfo.failedDCs.length;
4346
+ connectionInfo.numFailedHosts = connectionInfo.failedHosts.length;
4347
+ hasPendingConnectionAttempt = false;
4348
+ connectionAttemptInProgress = false;
4349
+ (_a = config.onConnected) === null || _a === void 0 ? void 0 : _a.call(config, vegaConnection, connectionInfo);
4350
+ }
4351
+ else {
4352
+ vegaConnection.close();
4353
+ }
4354
+ }, timeToWaitForEarlyServerClose);
4355
+ });
4356
+ vegaConnection.on("close", () => {
4357
+ var _a, _b;
4358
+ wasClosed = true;
4359
+ if (vegaConnection === nominatedConnection) {
4360
+ nominatedConnection = undefined;
4361
+ lastDisconnectTime = Date.now();
4362
+ hasNotifiedDisconnect = true;
4363
+ (_a = config.onDisconnected) === null || _a === void 0 ? void 0 : _a.call(config);
4364
+ }
4365
+ connectionsToResolve--;
4366
+ if (connectionsToResolve === 0 && !hasNotifiedDisconnect) {
4367
+ connectionAttemptInProgress = false;
4368
+ if (hasPendingConnectionAttempt) {
4369
+ setTimeout(connect, 0);
4370
+ }
4371
+ else {
4372
+ (_b = config.onFailed) === null || _b === void 0 ? void 0 : _b.call(config);
4373
+ }
4374
+ }
4375
+ });
4376
+ }, timeBeforeConnect);
4377
+ });
4378
+ };
4379
+ updateHostList(config.initialHostList);
4380
+ const networkIsUp = () => {
4381
+ lastNetworkUpTime = Math.max(Date.now(), lastNetworkUpTime || 0);
4382
+ };
4383
+ const networkIsPossiblyDown = () => {
4384
+ lastNetworkPossiblyDownTime = Date.now();
4385
+ };
4386
+ return { connect, updateHostList, networkIsUp, networkIsPossiblyDown };
4387
+ }
4388
+
4227
4389
  var _a$2;
4228
4390
  const adapter$2 = (_a$2 = adapterRaw.default) !== null && _a$2 !== void 0 ? _a$2 : adapterRaw;
4229
4391
  const logger$4 = new Logger();
@@ -4237,7 +4399,7 @@ if (browserName === "chrome")
4237
4399
  window.document.addEventListener("beforeunload", () => (unloading = true));
4238
4400
  class VegaRtcManager {
4239
4401
  constructor({ selfId, room, emitter, serverSocket, webrtcProvider, features, eventClaim, }) {
4240
- const { session, iceServers, sfuServer, mediaserverConfigTtlSeconds } = room;
4402
+ const { session, iceServers, sfuServer, sfuServers, mediaserverConfigTtlSeconds } = room;
4241
4403
  this._selfId = selfId;
4242
4404
  this._room = room;
4243
4405
  this._roomSessionId = session === null || session === void 0 ? void 0 : session.id;
@@ -4289,6 +4451,7 @@ class VegaRtcManager {
4289
4451
  };
4290
4452
  this._updateAndScheduleMediaServersRefresh({
4291
4453
  sfuServer,
4454
+ sfuServers,
4292
4455
  iceServers: iceServers.iceServers || [],
4293
4456
  mediaserverConfigTtlSeconds,
4294
4457
  });
@@ -4296,18 +4459,31 @@ class VegaRtcManager {
4296
4459
  this._reconnect = true;
4297
4460
  this._reconnectTimeOut = null;
4298
4461
  this._hasVegaConnection = false;
4462
+ this._isConnectingOrConnected = false;
4299
4463
  this._qualityMonitor = new VegaMediaQualityMonitor();
4300
4464
  this._qualityMonitor.on(PROTOCOL_EVENTS.MEDIA_QUALITY_CHANGED, (payload) => {
4301
4465
  this._emitToPWA(PROTOCOL_EVENTS.MEDIA_QUALITY_CHANGED, payload);
4302
4466
  });
4467
+ this._networkIsDetectedUpBySignal = false;
4303
4468
  }
4304
- _updateAndScheduleMediaServersRefresh({ iceServers, sfuServer, mediaserverConfigTtlSeconds, }) {
4305
- var _a, _b;
4469
+ _updateAndScheduleMediaServersRefresh({ iceServers, sfuServer, sfuServers, mediaserverConfigTtlSeconds, }) {
4470
+ var _a, _b, _c;
4306
4471
  this._iceServers = iceServers;
4307
4472
  this._sfuServer = sfuServer;
4473
+ this._sfuServers = sfuServers;
4474
+ if (!sfuServers && (sfuServer === null || sfuServer === void 0 ? void 0 : sfuServer.fallbackServers)) {
4475
+ this._sfuServers = sfuServer.fallbackServers.map((entry) => ({
4476
+ host: entry.host || entry.fqdn,
4477
+ dc: entry.dc,
4478
+ }));
4479
+ }
4308
4480
  this._mediaserverConfigTtlSeconds = mediaserverConfigTtlSeconds;
4309
- (_a = this._sendTransport) === null || _a === void 0 ? void 0 : _a.updateIceServers({ iceServers: this._iceServers });
4310
- (_b = this._receiveTransport) === null || _b === void 0 ? void 0 : _b.updateIceServers({ iceServers: this._iceServers });
4481
+ (_a = this._vegaConnectionManager) === null || _a === void 0 ? void 0 : _a.updateHostList(this._features.sfuServersOverride ||
4482
+ this._sfuServers ||
4483
+ this._features.sfuServerOverrideHost ||
4484
+ sfuServer.url);
4485
+ (_b = this._sendTransport) === null || _b === void 0 ? void 0 : _b.updateIceServers({ iceServers: this._iceServers });
4486
+ (_c = this._receiveTransport) === null || _c === void 0 ? void 0 : _c.updateIceServers({ iceServers: this._iceServers });
4311
4487
  this._clearMediaServersRefresh();
4312
4488
  if (!mediaserverConfigTtlSeconds) {
4313
4489
  return;
@@ -4320,6 +4496,20 @@ class VegaRtcManager {
4320
4496
  clearTimeout(this._fetchMediaServersTimer);
4321
4497
  this._fetchMediaServersTimer = null;
4322
4498
  }
4499
+ _onNetworkIsDetectedUpBySignal() {
4500
+ var _a;
4501
+ if (!this._networkIsDetectedUpBySignal) {
4502
+ this._networkIsDetectedUpBySignal = true;
4503
+ (_a = this._vegaConnectionManager) === null || _a === void 0 ? void 0 : _a.networkIsUp();
4504
+ }
4505
+ }
4506
+ _onNetworkIsDetectedPossiblyDownBySignal() {
4507
+ var _a;
4508
+ if (this._networkIsDetectedUpBySignal) {
4509
+ this._networkIsDetectedUpBySignal = false;
4510
+ (_a = this._vegaConnectionManager) === null || _a === void 0 ? void 0 : _a.networkIsPossiblyDown();
4511
+ }
4512
+ }
4323
4513
  setupSocketListeners() {
4324
4514
  this._socketListenerDeregisterFunctions.push(() => this._clearMediaServersRefresh(), this._serverSocket.on(PROTOCOL_RESPONSES.MEDIASERVER_CONFIG, (data) => {
4325
4515
  if (data.error) {
@@ -4333,7 +4523,7 @@ class VegaRtcManager {
4333
4523
  if (this._features.sfuReconnectV2On && !this._hasVegaConnection && this._reconnect) {
4334
4524
  this._connect();
4335
4525
  }
4336
- }));
4526
+ }), this._serverSocket.on("connect", () => this._onNetworkIsDetectedUpBySignal()), this._serverSocket.onEngineEvent("packet", () => this._onNetworkIsDetectedUpBySignal()), this._serverSocket.on("disconnect", () => this._onNetworkIsDetectedPossiblyDownBySignal()));
4337
4527
  this._connect();
4338
4528
  }
4339
4529
  _emitScreenshareStarted() {
@@ -4343,6 +4533,8 @@ class VegaRtcManager {
4343
4533
  });
4344
4534
  }
4345
4535
  _connect() {
4536
+ if (this._features.sfuConnectionManagerOn)
4537
+ return this._connect_v2();
4346
4538
  if (this._features.sfuReconnectV2On) {
4347
4539
  if (this._hasVegaConnection)
4348
4540
  return;
@@ -4368,6 +4560,56 @@ class VegaRtcManager {
4368
4560
  this._vegaConnection.on("close", () => this._onClose());
4369
4561
  this._vegaConnection.on("message", (message) => this._onMessage(message));
4370
4562
  }
4563
+ _connect_v2() {
4564
+ if (this._features.sfuReconnectV2On) {
4565
+ if (this._isConnectingOrConnected)
4566
+ return;
4567
+ if (!this._serverSocket.isConnected()) {
4568
+ const reconnectThresholdInMs = this._serverSocket.getReconnectThreshold();
4569
+ if (!reconnectThresholdInMs)
4570
+ return;
4571
+ if (Date.now() > (this._serverSocket.disconnectTimestamp || 0) + reconnectThresholdInMs)
4572
+ return;
4573
+ }
4574
+ if (this._reconnectTimeOut)
4575
+ clearTimeout(this._reconnectTimeOut);
4576
+ }
4577
+ if (!this._vegaConnectionManager) {
4578
+ const hostList = this._features.sfuServersOverride ||
4579
+ this._sfuServers ||
4580
+ this._features.sfuServerOverrideHost ||
4581
+ this._sfuServer.url;
4582
+ this._vegaConnectionManager = createVegaConnectionManager({
4583
+ initialHostList: hostList,
4584
+ getUrlForHost: (host) => {
4585
+ const searchParams = new URLSearchParams(Object.assign({ clientId: this._selfId, organizationId: this._room.organizationId, roomName: this._room.name, eventClaim: this._room.isClaimed ? this._eventClaim : null, lowBw: "true" }, Object.keys(this._features || {})
4586
+ .filter((featureKey) => this._features[featureKey] && /^sfu/.test(featureKey))
4587
+ .reduce((prev, current) => (Object.assign(Object.assign({}, prev), { [current]: this._features[current] })), {})));
4588
+ const queryString = searchParams.toString();
4589
+ const wsUrl = `wss://${host}?${queryString}`;
4590
+ return wsUrl;
4591
+ },
4592
+ onConnected: (vegaConnection, info) => {
4593
+ this._vegaConnection = vegaConnection;
4594
+ this._vegaConnection.on("message", (message) => this._onMessage(message));
4595
+ this._emitToPWA(rtcManagerEvents.SFU_CONNECTION_INFO, info);
4596
+ this._join();
4597
+ },
4598
+ onDisconnected: () => {
4599
+ this._vegaConnection = null;
4600
+ this._isConnectingOrConnected = false;
4601
+ this._onClose();
4602
+ },
4603
+ onFailed: () => {
4604
+ this._vegaConnection = null;
4605
+ this._isConnectingOrConnected = false;
4606
+ this._onClose();
4607
+ },
4608
+ });
4609
+ }
4610
+ this._vegaConnectionManager.connect();
4611
+ this._isConnectingOrConnected = true;
4612
+ }
4371
4613
  _onClose() {
4372
4614
  var _a, _b;
4373
4615
  logger$4.info("_onClose()");
@@ -6061,6 +6303,14 @@ class ServerSocket {
6061
6303
  this._socket.off(eventName, handler);
6062
6304
  };
6063
6305
  }
6306
+ onEngineEvent(eventName, handler) {
6307
+ var _a;
6308
+ (_a = this._socket.io) === null || _a === void 0 ? void 0 : _a.on(eventName, handler);
6309
+ return () => {
6310
+ var _a;
6311
+ (_a = this._socket.io) === null || _a === void 0 ? void 0 : _a.off(eventName, handler);
6312
+ };
6313
+ }
6064
6314
  once(eventName, handler) {
6065
6315
  this._socket.once(eventName, handler);
6066
6316
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@whereby.com/media",
3
3
  "description": "Media library for Whereby",
4
- "version": "1.17.16",
4
+ "version": "1.18.0",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/whereby/sdk",
7
7
  "repository": {