@whereby.com/media 11.1.2 → 11.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -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",
@@ -825,6 +835,9 @@ const PROTOCOL_RESPONSES = {
825
835
  PLAY_CLIENT_STICKER: "play_client_sticker",
826
836
  ROOM_INTEGRATION_ENABLED: "room_integration_enabled",
827
837
  ROOM_INTEGRATION_DISABLED: "room_integration_disabled",
838
+ ROOM_INTEGRATION_STARTED: "room_integration_started",
839
+ ROOM_INTEGRATION_STOPPED: "room_integration_stopped",
840
+ ROOM_INTEGRATION_PROPS_UPDATED: "room_integration_props_updated",
828
841
  ROOM_JOINED: "room_joined",
829
842
  ROOM_KNOCKED: "room_knocked",
830
843
  ROOM_LEFT: "room_left",
@@ -1063,7 +1076,7 @@ const getMediasoupDeviceAsync = (features) => __awaiter(void 0, void 0, void 0,
1063
1076
  return new mediasoupClient.Device({ handlerName });
1064
1077
  });
1065
1078
 
1066
- const logger$9 = new Logger();
1079
+ const logger$a = new Logger();
1067
1080
  const AUDIO_SETTINGS = {
1068
1081
  codecOptions: {
1069
1082
  opusDtx: true,
@@ -1243,7 +1256,7 @@ function sortCodecsByPowerEfficiency(codecs) {
1243
1256
  codecPowerEfficiencyEntries = yield Promise.all(codecs.map(({ mimeType }) => getIsCodecDecodingPowerEfficient(mimeType).then((val) => [mimeType, val])));
1244
1257
  }
1245
1258
  catch (error) {
1246
- logger$9.error(error);
1259
+ logger$a.error(error);
1247
1260
  return codecs;
1248
1261
  }
1249
1262
  const codecPowerEfficiencies = Object.fromEntries(codecPowerEfficiencyEntries);
@@ -1312,7 +1325,24 @@ function captureSsrcInfo(ssrcMetrics, currentSsrcStats, prevSsrcStats, timeDiff,
1312
1325
  ssrcMetrics.mid = currentSsrcStats.mid;
1313
1326
  ssrcMetrics.rid = currentSsrcStats.rid;
1314
1327
  }
1328
+ const selectedCandidatePairIdByReport = new WeakMap();
1329
+ function getSelectedCandidatePairId(report, transportId) {
1330
+ var _a;
1331
+ const selectedCandidatePairId = transportId ? (_a = report.get(transportId)) === null || _a === void 0 ? void 0 : _a.selectedCandidatePairId : undefined;
1332
+ if (selectedCandidatePairId)
1333
+ return selectedCandidatePairId;
1334
+ if (!selectedCandidatePairIdByReport.has(report)) {
1335
+ let selectedId;
1336
+ report.forEach((stats) => {
1337
+ if (stats.type === "candidate-pair" && stats.selected)
1338
+ selectedId = stats.id;
1339
+ });
1340
+ selectedCandidatePairIdByReport.set(report, selectedId);
1341
+ }
1342
+ return selectedCandidatePairIdByReport.get(report);
1343
+ }
1315
1344
  function captureCommonSsrcMetrics(ssrcMetrics, currentSsrcStats, prevSsrcStats, timeDiff, report) {
1345
+ ssrcMetrics.selectedCandidatePairId = getSelectedCandidatePairId(report, currentSsrcStats.transportId);
1316
1346
  const nackCountDiff = (currentSsrcStats.nackCount || 0) - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.nackCount) || 0);
1317
1347
  ssrcMetrics.nackCount = (ssrcMetrics.nackCount || 0) + nackCountDiff;
1318
1348
  ssrcMetrics.nackRate = (1000 * nackCountDiff) / timeDiff;
@@ -1366,6 +1396,7 @@ function captureCommonSsrcMetrics(ssrcMetrics, currentSsrcStats, prevSsrcStats,
1366
1396
  ssrcMetrics.roundTripTime = remoteReport.roundTripTime || 0;
1367
1397
  ssrcMetrics.jitter = remoteReport.jitter || 0;
1368
1398
  ssrcMetrics.fractionLost = remoteReport.fractionLost || 0;
1399
+ ssrcMetrics.remoteReportTimestamp = remoteReport.timestamp;
1369
1400
  }
1370
1401
  }
1371
1402
  }
@@ -1597,7 +1628,6 @@ const DEFAULT_CLIENT = {
1597
1628
  };
1598
1629
  function collectStats(state_1, _a, immediate_1) {
1599
1630
  return __awaiter(this, arguments, void 0, function* (state, { logger, interval }, immediate) {
1600
- const collectStatsBound = collectStats.bind(null, state, { interval, logger });
1601
1631
  try {
1602
1632
  const clients = state.getClients();
1603
1633
  const defaultClient = clients.find((c) => c.isLocalClient && !c.isPresentation) || DEFAULT_CLIENT;
@@ -1612,7 +1642,6 @@ function collectStats(state_1, _a, immediate_1) {
1612
1642
  if (immediate)
1613
1643
  return state.statsByView;
1614
1644
  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
1645
  return;
1617
1646
  }
1618
1647
  state.lastUpdateTime = Date.now();
@@ -1735,11 +1764,10 @@ function collectStats(state_1, _a, immediate_1) {
1735
1764
  message: e === null || e === void 0 ? void 0 : e.message,
1736
1765
  });
1737
1766
  }
1738
- state.nextTimeout = setTimeout(collectStatsBound, interval);
1739
1767
  });
1740
1768
  }
1741
1769
 
1742
- const logger$8 = new Logger();
1770
+ const logger$9 = new Logger();
1743
1771
  const CPU_OBSERVER_OPTIONS = {
1744
1772
  sampleRate: 1,
1745
1773
  };
@@ -1749,7 +1777,7 @@ function startCpuObserver(cb, { sampleRate } = CPU_OBSERVER_OPTIONS, window = gl
1749
1777
  if ("PressureObserver" in window &&
1750
1778
  (window.PressureObserver.knownSources || []).includes("cpu")) {
1751
1779
  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));
1780
+ (_a = pressureObserver.observe("cpu", { sampleInterval: sampleRate * 1000 })) === null || _a === void 0 ? void 0 : _a.catch((error) => logger$9.error(error));
1753
1781
  return {
1754
1782
  stop: () => {
1755
1783
  pressureObserver.unobserve("cpu");
@@ -1785,7 +1813,20 @@ const updateRenderedDimensions = (trackId, data) => {
1785
1813
  STATE.renderedDimensionsByTrack[trackId] = data;
1786
1814
  };
1787
1815
  function startStatsMonitor(state, { interval, logger }) {
1788
- const collectStatsBound = collectStats.bind(null, state, { interval, logger });
1816
+ let stopped = false;
1817
+ let nextTimeout;
1818
+ const scheduleNextRun = () => {
1819
+ nextTimeout = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
1820
+ try {
1821
+ yield collectStats(state, { interval, logger }, false);
1822
+ }
1823
+ catch (error) {
1824
+ logger.error("Stats collection failed unexpectedly", error);
1825
+ }
1826
+ if (!stopped)
1827
+ scheduleNextRun();
1828
+ }), interval);
1829
+ };
1789
1830
  let cpuObserver;
1790
1831
  try {
1791
1832
  cpuObserver = startCpuObserver((records) => (state.lastPressureObserverRecord = records.pop()));
@@ -1793,13 +1834,14 @@ function startStatsMonitor(state, { interval, logger }) {
1793
1834
  catch (ex) {
1794
1835
  logger.warn("Failed to observe CPU pressure", ex);
1795
1836
  }
1796
- setTimeout(collectStatsBound, interval);
1837
+ scheduleNextRun();
1797
1838
  return {
1798
1839
  getUpdatedStats: () => {
1799
- return collectStatsBound(true);
1840
+ return collectStats(state, { interval, logger }, true);
1800
1841
  },
1801
1842
  stop: () => {
1802
- clearTimeout(state.nextTimeout);
1843
+ stopped = true;
1844
+ clearTimeout(nextTimeout);
1803
1845
  cpuObserver === null || cpuObserver === void 0 ? void 0 : cpuObserver.stop();
1804
1846
  },
1805
1847
  };
@@ -1820,7 +1862,7 @@ function subscribeStats(subscription, options = OPTIONS, state = STATE) {
1820
1862
  };
1821
1863
  }
1822
1864
 
1823
- const logger$7 = new Logger();
1865
+ const logger$8 = new Logger();
1824
1866
  class ReconnectManager extends EventEmitter {
1825
1867
  constructor(socket) {
1826
1868
  super();
@@ -1908,7 +1950,7 @@ class ReconnectManager extends EventEmitter {
1908
1950
  client.mergeWithOldClientState = true;
1909
1951
  }
1910
1952
  catch (error) {
1911
- logger$7.error("Failed to evaluate if we should merge client state %o", error);
1953
+ logger$8.error("Failed to evaluate if we should merge client state %o", error);
1912
1954
  this.metrics.evaluationFailed++;
1913
1955
  }
1914
1956
  });
@@ -1936,7 +1978,7 @@ class ReconnectManager extends EventEmitter {
1936
1978
  const { clientId } = payload;
1937
1979
  const client = this._clients[clientId];
1938
1980
  if (!client) {
1939
- logger$7.warn(`client ${clientId} not found`);
1981
+ logger$8.warn(`client ${clientId} not found`);
1940
1982
  return;
1941
1983
  }
1942
1984
  if (client.isPendingToLeave) {
@@ -2369,6 +2411,16 @@ const FILE_SHARE_ERROR_CODES = [
2369
2411
  function isFileShareError(payload) {
2370
2412
  return "error" in payload && FILE_SHARE_ERROR_CODES.includes(payload.error);
2371
2413
  }
2414
+ const ROOM_INTEGRATION_ERROR_CODES = [
2415
+ "not_in_a_room",
2416
+ "forbidden",
2417
+ "missing_parameters",
2418
+ "invalid_parameters",
2419
+ "internal_server_error",
2420
+ ];
2421
+ function isRoomIntegrationErrorCode(error) {
2422
+ return ROOM_INTEGRATION_ERROR_CODES.includes(error);
2423
+ }
2372
2424
 
2373
2425
  const defaultSubdomainPattern = /^(?:([^.]+)[.])?((:?[^.]+[.]){1,}[^.]+)$/;
2374
2426
  const localstackPattern = /^(?:([^.]+)-)?(ip-[^.]*[.](?:hereby[.]dev|rfc1918[.]disappear[.]at)(?::\d+|))$/;
@@ -2409,7 +2461,7 @@ fromLocation(typeof window !== "undefined" ? window.location : undefined);
2409
2461
 
2410
2462
  var _a$2, _b$1;
2411
2463
  const adapter$2 = (_a$2 = adapterRaw.default) !== null && _a$2 !== void 0 ? _a$2 : adapterRaw;
2412
- const logger$6 = new Logger();
2464
+ const logger$7 = new Logger();
2413
2465
  const ICE_PUBLIC_IP_GATHERING_TIMEOUT = 3 * 1000;
2414
2466
  const ICE_RESTART_DELAY = 2 * 1000;
2415
2467
  const browserName$1 = (_b$1 = adapter$2.browserDetails) === null || _b$1 === void 0 ? void 0 : _b$1.browser;
@@ -2490,7 +2542,7 @@ class P2pRtcManager {
2490
2542
  return this._selfId === selfId && this._roomName === roomName && !isSfu;
2491
2543
  }
2492
2544
  addCameraStream(stream, { beforeEffectTracks = [] } = { beforeEffectTracks: [] }) {
2493
- logger$6.info("addCameraStream: [stream.id: %s]", stream.id);
2545
+ logger$7.info("addCameraStream: [stream.id: %s]", stream.id);
2494
2546
  if (stream === this._localCameraStream) {
2495
2547
  return;
2496
2548
  }
@@ -2533,7 +2585,7 @@ class P2pRtcManager {
2533
2585
  };
2534
2586
  }
2535
2587
  addScreenshareStream(stream) {
2536
- logger$6.info("addScreenshareStream() [stream.id: %s]", stream.id);
2588
+ logger$7.info("addScreenshareStream() [stream.id: %s]", stream.id);
2537
2589
  if (stream === this._localScreenshareStream) {
2538
2590
  return;
2539
2591
  }
@@ -2546,7 +2598,7 @@ class P2pRtcManager {
2546
2598
  this._addStreamToPeerConnections(stream);
2547
2599
  }
2548
2600
  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);
2601
+ logger$7.info("replaceTrack() [kind: %s, oldTrackId: %s, newTrackId: %s]", newTrack.kind, oldTrack === null || oldTrack === void 0 ? void 0 : oldTrack.id, newTrack.id);
2550
2602
  if (newTrack.kind === "audio" && !trackAnnotations(newTrack).isEffectTrack) {
2551
2603
  this._monitorAudioTrack(newTrack);
2552
2604
  }
@@ -2560,7 +2612,7 @@ class P2pRtcManager {
2560
2612
  this.disconnectAll();
2561
2613
  }
2562
2614
  disconnectAll() {
2563
- logger$6.info("disconnectAll()");
2615
+ logger$7.info("disconnectAll()");
2564
2616
  Object.keys(this.peerConnections).forEach((clientId) => {
2565
2617
  this.disconnect(clientId);
2566
2618
  });
@@ -2580,39 +2632,39 @@ class P2pRtcManager {
2580
2632
  () => this._clearMediaServersRefresh(),
2581
2633
  this._serverSocket.on(PROTOCOL_RESPONSES.MEDIASERVER_CONFIG, (data) => {
2582
2634
  if (data.error) {
2583
- logger$6.warn("FETCH_MEDIASERVER_CONFIG failed:", data.error);
2635
+ logger$7.warn("FETCH_MEDIASERVER_CONFIG failed:", data.error);
2584
2636
  return;
2585
2637
  }
2586
2638
  this._updateAndScheduleMediaServersRefresh(data);
2587
2639
  }),
2588
2640
  this._serverSocket.on(RELAY_MESSAGES.READY_TO_RECEIVE_OFFER, (data) => {
2589
- logger$6.info(`Got ready_to_receive_offer from client ${data.clientId}`);
2641
+ logger$7.info(`Got ready_to_receive_offer from client ${data.clientId}`);
2590
2642
  this._connect(data.clientId);
2591
2643
  }),
2592
2644
  this._serverSocket.on(RELAY_MESSAGES.ICE_CANDIDATE, (data) => {
2593
- logger$6.info(`Got ice_candidate from client ${data.clientId}`);
2645
+ logger$7.info(`Got ice_candidate from client ${data.clientId}`);
2594
2646
  const session = this._getSession(data.clientId);
2595
2647
  if (!session) {
2596
- logger$6.warn("No RTCPeerConnection on ICE_CANDIDATE", data);
2648
+ logger$7.warn("No RTCPeerConnection on ICE_CANDIDATE", data);
2597
2649
  return;
2598
2650
  }
2599
2651
  session.addIceCandidate(data.message);
2600
2652
  }),
2601
2653
  this._serverSocket.on(RELAY_MESSAGES.ICE_END_OF_CANDIDATES, (data) => {
2602
- logger$6.info(`Got end_of_ice_candidates from client ${data.clientId}`);
2654
+ logger$7.info(`Got end_of_ice_candidates from client ${data.clientId}`);
2603
2655
  const session = this._getSession(data.clientId);
2604
2656
  if (!session) {
2605
- logger$6.warn("No RTCPeerConnection on ICE_END_OF_CANDIDATES", data);
2657
+ logger$7.warn("No RTCPeerConnection on ICE_END_OF_CANDIDATES", data);
2606
2658
  return;
2607
2659
  }
2608
2660
  session.addIceCandidate(null);
2609
2661
  }),
2610
2662
  this._serverSocket.on(RELAY_MESSAGES.SDP_OFFER, (data) => {
2611
2663
  var _a, _b;
2612
- logger$6.info(`Got offer from client ${data.clientId}, isInitialOffer: ${Boolean(data.message.isInitialOffer)}`);
2664
+ logger$7.info(`Got offer from client ${data.clientId}, isInitialOffer: ${Boolean(data.message.isInitialOffer)}`);
2613
2665
  const session = this._getSession(data.clientId);
2614
2666
  if (!session) {
2615
- logger$6.warn("No RTCPeerConnection on SDP_OFFER", data);
2667
+ logger$7.warn("No RTCPeerConnection on SDP_OFFER", data);
2616
2668
  return;
2617
2669
  }
2618
2670
  const sdp = {
@@ -2624,7 +2676,7 @@ class P2pRtcManager {
2624
2676
  session.pc.connectionState === "new" &&
2625
2677
  session.pc.iceConnectionState === "new" &&
2626
2678
  !session.connectionStatus) {
2627
- logger$6.info("We have asked for an initial offer, ignoring all others");
2679
+ logger$7.info("We have asked for an initial offer, ignoring all others");
2628
2680
  this.analytics.P2POffendingInitialOffer++;
2629
2681
  rtcStats.sendEvent("P2POffendingInitialOffer", { clientId: session.clientId });
2630
2682
  return;
@@ -2632,22 +2684,22 @@ class P2pRtcManager {
2632
2684
  (_b = (_a = session
2633
2685
  .handleOffer(sdp)
2634
2686
  .then((answer) => {
2635
- logger$6.info(`Sending answer to client ${data.clientId}`);
2687
+ logger$7.info(`Sending answer to client ${data.clientId}`);
2636
2688
  this._emitServerEvent(RELAY_MESSAGES.SDP_ANSWER, {
2637
2689
  receiverId: data.clientId,
2638
2690
  message: answer,
2639
2691
  });
2640
2692
  })).catch) === null || _b === void 0 ? void 0 : _b.call(_a, (e) => {
2641
- logger$6.error(e);
2693
+ logger$7.error(e);
2642
2694
  this.analytics.numPcOnOfferFailure++;
2643
2695
  });
2644
2696
  }),
2645
2697
  this._serverSocket.on(RELAY_MESSAGES.SDP_ANSWER, (data) => {
2646
2698
  var _a, _b;
2647
- logger$6.info(`Got answer from client ${data.clientId}`);
2699
+ logger$7.info(`Got answer from client ${data.clientId}`);
2648
2700
  const session = this._getSession(data.clientId);
2649
2701
  if (!session) {
2650
- logger$6.warn("No RTCPeerConnection on SDP_ANSWER", data);
2702
+ logger$7.warn("No RTCPeerConnection on SDP_ANSWER", data);
2651
2703
  return;
2652
2704
  }
2653
2705
  const sdp = {
@@ -2655,7 +2707,7 @@ class P2pRtcManager {
2655
2707
  type: data.message.type,
2656
2708
  };
2657
2709
  (_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);
2710
+ logger$7.warn("Could not set remote description from remote answer: ", e);
2659
2711
  this.analytics.numPcOnAnswerFailure++;
2660
2712
  });
2661
2713
  }),
@@ -2743,12 +2795,12 @@ class P2pRtcManager {
2743
2795
  });
2744
2796
  }
2745
2797
  catch (error) {
2746
- logger$6.error("Error during setting jitter buffer target:", error);
2798
+ logger$7.error("Error during setting jitter buffer target:", error);
2747
2799
  }
2748
2800
  }
2749
2801
  _emitServerEvent(eventName, data) {
2750
2802
  if (this._closed) {
2751
- logger$6.warn("RtcManager closed. Will not send event", eventName, data);
2803
+ logger$7.warn("RtcManager closed. Will not send event", eventName, data);
2752
2804
  return;
2753
2805
  }
2754
2806
  if (this._features.awaitJoinRoomFinished && !this._serverSocket.joinRoomFinished) {
@@ -2853,7 +2905,7 @@ class P2pRtcManager {
2853
2905
  }
2854
2906
  }
2855
2907
  catch (error) {
2856
- logger$6.info("Error during parsing candidates! Error: ", { error });
2908
+ logger$7.info("Error during parsing candidates! Error: ", { error });
2857
2909
  }
2858
2910
  break;
2859
2911
  case "srflx":
@@ -2895,7 +2947,7 @@ class P2pRtcManager {
2895
2947
  if (pc.iceConnectionState === "new" || !session.connectionStatus) {
2896
2948
  return;
2897
2949
  }
2898
- logger$6.info(`onnegotiationneeded client ${clientId}`);
2950
+ logger$7.info(`onnegotiationneeded client ${clientId}`);
2899
2951
  this._negotiatePeerConnection({ clientId, session });
2900
2952
  };
2901
2953
  pc.ontrack = (event) => {
@@ -2920,7 +2972,7 @@ class P2pRtcManager {
2920
2972
  };
2921
2973
  pc.oniceconnectionstatechange = () => {
2922
2974
  var _a;
2923
- logger$6.info(`iceConnectionState changed to ${pc.iceConnectionState} for session ${session.clientId}`);
2975
+ logger$7.info(`iceConnectionState changed to ${pc.iceConnectionState} for session ${session.clientId}`);
2924
2976
  let newStatus;
2925
2977
  const currentStatus = session.connectionStatus;
2926
2978
  switch (pc.iceConnectionState) {
@@ -2975,7 +3027,7 @@ class P2pRtcManager {
2975
3027
  };
2976
3028
  pc.onconnectionstatechange = () => {
2977
3029
  var _a;
2978
- logger$6.info(`connectionState changed to ${pc.connectionState} for session ${session.clientId}`);
3030
+ logger$7.info(`connectionState changed to ${pc.connectionState} for session ${session.clientId}`);
2979
3031
  switch (pc.connectionState) {
2980
3032
  case "connected":
2981
3033
  (_a = session.registerConnected) === null || _a === void 0 ? void 0 : _a.call(session, {});
@@ -3032,7 +3084,7 @@ class P2pRtcManager {
3032
3084
  _cleanup(clientId) {
3033
3085
  const session = this._getSession(clientId);
3034
3086
  if (!session) {
3035
- logger$6.warn("No RTCPeerConnection in RTCManager.disconnect()", clientId);
3087
+ logger$7.warn("No RTCPeerConnection in RTCManager.disconnect()", clientId);
3036
3088
  return;
3037
3089
  }
3038
3090
  this.removeRemoteClientMediaPrefs(session.clientId);
@@ -3060,7 +3112,7 @@ class P2pRtcManager {
3060
3112
  if (!session.hasConnectedPeerConnection()) {
3061
3113
  if (session.pc.connectionState === "closed")
3062
3114
  return;
3063
- logger$6.info("Session doesn't have a connected PeerConnection, adding pending action!");
3115
+ logger$7.info("Session doesn't have a connected PeerConnection, adding pending action!");
3064
3116
  const promise = new Promise((resolve, reject) => {
3065
3117
  const action = () => __awaiter(this, void 0, void 0, function* () {
3066
3118
  try {
@@ -3079,7 +3131,7 @@ class P2pRtcManager {
3079
3131
  promises.push(session.replaceTrack(oldTrack, newTrack));
3080
3132
  });
3081
3133
  return Promise.all(promises).catch((error) => {
3082
- logger$6.error(String(error));
3134
+ logger$7.error(String(error));
3083
3135
  });
3084
3136
  }
3085
3137
  _removeStreamFromPeerConnections(stream) {
@@ -3127,7 +3179,7 @@ class P2pRtcManager {
3127
3179
  let session = this._getSession(clientId);
3128
3180
  let initialBandwidth = (session && session.bandwidth) || 0;
3129
3181
  if (session) {
3130
- logger$6.warn("Replacing peer session", clientId);
3182
+ logger$7.warn("Replacing peer session", clientId);
3131
3183
  this._cleanup(clientId);
3132
3184
  }
3133
3185
  else {
@@ -3198,13 +3250,13 @@ class P2pRtcManager {
3198
3250
  })));
3199
3251
  }
3200
3252
  catch (error) {
3201
- logger$6.error("Error during setting setCodecPreferences:", error);
3253
+ logger$7.error("Error during setting setCodecPreferences:", error);
3202
3254
  }
3203
3255
  });
3204
3256
  }
3205
3257
  _negotiatePeerConnection({ clientId, session, constraints, isInitialOffer = false, }) {
3206
3258
  if (!session) {
3207
- logger$6.warn("No RTCPeerConnection in negotiatePeerConnection()", clientId);
3259
+ logger$7.warn("No RTCPeerConnection in negotiatePeerConnection()", clientId);
3208
3260
  return;
3209
3261
  }
3210
3262
  const pc = session.pc;
@@ -3234,7 +3286,7 @@ class P2pRtcManager {
3234
3286
  offer.sdp = cleanSdp(offer.sdp);
3235
3287
  pc.setLocalDescription(offer)
3236
3288
  .catch((e) => {
3237
- logger$6.warn("RTCPeerConnection.setLocalDescription() failed with local offer", e);
3289
+ logger$7.warn("RTCPeerConnection.setLocalDescription() failed with local offer", e);
3238
3290
  this.analytics.numPcSldFailure++;
3239
3291
  throw e;
3240
3292
  })
@@ -3246,7 +3298,7 @@ class P2pRtcManager {
3246
3298
  type: offer.type,
3247
3299
  isInitialOffer,
3248
3300
  };
3249
- logger$6.info(`sending offer to client ${clientId}`);
3301
+ logger$7.info(`sending offer to client ${clientId}`);
3250
3302
  this._emitServerEvent(RELAY_MESSAGES.SDP_OFFER, {
3251
3303
  receiverId: clientId,
3252
3304
  message,
@@ -3254,7 +3306,7 @@ class P2pRtcManager {
3254
3306
  });
3255
3307
  })
3256
3308
  .catch((e) => {
3257
- logger$6.warn("RTCPeerConnection.createOffer() failed to create local offer", e);
3309
+ logger$7.warn("RTCPeerConnection.createOffer() failed to create local offer", e);
3258
3310
  }));
3259
3311
  }
3260
3312
  _withForcedRenegotiation(session, action) {
@@ -3296,7 +3348,7 @@ class P2pRtcManager {
3296
3348
  return bandwidth;
3297
3349
  }
3298
3350
  acceptNewStream({ streamId, clientId }) {
3299
- logger$6.info("acceptNewStream() [streamId: %s}, clientId: %s]", streamId, clientId);
3351
+ logger$7.info("acceptNewStream() [streamId: %s}, clientId: %s]", streamId, clientId);
3300
3352
  let session = this._getSession(clientId);
3301
3353
  if (session && streamId !== clientId) {
3302
3354
  return session;
@@ -3319,7 +3371,7 @@ class P2pRtcManager {
3319
3371
  return session;
3320
3372
  }
3321
3373
  disconnect(clientId) {
3322
- logger$6.info("disconnect() [clientId: %s]", clientId);
3374
+ logger$7.info("disconnect() [clientId: %s]", clientId);
3323
3375
  this._cleanup(clientId);
3324
3376
  this._changeBandwidthForAllClients(false);
3325
3377
  const numPeers = this.numberOfPeerconnections();
@@ -3356,7 +3408,7 @@ class P2pRtcManager {
3356
3408
  stopOrResumeVideo() {
3357
3409
  }
3358
3410
  removeScreenshareStream(stream, { requestedByClientId } = {}) {
3359
- logger$6.info("removeScreenshareStream() [stream.id: %s, requestedByClientId: %s]", stream.id, requestedByClientId);
3411
+ logger$7.info("removeScreenshareStream() [stream.id: %s, requestedByClientId: %s]", stream.id, requestedByClientId);
3360
3412
  this._removeStreamFromPeerConnections(stream);
3361
3413
  this._emitServerEvent(PROTOCOL_REQUESTS.STOP_SCREENSHARE, { streamId: stream.id, requestedByClientId });
3362
3414
  delete this._localScreenshareStream;
@@ -3477,7 +3529,7 @@ const defaultParams = {
3477
3529
  scoreFormula: "300 * bands[1].avg / Math.max(bands[1].avg + bands[0].avg, 0.01)",
3478
3530
  outFormula: "score",
3479
3531
  };
3480
- const logger$5 = new Logger();
3532
+ const logger$6 = new Logger();
3481
3533
  function createMicAnalyser({ micTrack, params, onScoreUpdated, }) {
3482
3534
  const audioCtx = new AudioContext();
3483
3535
  let analyser = null;
@@ -3499,7 +3551,7 @@ function createMicAnalyser({ micTrack, params, onScoreUpdated, }) {
3499
3551
  lastTrackWasOurs = true;
3500
3552
  }
3501
3553
  catch (ex) {
3502
- logger$5.warn("unable to fetch new track for colocation speaker analysis, using current", ex);
3554
+ logger$6.warn("unable to fetch new track for colocation speaker analysis, using current", ex);
3503
3555
  }
3504
3556
  }
3505
3557
  lastTrack = track;
@@ -3586,7 +3638,7 @@ function createMicAnalyser({ micTrack, params, onScoreUpdated, }) {
3586
3638
  };
3587
3639
  }
3588
3640
 
3589
- const logger$4 = new Logger();
3641
+ const logger$5 = new Logger();
3590
3642
  const MEDIA_QUALITY = Object.freeze({
3591
3643
  ok: "ok",
3592
3644
  warning: "warning",
@@ -3656,7 +3708,7 @@ class VegaMediaQualityMonitor extends EventEmitter {
3656
3708
  }
3657
3709
  addProducer(clientId, producerId) {
3658
3710
  if (!clientId || !producerId || !(typeof clientId === "string" && typeof producerId === "string")) {
3659
- logger$4.warn("Missing clientId or producerId");
3711
+ logger$5.warn("Missing clientId or producerId");
3660
3712
  return;
3661
3713
  }
3662
3714
  if (!this._producers[clientId]) {
@@ -3672,7 +3724,7 @@ class VegaMediaQualityMonitor extends EventEmitter {
3672
3724
  }
3673
3725
  addConsumer(clientId, consumerId) {
3674
3726
  if (!clientId || !consumerId) {
3675
- logger$4.warn("Missing clientId or consumerId");
3727
+ logger$5.warn("Missing clientId or consumerId");
3676
3728
  return;
3677
3729
  }
3678
3730
  if (!this._producers[clientId]) {
@@ -3690,14 +3742,14 @@ class VegaMediaQualityMonitor extends EventEmitter {
3690
3742
  if (!Array.isArray(score) ||
3691
3743
  score.length === 0 ||
3692
3744
  score.some((s) => !s || !s.hasOwnProperty("score") || typeof s.score !== "number" || isNaN(s.score))) {
3693
- logger$4.warn("Unexpected producer score format");
3745
+ logger$5.warn("Unexpected producer score format");
3694
3746
  return;
3695
3747
  }
3696
3748
  this._producers[clientId][producerId] = { kind, score: this._calcAvgProducerScore(score.map((s) => s.score)) };
3697
3749
  }
3698
3750
  addConsumerScore(clientId, consumerId, kind, score) {
3699
3751
  if (!score || !score.hasOwnProperty("producerScores") || !Array.isArray(score.producerScores)) {
3700
- logger$4.warn("Unexpected consumer score format");
3752
+ logger$5.warn("Unexpected consumer score format");
3701
3753
  return;
3702
3754
  }
3703
3755
  this._producers[clientId][consumerId] = { kind, score: this._calcAvgProducerScore(score.producerScores) };
@@ -3734,12 +3786,13 @@ class VegaMediaQualityMonitor extends EventEmitter {
3734
3786
  }
3735
3787
  }
3736
3788
  catch (error) {
3737
- logger$4.error(error);
3789
+ logger$5.error(error);
3738
3790
  return 0;
3739
3791
  }
3740
3792
  }
3741
3793
  }
3742
3794
 
3795
+ const logger$4 = new Logger();
3743
3796
  function getLayers({ width, height, }, { numberOfActiveVideos, numberOfTemporalLayers, uncappedSingleRemoteVideoOn, }) {
3744
3797
  const maxSide = Math.max(width, height);
3745
3798
  let spatialLayer = maxSide >= 480 ? (maxSide >= 960 ? 2 : 1) : 0;
@@ -3759,6 +3812,27 @@ function getLayers({ width, height, }, { numberOfActiveVideos, numberOfTemporalL
3759
3812
  }
3760
3813
  return { spatialLayer, temporalLayer };
3761
3814
  }
3815
+ function createMetricStats() {
3816
+ return { count: 0, sum: 0 };
3817
+ }
3818
+ function recordMetricSample(stats, value) {
3819
+ stats.count++;
3820
+ stats.sum += value;
3821
+ }
3822
+ function aggregateMetricStats(stats) {
3823
+ return {
3824
+ count: stats.count,
3825
+ avg: stats.count ? Math.round(stats.sum / stats.count) : undefined,
3826
+ };
3827
+ }
3828
+ function getPacketWeightedFractionLost(reports) {
3829
+ const weights = reports.map(({ packetRate }) => (packetRate && packetRate > 0 ? packetRate : 0));
3830
+ const totalWeight = weights.reduce((sum, weight) => sum + weight, 0);
3831
+ if (!totalWeight) {
3832
+ return reports.reduce((sum, { fractionLost }) => sum + (fractionLost || 0), 0) / (reports.length || 1);
3833
+ }
3834
+ return (reports.reduce((sum, { fractionLost }, index) => sum + (fractionLost || 0) * weights[index], 0) / totalWeight);
3835
+ }
3762
3836
  function getNumberOfActiveVideos(consumers) {
3763
3837
  let numberOfActiveVideos = 0;
3764
3838
  consumers.forEach((c) => {
@@ -3774,6 +3848,51 @@ function getNumberOfTemporalLayers(consumer) {
3774
3848
  var _a, _b, _c;
3775
3849
  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
3850
  }
3851
+ const SCALABILITY_MODE_REGEX = /^([LS])([1-9]\d?)T([1-9]\d?)(_KEY)?$/;
3852
+ function getTopSpatialLayer(encodings) {
3853
+ if (encodings.length > 1)
3854
+ return encodings.length - 1;
3855
+ const { scalabilityMode } = encodings[0];
3856
+ const match = SCALABILITY_MODE_REGEX.exec(scalabilityMode || "");
3857
+ if (!match) {
3858
+ if (scalabilityMode) {
3859
+ logger$4.warn("getTopSpatialLayer() unrecognized scalabilityMode %s, using a single spatial layer", scalabilityMode);
3860
+ }
3861
+ return 0;
3862
+ }
3863
+ const spatialLayers = Number(match[2]) || 1;
3864
+ return spatialLayers - 1;
3865
+ }
3866
+ function getInitialHighestPreferredLayer(encodings) {
3867
+ return Math.min(getTopSpatialLayer(encodings), INITIAL_HIGHEST_PREFERRED_LAYER);
3868
+ }
3869
+ function getReducedSvcEncodingParams(originalScalabilityMode, spatialLayer, originalMaxBitrate) {
3870
+ const match = SCALABILITY_MODE_REGEX.exec(originalScalabilityMode || "");
3871
+ if (!match)
3872
+ return undefined;
3873
+ const [, mode, originalSpatialLayers, temporalLayers, key = ""] = match;
3874
+ const topLayerIndex = Number(originalSpatialLayers) - 1;
3875
+ if (topLayerIndex === 0)
3876
+ return undefined;
3877
+ const preferredLayerIndex = Math.min(Math.max(spatialLayer, 0), topLayerIndex);
3878
+ const onlyLowestLayerPreferred = preferredLayerIndex === 0;
3879
+ const middleLayerPreferred = preferredLayerIndex > 0 && preferredLayerIndex < topLayerIndex;
3880
+ let maxBitrate = originalMaxBitrate;
3881
+ if (onlyLowestLayerPreferred) {
3882
+ maxBitrate = Math.min(LOWEST_SVC_LAYER_MAX_BITRATE, originalMaxBitrate !== null && originalMaxBitrate !== void 0 ? originalMaxBitrate : Infinity);
3883
+ }
3884
+ else if (middleLayerPreferred) {
3885
+ maxBitrate = Math.min(MIDDLE_SVC_LAYER_MAX_BITRATE, originalMaxBitrate !== null && originalMaxBitrate !== void 0 ? originalMaxBitrate : Infinity);
3886
+ }
3887
+ const scalabilityMode = onlyLowestLayerPreferred
3888
+ ? `L1T${temporalLayers}`
3889
+ : `${mode}${preferredLayerIndex + 1}T${temporalLayers}${key}`;
3890
+ return {
3891
+ scalabilityMode,
3892
+ scaleResolutionDownBy: Math.pow(2, (topLayerIndex - preferredLayerIndex)),
3893
+ maxBitrate,
3894
+ };
3895
+ }
3777
3896
  function addProducerCpuOveruseWatch({ producer, onOveruse }) {
3778
3897
  var _a;
3779
3898
  const encodings = (_a = producer.rtpParameters) === null || _a === void 0 ? void 0 : _a.encodings;
@@ -4230,6 +4349,7 @@ const RESTARTICE_ERROR_RETRY_THRESHOLD_IN_MS = 3500;
4230
4349
  const RESTARTICE_ERROR_MAX_RETRY_COUNT = 5;
4231
4350
  const OUTBOUND_CAM_OUTBOUND_STREAM_ID = uuid.v4();
4232
4351
  const OUTBOUND_SCREEN_OUTBOUND_STREAM_ID = uuid.v4();
4352
+ 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
4353
  if (browserName === "chrome")
4234
4354
  window.document.addEventListener("beforeunload", () => (unloading = true));
4235
4355
  class VegaRtcManager {
@@ -4267,6 +4387,11 @@ class VegaRtcManager {
4267
4387
  this._micScoreProducer = null;
4268
4388
  this._micScoreProducerPromise = null;
4269
4389
  this._webcamProducer = null;
4390
+ this._webcamProducerOriginalSvcScalabilityMode = undefined;
4391
+ this._webcamProducerOriginalSvcMaxBitrate = undefined;
4392
+ this._webcamProducerHighestPreferredLayer = undefined;
4393
+ this._highestPreferredLayerUpdate = null;
4394
+ this._highestPreferredLayerUpdatePending = false;
4270
4395
  this._webcamProducerPromise = null;
4271
4396
  this._webcamPaused = false;
4272
4397
  this._screenVideoProducer = null;
@@ -4308,12 +4433,19 @@ class VegaRtcManager {
4308
4433
  };
4309
4434
  (_a = window === null || window === void 0 ? void 0 : window.addEventListener) === null || _a === void 0 ? void 0 : _a.call(window, "offline", this._sfuZombie.onBrowserOffline);
4310
4435
  this.analytics = {
4436
+ avgPreferredLayerSwitchLatencyMs: undefined,
4437
+ camOutboundCongestedFraction: undefined,
4438
+ camOutboundRttInflationMs: undefined,
4311
4439
  camTrackEndedCount: 0,
4440
+ highestPreferredLayerChangeCounts: {},
4312
4441
  micTrackEndedCount: 0,
4442
+ numHighestPreferredLayerChanges: 0,
4313
4443
  numIceConnected: 0,
4314
4444
  numIceDisconnected: 0,
4315
4445
  numIceFailed: 0,
4316
4446
  numNewPc: 0,
4447
+ numPreferredSpatialLayerChanges: 0,
4448
+ preferredSpatialLayerChangeCounts: {},
4317
4449
  sfuMsFromOfflineToClose: 0,
4318
4450
  sfuOfflineToCloseCount: 0,
4319
4451
  sfuOfflineWhileConnectedCount: 0,
@@ -4333,6 +4465,15 @@ class VegaRtcManager {
4333
4465
  vegaUnknownResponse: 0,
4334
4466
  vegaWebcamProducerFailed: 0,
4335
4467
  };
4468
+ this._preferredLayerSwitchLatencyStats = createMetricStats();
4469
+ this._preferredLayerSwitchWatches = new Map();
4470
+ this._lastSeenRemoteReportTimestamps = new Map();
4471
+ this._camOutboundCandidatePairId = undefined;
4472
+ this._camOutboundSamplesToSkip = 0;
4473
+ this._camOutboundPathRtt = { sumMs: 0, count: 0, minMs: undefined };
4474
+ this._camOutboundRttInflation = { sumMs: 0, count: 0 };
4475
+ this._camOutboundSamples = { total: 0, congested: 0 };
4476
+ this._statsSubscription = null;
4336
4477
  }
4337
4478
  _updateAndScheduleMediaServersRefresh({ iceServers, turnServers, sfuServer, mediaserverConfigTtlSeconds, }) {
4338
4479
  var _a, _b, _c, _d;
@@ -4502,7 +4643,6 @@ class VegaRtcManager {
4502
4643
  this._sendTransport = null;
4503
4644
  this._receiveTransport = null;
4504
4645
  this._streamIdToVideoConsumerId.clear();
4505
- this._streamIdToVideoResolution.clear();
4506
4646
  if (this._reconnect) {
4507
4647
  this._reconnectTimeOut = setTimeout(() => this._connect(), 1000);
4508
4648
  }
@@ -4925,6 +5065,14 @@ class VegaRtcManager {
4925
5065
  const simulcastLayer3ShouldBeActive = !this._cpuOveruseDetected;
4926
5066
  const params = this._webcamProducer.rtpParameters;
4927
5067
  if (((_a = params === null || params === void 0 ? void 0 : params.encodings) === null || _a === void 0 ? void 0 : _a.length) === 3) {
5068
+ if (this._features.sfuHighestPreferredLayerTrackingOn) {
5069
+ this._syncWebcamEncoderToHighestPreferredLayer();
5070
+ rtcStats.sendEvent("simulcast_layer_activation_changed", {
5071
+ layerIndex: 2,
5072
+ active: simulcastLayer3ShouldBeActive,
5073
+ });
5074
+ return;
5075
+ }
4928
5076
  const targetMaxSpatialLayer = simulcastLayer3ShouldBeActive ? 2 : 1;
4929
5077
  if (this._webcamProducer.maxSpatialLayer !== targetMaxSpatialLayer) {
4930
5078
  this._webcamProducer.setMaxSpatialLayer(targetMaxSpatialLayer);
@@ -4947,7 +5095,7 @@ class VegaRtcManager {
4947
5095
  return;
4948
5096
  }
4949
5097
  this._webcamProducerPromise = (() => __awaiter(this, void 0, void 0, function* () {
4950
- var _a;
5098
+ var _a, _b, _c;
4951
5099
  try {
4952
5100
  const currentPaused = this._webcamPaused;
4953
5101
  if (!this._sendTransport) {
@@ -4973,6 +5121,16 @@ class VegaRtcManager {
4973
5121
  })
4974
5122
  : () => { };
4975
5123
  this._webcamProducer = producer;
5124
+ if (this._features.sfuHighestPreferredLayerTrackingOn) {
5125
+ const originalWebcamEncodings = (_b = (_a = producer.rtpSender) === null || _a === void 0 ? void 0 : _a.getParameters()) === null || _b === void 0 ? void 0 : _b.encodings;
5126
+ const svcEncoding = (originalWebcamEncodings === null || originalWebcamEncodings === void 0 ? void 0 : originalWebcamEncodings.length) === 1 ? originalWebcamEncodings[0] : undefined;
5127
+ this._webcamProducerOriginalSvcScalabilityMode = svcEncoding === null || svcEncoding === void 0 ? void 0 : svcEncoding.scalabilityMode;
5128
+ this._webcamProducerOriginalSvcMaxBitrate = svcEncoding === null || svcEncoding === void 0 ? void 0 : svcEncoding.maxBitrate;
5129
+ this._webcamProducerHighestPreferredLayer = (originalWebcamEncodings === null || originalWebcamEncodings === void 0 ? void 0 : originalWebcamEncodings.length)
5130
+ ? getInitialHighestPreferredLayer(originalWebcamEncodings)
5131
+ : undefined;
5132
+ this._syncWebcamEncoderToHighestPreferredLayer();
5133
+ }
4976
5134
  this._qualityMonitor.addProducer(this._selfId, producer.id);
4977
5135
  producer.observer.once("close", () => {
4978
5136
  var _a;
@@ -4980,11 +5138,16 @@ class VegaRtcManager {
4980
5138
  if (producer.appData.localClosed)
4981
5139
  (_a = this._vegaConnection) === null || _a === void 0 ? void 0 : _a.message("closeProducers", { producerIds: [producer.id] });
4982
5140
  cleanUpCpuWatch();
5141
+ this._stopWebcamStatsSubscription();
4983
5142
  this._webcamProducer = null;
5143
+ this._webcamProducerOriginalSvcScalabilityMode = undefined;
5144
+ this._webcamProducerOriginalSvcMaxBitrate = undefined;
5145
+ this._webcamProducerHighestPreferredLayer = undefined;
4984
5146
  this._webcamProducerPromise = null;
4985
5147
  this._qualityMonitor.removeProducer(this._selfId, producer.id);
4986
5148
  });
4987
- if (this._webcamTrack && this._webcamTrack !== ((_a = this._webcamProducer) === null || _a === void 0 ? void 0 : _a.track)) {
5149
+ this._startWebcamStatsSubscription();
5150
+ if (this._webcamTrack && this._webcamTrack !== ((_c = this._webcamProducer) === null || _c === void 0 ? void 0 : _c.track)) {
4988
5151
  this._webcamProducerPromise = null;
4989
5152
  this._replaceWebcamTrack();
4990
5153
  }
@@ -5001,6 +5164,9 @@ class VegaRtcManager {
5001
5164
  if (!this._webcamTrack) {
5002
5165
  this._stopProducer(this._webcamProducer);
5003
5166
  this._webcamProducer = null;
5167
+ this._webcamProducerOriginalSvcScalabilityMode = undefined;
5168
+ this._webcamProducerOriginalSvcMaxBitrate = undefined;
5169
+ this._webcamProducerHighestPreferredLayer = undefined;
5004
5170
  }
5005
5171
  }
5006
5172
  }))();
@@ -5252,6 +5418,7 @@ class VegaRtcManager {
5252
5418
  if (clientState) {
5253
5419
  clientState.hasAcceptedWebcamStream = false;
5254
5420
  clientState.hasAcceptedScreenStream = false;
5421
+ [clientState.webcamStream, clientState.screenStream].forEach((stream) => stream && this._streamIdToVideoResolution.delete(stream.id));
5255
5422
  this._syncIncomingStreamsWithPWA(clientId);
5256
5423
  }
5257
5424
  if (eventClaim) {
@@ -5375,6 +5542,9 @@ class VegaRtcManager {
5375
5542
  if (this._webcamProducer && !this._webcamProducer.closed && this._webcamProducer.track === track) {
5376
5543
  this._stopProducer(this._webcamProducer);
5377
5544
  this._webcamProducer = null;
5545
+ this._webcamProducerOriginalSvcScalabilityMode = undefined;
5546
+ this._webcamProducerOriginalSvcMaxBitrate = undefined;
5547
+ this._webcamProducerHighestPreferredLayer = undefined;
5378
5548
  this._webcamTrack = null;
5379
5549
  }
5380
5550
  }
@@ -5402,14 +5572,18 @@ class VegaRtcManager {
5402
5572
  this._syncIncomingStreamsWithPWA(clientId);
5403
5573
  }
5404
5574
  updateStreamResolution(streamId, _ignored, { width, height, }) {
5405
- var _a, _b, _c;
5406
5575
  logger$2.info("updateStreamResolution()", { streamId, width, height });
5576
+ this._streamIdToVideoResolution.set(streamId, { width, height });
5577
+ this._applyStreamResolution(streamId);
5578
+ }
5579
+ _applyStreamResolution(streamId) {
5580
+ var _a, _b, _c;
5581
+ const resolution = this._streamIdToVideoResolution.get(streamId);
5407
5582
  const consumerId = this._streamIdToVideoConsumerId.get(streamId);
5408
5583
  const consumer = this._consumers.get(consumerId);
5409
- if (!consumer) {
5410
- this._streamIdToVideoResolution.set(streamId, { width, height });
5584
+ if (!resolution || !consumer)
5411
5585
  return;
5412
- }
5586
+ const { width, height } = resolution;
5413
5587
  updateRenderedDimensions((_a = consumer.track) === null || _a === void 0 ? void 0 : _a.id, { width, height, time: Date.now() });
5414
5588
  const numberOfActiveVideos = getNumberOfActiveVideos(this._consumers);
5415
5589
  const numberOfTemporalLayers = getNumberOfTemporalLayers(consumer);
@@ -5419,6 +5593,12 @@ class VegaRtcManager {
5419
5593
  uncappedSingleRemoteVideoOn: (_b = this._features) === null || _b === void 0 ? void 0 : _b.uncappedSingleRemoteVideoOn,
5420
5594
  });
5421
5595
  if (consumer.appData.spatialLayer !== spatialLayer || consumer.appData.temporalLayer !== temporalLayer) {
5596
+ const previousSpatialLayer = consumer.appData.spatialLayer;
5597
+ const spatialLayerChanged = previousSpatialLayer !== spatialLayer;
5598
+ if (spatialLayerChanged) {
5599
+ this.analytics.numPreferredSpatialLayerChanges++;
5600
+ this._incrementHistogramCount(this.analytics.preferredSpatialLayerChangeCounts, `${previousSpatialLayer}->${spatialLayer}`);
5601
+ }
5422
5602
  consumer.appData.spatialLayer = spatialLayer;
5423
5603
  consumer.appData.temporalLayer = temporalLayer;
5424
5604
  (_c = this._vegaConnection) === null || _c === void 0 ? void 0 : _c.message("setConsumersPreferredLayers", {
@@ -5426,7 +5606,178 @@ class VegaRtcManager {
5426
5606
  spatialLayer,
5427
5607
  temporalLayer,
5428
5608
  });
5609
+ if (spatialLayerChanged) {
5610
+ this._watchForPreferredLayerSwitch(consumerId, consumer, {
5611
+ toHigherLayer: spatialLayer > previousSpatialLayer,
5612
+ });
5613
+ }
5614
+ }
5615
+ }
5616
+ _watchForPreferredLayerSwitch(consumerId, consumer, { toHigherLayer }) {
5617
+ const previousWatch = this._preferredLayerSwitchWatches.get(consumerId);
5618
+ if (!previousWatch && this._preferredLayerSwitchWatches.size >= MAX_CONCURRENT_PREFERRED_LAYER_SWITCH_WATCHES) {
5619
+ return;
5620
+ }
5621
+ previousWatch === null || previousWatch === void 0 ? void 0 : previousWatch.stop();
5622
+ let stopped = false;
5623
+ let intervalId;
5624
+ const stop = () => {
5625
+ if (stopped)
5626
+ return;
5627
+ stopped = true;
5628
+ clearInterval(intervalId);
5629
+ clearTimeout(timeoutId);
5630
+ this._preferredLayerSwitchWatches.delete(consumerId);
5631
+ };
5632
+ this._preferredLayerSwitchWatches.set(consumerId, { stop });
5633
+ const timeoutId = setTimeout(stop, PREFERRED_LAYER_SWITCH_WATCH_TIMEOUT_MS);
5634
+ (() => __awaiter(this, void 0, void 0, function* () {
5635
+ const sentAt = Date.now();
5636
+ const baseline = yield this._getConsumerFrameSize(consumer);
5637
+ if (stopped || !(baseline === null || baseline === void 0 ? void 0 : baseline.width) || !(baseline === null || baseline === void 0 ? void 0 : baseline.height)) {
5638
+ stop();
5639
+ return;
5640
+ }
5641
+ let polling = false;
5642
+ intervalId = setInterval(() => __awaiter(this, void 0, void 0, function* () {
5643
+ if (stopped || consumer.closed) {
5644
+ stop();
5645
+ return;
5646
+ }
5647
+ if (polling)
5648
+ return;
5649
+ polling = true;
5650
+ const current = yield this._getConsumerFrameSize(consumer);
5651
+ polling = false;
5652
+ if (stopped)
5653
+ return;
5654
+ const switched = toHigherLayer
5655
+ ? getFrameArea(current) > getFrameArea(baseline)
5656
+ : getFrameArea(current) < getFrameArea(baseline);
5657
+ if (current && switched) {
5658
+ this._recordPreferredLayerSwitchLatency(Date.now() - sentAt);
5659
+ stop();
5660
+ }
5661
+ }), PREFERRED_LAYER_SWITCH_POLL_INTERVAL_MS);
5662
+ }))();
5663
+ }
5664
+ _getConsumerFrameSize(consumer) {
5665
+ return __awaiter(this, void 0, void 0, function* () {
5666
+ try {
5667
+ const stats = yield consumer.getStats();
5668
+ let frameSize;
5669
+ stats.forEach((report) => {
5670
+ if (report.type === "inbound-rtp") {
5671
+ frameSize = { width: report.frameWidth, height: report.frameHeight };
5672
+ }
5673
+ });
5674
+ return frameSize;
5675
+ }
5676
+ catch (error) {
5677
+ logger$2.warn("_getConsumerFrameSize() failed to read stats", { error });
5678
+ return undefined;
5679
+ }
5680
+ });
5681
+ }
5682
+ _recordPreferredLayerSwitchLatency(latencyMs) {
5683
+ recordMetricSample(this._preferredLayerSwitchLatencyStats, latencyMs);
5684
+ const { avg } = aggregateMetricStats(this._preferredLayerSwitchLatencyStats);
5685
+ this.analytics.avgPreferredLayerSwitchLatencyMs = avg;
5686
+ }
5687
+ _onUpdatedStats(statsByView) {
5688
+ var _a, _b, _c, _d;
5689
+ const webcamProducerMid = (_b = (_a = this._webcamProducer) === null || _a === void 0 ? void 0 : _a.rtpParameters) === null || _b === void 0 ? void 0 : _b.mid;
5690
+ if (webcamProducerMid === undefined)
5691
+ return;
5692
+ const sendTransportPc = (_d = (_c = this._sendTransport) === null || _c === void 0 ? void 0 : _c.handler) === null || _d === void 0 ? void 0 : _d._pc;
5693
+ const sendTransportPcIndex = sendTransportPc ? getPeerConnectionIndex(sendTransportPc) : undefined;
5694
+ const newRemoteReports = [];
5695
+ Object.values(statsByView).forEach((viewStats) => {
5696
+ Object.values(viewStats.tracks || {}).forEach((trackStats) => {
5697
+ Object.entries(trackStats.ssrcs || {}).forEach(([ssrc, ssrcMetrics]) => {
5698
+ if (ssrcMetrics.direction !== "out" || String(ssrcMetrics.mid) !== webcamProducerMid)
5699
+ return;
5700
+ if (sendTransportPcIndex !== undefined && ssrcMetrics.pcIndex !== sendTransportPcIndex)
5701
+ return;
5702
+ this._followCamOutboundCandidatePair(ssrcMetrics);
5703
+ const { remoteReportTimestamp } = ssrcMetrics;
5704
+ if (remoteReportTimestamp === undefined)
5705
+ return;
5706
+ if (remoteReportTimestamp === this._lastSeenRemoteReportTimestamps.get(ssrc))
5707
+ return;
5708
+ this._lastSeenRemoteReportTimestamps.set(ssrc, remoteReportTimestamp);
5709
+ newRemoteReports.push(ssrcMetrics);
5710
+ });
5711
+ });
5712
+ });
5713
+ if (!newRemoteReports.length)
5714
+ return;
5715
+ if (this._camOutboundSamplesToSkip > 0) {
5716
+ this._camOutboundSamplesToSkip--;
5717
+ return;
5429
5718
  }
5719
+ this._recordCamOutboundSample(newRemoteReports);
5720
+ this._updateCamOutboundAnalytics();
5721
+ }
5722
+ _recordCamOutboundSample(newRemoteReports) {
5723
+ var _a, _b;
5724
+ const rttsMs = newRemoteReports.map(({ roundTripTime }) => (roundTripTime || 0) * 1000).filter((ms) => ms > 0);
5725
+ const rttMs = rttsMs.length ? Math.max(...rttsMs) : undefined;
5726
+ const fractionLost = getPacketWeightedFractionLost(newRemoteReports);
5727
+ const path = this._camOutboundPathRtt;
5728
+ if (rttMs !== undefined) {
5729
+ path.sumMs += rttMs;
5730
+ path.count++;
5731
+ path.minMs = Math.min((_a = path.minMs) !== null && _a !== void 0 ? _a : Infinity, rttMs);
5732
+ }
5733
+ const congested = (rttMs !== undefined && rttMs - ((_b = path.minMs) !== null && _b !== void 0 ? _b : rttMs) > CONGESTED_RTT_INFLATION_MS) ||
5734
+ fractionLost > CONGESTED_FRACTION_LOST;
5735
+ this._camOutboundSamples.total++;
5736
+ if (congested)
5737
+ this._camOutboundSamples.congested++;
5738
+ }
5739
+ _followCamOutboundCandidatePair({ selectedCandidatePairId }) {
5740
+ if (!selectedCandidatePairId || selectedCandidatePairId === this._camOutboundCandidatePairId)
5741
+ return;
5742
+ if (this._camOutboundCandidatePairId !== undefined) {
5743
+ this._finishCamOutboundRttPath();
5744
+ this._camOutboundSamplesToSkip = CAM_SAMPLES_SKIPPED_AFTER_CANDIDATE_PAIR_CHANGE;
5745
+ }
5746
+ this._camOutboundCandidatePairId = selectedCandidatePairId;
5747
+ }
5748
+ _finishCamOutboundRttPath() {
5749
+ const path = this._camOutboundPathRtt;
5750
+ if (path.count && path.minMs !== undefined) {
5751
+ this._camOutboundRttInflation.sumMs += path.sumMs - path.count * path.minMs;
5752
+ this._camOutboundRttInflation.count += path.count;
5753
+ }
5754
+ this._camOutboundPathRtt = { sumMs: 0, count: 0, minMs: undefined };
5755
+ }
5756
+ _updateCamOutboundAnalytics() {
5757
+ const path = this._camOutboundPathRtt;
5758
+ const inflationSumMs = this._camOutboundRttInflation.sumMs + (path.minMs !== undefined ? path.sumMs - path.count * path.minMs : 0);
5759
+ const inflationCount = this._camOutboundRttInflation.count + path.count;
5760
+ this.analytics.camOutboundRttInflationMs = inflationCount
5761
+ ? Math.round(inflationSumMs / inflationCount)
5762
+ : undefined;
5763
+ const { congested, total } = this._camOutboundSamples;
5764
+ this.analytics.camOutboundCongestedFraction = total ? congested / total : undefined;
5765
+ }
5766
+ _startWebcamStatsSubscription() {
5767
+ if (this._statsSubscription)
5768
+ return;
5769
+ this._statsSubscription = subscribeStats({
5770
+ onUpdatedStats: (statsByView) => this._onUpdatedStats(statsByView),
5771
+ });
5772
+ }
5773
+ _stopWebcamStatsSubscription() {
5774
+ var _a;
5775
+ (_a = this._statsSubscription) === null || _a === void 0 ? void 0 : _a.stop();
5776
+ this._statsSubscription = null;
5777
+ this._lastSeenRemoteReportTimestamps.clear();
5778
+ this._finishCamOutboundRttPath();
5779
+ this._camOutboundCandidatePairId = undefined;
5780
+ this._camOutboundSamplesToSkip = 0;
5430
5781
  }
5431
5782
  close() {
5432
5783
  this.disconnectAll();
@@ -5457,8 +5808,11 @@ class VegaRtcManager {
5457
5808
  this._screenVideoTrack = null;
5458
5809
  this._screenAudioTrack = null;
5459
5810
  this._streamIdToVideoConsumerId.clear();
5811
+ this._streamIdToVideoResolution.clear();
5460
5812
  this._mediasoupDeviceInitializedAsync = Promise.resolve(null);
5461
5813
  this._qualityMonitor.close();
5814
+ this._stopWebcamStatsSubscription();
5815
+ this._preferredLayerSwitchWatches.forEach(({ stop }) => stop());
5462
5816
  }
5463
5817
  sendStatsCustomEvent(eventName, data) {
5464
5818
  rtcStats.sendEvent(eventName, data);
@@ -5516,6 +5870,8 @@ class VegaRtcManager {
5516
5870
  return this._onConsumerScore(data);
5517
5871
  case "producerScore":
5518
5872
  return this._onProducerScore(data);
5873
+ case "changedHighestPreferredLayer":
5874
+ return this._onChangedHighestPreferredLayer(data);
5519
5875
  default:
5520
5876
  logger$2.info(`unknown message method "${method}"`);
5521
5877
  return;
@@ -5543,13 +5899,16 @@ class VegaRtcManager {
5543
5899
  }
5544
5900
  consumer.pause();
5545
5901
  consumer.appData.localPaused = true;
5546
- consumer.appData.spatialLayer = 2;
5902
+ consumer.appData.spatialLayer = INITIAL_CONSUMER_SPATIAL_LAYER;
5547
5903
  this._consumers.set(consumer.id, consumer);
5548
5904
  this._qualityMonitor.addConsumer(consumer.appData.sourceClientId, consumer.id);
5549
5905
  consumer.observer.once("close", () => {
5550
5906
  this._consumers.delete(consumer.id);
5551
5907
  this._qualityMonitor.removeConsumer(consumer.appData.sourceClientId, consumer.id);
5552
5908
  this._consumerClosedCleanup(consumer);
5909
+ if (consumer.kind === "video" && this._receiveTransport && !this._receiveTransport.closed) {
5910
+ this._reapplyStreamResolutions();
5911
+ }
5553
5912
  });
5554
5913
  if (this._features.increaseIncomingMediaBufferOn && consumer.rtpReceiver) {
5555
5914
  try {
@@ -5581,13 +5940,12 @@ class VegaRtcManager {
5581
5940
  }
5582
5941
  stream.addTrack(consumer.track);
5583
5942
  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
- }
5943
+ this._reapplyStreamResolutions();
5589
5944
  });
5590
5945
  }
5946
+ _reapplyStreamResolutions() {
5947
+ this._streamIdToVideoResolution.forEach((_resolution, streamId) => this._applyStreamResolution(streamId));
5948
+ }
5591
5949
  _onConsumerClosed(_a) {
5592
5950
  return __awaiter(this, arguments, void 0, function* ({ consumerId, reason }) {
5593
5951
  var _b;
@@ -5602,6 +5960,8 @@ class VegaRtcManager {
5602
5960
  return;
5603
5961
  consumer.appData.remotePaused = true;
5604
5962
  consumer.pause();
5963
+ if (consumer.kind === "video")
5964
+ this._reapplyStreamResolutions();
5605
5965
  }
5606
5966
  _onConsumerResumed({ consumerId }) {
5607
5967
  logger$2.info("_onConsumerResumed()", { consumerId });
@@ -5612,6 +5972,8 @@ class VegaRtcManager {
5612
5972
  if (!consumer.appData.localPaused) {
5613
5973
  consumer.resume();
5614
5974
  }
5975
+ if (consumer.kind === "video")
5976
+ this._reapplyStreamResolutions();
5615
5977
  }
5616
5978
  _onConsumerScore({ consumerId, kind, score }) {
5617
5979
  logger$2.info("_onConsumerScore()", { consumerId, kind, score });
@@ -5628,6 +5990,90 @@ class VegaRtcManager {
5628
5990
  }
5629
5991
  });
5630
5992
  }
5993
+ _getSvcEncodingUpdate(encoding, spatialLayer) {
5994
+ var _a;
5995
+ const reduced = getReducedSvcEncodingParams(this._webcamProducerOriginalSvcScalabilityMode, spatialLayer, this._webcamProducerOriginalSvcMaxBitrate);
5996
+ if (!reduced)
5997
+ return undefined;
5998
+ const changed = reduced.scalabilityMode !== encoding.scalabilityMode ||
5999
+ reduced.scaleResolutionDownBy !== ((_a = encoding.scaleResolutionDownBy) !== null && _a !== void 0 ? _a : 1) ||
6000
+ reduced.maxBitrate !== encoding.maxBitrate;
6001
+ return changed ? reduced : undefined;
6002
+ }
6003
+ _onChangedHighestPreferredLayer(_a) {
6004
+ return __awaiter(this, arguments, void 0, function* ({ producerId, spatialLayer }) {
6005
+ var _b;
6006
+ if (!this._features.sfuHighestPreferredLayerTrackingOn)
6007
+ return;
6008
+ if (((_b = this._webcamProducer) === null || _b === void 0 ? void 0 : _b.id) !== producerId)
6009
+ return;
6010
+ if (!Number.isFinite(spatialLayer)) {
6011
+ logger$2.warn("_onChangedHighestPreferredLayer() ignoring invalid spatialLayer", {
6012
+ producerId,
6013
+ spatialLayer,
6014
+ });
6015
+ return;
6016
+ }
6017
+ if (this._webcamProducerHighestPreferredLayer !== undefined &&
6018
+ this._webcamProducerHighestPreferredLayer !== spatialLayer) {
6019
+ this.analytics.numHighestPreferredLayerChanges++;
6020
+ this._incrementHistogramCount(this.analytics.highestPreferredLayerChangeCounts, `${this._webcamProducerHighestPreferredLayer}->${spatialLayer}`);
6021
+ }
6022
+ this._webcamProducerHighestPreferredLayer = spatialLayer;
6023
+ logger$2.info("_onChangedHighestPreferredLayer()", { producerId, spatialLayer });
6024
+ return this._syncWebcamEncoderToHighestPreferredLayer();
6025
+ });
6026
+ }
6027
+ _syncWebcamEncoderToHighestPreferredLayer() {
6028
+ this._highestPreferredLayerUpdatePending = true;
6029
+ if (!this._highestPreferredLayerUpdate) {
6030
+ this._highestPreferredLayerUpdate = this._applyPendingHighestPreferredLayerUpdates();
6031
+ }
6032
+ return this._highestPreferredLayerUpdate;
6033
+ }
6034
+ _applyPendingHighestPreferredLayerUpdates() {
6035
+ return __awaiter(this, void 0, void 0, function* () {
6036
+ while (this._highestPreferredLayerUpdatePending) {
6037
+ this._highestPreferredLayerUpdatePending = false;
6038
+ try {
6039
+ yield this._applyHighestPreferredLayerToWebcamEncoder();
6040
+ }
6041
+ catch (error) {
6042
+ logger$2.error("Failed to apply highest preferred layer: %o", error);
6043
+ }
6044
+ }
6045
+ this._highestPreferredLayerUpdate = null;
6046
+ });
6047
+ }
6048
+ _applyHighestPreferredLayerToWebcamEncoder() {
6049
+ return __awaiter(this, void 0, void 0, function* () {
6050
+ const producer = this._webcamProducer;
6051
+ const highestPreferredLayer = this._webcamProducerHighestPreferredLayer;
6052
+ if (!producer || highestPreferredLayer === undefined)
6053
+ return;
6054
+ const encodings = producer.rtpSender.getParameters().encodings;
6055
+ if (encodings.length > 1) {
6056
+ const cpuOveruseLimit = this._cpuOveruseDetected && encodings.length === 3 ? 1 : Infinity;
6057
+ const spatialLayer = Math.max(0, Math.min(highestPreferredLayer, cpuOveruseLimit, encodings.length - 1));
6058
+ if (producer.maxSpatialLayer === spatialLayer)
6059
+ return;
6060
+ yield producer.setMaxSpatialLayer(spatialLayer);
6061
+ const applied = producer.rtpSender
6062
+ .getParameters()
6063
+ .encodings.every((encoding, index) => encoding.active === index <= spatialLayer);
6064
+ if (!applied)
6065
+ logger$2.error("setMaxSpatialLayer(%d) was not applied to the encodings", spatialLayer);
6066
+ }
6067
+ else if (encodings.length === 1 && this._webcamProducerOriginalSvcScalabilityMode) {
6068
+ const update = this._getSvcEncodingUpdate(encodings[0], highestPreferredLayer);
6069
+ if (update)
6070
+ yield producer.setRtpEncodingParameters(update);
6071
+ }
6072
+ });
6073
+ }
6074
+ _incrementHistogramCount(histogram, key) {
6075
+ histogram[key] = (histogram[key] || 0) + 1;
6076
+ }
5631
6077
  _onDataConsumerReady(options) {
5632
6078
  return __awaiter(this, void 0, void 0, function* () {
5633
6079
  logger$2.info("_onDataConsumerReady()", { id: options.id, dataProducerId: options.dataProducerId });
@@ -5677,8 +6123,8 @@ class VegaRtcManager {
5677
6123
  stream.removeTrack(consumer.track);
5678
6124
  if (stream.getTracks().length === 0) {
5679
6125
  this._streamIdToVideoConsumerId.delete(stream.id);
5680
- this._streamIdToVideoResolution.delete(stream.id);
5681
6126
  if (screenShare) {
6127
+ this._streamIdToVideoResolution.delete(stream.id);
5682
6128
  clientState.screenStream = undefined;
5683
6129
  clientState.hasEmittedScreenStream = false;
5684
6130
  clientState.screenShareStreamId = undefined;
@@ -5724,6 +6170,8 @@ class VegaRtcManager {
5724
6170
  consumerIds: toResumeConsumers,
5725
6171
  });
5726
6172
  }
6173
+ if (toPauseConsumers.length > 0 || toResumeConsumers.length > 0)
6174
+ this._reapplyStreamResolutions();
5727
6175
  if (webcamStream && !hasEmittedWebcamStream && hasAcceptedWebcamStream) {
5728
6176
  this._emitToPWA(EVENTS.STREAM_ADDED, {
5729
6177
  clientId,
@@ -7496,19 +7944,30 @@ exports.ADDITIONAL_SCREEN_SHARE_SETTINGS = ADDITIONAL_SCREEN_SHARE_SETTINGS;
7496
7944
  exports.AUDIO_SETTINGS = AUDIO_SETTINGS;
7497
7945
  exports.BandwidthTester = BandwidthTester;
7498
7946
  exports.CAMERA_STREAM_ID = CAMERA_STREAM_ID;
7947
+ exports.CAM_SAMPLES_SKIPPED_AFTER_CANDIDATE_PAIR_CHANGE = CAM_SAMPLES_SKIPPED_AFTER_CANDIDATE_PAIR_CHANGE;
7948
+ exports.CONGESTED_FRACTION_LOST = CONGESTED_FRACTION_LOST;
7949
+ exports.CONGESTED_RTT_INFLATION_MS = CONGESTED_RTT_INFLATION_MS;
7499
7950
  exports.EVENTS = EVENTS;
7500
7951
  exports.FILE_SHARE_ERROR_CODES = FILE_SHARE_ERROR_CODES;
7952
+ exports.INITIAL_CONSUMER_SPATIAL_LAYER = INITIAL_CONSUMER_SPATIAL_LAYER;
7953
+ exports.INITIAL_HIGHEST_PREFERRED_LAYER = INITIAL_HIGHEST_PREFERRED_LAYER;
7501
7954
  exports.KNOCK_MESSAGES = KNOCK_MESSAGES;
7502
7955
  exports.KalmanFilter = KalmanFilter;
7956
+ exports.LOWEST_SVC_LAYER_MAX_BITRATE = LOWEST_SVC_LAYER_MAX_BITRATE;
7503
7957
  exports.Logger = Logger;
7958
+ exports.MAX_CONCURRENT_PREFERRED_LAYER_SWITCH_WATCHES = MAX_CONCURRENT_PREFERRED_LAYER_SWITCH_WATCHES;
7504
7959
  exports.MEDIA_JITTER_BUFFER_TARGET = MEDIA_JITTER_BUFFER_TARGET;
7960
+ exports.MIDDLE_SVC_LAYER_MAX_BITRATE = MIDDLE_SVC_LAYER_MAX_BITRATE;
7505
7961
  exports.NoDevicesError = NoDevicesError;
7506
7962
  exports.P2pRtcManager = P2pRtcManager;
7963
+ exports.PREFERRED_LAYER_SWITCH_POLL_INTERVAL_MS = PREFERRED_LAYER_SWITCH_POLL_INTERVAL_MS;
7964
+ exports.PREFERRED_LAYER_SWITCH_WATCH_TIMEOUT_MS = PREFERRED_LAYER_SWITCH_WATCH_TIMEOUT_MS;
7507
7965
  exports.PROTOCOL_ERRORS = PROTOCOL_ERRORS;
7508
7966
  exports.PROTOCOL_EVENTS = PROTOCOL_EVENTS;
7509
7967
  exports.PROTOCOL_REQUESTS = PROTOCOL_REQUESTS;
7510
7968
  exports.PROTOCOL_RESPONSES = PROTOCOL_RESPONSES;
7511
7969
  exports.RELAY_MESSAGES = RELAY_MESSAGES;
7970
+ exports.ROOM_INTEGRATION_ERROR_CODES = ROOM_INTEGRATION_ERROR_CODES;
7512
7971
  exports.ReconnectManager = ReconnectManager;
7513
7972
  exports.RtcManagerDispatcher = RtcManagerDispatcher;
7514
7973
  exports.SCREEN_SHARE_SETTINGS = SCREEN_SHARE_SETTINGS;
@@ -7560,6 +8019,7 @@ exports.getNumFailedStatsReports = getNumFailedStatsReports;
7560
8019
  exports.getNumFailedTrackSsrcLookups = getNumFailedTrackSsrcLookups;
7561
8020
  exports.getNumMissingTrackSsrcLookups = getNumMissingTrackSsrcLookups;
7562
8021
  exports.getPeerConnectionIndex = getPeerConnectionIndex;
8022
+ exports.getSelectedCandidatePairId = getSelectedCandidatePairId;
7563
8023
  exports.getStats = getStats;
7564
8024
  exports.getStream = getStream;
7565
8025
  exports.getUpdatedDevices = getUpdatedDevices;
@@ -7569,6 +8029,7 @@ exports.hasGetDisplayMedia = hasGetDisplayMedia;
7569
8029
  exports.ipRegex = ipRegex;
7570
8030
  exports.isFileShareError = isFileShareError;
7571
8031
  exports.isMobile = isMobile;
8032
+ exports.isRoomIntegrationErrorCode = isRoomIntegrationErrorCode;
7572
8033
  exports.issueDetectorOrMetricEnabled = issueDetectorOrMetricEnabled;
7573
8034
  exports.maybeTurnOnly = maybeTurnOnly;
7574
8035
  exports.modifyMediaCapabilities = modifyMediaCapabilities;