@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.
package/dist/index.cjs CHANGED
@@ -304,7 +304,7 @@ class Logger {
304
304
 
305
305
  var _a$5, _b$2;
306
306
  const adapter$5 = (_a$5 = adapterRaw.default) !== null && _a$5 !== void 0 ? _a$5 : adapterRaw;
307
- const logger$b = new Logger();
307
+ const logger$c = new Logger();
308
308
  const browserName$2 = (_b$2 = adapter$5.browserDetails) === null || _b$2 === void 0 ? void 0 : _b$2.browser;
309
309
  const browserVersion$1 = adapter$5.browserDetails.version;
310
310
  function setCodecPreferenceSDP({ sdp, redOn }) {
@@ -345,7 +345,7 @@ function setCodecPreferenceSDP({ sdp, redOn }) {
345
345
  return newSdp;
346
346
  }
347
347
  catch (error) {
348
- logger$b.error("setCodecPreferenceSDP error:", error);
348
+ logger$c.error("setCodecPreferenceSDP error:", error);
349
349
  return sdp;
350
350
  }
351
351
  }
@@ -496,7 +496,7 @@ function trackAnnotations(o) {
496
496
 
497
497
  var _a$4;
498
498
  const adapter$4 = (_a$4 = adapterRaw.default) !== null && _a$4 !== void 0 ? _a$4 : adapterRaw;
499
- const logger$a = new Logger();
499
+ const logger$b = new Logger();
500
500
  class Session {
501
501
  constructor({ clientId, bandwidth, peerConnectionConfig, deprioritizeH264Encoding, incrementAnalyticMetric, mediaPrefs, }) {
502
502
  this.relayCandidateSeen = false;
@@ -628,7 +628,7 @@ class Session {
628
628
  }
629
629
  handleAnswer(message) {
630
630
  if (this.pc.signalingState !== "have-local-offer") {
631
- logger$a.warn("Ignoring stale SDP answer for client %s (signalingState: %s)", this.clientId, this.pc.signalingState);
631
+ logger$b.warn("Ignoring stale SDP answer for client %s (signalingState: %s)", this.clientId, this.pc.signalingState);
632
632
  this._incrementAnalyticMetric("P2PStaleAnswerIgnored");
633
633
  rtcStats.sendEvent("P2PStaleAnswerIgnored", {
634
634
  clientId: this.clientId,
@@ -656,7 +656,7 @@ class Session {
656
656
  return;
657
657
  }
658
658
  this.pc.addIceCandidate(candidate).catch((e) => {
659
- logger$a.warn("Failed to add ICE candidate ('%s'): %s", candidate ? candidate.candidate : null, e);
659
+ logger$b.warn("Failed to add ICE candidate ('%s'): %s", candidate ? candidate.candidate : null, e);
660
660
  this._incrementAnalyticMetric("P2PAddIceCandidateFailure");
661
661
  rtcStats.sendEvent("P2PAddIceCandidateFailure", {
662
662
  clientId: this.clientId,
@@ -684,7 +684,7 @@ class Session {
684
684
  pc.close();
685
685
  }
686
686
  catch (e) {
687
- logger$a.warn("failures during close of session", e);
687
+ logger$b.warn("failures during close of session", e);
688
688
  }
689
689
  }
690
690
  hasConnectedPeerConnection() {
@@ -693,7 +693,7 @@ class Session {
693
693
  replaceTrack(oldTrack, newTrack) {
694
694
  return __awaiter(this, void 0, void 0, function* () {
695
695
  var _a;
696
- logger$a.info("replacetrack() [oldTrackId: %s, newTrackId: %s]", oldTrack === null || oldTrack === void 0 ? void 0 : oldTrack.id, newTrack.id);
696
+ logger$b.info("replacetrack() [oldTrackId: %s, newTrackId: %s]", oldTrack === null || oldTrack === void 0 ? void 0 : oldTrack.id, newTrack.id);
697
697
  if (newTrack.readyState === "ended") {
698
698
  throw new Error(`refusing to use ended track with id: ${newTrack.id}, kind: ${newTrack.kind}`);
699
699
  }
@@ -764,6 +764,16 @@ class Session {
764
764
  }
765
765
 
766
766
  const MEDIA_JITTER_BUFFER_TARGET = 400;
767
+ const INITIAL_CONSUMER_SPATIAL_LAYER = 1;
768
+ const INITIAL_HIGHEST_PREFERRED_LAYER = 1;
769
+ const LOWEST_SVC_LAYER_MAX_BITRATE = 100000;
770
+ const MIDDLE_SVC_LAYER_MAX_BITRATE = 500000;
771
+ const PREFERRED_LAYER_SWITCH_POLL_INTERVAL_MS = 100;
772
+ const PREFERRED_LAYER_SWITCH_WATCH_TIMEOUT_MS = 10000;
773
+ const MAX_CONCURRENT_PREFERRED_LAYER_SWITCH_WATCHES = 5;
774
+ const CONGESTED_RTT_INFLATION_MS = 100;
775
+ const CONGESTED_FRACTION_LOST = 0.02;
776
+ const CAM_SAMPLES_SKIPPED_AFTER_CANDIDATE_PAIR_CHANGE = 2;
767
777
 
768
778
  const PROTOCOL_REQUESTS = {
769
779
  BLOCK_CLIENT: "block_client",
@@ -1063,7 +1073,7 @@ const getMediasoupDeviceAsync = (features) => __awaiter(void 0, void 0, void 0,
1063
1073
  return new mediasoupClient.Device({ handlerName });
1064
1074
  });
1065
1075
 
1066
- const logger$9 = new Logger();
1076
+ const logger$a = new Logger();
1067
1077
  const AUDIO_SETTINGS = {
1068
1078
  codecOptions: {
1069
1079
  opusDtx: true,
@@ -1243,7 +1253,7 @@ function sortCodecsByPowerEfficiency(codecs) {
1243
1253
  codecPowerEfficiencyEntries = yield Promise.all(codecs.map(({ mimeType }) => getIsCodecDecodingPowerEfficient(mimeType).then((val) => [mimeType, val])));
1244
1254
  }
1245
1255
  catch (error) {
1246
- logger$9.error(error);
1256
+ logger$a.error(error);
1247
1257
  return codecs;
1248
1258
  }
1249
1259
  const codecPowerEfficiencies = Object.fromEntries(codecPowerEfficiencyEntries);
@@ -1312,7 +1322,24 @@ function captureSsrcInfo(ssrcMetrics, currentSsrcStats, prevSsrcStats, timeDiff,
1312
1322
  ssrcMetrics.mid = currentSsrcStats.mid;
1313
1323
  ssrcMetrics.rid = currentSsrcStats.rid;
1314
1324
  }
1325
+ const selectedCandidatePairIdByReport = new WeakMap();
1326
+ function getSelectedCandidatePairId(report, transportId) {
1327
+ var _a;
1328
+ const selectedCandidatePairId = transportId ? (_a = report.get(transportId)) === null || _a === void 0 ? void 0 : _a.selectedCandidatePairId : undefined;
1329
+ if (selectedCandidatePairId)
1330
+ return selectedCandidatePairId;
1331
+ if (!selectedCandidatePairIdByReport.has(report)) {
1332
+ let selectedId;
1333
+ report.forEach((stats) => {
1334
+ if (stats.type === "candidate-pair" && stats.selected)
1335
+ selectedId = stats.id;
1336
+ });
1337
+ selectedCandidatePairIdByReport.set(report, selectedId);
1338
+ }
1339
+ return selectedCandidatePairIdByReport.get(report);
1340
+ }
1315
1341
  function captureCommonSsrcMetrics(ssrcMetrics, currentSsrcStats, prevSsrcStats, timeDiff, report) {
1342
+ ssrcMetrics.selectedCandidatePairId = getSelectedCandidatePairId(report, currentSsrcStats.transportId);
1316
1343
  const nackCountDiff = (currentSsrcStats.nackCount || 0) - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.nackCount) || 0);
1317
1344
  ssrcMetrics.nackCount = (ssrcMetrics.nackCount || 0) + nackCountDiff;
1318
1345
  ssrcMetrics.nackRate = (1000 * nackCountDiff) / timeDiff;
@@ -1366,6 +1393,7 @@ function captureCommonSsrcMetrics(ssrcMetrics, currentSsrcStats, prevSsrcStats,
1366
1393
  ssrcMetrics.roundTripTime = remoteReport.roundTripTime || 0;
1367
1394
  ssrcMetrics.jitter = remoteReport.jitter || 0;
1368
1395
  ssrcMetrics.fractionLost = remoteReport.fractionLost || 0;
1396
+ ssrcMetrics.remoteReportTimestamp = remoteReport.timestamp;
1369
1397
  }
1370
1398
  }
1371
1399
  }
@@ -1597,7 +1625,6 @@ const DEFAULT_CLIENT = {
1597
1625
  };
1598
1626
  function collectStats(state_1, _a, immediate_1) {
1599
1627
  return __awaiter(this, arguments, void 0, function* (state, { logger, interval }, immediate) {
1600
- const collectStatsBound = collectStats.bind(null, state, { interval, logger });
1601
1628
  try {
1602
1629
  const clients = state.getClients();
1603
1630
  const defaultClient = clients.find((c) => c.isLocalClient && !c.isPresentation) || DEFAULT_CLIENT;
@@ -1612,7 +1639,6 @@ function collectStats(state_1, _a, immediate_1) {
1612
1639
  if (immediate)
1613
1640
  return state.statsByView;
1614
1641
  state.subscriptions.forEach((subscription) => { var _a; return (_a = subscription.onUpdatedStats) === null || _a === void 0 ? void 0 : _a.call(subscription, state.statsByView, clients, state.renderedDimensionsByTrack); });
1615
- state.nextTimeout = setTimeout(collectStatsBound, interval);
1616
1642
  return;
1617
1643
  }
1618
1644
  state.lastUpdateTime = Date.now();
@@ -1735,11 +1761,10 @@ function collectStats(state_1, _a, immediate_1) {
1735
1761
  message: e === null || e === void 0 ? void 0 : e.message,
1736
1762
  });
1737
1763
  }
1738
- state.nextTimeout = setTimeout(collectStatsBound, interval);
1739
1764
  });
1740
1765
  }
1741
1766
 
1742
- const logger$8 = new Logger();
1767
+ const logger$9 = new Logger();
1743
1768
  const CPU_OBSERVER_OPTIONS = {
1744
1769
  sampleRate: 1,
1745
1770
  };
@@ -1749,7 +1774,7 @@ function startCpuObserver(cb, { sampleRate } = CPU_OBSERVER_OPTIONS, window = gl
1749
1774
  if ("PressureObserver" in window &&
1750
1775
  (window.PressureObserver.knownSources || []).includes("cpu")) {
1751
1776
  pressureObserver = new window.PressureObserver(cb, { sampleRate });
1752
- (_a = pressureObserver.observe("cpu", { sampleInterval: sampleRate * 1000 })) === null || _a === void 0 ? void 0 : _a.catch((error) => logger$8.error(error));
1777
+ (_a = pressureObserver.observe("cpu", { sampleInterval: sampleRate * 1000 })) === null || _a === void 0 ? void 0 : _a.catch((error) => logger$9.error(error));
1753
1778
  return {
1754
1779
  stop: () => {
1755
1780
  pressureObserver.unobserve("cpu");
@@ -1785,7 +1810,20 @@ const updateRenderedDimensions = (trackId, data) => {
1785
1810
  STATE.renderedDimensionsByTrack[trackId] = data;
1786
1811
  };
1787
1812
  function startStatsMonitor(state, { interval, logger }) {
1788
- const collectStatsBound = collectStats.bind(null, state, { interval, logger });
1813
+ let stopped = false;
1814
+ let nextTimeout;
1815
+ const scheduleNextRun = () => {
1816
+ nextTimeout = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
1817
+ try {
1818
+ yield collectStats(state, { interval, logger }, false);
1819
+ }
1820
+ catch (error) {
1821
+ logger.error("Stats collection failed unexpectedly", error);
1822
+ }
1823
+ if (!stopped)
1824
+ scheduleNextRun();
1825
+ }), interval);
1826
+ };
1789
1827
  let cpuObserver;
1790
1828
  try {
1791
1829
  cpuObserver = startCpuObserver((records) => (state.lastPressureObserverRecord = records.pop()));
@@ -1793,13 +1831,14 @@ function startStatsMonitor(state, { interval, logger }) {
1793
1831
  catch (ex) {
1794
1832
  logger.warn("Failed to observe CPU pressure", ex);
1795
1833
  }
1796
- setTimeout(collectStatsBound, interval);
1834
+ scheduleNextRun();
1797
1835
  return {
1798
1836
  getUpdatedStats: () => {
1799
- return collectStatsBound(true);
1837
+ return collectStats(state, { interval, logger }, true);
1800
1838
  },
1801
1839
  stop: () => {
1802
- clearTimeout(state.nextTimeout);
1840
+ stopped = true;
1841
+ clearTimeout(nextTimeout);
1803
1842
  cpuObserver === null || cpuObserver === void 0 ? void 0 : cpuObserver.stop();
1804
1843
  },
1805
1844
  };
@@ -1820,7 +1859,7 @@ function subscribeStats(subscription, options = OPTIONS, state = STATE) {
1820
1859
  };
1821
1860
  }
1822
1861
 
1823
- const logger$7 = new Logger();
1862
+ const logger$8 = new Logger();
1824
1863
  class ReconnectManager extends EventEmitter {
1825
1864
  constructor(socket) {
1826
1865
  super();
@@ -1908,7 +1947,7 @@ class ReconnectManager extends EventEmitter {
1908
1947
  client.mergeWithOldClientState = true;
1909
1948
  }
1910
1949
  catch (error) {
1911
- logger$7.error("Failed to evaluate if we should merge client state %o", error);
1950
+ logger$8.error("Failed to evaluate if we should merge client state %o", error);
1912
1951
  this.metrics.evaluationFailed++;
1913
1952
  }
1914
1953
  });
@@ -1936,7 +1975,7 @@ class ReconnectManager extends EventEmitter {
1936
1975
  const { clientId } = payload;
1937
1976
  const client = this._clients[clientId];
1938
1977
  if (!client) {
1939
- logger$7.warn(`client ${clientId} not found`);
1978
+ logger$8.warn(`client ${clientId} not found`);
1940
1979
  return;
1941
1980
  }
1942
1981
  if (client.isPendingToLeave) {
@@ -2409,7 +2448,7 @@ fromLocation(typeof window !== "undefined" ? window.location : undefined);
2409
2448
 
2410
2449
  var _a$2, _b$1;
2411
2450
  const adapter$2 = (_a$2 = adapterRaw.default) !== null && _a$2 !== void 0 ? _a$2 : adapterRaw;
2412
- const logger$6 = new Logger();
2451
+ const logger$7 = new Logger();
2413
2452
  const ICE_PUBLIC_IP_GATHERING_TIMEOUT = 3 * 1000;
2414
2453
  const ICE_RESTART_DELAY = 2 * 1000;
2415
2454
  const browserName$1 = (_b$1 = adapter$2.browserDetails) === null || _b$1 === void 0 ? void 0 : _b$1.browser;
@@ -2490,7 +2529,7 @@ class P2pRtcManager {
2490
2529
  return this._selfId === selfId && this._roomName === roomName && !isSfu;
2491
2530
  }
2492
2531
  addCameraStream(stream, { beforeEffectTracks = [] } = { beforeEffectTracks: [] }) {
2493
- logger$6.info("addCameraStream: [stream.id: %s]", stream.id);
2532
+ logger$7.info("addCameraStream: [stream.id: %s]", stream.id);
2494
2533
  if (stream === this._localCameraStream) {
2495
2534
  return;
2496
2535
  }
@@ -2533,7 +2572,7 @@ class P2pRtcManager {
2533
2572
  };
2534
2573
  }
2535
2574
  addScreenshareStream(stream) {
2536
- logger$6.info("addScreenshareStream() [stream.id: %s]", stream.id);
2575
+ logger$7.info("addScreenshareStream() [stream.id: %s]", stream.id);
2537
2576
  if (stream === this._localScreenshareStream) {
2538
2577
  return;
2539
2578
  }
@@ -2546,7 +2585,7 @@ class P2pRtcManager {
2546
2585
  this._addStreamToPeerConnections(stream);
2547
2586
  }
2548
2587
  replaceTrack(oldTrack, newTrack) {
2549
- logger$6.info("replaceTrack() [kind: %s, oldTrackId: %s, newTrackId: %s]", newTrack.kind, oldTrack === null || oldTrack === void 0 ? void 0 : oldTrack.id, newTrack.id);
2588
+ logger$7.info("replaceTrack() [kind: %s, oldTrackId: %s, newTrackId: %s]", newTrack.kind, oldTrack === null || oldTrack === void 0 ? void 0 : oldTrack.id, newTrack.id);
2550
2589
  if (newTrack.kind === "audio" && !trackAnnotations(newTrack).isEffectTrack) {
2551
2590
  this._monitorAudioTrack(newTrack);
2552
2591
  }
@@ -2560,7 +2599,7 @@ class P2pRtcManager {
2560
2599
  this.disconnectAll();
2561
2600
  }
2562
2601
  disconnectAll() {
2563
- logger$6.info("disconnectAll()");
2602
+ logger$7.info("disconnectAll()");
2564
2603
  Object.keys(this.peerConnections).forEach((clientId) => {
2565
2604
  this.disconnect(clientId);
2566
2605
  });
@@ -2580,39 +2619,39 @@ class P2pRtcManager {
2580
2619
  () => this._clearMediaServersRefresh(),
2581
2620
  this._serverSocket.on(PROTOCOL_RESPONSES.MEDIASERVER_CONFIG, (data) => {
2582
2621
  if (data.error) {
2583
- logger$6.warn("FETCH_MEDIASERVER_CONFIG failed:", data.error);
2622
+ logger$7.warn("FETCH_MEDIASERVER_CONFIG failed:", data.error);
2584
2623
  return;
2585
2624
  }
2586
2625
  this._updateAndScheduleMediaServersRefresh(data);
2587
2626
  }),
2588
2627
  this._serverSocket.on(RELAY_MESSAGES.READY_TO_RECEIVE_OFFER, (data) => {
2589
- logger$6.info(`Got ready_to_receive_offer from client ${data.clientId}`);
2628
+ logger$7.info(`Got ready_to_receive_offer from client ${data.clientId}`);
2590
2629
  this._connect(data.clientId);
2591
2630
  }),
2592
2631
  this._serverSocket.on(RELAY_MESSAGES.ICE_CANDIDATE, (data) => {
2593
- logger$6.info(`Got ice_candidate from client ${data.clientId}`);
2632
+ logger$7.info(`Got ice_candidate from client ${data.clientId}`);
2594
2633
  const session = this._getSession(data.clientId);
2595
2634
  if (!session) {
2596
- logger$6.warn("No RTCPeerConnection on ICE_CANDIDATE", data);
2635
+ logger$7.warn("No RTCPeerConnection on ICE_CANDIDATE", data);
2597
2636
  return;
2598
2637
  }
2599
2638
  session.addIceCandidate(data.message);
2600
2639
  }),
2601
2640
  this._serverSocket.on(RELAY_MESSAGES.ICE_END_OF_CANDIDATES, (data) => {
2602
- logger$6.info(`Got end_of_ice_candidates from client ${data.clientId}`);
2641
+ logger$7.info(`Got end_of_ice_candidates from client ${data.clientId}`);
2603
2642
  const session = this._getSession(data.clientId);
2604
2643
  if (!session) {
2605
- logger$6.warn("No RTCPeerConnection on ICE_END_OF_CANDIDATES", data);
2644
+ logger$7.warn("No RTCPeerConnection on ICE_END_OF_CANDIDATES", data);
2606
2645
  return;
2607
2646
  }
2608
2647
  session.addIceCandidate(null);
2609
2648
  }),
2610
2649
  this._serverSocket.on(RELAY_MESSAGES.SDP_OFFER, (data) => {
2611
2650
  var _a, _b;
2612
- logger$6.info(`Got offer from client ${data.clientId}, isInitialOffer: ${Boolean(data.message.isInitialOffer)}`);
2651
+ logger$7.info(`Got offer from client ${data.clientId}, isInitialOffer: ${Boolean(data.message.isInitialOffer)}`);
2613
2652
  const session = this._getSession(data.clientId);
2614
2653
  if (!session) {
2615
- logger$6.warn("No RTCPeerConnection on SDP_OFFER", data);
2654
+ logger$7.warn("No RTCPeerConnection on SDP_OFFER", data);
2616
2655
  return;
2617
2656
  }
2618
2657
  const sdp = {
@@ -2624,7 +2663,7 @@ class P2pRtcManager {
2624
2663
  session.pc.connectionState === "new" &&
2625
2664
  session.pc.iceConnectionState === "new" &&
2626
2665
  !session.connectionStatus) {
2627
- logger$6.info("We have asked for an initial offer, ignoring all others");
2666
+ logger$7.info("We have asked for an initial offer, ignoring all others");
2628
2667
  this.analytics.P2POffendingInitialOffer++;
2629
2668
  rtcStats.sendEvent("P2POffendingInitialOffer", { clientId: session.clientId });
2630
2669
  return;
@@ -2632,22 +2671,22 @@ class P2pRtcManager {
2632
2671
  (_b = (_a = session
2633
2672
  .handleOffer(sdp)
2634
2673
  .then((answer) => {
2635
- logger$6.info(`Sending answer to client ${data.clientId}`);
2674
+ logger$7.info(`Sending answer to client ${data.clientId}`);
2636
2675
  this._emitServerEvent(RELAY_MESSAGES.SDP_ANSWER, {
2637
2676
  receiverId: data.clientId,
2638
2677
  message: answer,
2639
2678
  });
2640
2679
  })).catch) === null || _b === void 0 ? void 0 : _b.call(_a, (e) => {
2641
- logger$6.error(e);
2680
+ logger$7.error(e);
2642
2681
  this.analytics.numPcOnOfferFailure++;
2643
2682
  });
2644
2683
  }),
2645
2684
  this._serverSocket.on(RELAY_MESSAGES.SDP_ANSWER, (data) => {
2646
2685
  var _a, _b;
2647
- logger$6.info(`Got answer from client ${data.clientId}`);
2686
+ logger$7.info(`Got answer from client ${data.clientId}`);
2648
2687
  const session = this._getSession(data.clientId);
2649
2688
  if (!session) {
2650
- logger$6.warn("No RTCPeerConnection on SDP_ANSWER", data);
2689
+ logger$7.warn("No RTCPeerConnection on SDP_ANSWER", data);
2651
2690
  return;
2652
2691
  }
2653
2692
  const sdp = {
@@ -2655,7 +2694,7 @@ class P2pRtcManager {
2655
2694
  type: data.message.type,
2656
2695
  };
2657
2696
  (_b = (_a = session.handleAnswer(sdp)) === null || _a === void 0 ? void 0 : _a.catch) === null || _b === void 0 ? void 0 : _b.call(_a, (e) => {
2658
- logger$6.warn("Could not set remote description from remote answer: ", e);
2697
+ logger$7.warn("Could not set remote description from remote answer: ", e);
2659
2698
  this.analytics.numPcOnAnswerFailure++;
2660
2699
  });
2661
2700
  }),
@@ -2743,12 +2782,12 @@ class P2pRtcManager {
2743
2782
  });
2744
2783
  }
2745
2784
  catch (error) {
2746
- logger$6.error("Error during setting jitter buffer target:", error);
2785
+ logger$7.error("Error during setting jitter buffer target:", error);
2747
2786
  }
2748
2787
  }
2749
2788
  _emitServerEvent(eventName, data) {
2750
2789
  if (this._closed) {
2751
- logger$6.warn("RtcManager closed. Will not send event", eventName, data);
2790
+ logger$7.warn("RtcManager closed. Will not send event", eventName, data);
2752
2791
  return;
2753
2792
  }
2754
2793
  if (this._features.awaitJoinRoomFinished && !this._serverSocket.joinRoomFinished) {
@@ -2853,7 +2892,7 @@ class P2pRtcManager {
2853
2892
  }
2854
2893
  }
2855
2894
  catch (error) {
2856
- logger$6.info("Error during parsing candidates! Error: ", { error });
2895
+ logger$7.info("Error during parsing candidates! Error: ", { error });
2857
2896
  }
2858
2897
  break;
2859
2898
  case "srflx":
@@ -2895,7 +2934,7 @@ class P2pRtcManager {
2895
2934
  if (pc.iceConnectionState === "new" || !session.connectionStatus) {
2896
2935
  return;
2897
2936
  }
2898
- logger$6.info(`onnegotiationneeded client ${clientId}`);
2937
+ logger$7.info(`onnegotiationneeded client ${clientId}`);
2899
2938
  this._negotiatePeerConnection({ clientId, session });
2900
2939
  };
2901
2940
  pc.ontrack = (event) => {
@@ -2920,7 +2959,7 @@ class P2pRtcManager {
2920
2959
  };
2921
2960
  pc.oniceconnectionstatechange = () => {
2922
2961
  var _a;
2923
- logger$6.info(`iceConnectionState changed to ${pc.iceConnectionState} for session ${session.clientId}`);
2962
+ logger$7.info(`iceConnectionState changed to ${pc.iceConnectionState} for session ${session.clientId}`);
2924
2963
  let newStatus;
2925
2964
  const currentStatus = session.connectionStatus;
2926
2965
  switch (pc.iceConnectionState) {
@@ -2975,7 +3014,7 @@ class P2pRtcManager {
2975
3014
  };
2976
3015
  pc.onconnectionstatechange = () => {
2977
3016
  var _a;
2978
- logger$6.info(`connectionState changed to ${pc.connectionState} for session ${session.clientId}`);
3017
+ logger$7.info(`connectionState changed to ${pc.connectionState} for session ${session.clientId}`);
2979
3018
  switch (pc.connectionState) {
2980
3019
  case "connected":
2981
3020
  (_a = session.registerConnected) === null || _a === void 0 ? void 0 : _a.call(session, {});
@@ -3032,7 +3071,7 @@ class P2pRtcManager {
3032
3071
  _cleanup(clientId) {
3033
3072
  const session = this._getSession(clientId);
3034
3073
  if (!session) {
3035
- logger$6.warn("No RTCPeerConnection in RTCManager.disconnect()", clientId);
3074
+ logger$7.warn("No RTCPeerConnection in RTCManager.disconnect()", clientId);
3036
3075
  return;
3037
3076
  }
3038
3077
  this.removeRemoteClientMediaPrefs(session.clientId);
@@ -3060,7 +3099,7 @@ class P2pRtcManager {
3060
3099
  if (!session.hasConnectedPeerConnection()) {
3061
3100
  if (session.pc.connectionState === "closed")
3062
3101
  return;
3063
- logger$6.info("Session doesn't have a connected PeerConnection, adding pending action!");
3102
+ logger$7.info("Session doesn't have a connected PeerConnection, adding pending action!");
3064
3103
  const promise = new Promise((resolve, reject) => {
3065
3104
  const action = () => __awaiter(this, void 0, void 0, function* () {
3066
3105
  try {
@@ -3079,7 +3118,7 @@ class P2pRtcManager {
3079
3118
  promises.push(session.replaceTrack(oldTrack, newTrack));
3080
3119
  });
3081
3120
  return Promise.all(promises).catch((error) => {
3082
- logger$6.error(String(error));
3121
+ logger$7.error(String(error));
3083
3122
  });
3084
3123
  }
3085
3124
  _removeStreamFromPeerConnections(stream) {
@@ -3127,7 +3166,7 @@ class P2pRtcManager {
3127
3166
  let session = this._getSession(clientId);
3128
3167
  let initialBandwidth = (session && session.bandwidth) || 0;
3129
3168
  if (session) {
3130
- logger$6.warn("Replacing peer session", clientId);
3169
+ logger$7.warn("Replacing peer session", clientId);
3131
3170
  this._cleanup(clientId);
3132
3171
  }
3133
3172
  else {
@@ -3198,13 +3237,13 @@ class P2pRtcManager {
3198
3237
  })));
3199
3238
  }
3200
3239
  catch (error) {
3201
- logger$6.error("Error during setting setCodecPreferences:", error);
3240
+ logger$7.error("Error during setting setCodecPreferences:", error);
3202
3241
  }
3203
3242
  });
3204
3243
  }
3205
3244
  _negotiatePeerConnection({ clientId, session, constraints, isInitialOffer = false, }) {
3206
3245
  if (!session) {
3207
- logger$6.warn("No RTCPeerConnection in negotiatePeerConnection()", clientId);
3246
+ logger$7.warn("No RTCPeerConnection in negotiatePeerConnection()", clientId);
3208
3247
  return;
3209
3248
  }
3210
3249
  const pc = session.pc;
@@ -3234,7 +3273,7 @@ class P2pRtcManager {
3234
3273
  offer.sdp = cleanSdp(offer.sdp);
3235
3274
  pc.setLocalDescription(offer)
3236
3275
  .catch((e) => {
3237
- logger$6.warn("RTCPeerConnection.setLocalDescription() failed with local offer", e);
3276
+ logger$7.warn("RTCPeerConnection.setLocalDescription() failed with local offer", e);
3238
3277
  this.analytics.numPcSldFailure++;
3239
3278
  throw e;
3240
3279
  })
@@ -3246,7 +3285,7 @@ class P2pRtcManager {
3246
3285
  type: offer.type,
3247
3286
  isInitialOffer,
3248
3287
  };
3249
- logger$6.info(`sending offer to client ${clientId}`);
3288
+ logger$7.info(`sending offer to client ${clientId}`);
3250
3289
  this._emitServerEvent(RELAY_MESSAGES.SDP_OFFER, {
3251
3290
  receiverId: clientId,
3252
3291
  message,
@@ -3254,7 +3293,7 @@ class P2pRtcManager {
3254
3293
  });
3255
3294
  })
3256
3295
  .catch((e) => {
3257
- logger$6.warn("RTCPeerConnection.createOffer() failed to create local offer", e);
3296
+ logger$7.warn("RTCPeerConnection.createOffer() failed to create local offer", e);
3258
3297
  }));
3259
3298
  }
3260
3299
  _withForcedRenegotiation(session, action) {
@@ -3296,7 +3335,7 @@ class P2pRtcManager {
3296
3335
  return bandwidth;
3297
3336
  }
3298
3337
  acceptNewStream({ streamId, clientId }) {
3299
- logger$6.info("acceptNewStream() [streamId: %s}, clientId: %s]", streamId, clientId);
3338
+ logger$7.info("acceptNewStream() [streamId: %s}, clientId: %s]", streamId, clientId);
3300
3339
  let session = this._getSession(clientId);
3301
3340
  if (session && streamId !== clientId) {
3302
3341
  return session;
@@ -3319,7 +3358,7 @@ class P2pRtcManager {
3319
3358
  return session;
3320
3359
  }
3321
3360
  disconnect(clientId) {
3322
- logger$6.info("disconnect() [clientId: %s]", clientId);
3361
+ logger$7.info("disconnect() [clientId: %s]", clientId);
3323
3362
  this._cleanup(clientId);
3324
3363
  this._changeBandwidthForAllClients(false);
3325
3364
  const numPeers = this.numberOfPeerconnections();
@@ -3356,7 +3395,7 @@ class P2pRtcManager {
3356
3395
  stopOrResumeVideo() {
3357
3396
  }
3358
3397
  removeScreenshareStream(stream, { requestedByClientId } = {}) {
3359
- logger$6.info("removeScreenshareStream() [stream.id: %s, requestedByClientId: %s]", stream.id, requestedByClientId);
3398
+ logger$7.info("removeScreenshareStream() [stream.id: %s, requestedByClientId: %s]", stream.id, requestedByClientId);
3360
3399
  this._removeStreamFromPeerConnections(stream);
3361
3400
  this._emitServerEvent(PROTOCOL_REQUESTS.STOP_SCREENSHARE, { streamId: stream.id, requestedByClientId });
3362
3401
  delete this._localScreenshareStream;
@@ -3477,7 +3516,7 @@ const defaultParams = {
3477
3516
  scoreFormula: "300 * bands[1].avg / Math.max(bands[1].avg + bands[0].avg, 0.01)",
3478
3517
  outFormula: "score",
3479
3518
  };
3480
- const logger$5 = new Logger();
3519
+ const logger$6 = new Logger();
3481
3520
  function createMicAnalyser({ micTrack, params, onScoreUpdated, }) {
3482
3521
  const audioCtx = new AudioContext();
3483
3522
  let analyser = null;
@@ -3499,7 +3538,7 @@ function createMicAnalyser({ micTrack, params, onScoreUpdated, }) {
3499
3538
  lastTrackWasOurs = true;
3500
3539
  }
3501
3540
  catch (ex) {
3502
- logger$5.warn("unable to fetch new track for colocation speaker analysis, using current", ex);
3541
+ logger$6.warn("unable to fetch new track for colocation speaker analysis, using current", ex);
3503
3542
  }
3504
3543
  }
3505
3544
  lastTrack = track;
@@ -3586,7 +3625,7 @@ function createMicAnalyser({ micTrack, params, onScoreUpdated, }) {
3586
3625
  };
3587
3626
  }
3588
3627
 
3589
- const logger$4 = new Logger();
3628
+ const logger$5 = new Logger();
3590
3629
  const MEDIA_QUALITY = Object.freeze({
3591
3630
  ok: "ok",
3592
3631
  warning: "warning",
@@ -3656,7 +3695,7 @@ class VegaMediaQualityMonitor extends EventEmitter {
3656
3695
  }
3657
3696
  addProducer(clientId, producerId) {
3658
3697
  if (!clientId || !producerId || !(typeof clientId === "string" && typeof producerId === "string")) {
3659
- logger$4.warn("Missing clientId or producerId");
3698
+ logger$5.warn("Missing clientId or producerId");
3660
3699
  return;
3661
3700
  }
3662
3701
  if (!this._producers[clientId]) {
@@ -3672,7 +3711,7 @@ class VegaMediaQualityMonitor extends EventEmitter {
3672
3711
  }
3673
3712
  addConsumer(clientId, consumerId) {
3674
3713
  if (!clientId || !consumerId) {
3675
- logger$4.warn("Missing clientId or consumerId");
3714
+ logger$5.warn("Missing clientId or consumerId");
3676
3715
  return;
3677
3716
  }
3678
3717
  if (!this._producers[clientId]) {
@@ -3690,14 +3729,14 @@ class VegaMediaQualityMonitor extends EventEmitter {
3690
3729
  if (!Array.isArray(score) ||
3691
3730
  score.length === 0 ||
3692
3731
  score.some((s) => !s || !s.hasOwnProperty("score") || typeof s.score !== "number" || isNaN(s.score))) {
3693
- logger$4.warn("Unexpected producer score format");
3732
+ logger$5.warn("Unexpected producer score format");
3694
3733
  return;
3695
3734
  }
3696
3735
  this._producers[clientId][producerId] = { kind, score: this._calcAvgProducerScore(score.map((s) => s.score)) };
3697
3736
  }
3698
3737
  addConsumerScore(clientId, consumerId, kind, score) {
3699
3738
  if (!score || !score.hasOwnProperty("producerScores") || !Array.isArray(score.producerScores)) {
3700
- logger$4.warn("Unexpected consumer score format");
3739
+ logger$5.warn("Unexpected consumer score format");
3701
3740
  return;
3702
3741
  }
3703
3742
  this._producers[clientId][consumerId] = { kind, score: this._calcAvgProducerScore(score.producerScores) };
@@ -3734,12 +3773,13 @@ class VegaMediaQualityMonitor extends EventEmitter {
3734
3773
  }
3735
3774
  }
3736
3775
  catch (error) {
3737
- logger$4.error(error);
3776
+ logger$5.error(error);
3738
3777
  return 0;
3739
3778
  }
3740
3779
  }
3741
3780
  }
3742
3781
 
3782
+ const logger$4 = new Logger();
3743
3783
  function getLayers({ width, height, }, { numberOfActiveVideos, numberOfTemporalLayers, uncappedSingleRemoteVideoOn, }) {
3744
3784
  const maxSide = Math.max(width, height);
3745
3785
  let spatialLayer = maxSide >= 480 ? (maxSide >= 960 ? 2 : 1) : 0;
@@ -3759,6 +3799,27 @@ function getLayers({ width, height, }, { numberOfActiveVideos, numberOfTemporalL
3759
3799
  }
3760
3800
  return { spatialLayer, temporalLayer };
3761
3801
  }
3802
+ function createMetricStats() {
3803
+ return { count: 0, sum: 0 };
3804
+ }
3805
+ function recordMetricSample(stats, value) {
3806
+ stats.count++;
3807
+ stats.sum += value;
3808
+ }
3809
+ function aggregateMetricStats(stats) {
3810
+ return {
3811
+ count: stats.count,
3812
+ avg: stats.count ? Math.round(stats.sum / stats.count) : undefined,
3813
+ };
3814
+ }
3815
+ function getPacketWeightedFractionLost(reports) {
3816
+ const weights = reports.map(({ packetRate }) => (packetRate && packetRate > 0 ? packetRate : 0));
3817
+ const totalWeight = weights.reduce((sum, weight) => sum + weight, 0);
3818
+ if (!totalWeight) {
3819
+ return reports.reduce((sum, { fractionLost }) => sum + (fractionLost || 0), 0) / (reports.length || 1);
3820
+ }
3821
+ return (reports.reduce((sum, { fractionLost }, index) => sum + (fractionLost || 0) * weights[index], 0) / totalWeight);
3822
+ }
3762
3823
  function getNumberOfActiveVideos(consumers) {
3763
3824
  let numberOfActiveVideos = 0;
3764
3825
  consumers.forEach((c) => {
@@ -3774,6 +3835,51 @@ function getNumberOfTemporalLayers(consumer) {
3774
3835
  var _a, _b, _c;
3775
3836
  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;
3776
3837
  }
3838
+ const SCALABILITY_MODE_REGEX = /^([LS])([1-9]\d?)T([1-9]\d?)(_KEY)?$/;
3839
+ function getTopSpatialLayer(encodings) {
3840
+ if (encodings.length > 1)
3841
+ return encodings.length - 1;
3842
+ const { scalabilityMode } = encodings[0];
3843
+ const match = SCALABILITY_MODE_REGEX.exec(scalabilityMode || "");
3844
+ if (!match) {
3845
+ if (scalabilityMode) {
3846
+ logger$4.warn("getTopSpatialLayer() unrecognized scalabilityMode %s, using a single spatial layer", scalabilityMode);
3847
+ }
3848
+ return 0;
3849
+ }
3850
+ const spatialLayers = Number(match[2]) || 1;
3851
+ return spatialLayers - 1;
3852
+ }
3853
+ function getInitialHighestPreferredLayer(encodings) {
3854
+ return Math.min(getTopSpatialLayer(encodings), INITIAL_HIGHEST_PREFERRED_LAYER);
3855
+ }
3856
+ function getReducedSvcEncodingParams(originalScalabilityMode, spatialLayer, originalMaxBitrate) {
3857
+ const match = SCALABILITY_MODE_REGEX.exec(originalScalabilityMode || "");
3858
+ if (!match)
3859
+ return undefined;
3860
+ const [, mode, originalSpatialLayers, temporalLayers, key = ""] = match;
3861
+ const topLayerIndex = Number(originalSpatialLayers) - 1;
3862
+ if (topLayerIndex === 0)
3863
+ return undefined;
3864
+ const preferredLayerIndex = Math.min(Math.max(spatialLayer, 0), topLayerIndex);
3865
+ const onlyLowestLayerPreferred = preferredLayerIndex === 0;
3866
+ const middleLayerPreferred = preferredLayerIndex > 0 && preferredLayerIndex < topLayerIndex;
3867
+ let maxBitrate = originalMaxBitrate;
3868
+ if (onlyLowestLayerPreferred) {
3869
+ maxBitrate = Math.min(LOWEST_SVC_LAYER_MAX_BITRATE, originalMaxBitrate !== null && originalMaxBitrate !== void 0 ? originalMaxBitrate : Infinity);
3870
+ }
3871
+ else if (middleLayerPreferred) {
3872
+ maxBitrate = Math.min(MIDDLE_SVC_LAYER_MAX_BITRATE, originalMaxBitrate !== null && originalMaxBitrate !== void 0 ? originalMaxBitrate : Infinity);
3873
+ }
3874
+ const scalabilityMode = onlyLowestLayerPreferred
3875
+ ? `L1T${temporalLayers}`
3876
+ : `${mode}${preferredLayerIndex + 1}T${temporalLayers}${key}`;
3877
+ return {
3878
+ scalabilityMode,
3879
+ scaleResolutionDownBy: Math.pow(2, (topLayerIndex - preferredLayerIndex)),
3880
+ maxBitrate,
3881
+ };
3882
+ }
3777
3883
  function addProducerCpuOveruseWatch({ producer, onOveruse }) {
3778
3884
  var _a;
3779
3885
  const encodings = (_a = producer.rtpParameters) === null || _a === void 0 ? void 0 : _a.encodings;
@@ -4230,6 +4336,7 @@ const RESTARTICE_ERROR_RETRY_THRESHOLD_IN_MS = 3500;
4230
4336
  const RESTARTICE_ERROR_MAX_RETRY_COUNT = 5;
4231
4337
  const OUTBOUND_CAM_OUTBOUND_STREAM_ID = uuid.v4();
4232
4338
  const OUTBOUND_SCREEN_OUTBOUND_STREAM_ID = uuid.v4();
4339
+ 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); };
4233
4340
  if (browserName === "chrome")
4234
4341
  window.document.addEventListener("beforeunload", () => (unloading = true));
4235
4342
  class VegaRtcManager {
@@ -4267,6 +4374,11 @@ class VegaRtcManager {
4267
4374
  this._micScoreProducer = null;
4268
4375
  this._micScoreProducerPromise = null;
4269
4376
  this._webcamProducer = null;
4377
+ this._webcamProducerOriginalSvcScalabilityMode = undefined;
4378
+ this._webcamProducerOriginalSvcMaxBitrate = undefined;
4379
+ this._webcamProducerHighestPreferredLayer = undefined;
4380
+ this._highestPreferredLayerUpdate = null;
4381
+ this._highestPreferredLayerUpdatePending = false;
4270
4382
  this._webcamProducerPromise = null;
4271
4383
  this._webcamPaused = false;
4272
4384
  this._screenVideoProducer = null;
@@ -4308,12 +4420,19 @@ class VegaRtcManager {
4308
4420
  };
4309
4421
  (_a = window === null || window === void 0 ? void 0 : window.addEventListener) === null || _a === void 0 ? void 0 : _a.call(window, "offline", this._sfuZombie.onBrowserOffline);
4310
4422
  this.analytics = {
4423
+ avgPreferredLayerSwitchLatencyMs: undefined,
4424
+ camOutboundCongestedFraction: undefined,
4425
+ camOutboundRttInflationMs: undefined,
4311
4426
  camTrackEndedCount: 0,
4427
+ highestPreferredLayerChangeCounts: {},
4312
4428
  micTrackEndedCount: 0,
4429
+ numHighestPreferredLayerChanges: 0,
4313
4430
  numIceConnected: 0,
4314
4431
  numIceDisconnected: 0,
4315
4432
  numIceFailed: 0,
4316
4433
  numNewPc: 0,
4434
+ numPreferredSpatialLayerChanges: 0,
4435
+ preferredSpatialLayerChangeCounts: {},
4317
4436
  sfuMsFromOfflineToClose: 0,
4318
4437
  sfuOfflineToCloseCount: 0,
4319
4438
  sfuOfflineWhileConnectedCount: 0,
@@ -4333,6 +4452,15 @@ class VegaRtcManager {
4333
4452
  vegaUnknownResponse: 0,
4334
4453
  vegaWebcamProducerFailed: 0,
4335
4454
  };
4455
+ this._preferredLayerSwitchLatencyStats = createMetricStats();
4456
+ this._preferredLayerSwitchWatches = new Map();
4457
+ this._lastSeenRemoteReportTimestamps = new Map();
4458
+ this._camOutboundCandidatePairId = undefined;
4459
+ this._camOutboundSamplesToSkip = 0;
4460
+ this._camOutboundPathRtt = { sumMs: 0, count: 0, minMs: undefined };
4461
+ this._camOutboundRttInflation = { sumMs: 0, count: 0 };
4462
+ this._camOutboundSamples = { total: 0, congested: 0 };
4463
+ this._statsSubscription = null;
4336
4464
  }
4337
4465
  _updateAndScheduleMediaServersRefresh({ iceServers, turnServers, sfuServer, mediaserverConfigTtlSeconds, }) {
4338
4466
  var _a, _b, _c, _d;
@@ -4502,7 +4630,6 @@ class VegaRtcManager {
4502
4630
  this._sendTransport = null;
4503
4631
  this._receiveTransport = null;
4504
4632
  this._streamIdToVideoConsumerId.clear();
4505
- this._streamIdToVideoResolution.clear();
4506
4633
  if (this._reconnect) {
4507
4634
  this._reconnectTimeOut = setTimeout(() => this._connect(), 1000);
4508
4635
  }
@@ -4925,6 +5052,14 @@ class VegaRtcManager {
4925
5052
  const simulcastLayer3ShouldBeActive = !this._cpuOveruseDetected;
4926
5053
  const params = this._webcamProducer.rtpParameters;
4927
5054
  if (((_a = params === null || params === void 0 ? void 0 : params.encodings) === null || _a === void 0 ? void 0 : _a.length) === 3) {
5055
+ if (this._features.sfuHighestPreferredLayerTrackingOn) {
5056
+ this._syncWebcamEncoderToHighestPreferredLayer();
5057
+ rtcStats.sendEvent("simulcast_layer_activation_changed", {
5058
+ layerIndex: 2,
5059
+ active: simulcastLayer3ShouldBeActive,
5060
+ });
5061
+ return;
5062
+ }
4928
5063
  const targetMaxSpatialLayer = simulcastLayer3ShouldBeActive ? 2 : 1;
4929
5064
  if (this._webcamProducer.maxSpatialLayer !== targetMaxSpatialLayer) {
4930
5065
  this._webcamProducer.setMaxSpatialLayer(targetMaxSpatialLayer);
@@ -4947,7 +5082,7 @@ class VegaRtcManager {
4947
5082
  return;
4948
5083
  }
4949
5084
  this._webcamProducerPromise = (() => __awaiter(this, void 0, void 0, function* () {
4950
- var _a;
5085
+ var _a, _b, _c;
4951
5086
  try {
4952
5087
  const currentPaused = this._webcamPaused;
4953
5088
  if (!this._sendTransport) {
@@ -4973,6 +5108,16 @@ class VegaRtcManager {
4973
5108
  })
4974
5109
  : () => { };
4975
5110
  this._webcamProducer = producer;
5111
+ if (this._features.sfuHighestPreferredLayerTrackingOn) {
5112
+ const originalWebcamEncodings = (_b = (_a = producer.rtpSender) === null || _a === void 0 ? void 0 : _a.getParameters()) === null || _b === void 0 ? void 0 : _b.encodings;
5113
+ const svcEncoding = (originalWebcamEncodings === null || originalWebcamEncodings === void 0 ? void 0 : originalWebcamEncodings.length) === 1 ? originalWebcamEncodings[0] : undefined;
5114
+ this._webcamProducerOriginalSvcScalabilityMode = svcEncoding === null || svcEncoding === void 0 ? void 0 : svcEncoding.scalabilityMode;
5115
+ this._webcamProducerOriginalSvcMaxBitrate = svcEncoding === null || svcEncoding === void 0 ? void 0 : svcEncoding.maxBitrate;
5116
+ this._webcamProducerHighestPreferredLayer = (originalWebcamEncodings === null || originalWebcamEncodings === void 0 ? void 0 : originalWebcamEncodings.length)
5117
+ ? getInitialHighestPreferredLayer(originalWebcamEncodings)
5118
+ : undefined;
5119
+ this._syncWebcamEncoderToHighestPreferredLayer();
5120
+ }
4976
5121
  this._qualityMonitor.addProducer(this._selfId, producer.id);
4977
5122
  producer.observer.once("close", () => {
4978
5123
  var _a;
@@ -4980,11 +5125,16 @@ class VegaRtcManager {
4980
5125
  if (producer.appData.localClosed)
4981
5126
  (_a = this._vegaConnection) === null || _a === void 0 ? void 0 : _a.message("closeProducers", { producerIds: [producer.id] });
4982
5127
  cleanUpCpuWatch();
5128
+ this._stopWebcamStatsSubscription();
4983
5129
  this._webcamProducer = null;
5130
+ this._webcamProducerOriginalSvcScalabilityMode = undefined;
5131
+ this._webcamProducerOriginalSvcMaxBitrate = undefined;
5132
+ this._webcamProducerHighestPreferredLayer = undefined;
4984
5133
  this._webcamProducerPromise = null;
4985
5134
  this._qualityMonitor.removeProducer(this._selfId, producer.id);
4986
5135
  });
4987
- if (this._webcamTrack && this._webcamTrack !== ((_a = this._webcamProducer) === null || _a === void 0 ? void 0 : _a.track)) {
5136
+ this._startWebcamStatsSubscription();
5137
+ if (this._webcamTrack && this._webcamTrack !== ((_c = this._webcamProducer) === null || _c === void 0 ? void 0 : _c.track)) {
4988
5138
  this._webcamProducerPromise = null;
4989
5139
  this._replaceWebcamTrack();
4990
5140
  }
@@ -5001,6 +5151,9 @@ class VegaRtcManager {
5001
5151
  if (!this._webcamTrack) {
5002
5152
  this._stopProducer(this._webcamProducer);
5003
5153
  this._webcamProducer = null;
5154
+ this._webcamProducerOriginalSvcScalabilityMode = undefined;
5155
+ this._webcamProducerOriginalSvcMaxBitrate = undefined;
5156
+ this._webcamProducerHighestPreferredLayer = undefined;
5004
5157
  }
5005
5158
  }
5006
5159
  }))();
@@ -5252,6 +5405,7 @@ class VegaRtcManager {
5252
5405
  if (clientState) {
5253
5406
  clientState.hasAcceptedWebcamStream = false;
5254
5407
  clientState.hasAcceptedScreenStream = false;
5408
+ [clientState.webcamStream, clientState.screenStream].forEach((stream) => stream && this._streamIdToVideoResolution.delete(stream.id));
5255
5409
  this._syncIncomingStreamsWithPWA(clientId);
5256
5410
  }
5257
5411
  if (eventClaim) {
@@ -5375,6 +5529,9 @@ class VegaRtcManager {
5375
5529
  if (this._webcamProducer && !this._webcamProducer.closed && this._webcamProducer.track === track) {
5376
5530
  this._stopProducer(this._webcamProducer);
5377
5531
  this._webcamProducer = null;
5532
+ this._webcamProducerOriginalSvcScalabilityMode = undefined;
5533
+ this._webcamProducerOriginalSvcMaxBitrate = undefined;
5534
+ this._webcamProducerHighestPreferredLayer = undefined;
5378
5535
  this._webcamTrack = null;
5379
5536
  }
5380
5537
  }
@@ -5402,14 +5559,18 @@ class VegaRtcManager {
5402
5559
  this._syncIncomingStreamsWithPWA(clientId);
5403
5560
  }
5404
5561
  updateStreamResolution(streamId, _ignored, { width, height, }) {
5405
- var _a, _b, _c;
5406
5562
  logger$2.info("updateStreamResolution()", { streamId, width, height });
5563
+ this._streamIdToVideoResolution.set(streamId, { width, height });
5564
+ this._applyStreamResolution(streamId);
5565
+ }
5566
+ _applyStreamResolution(streamId) {
5567
+ var _a, _b, _c;
5568
+ const resolution = this._streamIdToVideoResolution.get(streamId);
5407
5569
  const consumerId = this._streamIdToVideoConsumerId.get(streamId);
5408
5570
  const consumer = this._consumers.get(consumerId);
5409
- if (!consumer) {
5410
- this._streamIdToVideoResolution.set(streamId, { width, height });
5571
+ if (!resolution || !consumer)
5411
5572
  return;
5412
- }
5573
+ const { width, height } = resolution;
5413
5574
  updateRenderedDimensions((_a = consumer.track) === null || _a === void 0 ? void 0 : _a.id, { width, height, time: Date.now() });
5414
5575
  const numberOfActiveVideos = getNumberOfActiveVideos(this._consumers);
5415
5576
  const numberOfTemporalLayers = getNumberOfTemporalLayers(consumer);
@@ -5419,6 +5580,12 @@ class VegaRtcManager {
5419
5580
  uncappedSingleRemoteVideoOn: (_b = this._features) === null || _b === void 0 ? void 0 : _b.uncappedSingleRemoteVideoOn,
5420
5581
  });
5421
5582
  if (consumer.appData.spatialLayer !== spatialLayer || consumer.appData.temporalLayer !== temporalLayer) {
5583
+ const previousSpatialLayer = consumer.appData.spatialLayer;
5584
+ const spatialLayerChanged = previousSpatialLayer !== spatialLayer;
5585
+ if (spatialLayerChanged) {
5586
+ this.analytics.numPreferredSpatialLayerChanges++;
5587
+ this._incrementHistogramCount(this.analytics.preferredSpatialLayerChangeCounts, `${previousSpatialLayer}->${spatialLayer}`);
5588
+ }
5422
5589
  consumer.appData.spatialLayer = spatialLayer;
5423
5590
  consumer.appData.temporalLayer = temporalLayer;
5424
5591
  (_c = this._vegaConnection) === null || _c === void 0 ? void 0 : _c.message("setConsumersPreferredLayers", {
@@ -5426,7 +5593,178 @@ class VegaRtcManager {
5426
5593
  spatialLayer,
5427
5594
  temporalLayer,
5428
5595
  });
5596
+ if (spatialLayerChanged) {
5597
+ this._watchForPreferredLayerSwitch(consumerId, consumer, {
5598
+ toHigherLayer: spatialLayer > previousSpatialLayer,
5599
+ });
5600
+ }
5601
+ }
5602
+ }
5603
+ _watchForPreferredLayerSwitch(consumerId, consumer, { toHigherLayer }) {
5604
+ const previousWatch = this._preferredLayerSwitchWatches.get(consumerId);
5605
+ if (!previousWatch && this._preferredLayerSwitchWatches.size >= MAX_CONCURRENT_PREFERRED_LAYER_SWITCH_WATCHES) {
5606
+ return;
5607
+ }
5608
+ previousWatch === null || previousWatch === void 0 ? void 0 : previousWatch.stop();
5609
+ let stopped = false;
5610
+ let intervalId;
5611
+ const stop = () => {
5612
+ if (stopped)
5613
+ return;
5614
+ stopped = true;
5615
+ clearInterval(intervalId);
5616
+ clearTimeout(timeoutId);
5617
+ this._preferredLayerSwitchWatches.delete(consumerId);
5618
+ };
5619
+ this._preferredLayerSwitchWatches.set(consumerId, { stop });
5620
+ const timeoutId = setTimeout(stop, PREFERRED_LAYER_SWITCH_WATCH_TIMEOUT_MS);
5621
+ (() => __awaiter(this, void 0, void 0, function* () {
5622
+ const sentAt = Date.now();
5623
+ const baseline = yield this._getConsumerFrameSize(consumer);
5624
+ if (stopped || !(baseline === null || baseline === void 0 ? void 0 : baseline.width) || !(baseline === null || baseline === void 0 ? void 0 : baseline.height)) {
5625
+ stop();
5626
+ return;
5627
+ }
5628
+ let polling = false;
5629
+ intervalId = setInterval(() => __awaiter(this, void 0, void 0, function* () {
5630
+ if (stopped || consumer.closed) {
5631
+ stop();
5632
+ return;
5633
+ }
5634
+ if (polling)
5635
+ return;
5636
+ polling = true;
5637
+ const current = yield this._getConsumerFrameSize(consumer);
5638
+ polling = false;
5639
+ if (stopped)
5640
+ return;
5641
+ const switched = toHigherLayer
5642
+ ? getFrameArea(current) > getFrameArea(baseline)
5643
+ : getFrameArea(current) < getFrameArea(baseline);
5644
+ if (current && switched) {
5645
+ this._recordPreferredLayerSwitchLatency(Date.now() - sentAt);
5646
+ stop();
5647
+ }
5648
+ }), PREFERRED_LAYER_SWITCH_POLL_INTERVAL_MS);
5649
+ }))();
5650
+ }
5651
+ _getConsumerFrameSize(consumer) {
5652
+ return __awaiter(this, void 0, void 0, function* () {
5653
+ try {
5654
+ const stats = yield consumer.getStats();
5655
+ let frameSize;
5656
+ stats.forEach((report) => {
5657
+ if (report.type === "inbound-rtp") {
5658
+ frameSize = { width: report.frameWidth, height: report.frameHeight };
5659
+ }
5660
+ });
5661
+ return frameSize;
5662
+ }
5663
+ catch (error) {
5664
+ logger$2.warn("_getConsumerFrameSize() failed to read stats", { error });
5665
+ return undefined;
5666
+ }
5667
+ });
5668
+ }
5669
+ _recordPreferredLayerSwitchLatency(latencyMs) {
5670
+ recordMetricSample(this._preferredLayerSwitchLatencyStats, latencyMs);
5671
+ const { avg } = aggregateMetricStats(this._preferredLayerSwitchLatencyStats);
5672
+ this.analytics.avgPreferredLayerSwitchLatencyMs = avg;
5673
+ }
5674
+ _onUpdatedStats(statsByView) {
5675
+ var _a, _b, _c, _d;
5676
+ const webcamProducerMid = (_b = (_a = this._webcamProducer) === null || _a === void 0 ? void 0 : _a.rtpParameters) === null || _b === void 0 ? void 0 : _b.mid;
5677
+ if (webcamProducerMid === undefined)
5678
+ return;
5679
+ const sendTransportPc = (_d = (_c = this._sendTransport) === null || _c === void 0 ? void 0 : _c.handler) === null || _d === void 0 ? void 0 : _d._pc;
5680
+ const sendTransportPcIndex = sendTransportPc ? getPeerConnectionIndex(sendTransportPc) : undefined;
5681
+ const newRemoteReports = [];
5682
+ Object.values(statsByView).forEach((viewStats) => {
5683
+ Object.values(viewStats.tracks || {}).forEach((trackStats) => {
5684
+ Object.entries(trackStats.ssrcs || {}).forEach(([ssrc, ssrcMetrics]) => {
5685
+ if (ssrcMetrics.direction !== "out" || String(ssrcMetrics.mid) !== webcamProducerMid)
5686
+ return;
5687
+ if (sendTransportPcIndex !== undefined && ssrcMetrics.pcIndex !== sendTransportPcIndex)
5688
+ return;
5689
+ this._followCamOutboundCandidatePair(ssrcMetrics);
5690
+ const { remoteReportTimestamp } = ssrcMetrics;
5691
+ if (remoteReportTimestamp === undefined)
5692
+ return;
5693
+ if (remoteReportTimestamp === this._lastSeenRemoteReportTimestamps.get(ssrc))
5694
+ return;
5695
+ this._lastSeenRemoteReportTimestamps.set(ssrc, remoteReportTimestamp);
5696
+ newRemoteReports.push(ssrcMetrics);
5697
+ });
5698
+ });
5699
+ });
5700
+ if (!newRemoteReports.length)
5701
+ return;
5702
+ if (this._camOutboundSamplesToSkip > 0) {
5703
+ this._camOutboundSamplesToSkip--;
5704
+ return;
5429
5705
  }
5706
+ this._recordCamOutboundSample(newRemoteReports);
5707
+ this._updateCamOutboundAnalytics();
5708
+ }
5709
+ _recordCamOutboundSample(newRemoteReports) {
5710
+ var _a, _b;
5711
+ const rttsMs = newRemoteReports.map(({ roundTripTime }) => (roundTripTime || 0) * 1000).filter((ms) => ms > 0);
5712
+ const rttMs = rttsMs.length ? Math.max(...rttsMs) : undefined;
5713
+ const fractionLost = getPacketWeightedFractionLost(newRemoteReports);
5714
+ const path = this._camOutboundPathRtt;
5715
+ if (rttMs !== undefined) {
5716
+ path.sumMs += rttMs;
5717
+ path.count++;
5718
+ path.minMs = Math.min((_a = path.minMs) !== null && _a !== void 0 ? _a : Infinity, rttMs);
5719
+ }
5720
+ const congested = (rttMs !== undefined && rttMs - ((_b = path.minMs) !== null && _b !== void 0 ? _b : rttMs) > CONGESTED_RTT_INFLATION_MS) ||
5721
+ fractionLost > CONGESTED_FRACTION_LOST;
5722
+ this._camOutboundSamples.total++;
5723
+ if (congested)
5724
+ this._camOutboundSamples.congested++;
5725
+ }
5726
+ _followCamOutboundCandidatePair({ selectedCandidatePairId }) {
5727
+ if (!selectedCandidatePairId || selectedCandidatePairId === this._camOutboundCandidatePairId)
5728
+ return;
5729
+ if (this._camOutboundCandidatePairId !== undefined) {
5730
+ this._finishCamOutboundRttPath();
5731
+ this._camOutboundSamplesToSkip = CAM_SAMPLES_SKIPPED_AFTER_CANDIDATE_PAIR_CHANGE;
5732
+ }
5733
+ this._camOutboundCandidatePairId = selectedCandidatePairId;
5734
+ }
5735
+ _finishCamOutboundRttPath() {
5736
+ const path = this._camOutboundPathRtt;
5737
+ if (path.count && path.minMs !== undefined) {
5738
+ this._camOutboundRttInflation.sumMs += path.sumMs - path.count * path.minMs;
5739
+ this._camOutboundRttInflation.count += path.count;
5740
+ }
5741
+ this._camOutboundPathRtt = { sumMs: 0, count: 0, minMs: undefined };
5742
+ }
5743
+ _updateCamOutboundAnalytics() {
5744
+ const path = this._camOutboundPathRtt;
5745
+ const inflationSumMs = this._camOutboundRttInflation.sumMs + (path.minMs !== undefined ? path.sumMs - path.count * path.minMs : 0);
5746
+ const inflationCount = this._camOutboundRttInflation.count + path.count;
5747
+ this.analytics.camOutboundRttInflationMs = inflationCount
5748
+ ? Math.round(inflationSumMs / inflationCount)
5749
+ : undefined;
5750
+ const { congested, total } = this._camOutboundSamples;
5751
+ this.analytics.camOutboundCongestedFraction = total ? congested / total : undefined;
5752
+ }
5753
+ _startWebcamStatsSubscription() {
5754
+ if (this._statsSubscription)
5755
+ return;
5756
+ this._statsSubscription = subscribeStats({
5757
+ onUpdatedStats: (statsByView) => this._onUpdatedStats(statsByView),
5758
+ });
5759
+ }
5760
+ _stopWebcamStatsSubscription() {
5761
+ var _a;
5762
+ (_a = this._statsSubscription) === null || _a === void 0 ? void 0 : _a.stop();
5763
+ this._statsSubscription = null;
5764
+ this._lastSeenRemoteReportTimestamps.clear();
5765
+ this._finishCamOutboundRttPath();
5766
+ this._camOutboundCandidatePairId = undefined;
5767
+ this._camOutboundSamplesToSkip = 0;
5430
5768
  }
5431
5769
  close() {
5432
5770
  this.disconnectAll();
@@ -5457,8 +5795,11 @@ class VegaRtcManager {
5457
5795
  this._screenVideoTrack = null;
5458
5796
  this._screenAudioTrack = null;
5459
5797
  this._streamIdToVideoConsumerId.clear();
5798
+ this._streamIdToVideoResolution.clear();
5460
5799
  this._mediasoupDeviceInitializedAsync = Promise.resolve(null);
5461
5800
  this._qualityMonitor.close();
5801
+ this._stopWebcamStatsSubscription();
5802
+ this._preferredLayerSwitchWatches.forEach(({ stop }) => stop());
5462
5803
  }
5463
5804
  sendStatsCustomEvent(eventName, data) {
5464
5805
  rtcStats.sendEvent(eventName, data);
@@ -5516,6 +5857,8 @@ class VegaRtcManager {
5516
5857
  return this._onConsumerScore(data);
5517
5858
  case "producerScore":
5518
5859
  return this._onProducerScore(data);
5860
+ case "changedHighestPreferredLayer":
5861
+ return this._onChangedHighestPreferredLayer(data);
5519
5862
  default:
5520
5863
  logger$2.info(`unknown message method "${method}"`);
5521
5864
  return;
@@ -5543,13 +5886,16 @@ class VegaRtcManager {
5543
5886
  }
5544
5887
  consumer.pause();
5545
5888
  consumer.appData.localPaused = true;
5546
- consumer.appData.spatialLayer = 2;
5889
+ consumer.appData.spatialLayer = INITIAL_CONSUMER_SPATIAL_LAYER;
5547
5890
  this._consumers.set(consumer.id, consumer);
5548
5891
  this._qualityMonitor.addConsumer(consumer.appData.sourceClientId, consumer.id);
5549
5892
  consumer.observer.once("close", () => {
5550
5893
  this._consumers.delete(consumer.id);
5551
5894
  this._qualityMonitor.removeConsumer(consumer.appData.sourceClientId, consumer.id);
5552
5895
  this._consumerClosedCleanup(consumer);
5896
+ if (consumer.kind === "video" && this._receiveTransport && !this._receiveTransport.closed) {
5897
+ this._reapplyStreamResolutions();
5898
+ }
5553
5899
  });
5554
5900
  if (this._features.increaseIncomingMediaBufferOn && consumer.rtpReceiver) {
5555
5901
  try {
@@ -5581,13 +5927,12 @@ class VegaRtcManager {
5581
5927
  }
5582
5928
  stream.addTrack(consumer.track);
5583
5929
  this._syncIncomingStreamsWithPWA(clientId);
5584
- const resolution = this._streamIdToVideoResolution.get(stream.id);
5585
- if (resolution) {
5586
- this.updateStreamResolution(stream.id, null, resolution);
5587
- this._streamIdToVideoResolution.delete(stream.id);
5588
- }
5930
+ this._reapplyStreamResolutions();
5589
5931
  });
5590
5932
  }
5933
+ _reapplyStreamResolutions() {
5934
+ this._streamIdToVideoResolution.forEach((_resolution, streamId) => this._applyStreamResolution(streamId));
5935
+ }
5591
5936
  _onConsumerClosed(_a) {
5592
5937
  return __awaiter(this, arguments, void 0, function* ({ consumerId, reason }) {
5593
5938
  var _b;
@@ -5602,6 +5947,8 @@ class VegaRtcManager {
5602
5947
  return;
5603
5948
  consumer.appData.remotePaused = true;
5604
5949
  consumer.pause();
5950
+ if (consumer.kind === "video")
5951
+ this._reapplyStreamResolutions();
5605
5952
  }
5606
5953
  _onConsumerResumed({ consumerId }) {
5607
5954
  logger$2.info("_onConsumerResumed()", { consumerId });
@@ -5612,6 +5959,8 @@ class VegaRtcManager {
5612
5959
  if (!consumer.appData.localPaused) {
5613
5960
  consumer.resume();
5614
5961
  }
5962
+ if (consumer.kind === "video")
5963
+ this._reapplyStreamResolutions();
5615
5964
  }
5616
5965
  _onConsumerScore({ consumerId, kind, score }) {
5617
5966
  logger$2.info("_onConsumerScore()", { consumerId, kind, score });
@@ -5628,6 +5977,90 @@ class VegaRtcManager {
5628
5977
  }
5629
5978
  });
5630
5979
  }
5980
+ _getSvcEncodingUpdate(encoding, spatialLayer) {
5981
+ var _a;
5982
+ const reduced = getReducedSvcEncodingParams(this._webcamProducerOriginalSvcScalabilityMode, spatialLayer, this._webcamProducerOriginalSvcMaxBitrate);
5983
+ if (!reduced)
5984
+ return undefined;
5985
+ const changed = reduced.scalabilityMode !== encoding.scalabilityMode ||
5986
+ reduced.scaleResolutionDownBy !== ((_a = encoding.scaleResolutionDownBy) !== null && _a !== void 0 ? _a : 1) ||
5987
+ reduced.maxBitrate !== encoding.maxBitrate;
5988
+ return changed ? reduced : undefined;
5989
+ }
5990
+ _onChangedHighestPreferredLayer(_a) {
5991
+ return __awaiter(this, arguments, void 0, function* ({ producerId, spatialLayer }) {
5992
+ var _b;
5993
+ if (!this._features.sfuHighestPreferredLayerTrackingOn)
5994
+ return;
5995
+ if (((_b = this._webcamProducer) === null || _b === void 0 ? void 0 : _b.id) !== producerId)
5996
+ return;
5997
+ if (!Number.isFinite(spatialLayer)) {
5998
+ logger$2.warn("_onChangedHighestPreferredLayer() ignoring invalid spatialLayer", {
5999
+ producerId,
6000
+ spatialLayer,
6001
+ });
6002
+ return;
6003
+ }
6004
+ if (this._webcamProducerHighestPreferredLayer !== undefined &&
6005
+ this._webcamProducerHighestPreferredLayer !== spatialLayer) {
6006
+ this.analytics.numHighestPreferredLayerChanges++;
6007
+ this._incrementHistogramCount(this.analytics.highestPreferredLayerChangeCounts, `${this._webcamProducerHighestPreferredLayer}->${spatialLayer}`);
6008
+ }
6009
+ this._webcamProducerHighestPreferredLayer = spatialLayer;
6010
+ logger$2.info("_onChangedHighestPreferredLayer()", { producerId, spatialLayer });
6011
+ return this._syncWebcamEncoderToHighestPreferredLayer();
6012
+ });
6013
+ }
6014
+ _syncWebcamEncoderToHighestPreferredLayer() {
6015
+ this._highestPreferredLayerUpdatePending = true;
6016
+ if (!this._highestPreferredLayerUpdate) {
6017
+ this._highestPreferredLayerUpdate = this._applyPendingHighestPreferredLayerUpdates();
6018
+ }
6019
+ return this._highestPreferredLayerUpdate;
6020
+ }
6021
+ _applyPendingHighestPreferredLayerUpdates() {
6022
+ return __awaiter(this, void 0, void 0, function* () {
6023
+ while (this._highestPreferredLayerUpdatePending) {
6024
+ this._highestPreferredLayerUpdatePending = false;
6025
+ try {
6026
+ yield this._applyHighestPreferredLayerToWebcamEncoder();
6027
+ }
6028
+ catch (error) {
6029
+ logger$2.error("Failed to apply highest preferred layer: %o", error);
6030
+ }
6031
+ }
6032
+ this._highestPreferredLayerUpdate = null;
6033
+ });
6034
+ }
6035
+ _applyHighestPreferredLayerToWebcamEncoder() {
6036
+ return __awaiter(this, void 0, void 0, function* () {
6037
+ const producer = this._webcamProducer;
6038
+ const highestPreferredLayer = this._webcamProducerHighestPreferredLayer;
6039
+ if (!producer || highestPreferredLayer === undefined)
6040
+ return;
6041
+ const encodings = producer.rtpSender.getParameters().encodings;
6042
+ if (encodings.length > 1) {
6043
+ const cpuOveruseLimit = this._cpuOveruseDetected && encodings.length === 3 ? 1 : Infinity;
6044
+ const spatialLayer = Math.max(0, Math.min(highestPreferredLayer, cpuOveruseLimit, encodings.length - 1));
6045
+ if (producer.maxSpatialLayer === spatialLayer)
6046
+ return;
6047
+ yield producer.setMaxSpatialLayer(spatialLayer);
6048
+ const applied = producer.rtpSender
6049
+ .getParameters()
6050
+ .encodings.every((encoding, index) => encoding.active === index <= spatialLayer);
6051
+ if (!applied)
6052
+ logger$2.error("setMaxSpatialLayer(%d) was not applied to the encodings", spatialLayer);
6053
+ }
6054
+ else if (encodings.length === 1 && this._webcamProducerOriginalSvcScalabilityMode) {
6055
+ const update = this._getSvcEncodingUpdate(encodings[0], highestPreferredLayer);
6056
+ if (update)
6057
+ yield producer.setRtpEncodingParameters(update);
6058
+ }
6059
+ });
6060
+ }
6061
+ _incrementHistogramCount(histogram, key) {
6062
+ histogram[key] = (histogram[key] || 0) + 1;
6063
+ }
5631
6064
  _onDataConsumerReady(options) {
5632
6065
  return __awaiter(this, void 0, void 0, function* () {
5633
6066
  logger$2.info("_onDataConsumerReady()", { id: options.id, dataProducerId: options.dataProducerId });
@@ -5677,8 +6110,8 @@ class VegaRtcManager {
5677
6110
  stream.removeTrack(consumer.track);
5678
6111
  if (stream.getTracks().length === 0) {
5679
6112
  this._streamIdToVideoConsumerId.delete(stream.id);
5680
- this._streamIdToVideoResolution.delete(stream.id);
5681
6113
  if (screenShare) {
6114
+ this._streamIdToVideoResolution.delete(stream.id);
5682
6115
  clientState.screenStream = undefined;
5683
6116
  clientState.hasEmittedScreenStream = false;
5684
6117
  clientState.screenShareStreamId = undefined;
@@ -5724,6 +6157,8 @@ class VegaRtcManager {
5724
6157
  consumerIds: toResumeConsumers,
5725
6158
  });
5726
6159
  }
6160
+ if (toPauseConsumers.length > 0 || toResumeConsumers.length > 0)
6161
+ this._reapplyStreamResolutions();
5727
6162
  if (webcamStream && !hasEmittedWebcamStream && hasAcceptedWebcamStream) {
5728
6163
  this._emitToPWA(EVENTS.STREAM_ADDED, {
5729
6164
  clientId,
@@ -7496,14 +7931,24 @@ exports.ADDITIONAL_SCREEN_SHARE_SETTINGS = ADDITIONAL_SCREEN_SHARE_SETTINGS;
7496
7931
  exports.AUDIO_SETTINGS = AUDIO_SETTINGS;
7497
7932
  exports.BandwidthTester = BandwidthTester;
7498
7933
  exports.CAMERA_STREAM_ID = CAMERA_STREAM_ID;
7934
+ exports.CAM_SAMPLES_SKIPPED_AFTER_CANDIDATE_PAIR_CHANGE = CAM_SAMPLES_SKIPPED_AFTER_CANDIDATE_PAIR_CHANGE;
7935
+ exports.CONGESTED_FRACTION_LOST = CONGESTED_FRACTION_LOST;
7936
+ exports.CONGESTED_RTT_INFLATION_MS = CONGESTED_RTT_INFLATION_MS;
7499
7937
  exports.EVENTS = EVENTS;
7500
7938
  exports.FILE_SHARE_ERROR_CODES = FILE_SHARE_ERROR_CODES;
7939
+ exports.INITIAL_CONSUMER_SPATIAL_LAYER = INITIAL_CONSUMER_SPATIAL_LAYER;
7940
+ exports.INITIAL_HIGHEST_PREFERRED_LAYER = INITIAL_HIGHEST_PREFERRED_LAYER;
7501
7941
  exports.KNOCK_MESSAGES = KNOCK_MESSAGES;
7502
7942
  exports.KalmanFilter = KalmanFilter;
7943
+ exports.LOWEST_SVC_LAYER_MAX_BITRATE = LOWEST_SVC_LAYER_MAX_BITRATE;
7503
7944
  exports.Logger = Logger;
7945
+ exports.MAX_CONCURRENT_PREFERRED_LAYER_SWITCH_WATCHES = MAX_CONCURRENT_PREFERRED_LAYER_SWITCH_WATCHES;
7504
7946
  exports.MEDIA_JITTER_BUFFER_TARGET = MEDIA_JITTER_BUFFER_TARGET;
7947
+ exports.MIDDLE_SVC_LAYER_MAX_BITRATE = MIDDLE_SVC_LAYER_MAX_BITRATE;
7505
7948
  exports.NoDevicesError = NoDevicesError;
7506
7949
  exports.P2pRtcManager = P2pRtcManager;
7950
+ exports.PREFERRED_LAYER_SWITCH_POLL_INTERVAL_MS = PREFERRED_LAYER_SWITCH_POLL_INTERVAL_MS;
7951
+ exports.PREFERRED_LAYER_SWITCH_WATCH_TIMEOUT_MS = PREFERRED_LAYER_SWITCH_WATCH_TIMEOUT_MS;
7507
7952
  exports.PROTOCOL_ERRORS = PROTOCOL_ERRORS;
7508
7953
  exports.PROTOCOL_EVENTS = PROTOCOL_EVENTS;
7509
7954
  exports.PROTOCOL_REQUESTS = PROTOCOL_REQUESTS;
@@ -7560,6 +8005,7 @@ exports.getNumFailedStatsReports = getNumFailedStatsReports;
7560
8005
  exports.getNumFailedTrackSsrcLookups = getNumFailedTrackSsrcLookups;
7561
8006
  exports.getNumMissingTrackSsrcLookups = getNumMissingTrackSsrcLookups;
7562
8007
  exports.getPeerConnectionIndex = getPeerConnectionIndex;
8008
+ exports.getSelectedCandidatePairId = getSelectedCandidatePairId;
7563
8009
  exports.getStats = getStats;
7564
8010
  exports.getStream = getStream;
7565
8011
  exports.getUpdatedDevices = getUpdatedDevices;