@whereby.com/media 11.1.2 → 11.1.3

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.
@@ -284,7 +284,7 @@ class Logger {
284
284
 
285
285
  var _a$5, _b$2;
286
286
  const adapter$5 = (_a$5 = adapterRaw.default) !== null && _a$5 !== void 0 ? _a$5 : adapterRaw;
287
- const logger$b = new Logger();
287
+ const logger$c = new Logger();
288
288
  const browserName$2 = (_b$2 = adapter$5.browserDetails) === null || _b$2 === void 0 ? void 0 : _b$2.browser;
289
289
  const browserVersion$1 = adapter$5.browserDetails.version;
290
290
  function setCodecPreferenceSDP({ sdp, redOn }) {
@@ -325,7 +325,7 @@ function setCodecPreferenceSDP({ sdp, redOn }) {
325
325
  return newSdp;
326
326
  }
327
327
  catch (error) {
328
- logger$b.error("setCodecPreferenceSDP error:", error);
328
+ logger$c.error("setCodecPreferenceSDP error:", error);
329
329
  return sdp;
330
330
  }
331
331
  }
@@ -476,7 +476,7 @@ function trackAnnotations(o) {
476
476
 
477
477
  var _a$4;
478
478
  const adapter$4 = (_a$4 = adapterRaw.default) !== null && _a$4 !== void 0 ? _a$4 : adapterRaw;
479
- const logger$a = new Logger();
479
+ const logger$b = new Logger();
480
480
  class Session {
481
481
  constructor({ clientId, bandwidth, peerConnectionConfig, deprioritizeH264Encoding, incrementAnalyticMetric, mediaPrefs, }) {
482
482
  this.relayCandidateSeen = false;
@@ -608,7 +608,7 @@ class Session {
608
608
  }
609
609
  handleAnswer(message) {
610
610
  if (this.pc.signalingState !== "have-local-offer") {
611
- logger$a.warn("Ignoring stale SDP answer for client %s (signalingState: %s)", this.clientId, this.pc.signalingState);
611
+ logger$b.warn("Ignoring stale SDP answer for client %s (signalingState: %s)", this.clientId, this.pc.signalingState);
612
612
  this._incrementAnalyticMetric("P2PStaleAnswerIgnored");
613
613
  rtcStats.sendEvent("P2PStaleAnswerIgnored", {
614
614
  clientId: this.clientId,
@@ -636,7 +636,7 @@ class Session {
636
636
  return;
637
637
  }
638
638
  this.pc.addIceCandidate(candidate).catch((e) => {
639
- logger$a.warn("Failed to add ICE candidate ('%s'): %s", candidate ? candidate.candidate : null, e);
639
+ logger$b.warn("Failed to add ICE candidate ('%s'): %s", candidate ? candidate.candidate : null, e);
640
640
  this._incrementAnalyticMetric("P2PAddIceCandidateFailure");
641
641
  rtcStats.sendEvent("P2PAddIceCandidateFailure", {
642
642
  clientId: this.clientId,
@@ -664,7 +664,7 @@ class Session {
664
664
  pc.close();
665
665
  }
666
666
  catch (e) {
667
- logger$a.warn("failures during close of session", e);
667
+ logger$b.warn("failures during close of session", e);
668
668
  }
669
669
  }
670
670
  hasConnectedPeerConnection() {
@@ -673,7 +673,7 @@ class Session {
673
673
  replaceTrack(oldTrack, newTrack) {
674
674
  return __awaiter(this, void 0, void 0, function* () {
675
675
  var _a;
676
- logger$a.info("replacetrack() [oldTrackId: %s, newTrackId: %s]", oldTrack === null || oldTrack === void 0 ? void 0 : oldTrack.id, newTrack.id);
676
+ logger$b.info("replacetrack() [oldTrackId: %s, newTrackId: %s]", oldTrack === null || oldTrack === void 0 ? void 0 : oldTrack.id, newTrack.id);
677
677
  if (newTrack.readyState === "ended") {
678
678
  throw new Error(`refusing to use ended track with id: ${newTrack.id}, kind: ${newTrack.kind}`);
679
679
  }
@@ -744,6 +744,16 @@ class Session {
744
744
  }
745
745
 
746
746
  const MEDIA_JITTER_BUFFER_TARGET = 400;
747
+ const INITIAL_CONSUMER_SPATIAL_LAYER = 1;
748
+ const INITIAL_HIGHEST_PREFERRED_LAYER = 1;
749
+ const LOWEST_SVC_LAYER_MAX_BITRATE = 100000;
750
+ const MIDDLE_SVC_LAYER_MAX_BITRATE = 500000;
751
+ const PREFERRED_LAYER_SWITCH_POLL_INTERVAL_MS = 100;
752
+ const PREFERRED_LAYER_SWITCH_WATCH_TIMEOUT_MS = 10000;
753
+ const MAX_CONCURRENT_PREFERRED_LAYER_SWITCH_WATCHES = 5;
754
+ const CONGESTED_RTT_INFLATION_MS = 100;
755
+ const CONGESTED_FRACTION_LOST = 0.02;
756
+ const CAM_SAMPLES_SKIPPED_AFTER_CANDIDATE_PAIR_CHANGE = 2;
747
757
 
748
758
  const PROTOCOL_REQUESTS = {
749
759
  BLOCK_CLIENT: "block_client",
@@ -1043,7 +1053,7 @@ const getMediasoupDeviceAsync = (features) => __awaiter(void 0, void 0, void 0,
1043
1053
  return new Device({ handlerName });
1044
1054
  });
1045
1055
 
1046
- const logger$9 = new Logger();
1056
+ const logger$a = new Logger();
1047
1057
  const AUDIO_SETTINGS = {
1048
1058
  codecOptions: {
1049
1059
  opusDtx: true,
@@ -1223,7 +1233,7 @@ function sortCodecsByPowerEfficiency(codecs) {
1223
1233
  codecPowerEfficiencyEntries = yield Promise.all(codecs.map(({ mimeType }) => getIsCodecDecodingPowerEfficient(mimeType).then((val) => [mimeType, val])));
1224
1234
  }
1225
1235
  catch (error) {
1226
- logger$9.error(error);
1236
+ logger$a.error(error);
1227
1237
  return codecs;
1228
1238
  }
1229
1239
  const codecPowerEfficiencies = Object.fromEntries(codecPowerEfficiencyEntries);
@@ -1292,7 +1302,24 @@ function captureSsrcInfo(ssrcMetrics, currentSsrcStats, prevSsrcStats, timeDiff,
1292
1302
  ssrcMetrics.mid = currentSsrcStats.mid;
1293
1303
  ssrcMetrics.rid = currentSsrcStats.rid;
1294
1304
  }
1305
+ const selectedCandidatePairIdByReport = new WeakMap();
1306
+ function getSelectedCandidatePairId(report, transportId) {
1307
+ var _a;
1308
+ const selectedCandidatePairId = transportId ? (_a = report.get(transportId)) === null || _a === void 0 ? void 0 : _a.selectedCandidatePairId : undefined;
1309
+ if (selectedCandidatePairId)
1310
+ return selectedCandidatePairId;
1311
+ if (!selectedCandidatePairIdByReport.has(report)) {
1312
+ let selectedId;
1313
+ report.forEach((stats) => {
1314
+ if (stats.type === "candidate-pair" && stats.selected)
1315
+ selectedId = stats.id;
1316
+ });
1317
+ selectedCandidatePairIdByReport.set(report, selectedId);
1318
+ }
1319
+ return selectedCandidatePairIdByReport.get(report);
1320
+ }
1295
1321
  function captureCommonSsrcMetrics(ssrcMetrics, currentSsrcStats, prevSsrcStats, timeDiff, report) {
1322
+ ssrcMetrics.selectedCandidatePairId = getSelectedCandidatePairId(report, currentSsrcStats.transportId);
1296
1323
  const nackCountDiff = (currentSsrcStats.nackCount || 0) - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.nackCount) || 0);
1297
1324
  ssrcMetrics.nackCount = (ssrcMetrics.nackCount || 0) + nackCountDiff;
1298
1325
  ssrcMetrics.nackRate = (1000 * nackCountDiff) / timeDiff;
@@ -1346,6 +1373,7 @@ function captureCommonSsrcMetrics(ssrcMetrics, currentSsrcStats, prevSsrcStats,
1346
1373
  ssrcMetrics.roundTripTime = remoteReport.roundTripTime || 0;
1347
1374
  ssrcMetrics.jitter = remoteReport.jitter || 0;
1348
1375
  ssrcMetrics.fractionLost = remoteReport.fractionLost || 0;
1376
+ ssrcMetrics.remoteReportTimestamp = remoteReport.timestamp;
1349
1377
  }
1350
1378
  }
1351
1379
  }
@@ -1577,7 +1605,6 @@ const DEFAULT_CLIENT = {
1577
1605
  };
1578
1606
  function collectStats(state_1, _a, immediate_1) {
1579
1607
  return __awaiter(this, arguments, void 0, function* (state, { logger, interval }, immediate) {
1580
- const collectStatsBound = collectStats.bind(null, state, { interval, logger });
1581
1608
  try {
1582
1609
  const clients = state.getClients();
1583
1610
  const defaultClient = clients.find((c) => c.isLocalClient && !c.isPresentation) || DEFAULT_CLIENT;
@@ -1592,7 +1619,6 @@ function collectStats(state_1, _a, immediate_1) {
1592
1619
  if (immediate)
1593
1620
  return state.statsByView;
1594
1621
  state.subscriptions.forEach((subscription) => { var _a; return (_a = subscription.onUpdatedStats) === null || _a === void 0 ? void 0 : _a.call(subscription, state.statsByView, clients, state.renderedDimensionsByTrack); });
1595
- state.nextTimeout = setTimeout(collectStatsBound, interval);
1596
1622
  return;
1597
1623
  }
1598
1624
  state.lastUpdateTime = Date.now();
@@ -1715,11 +1741,10 @@ function collectStats(state_1, _a, immediate_1) {
1715
1741
  message: e === null || e === void 0 ? void 0 : e.message,
1716
1742
  });
1717
1743
  }
1718
- state.nextTimeout = setTimeout(collectStatsBound, interval);
1719
1744
  });
1720
1745
  }
1721
1746
 
1722
- const logger$8 = new Logger();
1747
+ const logger$9 = new Logger();
1723
1748
  const CPU_OBSERVER_OPTIONS = {
1724
1749
  sampleRate: 1,
1725
1750
  };
@@ -1729,7 +1754,7 @@ function startCpuObserver(cb, { sampleRate } = CPU_OBSERVER_OPTIONS, window = gl
1729
1754
  if ("PressureObserver" in window &&
1730
1755
  (window.PressureObserver.knownSources || []).includes("cpu")) {
1731
1756
  pressureObserver = new window.PressureObserver(cb, { sampleRate });
1732
- (_a = pressureObserver.observe("cpu", { sampleInterval: sampleRate * 1000 })) === null || _a === void 0 ? void 0 : _a.catch((error) => logger$8.error(error));
1757
+ (_a = pressureObserver.observe("cpu", { sampleInterval: sampleRate * 1000 })) === null || _a === void 0 ? void 0 : _a.catch((error) => logger$9.error(error));
1733
1758
  return {
1734
1759
  stop: () => {
1735
1760
  pressureObserver.unobserve("cpu");
@@ -1765,7 +1790,20 @@ const updateRenderedDimensions = (trackId, data) => {
1765
1790
  STATE.renderedDimensionsByTrack[trackId] = data;
1766
1791
  };
1767
1792
  function startStatsMonitor(state, { interval, logger }) {
1768
- const collectStatsBound = collectStats.bind(null, state, { interval, logger });
1793
+ let stopped = false;
1794
+ let nextTimeout;
1795
+ const scheduleNextRun = () => {
1796
+ nextTimeout = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
1797
+ try {
1798
+ yield collectStats(state, { interval, logger }, false);
1799
+ }
1800
+ catch (error) {
1801
+ logger.error("Stats collection failed unexpectedly", error);
1802
+ }
1803
+ if (!stopped)
1804
+ scheduleNextRun();
1805
+ }), interval);
1806
+ };
1769
1807
  let cpuObserver;
1770
1808
  try {
1771
1809
  cpuObserver = startCpuObserver((records) => (state.lastPressureObserverRecord = records.pop()));
@@ -1773,13 +1811,14 @@ function startStatsMonitor(state, { interval, logger }) {
1773
1811
  catch (ex) {
1774
1812
  logger.warn("Failed to observe CPU pressure", ex);
1775
1813
  }
1776
- setTimeout(collectStatsBound, interval);
1814
+ scheduleNextRun();
1777
1815
  return {
1778
1816
  getUpdatedStats: () => {
1779
- return collectStatsBound(true);
1817
+ return collectStats(state, { interval, logger }, true);
1780
1818
  },
1781
1819
  stop: () => {
1782
- clearTimeout(state.nextTimeout);
1820
+ stopped = true;
1821
+ clearTimeout(nextTimeout);
1783
1822
  cpuObserver === null || cpuObserver === void 0 ? void 0 : cpuObserver.stop();
1784
1823
  },
1785
1824
  };
@@ -1800,7 +1839,7 @@ function subscribeStats(subscription, options = OPTIONS, state = STATE) {
1800
1839
  };
1801
1840
  }
1802
1841
 
1803
- const logger$7 = new Logger();
1842
+ const logger$8 = new Logger();
1804
1843
  class ReconnectManager extends EventEmitter {
1805
1844
  constructor(socket) {
1806
1845
  super();
@@ -1888,7 +1927,7 @@ class ReconnectManager extends EventEmitter {
1888
1927
  client.mergeWithOldClientState = true;
1889
1928
  }
1890
1929
  catch (error) {
1891
- logger$7.error("Failed to evaluate if we should merge client state %o", error);
1930
+ logger$8.error("Failed to evaluate if we should merge client state %o", error);
1892
1931
  this.metrics.evaluationFailed++;
1893
1932
  }
1894
1933
  });
@@ -1916,7 +1955,7 @@ class ReconnectManager extends EventEmitter {
1916
1955
  const { clientId } = payload;
1917
1956
  const client = this._clients[clientId];
1918
1957
  if (!client) {
1919
- logger$7.warn(`client ${clientId} not found`);
1958
+ logger$8.warn(`client ${clientId} not found`);
1920
1959
  return;
1921
1960
  }
1922
1961
  if (client.isPendingToLeave) {
@@ -2389,7 +2428,7 @@ fromLocation(typeof window !== "undefined" ? window.location : undefined);
2389
2428
 
2390
2429
  var _a$2, _b$1;
2391
2430
  const adapter$2 = (_a$2 = adapterRaw.default) !== null && _a$2 !== void 0 ? _a$2 : adapterRaw;
2392
- const logger$6 = new Logger();
2431
+ const logger$7 = new Logger();
2393
2432
  const ICE_PUBLIC_IP_GATHERING_TIMEOUT = 3 * 1000;
2394
2433
  const ICE_RESTART_DELAY = 2 * 1000;
2395
2434
  const browserName$1 = (_b$1 = adapter$2.browserDetails) === null || _b$1 === void 0 ? void 0 : _b$1.browser;
@@ -2470,7 +2509,7 @@ class P2pRtcManager {
2470
2509
  return this._selfId === selfId && this._roomName === roomName && !isSfu;
2471
2510
  }
2472
2511
  addCameraStream(stream, { beforeEffectTracks = [] } = { beforeEffectTracks: [] }) {
2473
- logger$6.info("addCameraStream: [stream.id: %s]", stream.id);
2512
+ logger$7.info("addCameraStream: [stream.id: %s]", stream.id);
2474
2513
  if (stream === this._localCameraStream) {
2475
2514
  return;
2476
2515
  }
@@ -2513,7 +2552,7 @@ class P2pRtcManager {
2513
2552
  };
2514
2553
  }
2515
2554
  addScreenshareStream(stream) {
2516
- logger$6.info("addScreenshareStream() [stream.id: %s]", stream.id);
2555
+ logger$7.info("addScreenshareStream() [stream.id: %s]", stream.id);
2517
2556
  if (stream === this._localScreenshareStream) {
2518
2557
  return;
2519
2558
  }
@@ -2526,7 +2565,7 @@ class P2pRtcManager {
2526
2565
  this._addStreamToPeerConnections(stream);
2527
2566
  }
2528
2567
  replaceTrack(oldTrack, newTrack) {
2529
- logger$6.info("replaceTrack() [kind: %s, oldTrackId: %s, newTrackId: %s]", newTrack.kind, oldTrack === null || oldTrack === void 0 ? void 0 : oldTrack.id, newTrack.id);
2568
+ logger$7.info("replaceTrack() [kind: %s, oldTrackId: %s, newTrackId: %s]", newTrack.kind, oldTrack === null || oldTrack === void 0 ? void 0 : oldTrack.id, newTrack.id);
2530
2569
  if (newTrack.kind === "audio" && !trackAnnotations(newTrack).isEffectTrack) {
2531
2570
  this._monitorAudioTrack(newTrack);
2532
2571
  }
@@ -2540,7 +2579,7 @@ class P2pRtcManager {
2540
2579
  this.disconnectAll();
2541
2580
  }
2542
2581
  disconnectAll() {
2543
- logger$6.info("disconnectAll()");
2582
+ logger$7.info("disconnectAll()");
2544
2583
  Object.keys(this.peerConnections).forEach((clientId) => {
2545
2584
  this.disconnect(clientId);
2546
2585
  });
@@ -2560,39 +2599,39 @@ class P2pRtcManager {
2560
2599
  () => this._clearMediaServersRefresh(),
2561
2600
  this._serverSocket.on(PROTOCOL_RESPONSES.MEDIASERVER_CONFIG, (data) => {
2562
2601
  if (data.error) {
2563
- logger$6.warn("FETCH_MEDIASERVER_CONFIG failed:", data.error);
2602
+ logger$7.warn("FETCH_MEDIASERVER_CONFIG failed:", data.error);
2564
2603
  return;
2565
2604
  }
2566
2605
  this._updateAndScheduleMediaServersRefresh(data);
2567
2606
  }),
2568
2607
  this._serverSocket.on(RELAY_MESSAGES.READY_TO_RECEIVE_OFFER, (data) => {
2569
- logger$6.info(`Got ready_to_receive_offer from client ${data.clientId}`);
2608
+ logger$7.info(`Got ready_to_receive_offer from client ${data.clientId}`);
2570
2609
  this._connect(data.clientId);
2571
2610
  }),
2572
2611
  this._serverSocket.on(RELAY_MESSAGES.ICE_CANDIDATE, (data) => {
2573
- logger$6.info(`Got ice_candidate from client ${data.clientId}`);
2612
+ logger$7.info(`Got ice_candidate from client ${data.clientId}`);
2574
2613
  const session = this._getSession(data.clientId);
2575
2614
  if (!session) {
2576
- logger$6.warn("No RTCPeerConnection on ICE_CANDIDATE", data);
2615
+ logger$7.warn("No RTCPeerConnection on ICE_CANDIDATE", data);
2577
2616
  return;
2578
2617
  }
2579
2618
  session.addIceCandidate(data.message);
2580
2619
  }),
2581
2620
  this._serverSocket.on(RELAY_MESSAGES.ICE_END_OF_CANDIDATES, (data) => {
2582
- logger$6.info(`Got end_of_ice_candidates from client ${data.clientId}`);
2621
+ logger$7.info(`Got end_of_ice_candidates from client ${data.clientId}`);
2583
2622
  const session = this._getSession(data.clientId);
2584
2623
  if (!session) {
2585
- logger$6.warn("No RTCPeerConnection on ICE_END_OF_CANDIDATES", data);
2624
+ logger$7.warn("No RTCPeerConnection on ICE_END_OF_CANDIDATES", data);
2586
2625
  return;
2587
2626
  }
2588
2627
  session.addIceCandidate(null);
2589
2628
  }),
2590
2629
  this._serverSocket.on(RELAY_MESSAGES.SDP_OFFER, (data) => {
2591
2630
  var _a, _b;
2592
- logger$6.info(`Got offer from client ${data.clientId}, isInitialOffer: ${Boolean(data.message.isInitialOffer)}`);
2631
+ logger$7.info(`Got offer from client ${data.clientId}, isInitialOffer: ${Boolean(data.message.isInitialOffer)}`);
2593
2632
  const session = this._getSession(data.clientId);
2594
2633
  if (!session) {
2595
- logger$6.warn("No RTCPeerConnection on SDP_OFFER", data);
2634
+ logger$7.warn("No RTCPeerConnection on SDP_OFFER", data);
2596
2635
  return;
2597
2636
  }
2598
2637
  const sdp = {
@@ -2604,7 +2643,7 @@ class P2pRtcManager {
2604
2643
  session.pc.connectionState === "new" &&
2605
2644
  session.pc.iceConnectionState === "new" &&
2606
2645
  !session.connectionStatus) {
2607
- logger$6.info("We have asked for an initial offer, ignoring all others");
2646
+ logger$7.info("We have asked for an initial offer, ignoring all others");
2608
2647
  this.analytics.P2POffendingInitialOffer++;
2609
2648
  rtcStats.sendEvent("P2POffendingInitialOffer", { clientId: session.clientId });
2610
2649
  return;
@@ -2612,22 +2651,22 @@ class P2pRtcManager {
2612
2651
  (_b = (_a = session
2613
2652
  .handleOffer(sdp)
2614
2653
  .then((answer) => {
2615
- logger$6.info(`Sending answer to client ${data.clientId}`);
2654
+ logger$7.info(`Sending answer to client ${data.clientId}`);
2616
2655
  this._emitServerEvent(RELAY_MESSAGES.SDP_ANSWER, {
2617
2656
  receiverId: data.clientId,
2618
2657
  message: answer,
2619
2658
  });
2620
2659
  })).catch) === null || _b === void 0 ? void 0 : _b.call(_a, (e) => {
2621
- logger$6.error(e);
2660
+ logger$7.error(e);
2622
2661
  this.analytics.numPcOnOfferFailure++;
2623
2662
  });
2624
2663
  }),
2625
2664
  this._serverSocket.on(RELAY_MESSAGES.SDP_ANSWER, (data) => {
2626
2665
  var _a, _b;
2627
- logger$6.info(`Got answer from client ${data.clientId}`);
2666
+ logger$7.info(`Got answer from client ${data.clientId}`);
2628
2667
  const session = this._getSession(data.clientId);
2629
2668
  if (!session) {
2630
- logger$6.warn("No RTCPeerConnection on SDP_ANSWER", data);
2669
+ logger$7.warn("No RTCPeerConnection on SDP_ANSWER", data);
2631
2670
  return;
2632
2671
  }
2633
2672
  const sdp = {
@@ -2635,7 +2674,7 @@ class P2pRtcManager {
2635
2674
  type: data.message.type,
2636
2675
  };
2637
2676
  (_b = (_a = session.handleAnswer(sdp)) === null || _a === void 0 ? void 0 : _a.catch) === null || _b === void 0 ? void 0 : _b.call(_a, (e) => {
2638
- logger$6.warn("Could not set remote description from remote answer: ", e);
2677
+ logger$7.warn("Could not set remote description from remote answer: ", e);
2639
2678
  this.analytics.numPcOnAnswerFailure++;
2640
2679
  });
2641
2680
  }),
@@ -2723,12 +2762,12 @@ class P2pRtcManager {
2723
2762
  });
2724
2763
  }
2725
2764
  catch (error) {
2726
- logger$6.error("Error during setting jitter buffer target:", error);
2765
+ logger$7.error("Error during setting jitter buffer target:", error);
2727
2766
  }
2728
2767
  }
2729
2768
  _emitServerEvent(eventName, data) {
2730
2769
  if (this._closed) {
2731
- logger$6.warn("RtcManager closed. Will not send event", eventName, data);
2770
+ logger$7.warn("RtcManager closed. Will not send event", eventName, data);
2732
2771
  return;
2733
2772
  }
2734
2773
  if (this._features.awaitJoinRoomFinished && !this._serverSocket.joinRoomFinished) {
@@ -2833,7 +2872,7 @@ class P2pRtcManager {
2833
2872
  }
2834
2873
  }
2835
2874
  catch (error) {
2836
- logger$6.info("Error during parsing candidates! Error: ", { error });
2875
+ logger$7.info("Error during parsing candidates! Error: ", { error });
2837
2876
  }
2838
2877
  break;
2839
2878
  case "srflx":
@@ -2875,7 +2914,7 @@ class P2pRtcManager {
2875
2914
  if (pc.iceConnectionState === "new" || !session.connectionStatus) {
2876
2915
  return;
2877
2916
  }
2878
- logger$6.info(`onnegotiationneeded client ${clientId}`);
2917
+ logger$7.info(`onnegotiationneeded client ${clientId}`);
2879
2918
  this._negotiatePeerConnection({ clientId, session });
2880
2919
  };
2881
2920
  pc.ontrack = (event) => {
@@ -2900,7 +2939,7 @@ class P2pRtcManager {
2900
2939
  };
2901
2940
  pc.oniceconnectionstatechange = () => {
2902
2941
  var _a;
2903
- logger$6.info(`iceConnectionState changed to ${pc.iceConnectionState} for session ${session.clientId}`);
2942
+ logger$7.info(`iceConnectionState changed to ${pc.iceConnectionState} for session ${session.clientId}`);
2904
2943
  let newStatus;
2905
2944
  const currentStatus = session.connectionStatus;
2906
2945
  switch (pc.iceConnectionState) {
@@ -2955,7 +2994,7 @@ class P2pRtcManager {
2955
2994
  };
2956
2995
  pc.onconnectionstatechange = () => {
2957
2996
  var _a;
2958
- logger$6.info(`connectionState changed to ${pc.connectionState} for session ${session.clientId}`);
2997
+ logger$7.info(`connectionState changed to ${pc.connectionState} for session ${session.clientId}`);
2959
2998
  switch (pc.connectionState) {
2960
2999
  case "connected":
2961
3000
  (_a = session.registerConnected) === null || _a === void 0 ? void 0 : _a.call(session, {});
@@ -3012,7 +3051,7 @@ class P2pRtcManager {
3012
3051
  _cleanup(clientId) {
3013
3052
  const session = this._getSession(clientId);
3014
3053
  if (!session) {
3015
- logger$6.warn("No RTCPeerConnection in RTCManager.disconnect()", clientId);
3054
+ logger$7.warn("No RTCPeerConnection in RTCManager.disconnect()", clientId);
3016
3055
  return;
3017
3056
  }
3018
3057
  this.removeRemoteClientMediaPrefs(session.clientId);
@@ -3040,7 +3079,7 @@ class P2pRtcManager {
3040
3079
  if (!session.hasConnectedPeerConnection()) {
3041
3080
  if (session.pc.connectionState === "closed")
3042
3081
  return;
3043
- logger$6.info("Session doesn't have a connected PeerConnection, adding pending action!");
3082
+ logger$7.info("Session doesn't have a connected PeerConnection, adding pending action!");
3044
3083
  const promise = new Promise((resolve, reject) => {
3045
3084
  const action = () => __awaiter(this, void 0, void 0, function* () {
3046
3085
  try {
@@ -3059,7 +3098,7 @@ class P2pRtcManager {
3059
3098
  promises.push(session.replaceTrack(oldTrack, newTrack));
3060
3099
  });
3061
3100
  return Promise.all(promises).catch((error) => {
3062
- logger$6.error(String(error));
3101
+ logger$7.error(String(error));
3063
3102
  });
3064
3103
  }
3065
3104
  _removeStreamFromPeerConnections(stream) {
@@ -3107,7 +3146,7 @@ class P2pRtcManager {
3107
3146
  let session = this._getSession(clientId);
3108
3147
  let initialBandwidth = (session && session.bandwidth) || 0;
3109
3148
  if (session) {
3110
- logger$6.warn("Replacing peer session", clientId);
3149
+ logger$7.warn("Replacing peer session", clientId);
3111
3150
  this._cleanup(clientId);
3112
3151
  }
3113
3152
  else {
@@ -3178,13 +3217,13 @@ class P2pRtcManager {
3178
3217
  })));
3179
3218
  }
3180
3219
  catch (error) {
3181
- logger$6.error("Error during setting setCodecPreferences:", error);
3220
+ logger$7.error("Error during setting setCodecPreferences:", error);
3182
3221
  }
3183
3222
  });
3184
3223
  }
3185
3224
  _negotiatePeerConnection({ clientId, session, constraints, isInitialOffer = false, }) {
3186
3225
  if (!session) {
3187
- logger$6.warn("No RTCPeerConnection in negotiatePeerConnection()", clientId);
3226
+ logger$7.warn("No RTCPeerConnection in negotiatePeerConnection()", clientId);
3188
3227
  return;
3189
3228
  }
3190
3229
  const pc = session.pc;
@@ -3214,7 +3253,7 @@ class P2pRtcManager {
3214
3253
  offer.sdp = cleanSdp(offer.sdp);
3215
3254
  pc.setLocalDescription(offer)
3216
3255
  .catch((e) => {
3217
- logger$6.warn("RTCPeerConnection.setLocalDescription() failed with local offer", e);
3256
+ logger$7.warn("RTCPeerConnection.setLocalDescription() failed with local offer", e);
3218
3257
  this.analytics.numPcSldFailure++;
3219
3258
  throw e;
3220
3259
  })
@@ -3226,7 +3265,7 @@ class P2pRtcManager {
3226
3265
  type: offer.type,
3227
3266
  isInitialOffer,
3228
3267
  };
3229
- logger$6.info(`sending offer to client ${clientId}`);
3268
+ logger$7.info(`sending offer to client ${clientId}`);
3230
3269
  this._emitServerEvent(RELAY_MESSAGES.SDP_OFFER, {
3231
3270
  receiverId: clientId,
3232
3271
  message,
@@ -3234,7 +3273,7 @@ class P2pRtcManager {
3234
3273
  });
3235
3274
  })
3236
3275
  .catch((e) => {
3237
- logger$6.warn("RTCPeerConnection.createOffer() failed to create local offer", e);
3276
+ logger$7.warn("RTCPeerConnection.createOffer() failed to create local offer", e);
3238
3277
  }));
3239
3278
  }
3240
3279
  _withForcedRenegotiation(session, action) {
@@ -3276,7 +3315,7 @@ class P2pRtcManager {
3276
3315
  return bandwidth;
3277
3316
  }
3278
3317
  acceptNewStream({ streamId, clientId }) {
3279
- logger$6.info("acceptNewStream() [streamId: %s}, clientId: %s]", streamId, clientId);
3318
+ logger$7.info("acceptNewStream() [streamId: %s}, clientId: %s]", streamId, clientId);
3280
3319
  let session = this._getSession(clientId);
3281
3320
  if (session && streamId !== clientId) {
3282
3321
  return session;
@@ -3299,7 +3338,7 @@ class P2pRtcManager {
3299
3338
  return session;
3300
3339
  }
3301
3340
  disconnect(clientId) {
3302
- logger$6.info("disconnect() [clientId: %s]", clientId);
3341
+ logger$7.info("disconnect() [clientId: %s]", clientId);
3303
3342
  this._cleanup(clientId);
3304
3343
  this._changeBandwidthForAllClients(false);
3305
3344
  const numPeers = this.numberOfPeerconnections();
@@ -3336,7 +3375,7 @@ class P2pRtcManager {
3336
3375
  stopOrResumeVideo() {
3337
3376
  }
3338
3377
  removeScreenshareStream(stream, { requestedByClientId } = {}) {
3339
- logger$6.info("removeScreenshareStream() [stream.id: %s, requestedByClientId: %s]", stream.id, requestedByClientId);
3378
+ logger$7.info("removeScreenshareStream() [stream.id: %s, requestedByClientId: %s]", stream.id, requestedByClientId);
3340
3379
  this._removeStreamFromPeerConnections(stream);
3341
3380
  this._emitServerEvent(PROTOCOL_REQUESTS.STOP_SCREENSHARE, { streamId: stream.id, requestedByClientId });
3342
3381
  delete this._localScreenshareStream;
@@ -3457,7 +3496,7 @@ const defaultParams = {
3457
3496
  scoreFormula: "300 * bands[1].avg / Math.max(bands[1].avg + bands[0].avg, 0.01)",
3458
3497
  outFormula: "score",
3459
3498
  };
3460
- const logger$5 = new Logger();
3499
+ const logger$6 = new Logger();
3461
3500
  function createMicAnalyser({ micTrack, params, onScoreUpdated, }) {
3462
3501
  const audioCtx = new AudioContext();
3463
3502
  let analyser = null;
@@ -3479,7 +3518,7 @@ function createMicAnalyser({ micTrack, params, onScoreUpdated, }) {
3479
3518
  lastTrackWasOurs = true;
3480
3519
  }
3481
3520
  catch (ex) {
3482
- logger$5.warn("unable to fetch new track for colocation speaker analysis, using current", ex);
3521
+ logger$6.warn("unable to fetch new track for colocation speaker analysis, using current", ex);
3483
3522
  }
3484
3523
  }
3485
3524
  lastTrack = track;
@@ -3566,7 +3605,7 @@ function createMicAnalyser({ micTrack, params, onScoreUpdated, }) {
3566
3605
  };
3567
3606
  }
3568
3607
 
3569
- const logger$4 = new Logger();
3608
+ const logger$5 = new Logger();
3570
3609
  const MEDIA_QUALITY = Object.freeze({
3571
3610
  ok: "ok",
3572
3611
  warning: "warning",
@@ -3636,7 +3675,7 @@ class VegaMediaQualityMonitor extends EventEmitter {
3636
3675
  }
3637
3676
  addProducer(clientId, producerId) {
3638
3677
  if (!clientId || !producerId || !(typeof clientId === "string" && typeof producerId === "string")) {
3639
- logger$4.warn("Missing clientId or producerId");
3678
+ logger$5.warn("Missing clientId or producerId");
3640
3679
  return;
3641
3680
  }
3642
3681
  if (!this._producers[clientId]) {
@@ -3652,7 +3691,7 @@ class VegaMediaQualityMonitor extends EventEmitter {
3652
3691
  }
3653
3692
  addConsumer(clientId, consumerId) {
3654
3693
  if (!clientId || !consumerId) {
3655
- logger$4.warn("Missing clientId or consumerId");
3694
+ logger$5.warn("Missing clientId or consumerId");
3656
3695
  return;
3657
3696
  }
3658
3697
  if (!this._producers[clientId]) {
@@ -3670,14 +3709,14 @@ class VegaMediaQualityMonitor extends EventEmitter {
3670
3709
  if (!Array.isArray(score) ||
3671
3710
  score.length === 0 ||
3672
3711
  score.some((s) => !s || !s.hasOwnProperty("score") || typeof s.score !== "number" || isNaN(s.score))) {
3673
- logger$4.warn("Unexpected producer score format");
3712
+ logger$5.warn("Unexpected producer score format");
3674
3713
  return;
3675
3714
  }
3676
3715
  this._producers[clientId][producerId] = { kind, score: this._calcAvgProducerScore(score.map((s) => s.score)) };
3677
3716
  }
3678
3717
  addConsumerScore(clientId, consumerId, kind, score) {
3679
3718
  if (!score || !score.hasOwnProperty("producerScores") || !Array.isArray(score.producerScores)) {
3680
- logger$4.warn("Unexpected consumer score format");
3719
+ logger$5.warn("Unexpected consumer score format");
3681
3720
  return;
3682
3721
  }
3683
3722
  this._producers[clientId][consumerId] = { kind, score: this._calcAvgProducerScore(score.producerScores) };
@@ -3714,12 +3753,13 @@ class VegaMediaQualityMonitor extends EventEmitter {
3714
3753
  }
3715
3754
  }
3716
3755
  catch (error) {
3717
- logger$4.error(error);
3756
+ logger$5.error(error);
3718
3757
  return 0;
3719
3758
  }
3720
3759
  }
3721
3760
  }
3722
3761
 
3762
+ const logger$4 = new Logger();
3723
3763
  function getLayers({ width, height, }, { numberOfActiveVideos, numberOfTemporalLayers, uncappedSingleRemoteVideoOn, }) {
3724
3764
  const maxSide = Math.max(width, height);
3725
3765
  let spatialLayer = maxSide >= 480 ? (maxSide >= 960 ? 2 : 1) : 0;
@@ -3739,6 +3779,27 @@ function getLayers({ width, height, }, { numberOfActiveVideos, numberOfTemporalL
3739
3779
  }
3740
3780
  return { spatialLayer, temporalLayer };
3741
3781
  }
3782
+ function createMetricStats() {
3783
+ return { count: 0, sum: 0 };
3784
+ }
3785
+ function recordMetricSample(stats, value) {
3786
+ stats.count++;
3787
+ stats.sum += value;
3788
+ }
3789
+ function aggregateMetricStats(stats) {
3790
+ return {
3791
+ count: stats.count,
3792
+ avg: stats.count ? Math.round(stats.sum / stats.count) : undefined,
3793
+ };
3794
+ }
3795
+ function getPacketWeightedFractionLost(reports) {
3796
+ const weights = reports.map(({ packetRate }) => (packetRate && packetRate > 0 ? packetRate : 0));
3797
+ const totalWeight = weights.reduce((sum, weight) => sum + weight, 0);
3798
+ if (!totalWeight) {
3799
+ return reports.reduce((sum, { fractionLost }) => sum + (fractionLost || 0), 0) / (reports.length || 1);
3800
+ }
3801
+ return (reports.reduce((sum, { fractionLost }, index) => sum + (fractionLost || 0) * weights[index], 0) / totalWeight);
3802
+ }
3742
3803
  function getNumberOfActiveVideos(consumers) {
3743
3804
  let numberOfActiveVideos = 0;
3744
3805
  consumers.forEach((c) => {
@@ -3754,6 +3815,51 @@ function getNumberOfTemporalLayers(consumer) {
3754
3815
  var _a, _b, _c;
3755
3816
  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;
3756
3817
  }
3818
+ const SCALABILITY_MODE_REGEX = /^([LS])([1-9]\d?)T([1-9]\d?)(_KEY)?$/;
3819
+ function getTopSpatialLayer(encodings) {
3820
+ if (encodings.length > 1)
3821
+ return encodings.length - 1;
3822
+ const { scalabilityMode } = encodings[0];
3823
+ const match = SCALABILITY_MODE_REGEX.exec(scalabilityMode || "");
3824
+ if (!match) {
3825
+ if (scalabilityMode) {
3826
+ logger$4.warn("getTopSpatialLayer() unrecognized scalabilityMode %s, using a single spatial layer", scalabilityMode);
3827
+ }
3828
+ return 0;
3829
+ }
3830
+ const spatialLayers = Number(match[2]) || 1;
3831
+ return spatialLayers - 1;
3832
+ }
3833
+ function getInitialHighestPreferredLayer(encodings) {
3834
+ return Math.min(getTopSpatialLayer(encodings), INITIAL_HIGHEST_PREFERRED_LAYER);
3835
+ }
3836
+ function getReducedSvcEncodingParams(originalScalabilityMode, spatialLayer, originalMaxBitrate) {
3837
+ const match = SCALABILITY_MODE_REGEX.exec(originalScalabilityMode || "");
3838
+ if (!match)
3839
+ return undefined;
3840
+ const [, mode, originalSpatialLayers, temporalLayers, key = ""] = match;
3841
+ const topLayerIndex = Number(originalSpatialLayers) - 1;
3842
+ if (topLayerIndex === 0)
3843
+ return undefined;
3844
+ const preferredLayerIndex = Math.min(Math.max(spatialLayer, 0), topLayerIndex);
3845
+ const onlyLowestLayerPreferred = preferredLayerIndex === 0;
3846
+ const middleLayerPreferred = preferredLayerIndex > 0 && preferredLayerIndex < topLayerIndex;
3847
+ let maxBitrate = originalMaxBitrate;
3848
+ if (onlyLowestLayerPreferred) {
3849
+ maxBitrate = Math.min(LOWEST_SVC_LAYER_MAX_BITRATE, originalMaxBitrate !== null && originalMaxBitrate !== void 0 ? originalMaxBitrate : Infinity);
3850
+ }
3851
+ else if (middleLayerPreferred) {
3852
+ maxBitrate = Math.min(MIDDLE_SVC_LAYER_MAX_BITRATE, originalMaxBitrate !== null && originalMaxBitrate !== void 0 ? originalMaxBitrate : Infinity);
3853
+ }
3854
+ const scalabilityMode = onlyLowestLayerPreferred
3855
+ ? `L1T${temporalLayers}`
3856
+ : `${mode}${preferredLayerIndex + 1}T${temporalLayers}${key}`;
3857
+ return {
3858
+ scalabilityMode,
3859
+ scaleResolutionDownBy: Math.pow(2, (topLayerIndex - preferredLayerIndex)),
3860
+ maxBitrate,
3861
+ };
3862
+ }
3757
3863
  function addProducerCpuOveruseWatch({ producer, onOveruse }) {
3758
3864
  var _a;
3759
3865
  const encodings = (_a = producer.rtpParameters) === null || _a === void 0 ? void 0 : _a.encodings;
@@ -4210,6 +4316,7 @@ const RESTARTICE_ERROR_RETRY_THRESHOLD_IN_MS = 3500;
4210
4316
  const RESTARTICE_ERROR_MAX_RETRY_COUNT = 5;
4211
4317
  const OUTBOUND_CAM_OUTBOUND_STREAM_ID = v4$1();
4212
4318
  const OUTBOUND_SCREEN_OUTBOUND_STREAM_ID = v4$1();
4319
+ const getFrameArea = (frameSize) => { var _a, _b; return ((_a = frameSize === null || frameSize === void 0 ? void 0 : frameSize.width) !== null && _a !== void 0 ? _a : 0) * ((_b = frameSize === null || frameSize === void 0 ? void 0 : frameSize.height) !== null && _b !== void 0 ? _b : 0); };
4213
4320
  if (browserName === "chrome")
4214
4321
  window.document.addEventListener("beforeunload", () => (unloading = true));
4215
4322
  class VegaRtcManager {
@@ -4247,6 +4354,11 @@ class VegaRtcManager {
4247
4354
  this._micScoreProducer = null;
4248
4355
  this._micScoreProducerPromise = null;
4249
4356
  this._webcamProducer = null;
4357
+ this._webcamProducerOriginalSvcScalabilityMode = undefined;
4358
+ this._webcamProducerOriginalSvcMaxBitrate = undefined;
4359
+ this._webcamProducerHighestPreferredLayer = undefined;
4360
+ this._highestPreferredLayerUpdate = null;
4361
+ this._highestPreferredLayerUpdatePending = false;
4250
4362
  this._webcamProducerPromise = null;
4251
4363
  this._webcamPaused = false;
4252
4364
  this._screenVideoProducer = null;
@@ -4288,12 +4400,19 @@ class VegaRtcManager {
4288
4400
  };
4289
4401
  (_a = window === null || window === void 0 ? void 0 : window.addEventListener) === null || _a === void 0 ? void 0 : _a.call(window, "offline", this._sfuZombie.onBrowserOffline);
4290
4402
  this.analytics = {
4403
+ avgPreferredLayerSwitchLatencyMs: undefined,
4404
+ camOutboundCongestedFraction: undefined,
4405
+ camOutboundRttInflationMs: undefined,
4291
4406
  camTrackEndedCount: 0,
4407
+ highestPreferredLayerChangeCounts: {},
4292
4408
  micTrackEndedCount: 0,
4409
+ numHighestPreferredLayerChanges: 0,
4293
4410
  numIceConnected: 0,
4294
4411
  numIceDisconnected: 0,
4295
4412
  numIceFailed: 0,
4296
4413
  numNewPc: 0,
4414
+ numPreferredSpatialLayerChanges: 0,
4415
+ preferredSpatialLayerChangeCounts: {},
4297
4416
  sfuMsFromOfflineToClose: 0,
4298
4417
  sfuOfflineToCloseCount: 0,
4299
4418
  sfuOfflineWhileConnectedCount: 0,
@@ -4313,6 +4432,15 @@ class VegaRtcManager {
4313
4432
  vegaUnknownResponse: 0,
4314
4433
  vegaWebcamProducerFailed: 0,
4315
4434
  };
4435
+ this._preferredLayerSwitchLatencyStats = createMetricStats();
4436
+ this._preferredLayerSwitchWatches = new Map();
4437
+ this._lastSeenRemoteReportTimestamps = new Map();
4438
+ this._camOutboundCandidatePairId = undefined;
4439
+ this._camOutboundSamplesToSkip = 0;
4440
+ this._camOutboundPathRtt = { sumMs: 0, count: 0, minMs: undefined };
4441
+ this._camOutboundRttInflation = { sumMs: 0, count: 0 };
4442
+ this._camOutboundSamples = { total: 0, congested: 0 };
4443
+ this._statsSubscription = null;
4316
4444
  }
4317
4445
  _updateAndScheduleMediaServersRefresh({ iceServers, turnServers, sfuServer, mediaserverConfigTtlSeconds, }) {
4318
4446
  var _a, _b, _c, _d;
@@ -4482,7 +4610,6 @@ class VegaRtcManager {
4482
4610
  this._sendTransport = null;
4483
4611
  this._receiveTransport = null;
4484
4612
  this._streamIdToVideoConsumerId.clear();
4485
- this._streamIdToVideoResolution.clear();
4486
4613
  if (this._reconnect) {
4487
4614
  this._reconnectTimeOut = setTimeout(() => this._connect(), 1000);
4488
4615
  }
@@ -4905,6 +5032,14 @@ class VegaRtcManager {
4905
5032
  const simulcastLayer3ShouldBeActive = !this._cpuOveruseDetected;
4906
5033
  const params = this._webcamProducer.rtpParameters;
4907
5034
  if (((_a = params === null || params === void 0 ? void 0 : params.encodings) === null || _a === void 0 ? void 0 : _a.length) === 3) {
5035
+ if (this._features.sfuHighestPreferredLayerTrackingOn) {
5036
+ this._syncWebcamEncoderToHighestPreferredLayer();
5037
+ rtcStats.sendEvent("simulcast_layer_activation_changed", {
5038
+ layerIndex: 2,
5039
+ active: simulcastLayer3ShouldBeActive,
5040
+ });
5041
+ return;
5042
+ }
4908
5043
  const targetMaxSpatialLayer = simulcastLayer3ShouldBeActive ? 2 : 1;
4909
5044
  if (this._webcamProducer.maxSpatialLayer !== targetMaxSpatialLayer) {
4910
5045
  this._webcamProducer.setMaxSpatialLayer(targetMaxSpatialLayer);
@@ -4927,7 +5062,7 @@ class VegaRtcManager {
4927
5062
  return;
4928
5063
  }
4929
5064
  this._webcamProducerPromise = (() => __awaiter(this, void 0, void 0, function* () {
4930
- var _a;
5065
+ var _a, _b, _c;
4931
5066
  try {
4932
5067
  const currentPaused = this._webcamPaused;
4933
5068
  if (!this._sendTransport) {
@@ -4953,6 +5088,16 @@ class VegaRtcManager {
4953
5088
  })
4954
5089
  : () => { };
4955
5090
  this._webcamProducer = producer;
5091
+ if (this._features.sfuHighestPreferredLayerTrackingOn) {
5092
+ const originalWebcamEncodings = (_b = (_a = producer.rtpSender) === null || _a === void 0 ? void 0 : _a.getParameters()) === null || _b === void 0 ? void 0 : _b.encodings;
5093
+ const svcEncoding = (originalWebcamEncodings === null || originalWebcamEncodings === void 0 ? void 0 : originalWebcamEncodings.length) === 1 ? originalWebcamEncodings[0] : undefined;
5094
+ this._webcamProducerOriginalSvcScalabilityMode = svcEncoding === null || svcEncoding === void 0 ? void 0 : svcEncoding.scalabilityMode;
5095
+ this._webcamProducerOriginalSvcMaxBitrate = svcEncoding === null || svcEncoding === void 0 ? void 0 : svcEncoding.maxBitrate;
5096
+ this._webcamProducerHighestPreferredLayer = (originalWebcamEncodings === null || originalWebcamEncodings === void 0 ? void 0 : originalWebcamEncodings.length)
5097
+ ? getInitialHighestPreferredLayer(originalWebcamEncodings)
5098
+ : undefined;
5099
+ this._syncWebcamEncoderToHighestPreferredLayer();
5100
+ }
4956
5101
  this._qualityMonitor.addProducer(this._selfId, producer.id);
4957
5102
  producer.observer.once("close", () => {
4958
5103
  var _a;
@@ -4960,11 +5105,16 @@ class VegaRtcManager {
4960
5105
  if (producer.appData.localClosed)
4961
5106
  (_a = this._vegaConnection) === null || _a === void 0 ? void 0 : _a.message("closeProducers", { producerIds: [producer.id] });
4962
5107
  cleanUpCpuWatch();
5108
+ this._stopWebcamStatsSubscription();
4963
5109
  this._webcamProducer = null;
5110
+ this._webcamProducerOriginalSvcScalabilityMode = undefined;
5111
+ this._webcamProducerOriginalSvcMaxBitrate = undefined;
5112
+ this._webcamProducerHighestPreferredLayer = undefined;
4964
5113
  this._webcamProducerPromise = null;
4965
5114
  this._qualityMonitor.removeProducer(this._selfId, producer.id);
4966
5115
  });
4967
- if (this._webcamTrack && this._webcamTrack !== ((_a = this._webcamProducer) === null || _a === void 0 ? void 0 : _a.track)) {
5116
+ this._startWebcamStatsSubscription();
5117
+ if (this._webcamTrack && this._webcamTrack !== ((_c = this._webcamProducer) === null || _c === void 0 ? void 0 : _c.track)) {
4968
5118
  this._webcamProducerPromise = null;
4969
5119
  this._replaceWebcamTrack();
4970
5120
  }
@@ -4981,6 +5131,9 @@ class VegaRtcManager {
4981
5131
  if (!this._webcamTrack) {
4982
5132
  this._stopProducer(this._webcamProducer);
4983
5133
  this._webcamProducer = null;
5134
+ this._webcamProducerOriginalSvcScalabilityMode = undefined;
5135
+ this._webcamProducerOriginalSvcMaxBitrate = undefined;
5136
+ this._webcamProducerHighestPreferredLayer = undefined;
4984
5137
  }
4985
5138
  }
4986
5139
  }))();
@@ -5232,6 +5385,7 @@ class VegaRtcManager {
5232
5385
  if (clientState) {
5233
5386
  clientState.hasAcceptedWebcamStream = false;
5234
5387
  clientState.hasAcceptedScreenStream = false;
5388
+ [clientState.webcamStream, clientState.screenStream].forEach((stream) => stream && this._streamIdToVideoResolution.delete(stream.id));
5235
5389
  this._syncIncomingStreamsWithPWA(clientId);
5236
5390
  }
5237
5391
  if (eventClaim) {
@@ -5355,6 +5509,9 @@ class VegaRtcManager {
5355
5509
  if (this._webcamProducer && !this._webcamProducer.closed && this._webcamProducer.track === track) {
5356
5510
  this._stopProducer(this._webcamProducer);
5357
5511
  this._webcamProducer = null;
5512
+ this._webcamProducerOriginalSvcScalabilityMode = undefined;
5513
+ this._webcamProducerOriginalSvcMaxBitrate = undefined;
5514
+ this._webcamProducerHighestPreferredLayer = undefined;
5358
5515
  this._webcamTrack = null;
5359
5516
  }
5360
5517
  }
@@ -5382,14 +5539,18 @@ class VegaRtcManager {
5382
5539
  this._syncIncomingStreamsWithPWA(clientId);
5383
5540
  }
5384
5541
  updateStreamResolution(streamId, _ignored, { width, height, }) {
5385
- var _a, _b, _c;
5386
5542
  logger$2.info("updateStreamResolution()", { streamId, width, height });
5543
+ this._streamIdToVideoResolution.set(streamId, { width, height });
5544
+ this._applyStreamResolution(streamId);
5545
+ }
5546
+ _applyStreamResolution(streamId) {
5547
+ var _a, _b, _c;
5548
+ const resolution = this._streamIdToVideoResolution.get(streamId);
5387
5549
  const consumerId = this._streamIdToVideoConsumerId.get(streamId);
5388
5550
  const consumer = this._consumers.get(consumerId);
5389
- if (!consumer) {
5390
- this._streamIdToVideoResolution.set(streamId, { width, height });
5551
+ if (!resolution || !consumer)
5391
5552
  return;
5392
- }
5553
+ const { width, height } = resolution;
5393
5554
  updateRenderedDimensions((_a = consumer.track) === null || _a === void 0 ? void 0 : _a.id, { width, height, time: Date.now() });
5394
5555
  const numberOfActiveVideos = getNumberOfActiveVideos(this._consumers);
5395
5556
  const numberOfTemporalLayers = getNumberOfTemporalLayers(consumer);
@@ -5399,6 +5560,12 @@ class VegaRtcManager {
5399
5560
  uncappedSingleRemoteVideoOn: (_b = this._features) === null || _b === void 0 ? void 0 : _b.uncappedSingleRemoteVideoOn,
5400
5561
  });
5401
5562
  if (consumer.appData.spatialLayer !== spatialLayer || consumer.appData.temporalLayer !== temporalLayer) {
5563
+ const previousSpatialLayer = consumer.appData.spatialLayer;
5564
+ const spatialLayerChanged = previousSpatialLayer !== spatialLayer;
5565
+ if (spatialLayerChanged) {
5566
+ this.analytics.numPreferredSpatialLayerChanges++;
5567
+ this._incrementHistogramCount(this.analytics.preferredSpatialLayerChangeCounts, `${previousSpatialLayer}->${spatialLayer}`);
5568
+ }
5402
5569
  consumer.appData.spatialLayer = spatialLayer;
5403
5570
  consumer.appData.temporalLayer = temporalLayer;
5404
5571
  (_c = this._vegaConnection) === null || _c === void 0 ? void 0 : _c.message("setConsumersPreferredLayers", {
@@ -5406,7 +5573,178 @@ class VegaRtcManager {
5406
5573
  spatialLayer,
5407
5574
  temporalLayer,
5408
5575
  });
5576
+ if (spatialLayerChanged) {
5577
+ this._watchForPreferredLayerSwitch(consumerId, consumer, {
5578
+ toHigherLayer: spatialLayer > previousSpatialLayer,
5579
+ });
5580
+ }
5581
+ }
5582
+ }
5583
+ _watchForPreferredLayerSwitch(consumerId, consumer, { toHigherLayer }) {
5584
+ const previousWatch = this._preferredLayerSwitchWatches.get(consumerId);
5585
+ if (!previousWatch && this._preferredLayerSwitchWatches.size >= MAX_CONCURRENT_PREFERRED_LAYER_SWITCH_WATCHES) {
5586
+ return;
5587
+ }
5588
+ previousWatch === null || previousWatch === void 0 ? void 0 : previousWatch.stop();
5589
+ let stopped = false;
5590
+ let intervalId;
5591
+ const stop = () => {
5592
+ if (stopped)
5593
+ return;
5594
+ stopped = true;
5595
+ clearInterval(intervalId);
5596
+ clearTimeout(timeoutId);
5597
+ this._preferredLayerSwitchWatches.delete(consumerId);
5598
+ };
5599
+ this._preferredLayerSwitchWatches.set(consumerId, { stop });
5600
+ const timeoutId = setTimeout(stop, PREFERRED_LAYER_SWITCH_WATCH_TIMEOUT_MS);
5601
+ (() => __awaiter(this, void 0, void 0, function* () {
5602
+ const sentAt = Date.now();
5603
+ const baseline = yield this._getConsumerFrameSize(consumer);
5604
+ if (stopped || !(baseline === null || baseline === void 0 ? void 0 : baseline.width) || !(baseline === null || baseline === void 0 ? void 0 : baseline.height)) {
5605
+ stop();
5606
+ return;
5607
+ }
5608
+ let polling = false;
5609
+ intervalId = setInterval(() => __awaiter(this, void 0, void 0, function* () {
5610
+ if (stopped || consumer.closed) {
5611
+ stop();
5612
+ return;
5613
+ }
5614
+ if (polling)
5615
+ return;
5616
+ polling = true;
5617
+ const current = yield this._getConsumerFrameSize(consumer);
5618
+ polling = false;
5619
+ if (stopped)
5620
+ return;
5621
+ const switched = toHigherLayer
5622
+ ? getFrameArea(current) > getFrameArea(baseline)
5623
+ : getFrameArea(current) < getFrameArea(baseline);
5624
+ if (current && switched) {
5625
+ this._recordPreferredLayerSwitchLatency(Date.now() - sentAt);
5626
+ stop();
5627
+ }
5628
+ }), PREFERRED_LAYER_SWITCH_POLL_INTERVAL_MS);
5629
+ }))();
5630
+ }
5631
+ _getConsumerFrameSize(consumer) {
5632
+ return __awaiter(this, void 0, void 0, function* () {
5633
+ try {
5634
+ const stats = yield consumer.getStats();
5635
+ let frameSize;
5636
+ stats.forEach((report) => {
5637
+ if (report.type === "inbound-rtp") {
5638
+ frameSize = { width: report.frameWidth, height: report.frameHeight };
5639
+ }
5640
+ });
5641
+ return frameSize;
5642
+ }
5643
+ catch (error) {
5644
+ logger$2.warn("_getConsumerFrameSize() failed to read stats", { error });
5645
+ return undefined;
5646
+ }
5647
+ });
5648
+ }
5649
+ _recordPreferredLayerSwitchLatency(latencyMs) {
5650
+ recordMetricSample(this._preferredLayerSwitchLatencyStats, latencyMs);
5651
+ const { avg } = aggregateMetricStats(this._preferredLayerSwitchLatencyStats);
5652
+ this.analytics.avgPreferredLayerSwitchLatencyMs = avg;
5653
+ }
5654
+ _onUpdatedStats(statsByView) {
5655
+ var _a, _b, _c, _d;
5656
+ const webcamProducerMid = (_b = (_a = this._webcamProducer) === null || _a === void 0 ? void 0 : _a.rtpParameters) === null || _b === void 0 ? void 0 : _b.mid;
5657
+ if (webcamProducerMid === undefined)
5658
+ return;
5659
+ const sendTransportPc = (_d = (_c = this._sendTransport) === null || _c === void 0 ? void 0 : _c.handler) === null || _d === void 0 ? void 0 : _d._pc;
5660
+ const sendTransportPcIndex = sendTransportPc ? getPeerConnectionIndex(sendTransportPc) : undefined;
5661
+ const newRemoteReports = [];
5662
+ Object.values(statsByView).forEach((viewStats) => {
5663
+ Object.values(viewStats.tracks || {}).forEach((trackStats) => {
5664
+ Object.entries(trackStats.ssrcs || {}).forEach(([ssrc, ssrcMetrics]) => {
5665
+ if (ssrcMetrics.direction !== "out" || String(ssrcMetrics.mid) !== webcamProducerMid)
5666
+ return;
5667
+ if (sendTransportPcIndex !== undefined && ssrcMetrics.pcIndex !== sendTransportPcIndex)
5668
+ return;
5669
+ this._followCamOutboundCandidatePair(ssrcMetrics);
5670
+ const { remoteReportTimestamp } = ssrcMetrics;
5671
+ if (remoteReportTimestamp === undefined)
5672
+ return;
5673
+ if (remoteReportTimestamp === this._lastSeenRemoteReportTimestamps.get(ssrc))
5674
+ return;
5675
+ this._lastSeenRemoteReportTimestamps.set(ssrc, remoteReportTimestamp);
5676
+ newRemoteReports.push(ssrcMetrics);
5677
+ });
5678
+ });
5679
+ });
5680
+ if (!newRemoteReports.length)
5681
+ return;
5682
+ if (this._camOutboundSamplesToSkip > 0) {
5683
+ this._camOutboundSamplesToSkip--;
5684
+ return;
5409
5685
  }
5686
+ this._recordCamOutboundSample(newRemoteReports);
5687
+ this._updateCamOutboundAnalytics();
5688
+ }
5689
+ _recordCamOutboundSample(newRemoteReports) {
5690
+ var _a, _b;
5691
+ const rttsMs = newRemoteReports.map(({ roundTripTime }) => (roundTripTime || 0) * 1000).filter((ms) => ms > 0);
5692
+ const rttMs = rttsMs.length ? Math.max(...rttsMs) : undefined;
5693
+ const fractionLost = getPacketWeightedFractionLost(newRemoteReports);
5694
+ const path = this._camOutboundPathRtt;
5695
+ if (rttMs !== undefined) {
5696
+ path.sumMs += rttMs;
5697
+ path.count++;
5698
+ path.minMs = Math.min((_a = path.minMs) !== null && _a !== void 0 ? _a : Infinity, rttMs);
5699
+ }
5700
+ const congested = (rttMs !== undefined && rttMs - ((_b = path.minMs) !== null && _b !== void 0 ? _b : rttMs) > CONGESTED_RTT_INFLATION_MS) ||
5701
+ fractionLost > CONGESTED_FRACTION_LOST;
5702
+ this._camOutboundSamples.total++;
5703
+ if (congested)
5704
+ this._camOutboundSamples.congested++;
5705
+ }
5706
+ _followCamOutboundCandidatePair({ selectedCandidatePairId }) {
5707
+ if (!selectedCandidatePairId || selectedCandidatePairId === this._camOutboundCandidatePairId)
5708
+ return;
5709
+ if (this._camOutboundCandidatePairId !== undefined) {
5710
+ this._finishCamOutboundRttPath();
5711
+ this._camOutboundSamplesToSkip = CAM_SAMPLES_SKIPPED_AFTER_CANDIDATE_PAIR_CHANGE;
5712
+ }
5713
+ this._camOutboundCandidatePairId = selectedCandidatePairId;
5714
+ }
5715
+ _finishCamOutboundRttPath() {
5716
+ const path = this._camOutboundPathRtt;
5717
+ if (path.count && path.minMs !== undefined) {
5718
+ this._camOutboundRttInflation.sumMs += path.sumMs - path.count * path.minMs;
5719
+ this._camOutboundRttInflation.count += path.count;
5720
+ }
5721
+ this._camOutboundPathRtt = { sumMs: 0, count: 0, minMs: undefined };
5722
+ }
5723
+ _updateCamOutboundAnalytics() {
5724
+ const path = this._camOutboundPathRtt;
5725
+ const inflationSumMs = this._camOutboundRttInflation.sumMs + (path.minMs !== undefined ? path.sumMs - path.count * path.minMs : 0);
5726
+ const inflationCount = this._camOutboundRttInflation.count + path.count;
5727
+ this.analytics.camOutboundRttInflationMs = inflationCount
5728
+ ? Math.round(inflationSumMs / inflationCount)
5729
+ : undefined;
5730
+ const { congested, total } = this._camOutboundSamples;
5731
+ this.analytics.camOutboundCongestedFraction = total ? congested / total : undefined;
5732
+ }
5733
+ _startWebcamStatsSubscription() {
5734
+ if (this._statsSubscription)
5735
+ return;
5736
+ this._statsSubscription = subscribeStats({
5737
+ onUpdatedStats: (statsByView) => this._onUpdatedStats(statsByView),
5738
+ });
5739
+ }
5740
+ _stopWebcamStatsSubscription() {
5741
+ var _a;
5742
+ (_a = this._statsSubscription) === null || _a === void 0 ? void 0 : _a.stop();
5743
+ this._statsSubscription = null;
5744
+ this._lastSeenRemoteReportTimestamps.clear();
5745
+ this._finishCamOutboundRttPath();
5746
+ this._camOutboundCandidatePairId = undefined;
5747
+ this._camOutboundSamplesToSkip = 0;
5410
5748
  }
5411
5749
  close() {
5412
5750
  this.disconnectAll();
@@ -5437,8 +5775,11 @@ class VegaRtcManager {
5437
5775
  this._screenVideoTrack = null;
5438
5776
  this._screenAudioTrack = null;
5439
5777
  this._streamIdToVideoConsumerId.clear();
5778
+ this._streamIdToVideoResolution.clear();
5440
5779
  this._mediasoupDeviceInitializedAsync = Promise.resolve(null);
5441
5780
  this._qualityMonitor.close();
5781
+ this._stopWebcamStatsSubscription();
5782
+ this._preferredLayerSwitchWatches.forEach(({ stop }) => stop());
5442
5783
  }
5443
5784
  sendStatsCustomEvent(eventName, data) {
5444
5785
  rtcStats.sendEvent(eventName, data);
@@ -5496,6 +5837,8 @@ class VegaRtcManager {
5496
5837
  return this._onConsumerScore(data);
5497
5838
  case "producerScore":
5498
5839
  return this._onProducerScore(data);
5840
+ case "changedHighestPreferredLayer":
5841
+ return this._onChangedHighestPreferredLayer(data);
5499
5842
  default:
5500
5843
  logger$2.info(`unknown message method "${method}"`);
5501
5844
  return;
@@ -5523,13 +5866,16 @@ class VegaRtcManager {
5523
5866
  }
5524
5867
  consumer.pause();
5525
5868
  consumer.appData.localPaused = true;
5526
- consumer.appData.spatialLayer = 2;
5869
+ consumer.appData.spatialLayer = INITIAL_CONSUMER_SPATIAL_LAYER;
5527
5870
  this._consumers.set(consumer.id, consumer);
5528
5871
  this._qualityMonitor.addConsumer(consumer.appData.sourceClientId, consumer.id);
5529
5872
  consumer.observer.once("close", () => {
5530
5873
  this._consumers.delete(consumer.id);
5531
5874
  this._qualityMonitor.removeConsumer(consumer.appData.sourceClientId, consumer.id);
5532
5875
  this._consumerClosedCleanup(consumer);
5876
+ if (consumer.kind === "video" && this._receiveTransport && !this._receiveTransport.closed) {
5877
+ this._reapplyStreamResolutions();
5878
+ }
5533
5879
  });
5534
5880
  if (this._features.increaseIncomingMediaBufferOn && consumer.rtpReceiver) {
5535
5881
  try {
@@ -5561,13 +5907,12 @@ class VegaRtcManager {
5561
5907
  }
5562
5908
  stream.addTrack(consumer.track);
5563
5909
  this._syncIncomingStreamsWithPWA(clientId);
5564
- const resolution = this._streamIdToVideoResolution.get(stream.id);
5565
- if (resolution) {
5566
- this.updateStreamResolution(stream.id, null, resolution);
5567
- this._streamIdToVideoResolution.delete(stream.id);
5568
- }
5910
+ this._reapplyStreamResolutions();
5569
5911
  });
5570
5912
  }
5913
+ _reapplyStreamResolutions() {
5914
+ this._streamIdToVideoResolution.forEach((_resolution, streamId) => this._applyStreamResolution(streamId));
5915
+ }
5571
5916
  _onConsumerClosed(_a) {
5572
5917
  return __awaiter(this, arguments, void 0, function* ({ consumerId, reason }) {
5573
5918
  var _b;
@@ -5582,6 +5927,8 @@ class VegaRtcManager {
5582
5927
  return;
5583
5928
  consumer.appData.remotePaused = true;
5584
5929
  consumer.pause();
5930
+ if (consumer.kind === "video")
5931
+ this._reapplyStreamResolutions();
5585
5932
  }
5586
5933
  _onConsumerResumed({ consumerId }) {
5587
5934
  logger$2.info("_onConsumerResumed()", { consumerId });
@@ -5592,6 +5939,8 @@ class VegaRtcManager {
5592
5939
  if (!consumer.appData.localPaused) {
5593
5940
  consumer.resume();
5594
5941
  }
5942
+ if (consumer.kind === "video")
5943
+ this._reapplyStreamResolutions();
5595
5944
  }
5596
5945
  _onConsumerScore({ consumerId, kind, score }) {
5597
5946
  logger$2.info("_onConsumerScore()", { consumerId, kind, score });
@@ -5608,6 +5957,90 @@ class VegaRtcManager {
5608
5957
  }
5609
5958
  });
5610
5959
  }
5960
+ _getSvcEncodingUpdate(encoding, spatialLayer) {
5961
+ var _a;
5962
+ const reduced = getReducedSvcEncodingParams(this._webcamProducerOriginalSvcScalabilityMode, spatialLayer, this._webcamProducerOriginalSvcMaxBitrate);
5963
+ if (!reduced)
5964
+ return undefined;
5965
+ const changed = reduced.scalabilityMode !== encoding.scalabilityMode ||
5966
+ reduced.scaleResolutionDownBy !== ((_a = encoding.scaleResolutionDownBy) !== null && _a !== void 0 ? _a : 1) ||
5967
+ reduced.maxBitrate !== encoding.maxBitrate;
5968
+ return changed ? reduced : undefined;
5969
+ }
5970
+ _onChangedHighestPreferredLayer(_a) {
5971
+ return __awaiter(this, arguments, void 0, function* ({ producerId, spatialLayer }) {
5972
+ var _b;
5973
+ if (!this._features.sfuHighestPreferredLayerTrackingOn)
5974
+ return;
5975
+ if (((_b = this._webcamProducer) === null || _b === void 0 ? void 0 : _b.id) !== producerId)
5976
+ return;
5977
+ if (!Number.isFinite(spatialLayer)) {
5978
+ logger$2.warn("_onChangedHighestPreferredLayer() ignoring invalid spatialLayer", {
5979
+ producerId,
5980
+ spatialLayer,
5981
+ });
5982
+ return;
5983
+ }
5984
+ if (this._webcamProducerHighestPreferredLayer !== undefined &&
5985
+ this._webcamProducerHighestPreferredLayer !== spatialLayer) {
5986
+ this.analytics.numHighestPreferredLayerChanges++;
5987
+ this._incrementHistogramCount(this.analytics.highestPreferredLayerChangeCounts, `${this._webcamProducerHighestPreferredLayer}->${spatialLayer}`);
5988
+ }
5989
+ this._webcamProducerHighestPreferredLayer = spatialLayer;
5990
+ logger$2.info("_onChangedHighestPreferredLayer()", { producerId, spatialLayer });
5991
+ return this._syncWebcamEncoderToHighestPreferredLayer();
5992
+ });
5993
+ }
5994
+ _syncWebcamEncoderToHighestPreferredLayer() {
5995
+ this._highestPreferredLayerUpdatePending = true;
5996
+ if (!this._highestPreferredLayerUpdate) {
5997
+ this._highestPreferredLayerUpdate = this._applyPendingHighestPreferredLayerUpdates();
5998
+ }
5999
+ return this._highestPreferredLayerUpdate;
6000
+ }
6001
+ _applyPendingHighestPreferredLayerUpdates() {
6002
+ return __awaiter(this, void 0, void 0, function* () {
6003
+ while (this._highestPreferredLayerUpdatePending) {
6004
+ this._highestPreferredLayerUpdatePending = false;
6005
+ try {
6006
+ yield this._applyHighestPreferredLayerToWebcamEncoder();
6007
+ }
6008
+ catch (error) {
6009
+ logger$2.error("Failed to apply highest preferred layer: %o", error);
6010
+ }
6011
+ }
6012
+ this._highestPreferredLayerUpdate = null;
6013
+ });
6014
+ }
6015
+ _applyHighestPreferredLayerToWebcamEncoder() {
6016
+ return __awaiter(this, void 0, void 0, function* () {
6017
+ const producer = this._webcamProducer;
6018
+ const highestPreferredLayer = this._webcamProducerHighestPreferredLayer;
6019
+ if (!producer || highestPreferredLayer === undefined)
6020
+ return;
6021
+ const encodings = producer.rtpSender.getParameters().encodings;
6022
+ if (encodings.length > 1) {
6023
+ const cpuOveruseLimit = this._cpuOveruseDetected && encodings.length === 3 ? 1 : Infinity;
6024
+ const spatialLayer = Math.max(0, Math.min(highestPreferredLayer, cpuOveruseLimit, encodings.length - 1));
6025
+ if (producer.maxSpatialLayer === spatialLayer)
6026
+ return;
6027
+ yield producer.setMaxSpatialLayer(spatialLayer);
6028
+ const applied = producer.rtpSender
6029
+ .getParameters()
6030
+ .encodings.every((encoding, index) => encoding.active === index <= spatialLayer);
6031
+ if (!applied)
6032
+ logger$2.error("setMaxSpatialLayer(%d) was not applied to the encodings", spatialLayer);
6033
+ }
6034
+ else if (encodings.length === 1 && this._webcamProducerOriginalSvcScalabilityMode) {
6035
+ const update = this._getSvcEncodingUpdate(encodings[0], highestPreferredLayer);
6036
+ if (update)
6037
+ yield producer.setRtpEncodingParameters(update);
6038
+ }
6039
+ });
6040
+ }
6041
+ _incrementHistogramCount(histogram, key) {
6042
+ histogram[key] = (histogram[key] || 0) + 1;
6043
+ }
5611
6044
  _onDataConsumerReady(options) {
5612
6045
  return __awaiter(this, void 0, void 0, function* () {
5613
6046
  logger$2.info("_onDataConsumerReady()", { id: options.id, dataProducerId: options.dataProducerId });
@@ -5657,8 +6090,8 @@ class VegaRtcManager {
5657
6090
  stream.removeTrack(consumer.track);
5658
6091
  if (stream.getTracks().length === 0) {
5659
6092
  this._streamIdToVideoConsumerId.delete(stream.id);
5660
- this._streamIdToVideoResolution.delete(stream.id);
5661
6093
  if (screenShare) {
6094
+ this._streamIdToVideoResolution.delete(stream.id);
5662
6095
  clientState.screenStream = undefined;
5663
6096
  clientState.hasEmittedScreenStream = false;
5664
6097
  clientState.screenShareStreamId = undefined;
@@ -5704,6 +6137,8 @@ class VegaRtcManager {
5704
6137
  consumerIds: toResumeConsumers,
5705
6138
  });
5706
6139
  }
6140
+ if (toPauseConsumers.length > 0 || toResumeConsumers.length > 0)
6141
+ this._reapplyStreamResolutions();
5707
6142
  if (webcamStream && !hasEmittedWebcamStream && hasAcceptedWebcamStream) {
5708
6143
  this._emitToPWA(EVENTS.STREAM_ADDED, {
5709
6144
  clientId,
@@ -7468,5 +7903,5 @@ var RtcEventNames;
7468
7903
  RtcEventNames["stream_added"] = "stream_added";
7469
7904
  })(RtcEventNames || (RtcEventNames = {}));
7470
7905
 
7471
- export { ADDITIONAL_SCREEN_SHARE_SETTINGS, AUDIO_SETTINGS, BandwidthTester, CAMERA_STREAM_ID, EVENTS, FILE_SHARE_ERROR_CODES, KNOCK_MESSAGES, KalmanFilter, Logger, MEDIA_JITTER_BUFFER_TARGET, NoDevicesError, P2pRtcManager, PROTOCOL_ERRORS, PROTOCOL_EVENTS, PROTOCOL_REQUESTS, PROTOCOL_RESPONSES, RELAY_MESSAGES, ReconnectManager, RtcEventNames, RtcManagerDispatcher, SCREEN_SHARE_SETTINGS, SCREEN_SHARE_SIMULCAST_SETTINGS, STREAM_TYPES, ServerSocket, Session, SfuV2Parser, TYPES, VIDEO_SETTINGS_HD, VIDEO_SETTINGS_SD, VIDEO_SETTINGS_VP9, VIDEO_SETTINGS_VP9_LOW_BANDWIDTH, VegaConnection, VegaMediaQualityMonitor, VegaRtcManager, addAbsCaptureTimeExtMap, addExtMap, assert, buildDeviceList, calculateStd, captureAudioSsrcMetrics, captureCandidatePairInfoMetrics, captureCommonSsrcMetrics, captureSsrcInfo, captureVideoSsrcMetrics, cleanSdp, compareLocalDevices, createACFCalculator, createMicAnalyser, createWorker, deprioritizeH264, enumerate, external_stun_servers, filterMidExtension, filterMsidSemantic, fromLocation, generateByteString, getConstraints, getCurrentPeerConnections, getDeviceData, getDisplayMedia, getInitialStream, getIssuesAndMetrics, getMediaConstraints, getMediaSettings, getMediasoupDeviceAsync, getNumFailedStatsReports, getNumFailedTrackSsrcLookups, getNumMissingTrackSsrcLookups, getPeerConnectionIndex, getStats, getStream, getUpdatedDevices, getUpdatedStats, getUserMedia, hasGetDisplayMedia, ipRegex, isFileShareError, isMobile, issueDetectorOrMetricEnabled, maybeTurnOnly, modifyMediaCapabilities, removePeerConnection, replaceTracksInStream, rtcManagerEvents, rtcStats, setClientProvider, setCodecPreferenceSDP, setPeerConnectionsForTests, setVideoBandwidthUsingSetParameters, sortCodecs, standardDeviation, startPerformanceMonitor, stopStreamTracks, subscribeIssues, subscribeStats, trackAnnotations, turnServerOverride, updateRenderedDimensions, variance };
7906
+ export { ADDITIONAL_SCREEN_SHARE_SETTINGS, AUDIO_SETTINGS, BandwidthTester, CAMERA_STREAM_ID, CAM_SAMPLES_SKIPPED_AFTER_CANDIDATE_PAIR_CHANGE, CONGESTED_FRACTION_LOST, CONGESTED_RTT_INFLATION_MS, EVENTS, FILE_SHARE_ERROR_CODES, INITIAL_CONSUMER_SPATIAL_LAYER, INITIAL_HIGHEST_PREFERRED_LAYER, KNOCK_MESSAGES, KalmanFilter, LOWEST_SVC_LAYER_MAX_BITRATE, Logger, MAX_CONCURRENT_PREFERRED_LAYER_SWITCH_WATCHES, MEDIA_JITTER_BUFFER_TARGET, MIDDLE_SVC_LAYER_MAX_BITRATE, NoDevicesError, P2pRtcManager, PREFERRED_LAYER_SWITCH_POLL_INTERVAL_MS, PREFERRED_LAYER_SWITCH_WATCH_TIMEOUT_MS, PROTOCOL_ERRORS, PROTOCOL_EVENTS, PROTOCOL_REQUESTS, PROTOCOL_RESPONSES, RELAY_MESSAGES, ReconnectManager, RtcEventNames, RtcManagerDispatcher, SCREEN_SHARE_SETTINGS, SCREEN_SHARE_SIMULCAST_SETTINGS, STREAM_TYPES, ServerSocket, Session, SfuV2Parser, TYPES, VIDEO_SETTINGS_HD, VIDEO_SETTINGS_SD, VIDEO_SETTINGS_VP9, VIDEO_SETTINGS_VP9_LOW_BANDWIDTH, VegaConnection, VegaMediaQualityMonitor, VegaRtcManager, addAbsCaptureTimeExtMap, addExtMap, assert, buildDeviceList, calculateStd, captureAudioSsrcMetrics, captureCandidatePairInfoMetrics, captureCommonSsrcMetrics, captureSsrcInfo, captureVideoSsrcMetrics, cleanSdp, compareLocalDevices, createACFCalculator, createMicAnalyser, createWorker, deprioritizeH264, enumerate, external_stun_servers, filterMidExtension, filterMsidSemantic, fromLocation, generateByteString, getConstraints, getCurrentPeerConnections, getDeviceData, getDisplayMedia, getInitialStream, getIssuesAndMetrics, getMediaConstraints, getMediaSettings, getMediasoupDeviceAsync, getNumFailedStatsReports, getNumFailedTrackSsrcLookups, getNumMissingTrackSsrcLookups, getPeerConnectionIndex, getSelectedCandidatePairId, getStats, getStream, getUpdatedDevices, getUpdatedStats, getUserMedia, hasGetDisplayMedia, ipRegex, isFileShareError, isMobile, issueDetectorOrMetricEnabled, maybeTurnOnly, modifyMediaCapabilities, removePeerConnection, replaceTracksInStream, rtcManagerEvents, rtcStats, setClientProvider, setCodecPreferenceSDP, setPeerConnectionsForTests, setVideoBandwidthUsingSetParameters, sortCodecs, standardDeviation, startPerformanceMonitor, stopStreamTracks, subscribeIssues, subscribeStats, trackAnnotations, turnServerOverride, updateRenderedDimensions, variance };
7472
7907
  //# sourceMappingURL=legacy-esm.js.map