@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.
@@ -284,7 +284,7 @@ class Logger {
284
284
 
285
285
  var _a$5, _b$2;
286
286
  const adapter$5 = (_a$5 = adapterRaw.default) !== null && _a$5 !== void 0 ? _a$5 : adapterRaw;
287
- const logger$b = new Logger();
287
+ const logger$c = new Logger();
288
288
  const browserName$2 = (_b$2 = adapter$5.browserDetails) === null || _b$2 === void 0 ? void 0 : _b$2.browser;
289
289
  const browserVersion$1 = adapter$5.browserDetails.version;
290
290
  function setCodecPreferenceSDP({ sdp, redOn }) {
@@ -325,7 +325,7 @@ function setCodecPreferenceSDP({ sdp, redOn }) {
325
325
  return newSdp;
326
326
  }
327
327
  catch (error) {
328
- logger$b.error("setCodecPreferenceSDP error:", error);
328
+ logger$c.error("setCodecPreferenceSDP error:", error);
329
329
  return sdp;
330
330
  }
331
331
  }
@@ -476,7 +476,7 @@ function trackAnnotations(o) {
476
476
 
477
477
  var _a$4;
478
478
  const adapter$4 = (_a$4 = adapterRaw.default) !== null && _a$4 !== void 0 ? _a$4 : adapterRaw;
479
- const logger$a = new Logger();
479
+ const logger$b = new Logger();
480
480
  class Session {
481
481
  constructor({ clientId, bandwidth, peerConnectionConfig, deprioritizeH264Encoding, incrementAnalyticMetric, mediaPrefs, }) {
482
482
  this.relayCandidateSeen = false;
@@ -608,7 +608,7 @@ class Session {
608
608
  }
609
609
  handleAnswer(message) {
610
610
  if (this.pc.signalingState !== "have-local-offer") {
611
- logger$a.warn("Ignoring stale SDP answer for client %s (signalingState: %s)", this.clientId, this.pc.signalingState);
611
+ logger$b.warn("Ignoring stale SDP answer for client %s (signalingState: %s)", this.clientId, this.pc.signalingState);
612
612
  this._incrementAnalyticMetric("P2PStaleAnswerIgnored");
613
613
  rtcStats.sendEvent("P2PStaleAnswerIgnored", {
614
614
  clientId: this.clientId,
@@ -636,7 +636,7 @@ class Session {
636
636
  return;
637
637
  }
638
638
  this.pc.addIceCandidate(candidate).catch((e) => {
639
- logger$a.warn("Failed to add ICE candidate ('%s'): %s", candidate ? candidate.candidate : null, e);
639
+ logger$b.warn("Failed to add ICE candidate ('%s'): %s", candidate ? candidate.candidate : null, e);
640
640
  this._incrementAnalyticMetric("P2PAddIceCandidateFailure");
641
641
  rtcStats.sendEvent("P2PAddIceCandidateFailure", {
642
642
  clientId: this.clientId,
@@ -664,7 +664,7 @@ class Session {
664
664
  pc.close();
665
665
  }
666
666
  catch (e) {
667
- logger$a.warn("failures during close of session", e);
667
+ logger$b.warn("failures during close of session", e);
668
668
  }
669
669
  }
670
670
  hasConnectedPeerConnection() {
@@ -673,7 +673,7 @@ class Session {
673
673
  replaceTrack(oldTrack, newTrack) {
674
674
  return __awaiter(this, void 0, void 0, function* () {
675
675
  var _a;
676
- logger$a.info("replacetrack() [oldTrackId: %s, newTrackId: %s]", oldTrack === null || oldTrack === void 0 ? void 0 : oldTrack.id, newTrack.id);
676
+ logger$b.info("replacetrack() [oldTrackId: %s, newTrackId: %s]", oldTrack === null || oldTrack === void 0 ? void 0 : oldTrack.id, newTrack.id);
677
677
  if (newTrack.readyState === "ended") {
678
678
  throw new Error(`refusing to use ended track with id: ${newTrack.id}, kind: ${newTrack.kind}`);
679
679
  }
@@ -744,6 +744,16 @@ class Session {
744
744
  }
745
745
 
746
746
  const MEDIA_JITTER_BUFFER_TARGET = 400;
747
+ const INITIAL_CONSUMER_SPATIAL_LAYER = 1;
748
+ const INITIAL_HIGHEST_PREFERRED_LAYER = 1;
749
+ const LOWEST_SVC_LAYER_MAX_BITRATE = 100000;
750
+ const MIDDLE_SVC_LAYER_MAX_BITRATE = 500000;
751
+ const PREFERRED_LAYER_SWITCH_POLL_INTERVAL_MS = 100;
752
+ const PREFERRED_LAYER_SWITCH_WATCH_TIMEOUT_MS = 10000;
753
+ const MAX_CONCURRENT_PREFERRED_LAYER_SWITCH_WATCHES = 5;
754
+ const CONGESTED_RTT_INFLATION_MS = 100;
755
+ const CONGESTED_FRACTION_LOST = 0.02;
756
+ const CAM_SAMPLES_SKIPPED_AFTER_CANDIDATE_PAIR_CHANGE = 2;
747
757
 
748
758
  const PROTOCOL_REQUESTS = {
749
759
  BLOCK_CLIENT: "block_client",
@@ -805,6 +815,9 @@ const PROTOCOL_RESPONSES = {
805
815
  PLAY_CLIENT_STICKER: "play_client_sticker",
806
816
  ROOM_INTEGRATION_ENABLED: "room_integration_enabled",
807
817
  ROOM_INTEGRATION_DISABLED: "room_integration_disabled",
818
+ ROOM_INTEGRATION_STARTED: "room_integration_started",
819
+ ROOM_INTEGRATION_STOPPED: "room_integration_stopped",
820
+ ROOM_INTEGRATION_PROPS_UPDATED: "room_integration_props_updated",
808
821
  ROOM_JOINED: "room_joined",
809
822
  ROOM_KNOCKED: "room_knocked",
810
823
  ROOM_LEFT: "room_left",
@@ -1043,7 +1056,7 @@ const getMediasoupDeviceAsync = (features) => __awaiter(void 0, void 0, void 0,
1043
1056
  return new Device({ handlerName });
1044
1057
  });
1045
1058
 
1046
- const logger$9 = new Logger();
1059
+ const logger$a = new Logger();
1047
1060
  const AUDIO_SETTINGS = {
1048
1061
  codecOptions: {
1049
1062
  opusDtx: true,
@@ -1223,7 +1236,7 @@ function sortCodecsByPowerEfficiency(codecs) {
1223
1236
  codecPowerEfficiencyEntries = yield Promise.all(codecs.map(({ mimeType }) => getIsCodecDecodingPowerEfficient(mimeType).then((val) => [mimeType, val])));
1224
1237
  }
1225
1238
  catch (error) {
1226
- logger$9.error(error);
1239
+ logger$a.error(error);
1227
1240
  return codecs;
1228
1241
  }
1229
1242
  const codecPowerEfficiencies = Object.fromEntries(codecPowerEfficiencyEntries);
@@ -1292,7 +1305,24 @@ function captureSsrcInfo(ssrcMetrics, currentSsrcStats, prevSsrcStats, timeDiff,
1292
1305
  ssrcMetrics.mid = currentSsrcStats.mid;
1293
1306
  ssrcMetrics.rid = currentSsrcStats.rid;
1294
1307
  }
1308
+ const selectedCandidatePairIdByReport = new WeakMap();
1309
+ function getSelectedCandidatePairId(report, transportId) {
1310
+ var _a;
1311
+ const selectedCandidatePairId = transportId ? (_a = report.get(transportId)) === null || _a === void 0 ? void 0 : _a.selectedCandidatePairId : undefined;
1312
+ if (selectedCandidatePairId)
1313
+ return selectedCandidatePairId;
1314
+ if (!selectedCandidatePairIdByReport.has(report)) {
1315
+ let selectedId;
1316
+ report.forEach((stats) => {
1317
+ if (stats.type === "candidate-pair" && stats.selected)
1318
+ selectedId = stats.id;
1319
+ });
1320
+ selectedCandidatePairIdByReport.set(report, selectedId);
1321
+ }
1322
+ return selectedCandidatePairIdByReport.get(report);
1323
+ }
1295
1324
  function captureCommonSsrcMetrics(ssrcMetrics, currentSsrcStats, prevSsrcStats, timeDiff, report) {
1325
+ ssrcMetrics.selectedCandidatePairId = getSelectedCandidatePairId(report, currentSsrcStats.transportId);
1296
1326
  const nackCountDiff = (currentSsrcStats.nackCount || 0) - ((prevSsrcStats === null || prevSsrcStats === void 0 ? void 0 : prevSsrcStats.nackCount) || 0);
1297
1327
  ssrcMetrics.nackCount = (ssrcMetrics.nackCount || 0) + nackCountDiff;
1298
1328
  ssrcMetrics.nackRate = (1000 * nackCountDiff) / timeDiff;
@@ -1346,6 +1376,7 @@ function captureCommonSsrcMetrics(ssrcMetrics, currentSsrcStats, prevSsrcStats,
1346
1376
  ssrcMetrics.roundTripTime = remoteReport.roundTripTime || 0;
1347
1377
  ssrcMetrics.jitter = remoteReport.jitter || 0;
1348
1378
  ssrcMetrics.fractionLost = remoteReport.fractionLost || 0;
1379
+ ssrcMetrics.remoteReportTimestamp = remoteReport.timestamp;
1349
1380
  }
1350
1381
  }
1351
1382
  }
@@ -1577,7 +1608,6 @@ const DEFAULT_CLIENT = {
1577
1608
  };
1578
1609
  function collectStats(state_1, _a, immediate_1) {
1579
1610
  return __awaiter(this, arguments, void 0, function* (state, { logger, interval }, immediate) {
1580
- const collectStatsBound = collectStats.bind(null, state, { interval, logger });
1581
1611
  try {
1582
1612
  const clients = state.getClients();
1583
1613
  const defaultClient = clients.find((c) => c.isLocalClient && !c.isPresentation) || DEFAULT_CLIENT;
@@ -1592,7 +1622,6 @@ function collectStats(state_1, _a, immediate_1) {
1592
1622
  if (immediate)
1593
1623
  return state.statsByView;
1594
1624
  state.subscriptions.forEach((subscription) => { var _a; return (_a = subscription.onUpdatedStats) === null || _a === void 0 ? void 0 : _a.call(subscription, state.statsByView, clients, state.renderedDimensionsByTrack); });
1595
- state.nextTimeout = setTimeout(collectStatsBound, interval);
1596
1625
  return;
1597
1626
  }
1598
1627
  state.lastUpdateTime = Date.now();
@@ -1715,11 +1744,10 @@ function collectStats(state_1, _a, immediate_1) {
1715
1744
  message: e === null || e === void 0 ? void 0 : e.message,
1716
1745
  });
1717
1746
  }
1718
- state.nextTimeout = setTimeout(collectStatsBound, interval);
1719
1747
  });
1720
1748
  }
1721
1749
 
1722
- const logger$8 = new Logger();
1750
+ const logger$9 = new Logger();
1723
1751
  const CPU_OBSERVER_OPTIONS = {
1724
1752
  sampleRate: 1,
1725
1753
  };
@@ -1729,7 +1757,7 @@ function startCpuObserver(cb, { sampleRate } = CPU_OBSERVER_OPTIONS, window = gl
1729
1757
  if ("PressureObserver" in window &&
1730
1758
  (window.PressureObserver.knownSources || []).includes("cpu")) {
1731
1759
  pressureObserver = new window.PressureObserver(cb, { sampleRate });
1732
- (_a = pressureObserver.observe("cpu", { sampleInterval: sampleRate * 1000 })) === null || _a === void 0 ? void 0 : _a.catch((error) => logger$8.error(error));
1760
+ (_a = pressureObserver.observe("cpu", { sampleInterval: sampleRate * 1000 })) === null || _a === void 0 ? void 0 : _a.catch((error) => logger$9.error(error));
1733
1761
  return {
1734
1762
  stop: () => {
1735
1763
  pressureObserver.unobserve("cpu");
@@ -1765,7 +1793,20 @@ const updateRenderedDimensions = (trackId, data) => {
1765
1793
  STATE.renderedDimensionsByTrack[trackId] = data;
1766
1794
  };
1767
1795
  function startStatsMonitor(state, { interval, logger }) {
1768
- const collectStatsBound = collectStats.bind(null, state, { interval, logger });
1796
+ let stopped = false;
1797
+ let nextTimeout;
1798
+ const scheduleNextRun = () => {
1799
+ nextTimeout = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
1800
+ try {
1801
+ yield collectStats(state, { interval, logger }, false);
1802
+ }
1803
+ catch (error) {
1804
+ logger.error("Stats collection failed unexpectedly", error);
1805
+ }
1806
+ if (!stopped)
1807
+ scheduleNextRun();
1808
+ }), interval);
1809
+ };
1769
1810
  let cpuObserver;
1770
1811
  try {
1771
1812
  cpuObserver = startCpuObserver((records) => (state.lastPressureObserverRecord = records.pop()));
@@ -1773,13 +1814,14 @@ function startStatsMonitor(state, { interval, logger }) {
1773
1814
  catch (ex) {
1774
1815
  logger.warn("Failed to observe CPU pressure", ex);
1775
1816
  }
1776
- setTimeout(collectStatsBound, interval);
1817
+ scheduleNextRun();
1777
1818
  return {
1778
1819
  getUpdatedStats: () => {
1779
- return collectStatsBound(true);
1820
+ return collectStats(state, { interval, logger }, true);
1780
1821
  },
1781
1822
  stop: () => {
1782
- clearTimeout(state.nextTimeout);
1823
+ stopped = true;
1824
+ clearTimeout(nextTimeout);
1783
1825
  cpuObserver === null || cpuObserver === void 0 ? void 0 : cpuObserver.stop();
1784
1826
  },
1785
1827
  };
@@ -1800,7 +1842,7 @@ function subscribeStats(subscription, options = OPTIONS, state = STATE) {
1800
1842
  };
1801
1843
  }
1802
1844
 
1803
- const logger$7 = new Logger();
1845
+ const logger$8 = new Logger();
1804
1846
  class ReconnectManager extends EventEmitter {
1805
1847
  constructor(socket) {
1806
1848
  super();
@@ -1888,7 +1930,7 @@ class ReconnectManager extends EventEmitter {
1888
1930
  client.mergeWithOldClientState = true;
1889
1931
  }
1890
1932
  catch (error) {
1891
- logger$7.error("Failed to evaluate if we should merge client state %o", error);
1933
+ logger$8.error("Failed to evaluate if we should merge client state %o", error);
1892
1934
  this.metrics.evaluationFailed++;
1893
1935
  }
1894
1936
  });
@@ -1916,7 +1958,7 @@ class ReconnectManager extends EventEmitter {
1916
1958
  const { clientId } = payload;
1917
1959
  const client = this._clients[clientId];
1918
1960
  if (!client) {
1919
- logger$7.warn(`client ${clientId} not found`);
1961
+ logger$8.warn(`client ${clientId} not found`);
1920
1962
  return;
1921
1963
  }
1922
1964
  if (client.isPendingToLeave) {
@@ -2349,6 +2391,16 @@ const FILE_SHARE_ERROR_CODES = [
2349
2391
  function isFileShareError(payload) {
2350
2392
  return "error" in payload && FILE_SHARE_ERROR_CODES.includes(payload.error);
2351
2393
  }
2394
+ const ROOM_INTEGRATION_ERROR_CODES = [
2395
+ "not_in_a_room",
2396
+ "forbidden",
2397
+ "missing_parameters",
2398
+ "invalid_parameters",
2399
+ "internal_server_error",
2400
+ ];
2401
+ function isRoomIntegrationErrorCode(error) {
2402
+ return ROOM_INTEGRATION_ERROR_CODES.includes(error);
2403
+ }
2352
2404
 
2353
2405
  const defaultSubdomainPattern = /^(?:([^.]+)[.])?((:?[^.]+[.]){1,}[^.]+)$/;
2354
2406
  const localstackPattern = /^(?:([^.]+)-)?(ip-[^.]*[.](?:hereby[.]dev|rfc1918[.]disappear[.]at)(?::\d+|))$/;
@@ -2389,7 +2441,7 @@ fromLocation(typeof window !== "undefined" ? window.location : undefined);
2389
2441
 
2390
2442
  var _a$2, _b$1;
2391
2443
  const adapter$2 = (_a$2 = adapterRaw.default) !== null && _a$2 !== void 0 ? _a$2 : adapterRaw;
2392
- const logger$6 = new Logger();
2444
+ const logger$7 = new Logger();
2393
2445
  const ICE_PUBLIC_IP_GATHERING_TIMEOUT = 3 * 1000;
2394
2446
  const ICE_RESTART_DELAY = 2 * 1000;
2395
2447
  const browserName$1 = (_b$1 = adapter$2.browserDetails) === null || _b$1 === void 0 ? void 0 : _b$1.browser;
@@ -2470,7 +2522,7 @@ class P2pRtcManager {
2470
2522
  return this._selfId === selfId && this._roomName === roomName && !isSfu;
2471
2523
  }
2472
2524
  addCameraStream(stream, { beforeEffectTracks = [] } = { beforeEffectTracks: [] }) {
2473
- logger$6.info("addCameraStream: [stream.id: %s]", stream.id);
2525
+ logger$7.info("addCameraStream: [stream.id: %s]", stream.id);
2474
2526
  if (stream === this._localCameraStream) {
2475
2527
  return;
2476
2528
  }
@@ -2513,7 +2565,7 @@ class P2pRtcManager {
2513
2565
  };
2514
2566
  }
2515
2567
  addScreenshareStream(stream) {
2516
- logger$6.info("addScreenshareStream() [stream.id: %s]", stream.id);
2568
+ logger$7.info("addScreenshareStream() [stream.id: %s]", stream.id);
2517
2569
  if (stream === this._localScreenshareStream) {
2518
2570
  return;
2519
2571
  }
@@ -2526,7 +2578,7 @@ class P2pRtcManager {
2526
2578
  this._addStreamToPeerConnections(stream);
2527
2579
  }
2528
2580
  replaceTrack(oldTrack, newTrack) {
2529
- logger$6.info("replaceTrack() [kind: %s, oldTrackId: %s, newTrackId: %s]", newTrack.kind, oldTrack === null || oldTrack === void 0 ? void 0 : oldTrack.id, newTrack.id);
2581
+ logger$7.info("replaceTrack() [kind: %s, oldTrackId: %s, newTrackId: %s]", newTrack.kind, oldTrack === null || oldTrack === void 0 ? void 0 : oldTrack.id, newTrack.id);
2530
2582
  if (newTrack.kind === "audio" && !trackAnnotations(newTrack).isEffectTrack) {
2531
2583
  this._monitorAudioTrack(newTrack);
2532
2584
  }
@@ -2540,7 +2592,7 @@ class P2pRtcManager {
2540
2592
  this.disconnectAll();
2541
2593
  }
2542
2594
  disconnectAll() {
2543
- logger$6.info("disconnectAll()");
2595
+ logger$7.info("disconnectAll()");
2544
2596
  Object.keys(this.peerConnections).forEach((clientId) => {
2545
2597
  this.disconnect(clientId);
2546
2598
  });
@@ -2560,39 +2612,39 @@ class P2pRtcManager {
2560
2612
  () => this._clearMediaServersRefresh(),
2561
2613
  this._serverSocket.on(PROTOCOL_RESPONSES.MEDIASERVER_CONFIG, (data) => {
2562
2614
  if (data.error) {
2563
- logger$6.warn("FETCH_MEDIASERVER_CONFIG failed:", data.error);
2615
+ logger$7.warn("FETCH_MEDIASERVER_CONFIG failed:", data.error);
2564
2616
  return;
2565
2617
  }
2566
2618
  this._updateAndScheduleMediaServersRefresh(data);
2567
2619
  }),
2568
2620
  this._serverSocket.on(RELAY_MESSAGES.READY_TO_RECEIVE_OFFER, (data) => {
2569
- logger$6.info(`Got ready_to_receive_offer from client ${data.clientId}`);
2621
+ logger$7.info(`Got ready_to_receive_offer from client ${data.clientId}`);
2570
2622
  this._connect(data.clientId);
2571
2623
  }),
2572
2624
  this._serverSocket.on(RELAY_MESSAGES.ICE_CANDIDATE, (data) => {
2573
- logger$6.info(`Got ice_candidate from client ${data.clientId}`);
2625
+ logger$7.info(`Got ice_candidate from client ${data.clientId}`);
2574
2626
  const session = this._getSession(data.clientId);
2575
2627
  if (!session) {
2576
- logger$6.warn("No RTCPeerConnection on ICE_CANDIDATE", data);
2628
+ logger$7.warn("No RTCPeerConnection on ICE_CANDIDATE", data);
2577
2629
  return;
2578
2630
  }
2579
2631
  session.addIceCandidate(data.message);
2580
2632
  }),
2581
2633
  this._serverSocket.on(RELAY_MESSAGES.ICE_END_OF_CANDIDATES, (data) => {
2582
- logger$6.info(`Got end_of_ice_candidates from client ${data.clientId}`);
2634
+ logger$7.info(`Got end_of_ice_candidates from client ${data.clientId}`);
2583
2635
  const session = this._getSession(data.clientId);
2584
2636
  if (!session) {
2585
- logger$6.warn("No RTCPeerConnection on ICE_END_OF_CANDIDATES", data);
2637
+ logger$7.warn("No RTCPeerConnection on ICE_END_OF_CANDIDATES", data);
2586
2638
  return;
2587
2639
  }
2588
2640
  session.addIceCandidate(null);
2589
2641
  }),
2590
2642
  this._serverSocket.on(RELAY_MESSAGES.SDP_OFFER, (data) => {
2591
2643
  var _a, _b;
2592
- logger$6.info(`Got offer from client ${data.clientId}, isInitialOffer: ${Boolean(data.message.isInitialOffer)}`);
2644
+ logger$7.info(`Got offer from client ${data.clientId}, isInitialOffer: ${Boolean(data.message.isInitialOffer)}`);
2593
2645
  const session = this._getSession(data.clientId);
2594
2646
  if (!session) {
2595
- logger$6.warn("No RTCPeerConnection on SDP_OFFER", data);
2647
+ logger$7.warn("No RTCPeerConnection on SDP_OFFER", data);
2596
2648
  return;
2597
2649
  }
2598
2650
  const sdp = {
@@ -2604,7 +2656,7 @@ class P2pRtcManager {
2604
2656
  session.pc.connectionState === "new" &&
2605
2657
  session.pc.iceConnectionState === "new" &&
2606
2658
  !session.connectionStatus) {
2607
- logger$6.info("We have asked for an initial offer, ignoring all others");
2659
+ logger$7.info("We have asked for an initial offer, ignoring all others");
2608
2660
  this.analytics.P2POffendingInitialOffer++;
2609
2661
  rtcStats.sendEvent("P2POffendingInitialOffer", { clientId: session.clientId });
2610
2662
  return;
@@ -2612,22 +2664,22 @@ class P2pRtcManager {
2612
2664
  (_b = (_a = session
2613
2665
  .handleOffer(sdp)
2614
2666
  .then((answer) => {
2615
- logger$6.info(`Sending answer to client ${data.clientId}`);
2667
+ logger$7.info(`Sending answer to client ${data.clientId}`);
2616
2668
  this._emitServerEvent(RELAY_MESSAGES.SDP_ANSWER, {
2617
2669
  receiverId: data.clientId,
2618
2670
  message: answer,
2619
2671
  });
2620
2672
  })).catch) === null || _b === void 0 ? void 0 : _b.call(_a, (e) => {
2621
- logger$6.error(e);
2673
+ logger$7.error(e);
2622
2674
  this.analytics.numPcOnOfferFailure++;
2623
2675
  });
2624
2676
  }),
2625
2677
  this._serverSocket.on(RELAY_MESSAGES.SDP_ANSWER, (data) => {
2626
2678
  var _a, _b;
2627
- logger$6.info(`Got answer from client ${data.clientId}`);
2679
+ logger$7.info(`Got answer from client ${data.clientId}`);
2628
2680
  const session = this._getSession(data.clientId);
2629
2681
  if (!session) {
2630
- logger$6.warn("No RTCPeerConnection on SDP_ANSWER", data);
2682
+ logger$7.warn("No RTCPeerConnection on SDP_ANSWER", data);
2631
2683
  return;
2632
2684
  }
2633
2685
  const sdp = {
@@ -2635,7 +2687,7 @@ class P2pRtcManager {
2635
2687
  type: data.message.type,
2636
2688
  };
2637
2689
  (_b = (_a = session.handleAnswer(sdp)) === null || _a === void 0 ? void 0 : _a.catch) === null || _b === void 0 ? void 0 : _b.call(_a, (e) => {
2638
- logger$6.warn("Could not set remote description from remote answer: ", e);
2690
+ logger$7.warn("Could not set remote description from remote answer: ", e);
2639
2691
  this.analytics.numPcOnAnswerFailure++;
2640
2692
  });
2641
2693
  }),
@@ -2723,12 +2775,12 @@ class P2pRtcManager {
2723
2775
  });
2724
2776
  }
2725
2777
  catch (error) {
2726
- logger$6.error("Error during setting jitter buffer target:", error);
2778
+ logger$7.error("Error during setting jitter buffer target:", error);
2727
2779
  }
2728
2780
  }
2729
2781
  _emitServerEvent(eventName, data) {
2730
2782
  if (this._closed) {
2731
- logger$6.warn("RtcManager closed. Will not send event", eventName, data);
2783
+ logger$7.warn("RtcManager closed. Will not send event", eventName, data);
2732
2784
  return;
2733
2785
  }
2734
2786
  if (this._features.awaitJoinRoomFinished && !this._serverSocket.joinRoomFinished) {
@@ -2833,7 +2885,7 @@ class P2pRtcManager {
2833
2885
  }
2834
2886
  }
2835
2887
  catch (error) {
2836
- logger$6.info("Error during parsing candidates! Error: ", { error });
2888
+ logger$7.info("Error during parsing candidates! Error: ", { error });
2837
2889
  }
2838
2890
  break;
2839
2891
  case "srflx":
@@ -2875,7 +2927,7 @@ class P2pRtcManager {
2875
2927
  if (pc.iceConnectionState === "new" || !session.connectionStatus) {
2876
2928
  return;
2877
2929
  }
2878
- logger$6.info(`onnegotiationneeded client ${clientId}`);
2930
+ logger$7.info(`onnegotiationneeded client ${clientId}`);
2879
2931
  this._negotiatePeerConnection({ clientId, session });
2880
2932
  };
2881
2933
  pc.ontrack = (event) => {
@@ -2900,7 +2952,7 @@ class P2pRtcManager {
2900
2952
  };
2901
2953
  pc.oniceconnectionstatechange = () => {
2902
2954
  var _a;
2903
- logger$6.info(`iceConnectionState changed to ${pc.iceConnectionState} for session ${session.clientId}`);
2955
+ logger$7.info(`iceConnectionState changed to ${pc.iceConnectionState} for session ${session.clientId}`);
2904
2956
  let newStatus;
2905
2957
  const currentStatus = session.connectionStatus;
2906
2958
  switch (pc.iceConnectionState) {
@@ -2955,7 +3007,7 @@ class P2pRtcManager {
2955
3007
  };
2956
3008
  pc.onconnectionstatechange = () => {
2957
3009
  var _a;
2958
- logger$6.info(`connectionState changed to ${pc.connectionState} for session ${session.clientId}`);
3010
+ logger$7.info(`connectionState changed to ${pc.connectionState} for session ${session.clientId}`);
2959
3011
  switch (pc.connectionState) {
2960
3012
  case "connected":
2961
3013
  (_a = session.registerConnected) === null || _a === void 0 ? void 0 : _a.call(session, {});
@@ -3012,7 +3064,7 @@ class P2pRtcManager {
3012
3064
  _cleanup(clientId) {
3013
3065
  const session = this._getSession(clientId);
3014
3066
  if (!session) {
3015
- logger$6.warn("No RTCPeerConnection in RTCManager.disconnect()", clientId);
3067
+ logger$7.warn("No RTCPeerConnection in RTCManager.disconnect()", clientId);
3016
3068
  return;
3017
3069
  }
3018
3070
  this.removeRemoteClientMediaPrefs(session.clientId);
@@ -3040,7 +3092,7 @@ class P2pRtcManager {
3040
3092
  if (!session.hasConnectedPeerConnection()) {
3041
3093
  if (session.pc.connectionState === "closed")
3042
3094
  return;
3043
- logger$6.info("Session doesn't have a connected PeerConnection, adding pending action!");
3095
+ logger$7.info("Session doesn't have a connected PeerConnection, adding pending action!");
3044
3096
  const promise = new Promise((resolve, reject) => {
3045
3097
  const action = () => __awaiter(this, void 0, void 0, function* () {
3046
3098
  try {
@@ -3059,7 +3111,7 @@ class P2pRtcManager {
3059
3111
  promises.push(session.replaceTrack(oldTrack, newTrack));
3060
3112
  });
3061
3113
  return Promise.all(promises).catch((error) => {
3062
- logger$6.error(String(error));
3114
+ logger$7.error(String(error));
3063
3115
  });
3064
3116
  }
3065
3117
  _removeStreamFromPeerConnections(stream) {
@@ -3107,7 +3159,7 @@ class P2pRtcManager {
3107
3159
  let session = this._getSession(clientId);
3108
3160
  let initialBandwidth = (session && session.bandwidth) || 0;
3109
3161
  if (session) {
3110
- logger$6.warn("Replacing peer session", clientId);
3162
+ logger$7.warn("Replacing peer session", clientId);
3111
3163
  this._cleanup(clientId);
3112
3164
  }
3113
3165
  else {
@@ -3178,13 +3230,13 @@ class P2pRtcManager {
3178
3230
  })));
3179
3231
  }
3180
3232
  catch (error) {
3181
- logger$6.error("Error during setting setCodecPreferences:", error);
3233
+ logger$7.error("Error during setting setCodecPreferences:", error);
3182
3234
  }
3183
3235
  });
3184
3236
  }
3185
3237
  _negotiatePeerConnection({ clientId, session, constraints, isInitialOffer = false, }) {
3186
3238
  if (!session) {
3187
- logger$6.warn("No RTCPeerConnection in negotiatePeerConnection()", clientId);
3239
+ logger$7.warn("No RTCPeerConnection in negotiatePeerConnection()", clientId);
3188
3240
  return;
3189
3241
  }
3190
3242
  const pc = session.pc;
@@ -3214,7 +3266,7 @@ class P2pRtcManager {
3214
3266
  offer.sdp = cleanSdp(offer.sdp);
3215
3267
  pc.setLocalDescription(offer)
3216
3268
  .catch((e) => {
3217
- logger$6.warn("RTCPeerConnection.setLocalDescription() failed with local offer", e);
3269
+ logger$7.warn("RTCPeerConnection.setLocalDescription() failed with local offer", e);
3218
3270
  this.analytics.numPcSldFailure++;
3219
3271
  throw e;
3220
3272
  })
@@ -3226,7 +3278,7 @@ class P2pRtcManager {
3226
3278
  type: offer.type,
3227
3279
  isInitialOffer,
3228
3280
  };
3229
- logger$6.info(`sending offer to client ${clientId}`);
3281
+ logger$7.info(`sending offer to client ${clientId}`);
3230
3282
  this._emitServerEvent(RELAY_MESSAGES.SDP_OFFER, {
3231
3283
  receiverId: clientId,
3232
3284
  message,
@@ -3234,7 +3286,7 @@ class P2pRtcManager {
3234
3286
  });
3235
3287
  })
3236
3288
  .catch((e) => {
3237
- logger$6.warn("RTCPeerConnection.createOffer() failed to create local offer", e);
3289
+ logger$7.warn("RTCPeerConnection.createOffer() failed to create local offer", e);
3238
3290
  }));
3239
3291
  }
3240
3292
  _withForcedRenegotiation(session, action) {
@@ -3276,7 +3328,7 @@ class P2pRtcManager {
3276
3328
  return bandwidth;
3277
3329
  }
3278
3330
  acceptNewStream({ streamId, clientId }) {
3279
- logger$6.info("acceptNewStream() [streamId: %s}, clientId: %s]", streamId, clientId);
3331
+ logger$7.info("acceptNewStream() [streamId: %s}, clientId: %s]", streamId, clientId);
3280
3332
  let session = this._getSession(clientId);
3281
3333
  if (session && streamId !== clientId) {
3282
3334
  return session;
@@ -3299,7 +3351,7 @@ class P2pRtcManager {
3299
3351
  return session;
3300
3352
  }
3301
3353
  disconnect(clientId) {
3302
- logger$6.info("disconnect() [clientId: %s]", clientId);
3354
+ logger$7.info("disconnect() [clientId: %s]", clientId);
3303
3355
  this._cleanup(clientId);
3304
3356
  this._changeBandwidthForAllClients(false);
3305
3357
  const numPeers = this.numberOfPeerconnections();
@@ -3336,7 +3388,7 @@ class P2pRtcManager {
3336
3388
  stopOrResumeVideo() {
3337
3389
  }
3338
3390
  removeScreenshareStream(stream, { requestedByClientId } = {}) {
3339
- logger$6.info("removeScreenshareStream() [stream.id: %s, requestedByClientId: %s]", stream.id, requestedByClientId);
3391
+ logger$7.info("removeScreenshareStream() [stream.id: %s, requestedByClientId: %s]", stream.id, requestedByClientId);
3340
3392
  this._removeStreamFromPeerConnections(stream);
3341
3393
  this._emitServerEvent(PROTOCOL_REQUESTS.STOP_SCREENSHARE, { streamId: stream.id, requestedByClientId });
3342
3394
  delete this._localScreenshareStream;
@@ -3457,7 +3509,7 @@ const defaultParams = {
3457
3509
  scoreFormula: "300 * bands[1].avg / Math.max(bands[1].avg + bands[0].avg, 0.01)",
3458
3510
  outFormula: "score",
3459
3511
  };
3460
- const logger$5 = new Logger();
3512
+ const logger$6 = new Logger();
3461
3513
  function createMicAnalyser({ micTrack, params, onScoreUpdated, }) {
3462
3514
  const audioCtx = new AudioContext();
3463
3515
  let analyser = null;
@@ -3479,7 +3531,7 @@ function createMicAnalyser({ micTrack, params, onScoreUpdated, }) {
3479
3531
  lastTrackWasOurs = true;
3480
3532
  }
3481
3533
  catch (ex) {
3482
- logger$5.warn("unable to fetch new track for colocation speaker analysis, using current", ex);
3534
+ logger$6.warn("unable to fetch new track for colocation speaker analysis, using current", ex);
3483
3535
  }
3484
3536
  }
3485
3537
  lastTrack = track;
@@ -3566,7 +3618,7 @@ function createMicAnalyser({ micTrack, params, onScoreUpdated, }) {
3566
3618
  };
3567
3619
  }
3568
3620
 
3569
- const logger$4 = new Logger();
3621
+ const logger$5 = new Logger();
3570
3622
  const MEDIA_QUALITY = Object.freeze({
3571
3623
  ok: "ok",
3572
3624
  warning: "warning",
@@ -3636,7 +3688,7 @@ class VegaMediaQualityMonitor extends EventEmitter {
3636
3688
  }
3637
3689
  addProducer(clientId, producerId) {
3638
3690
  if (!clientId || !producerId || !(typeof clientId === "string" && typeof producerId === "string")) {
3639
- logger$4.warn("Missing clientId or producerId");
3691
+ logger$5.warn("Missing clientId or producerId");
3640
3692
  return;
3641
3693
  }
3642
3694
  if (!this._producers[clientId]) {
@@ -3652,7 +3704,7 @@ class VegaMediaQualityMonitor extends EventEmitter {
3652
3704
  }
3653
3705
  addConsumer(clientId, consumerId) {
3654
3706
  if (!clientId || !consumerId) {
3655
- logger$4.warn("Missing clientId or consumerId");
3707
+ logger$5.warn("Missing clientId or consumerId");
3656
3708
  return;
3657
3709
  }
3658
3710
  if (!this._producers[clientId]) {
@@ -3670,14 +3722,14 @@ class VegaMediaQualityMonitor extends EventEmitter {
3670
3722
  if (!Array.isArray(score) ||
3671
3723
  score.length === 0 ||
3672
3724
  score.some((s) => !s || !s.hasOwnProperty("score") || typeof s.score !== "number" || isNaN(s.score))) {
3673
- logger$4.warn("Unexpected producer score format");
3725
+ logger$5.warn("Unexpected producer score format");
3674
3726
  return;
3675
3727
  }
3676
3728
  this._producers[clientId][producerId] = { kind, score: this._calcAvgProducerScore(score.map((s) => s.score)) };
3677
3729
  }
3678
3730
  addConsumerScore(clientId, consumerId, kind, score) {
3679
3731
  if (!score || !score.hasOwnProperty("producerScores") || !Array.isArray(score.producerScores)) {
3680
- logger$4.warn("Unexpected consumer score format");
3732
+ logger$5.warn("Unexpected consumer score format");
3681
3733
  return;
3682
3734
  }
3683
3735
  this._producers[clientId][consumerId] = { kind, score: this._calcAvgProducerScore(score.producerScores) };
@@ -3714,12 +3766,13 @@ class VegaMediaQualityMonitor extends EventEmitter {
3714
3766
  }
3715
3767
  }
3716
3768
  catch (error) {
3717
- logger$4.error(error);
3769
+ logger$5.error(error);
3718
3770
  return 0;
3719
3771
  }
3720
3772
  }
3721
3773
  }
3722
3774
 
3775
+ const logger$4 = new Logger();
3723
3776
  function getLayers({ width, height, }, { numberOfActiveVideos, numberOfTemporalLayers, uncappedSingleRemoteVideoOn, }) {
3724
3777
  const maxSide = Math.max(width, height);
3725
3778
  let spatialLayer = maxSide >= 480 ? (maxSide >= 960 ? 2 : 1) : 0;
@@ -3739,6 +3792,27 @@ function getLayers({ width, height, }, { numberOfActiveVideos, numberOfTemporalL
3739
3792
  }
3740
3793
  return { spatialLayer, temporalLayer };
3741
3794
  }
3795
+ function createMetricStats() {
3796
+ return { count: 0, sum: 0 };
3797
+ }
3798
+ function recordMetricSample(stats, value) {
3799
+ stats.count++;
3800
+ stats.sum += value;
3801
+ }
3802
+ function aggregateMetricStats(stats) {
3803
+ return {
3804
+ count: stats.count,
3805
+ avg: stats.count ? Math.round(stats.sum / stats.count) : undefined,
3806
+ };
3807
+ }
3808
+ function getPacketWeightedFractionLost(reports) {
3809
+ const weights = reports.map(({ packetRate }) => (packetRate && packetRate > 0 ? packetRate : 0));
3810
+ const totalWeight = weights.reduce((sum, weight) => sum + weight, 0);
3811
+ if (!totalWeight) {
3812
+ return reports.reduce((sum, { fractionLost }) => sum + (fractionLost || 0), 0) / (reports.length || 1);
3813
+ }
3814
+ return (reports.reduce((sum, { fractionLost }, index) => sum + (fractionLost || 0) * weights[index], 0) / totalWeight);
3815
+ }
3742
3816
  function getNumberOfActiveVideos(consumers) {
3743
3817
  let numberOfActiveVideos = 0;
3744
3818
  consumers.forEach((c) => {
@@ -3754,6 +3828,51 @@ function getNumberOfTemporalLayers(consumer) {
3754
3828
  var _a, _b, _c;
3755
3829
  return /T3/.test(((_c = (_b = (_a = consumer._rtpParameters) === null || _a === void 0 ? void 0 : _a.encodings) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.scalabilityMode) || "") ? 3 : 2;
3756
3830
  }
3831
+ const SCALABILITY_MODE_REGEX = /^([LS])([1-9]\d?)T([1-9]\d?)(_KEY)?$/;
3832
+ function getTopSpatialLayer(encodings) {
3833
+ if (encodings.length > 1)
3834
+ return encodings.length - 1;
3835
+ const { scalabilityMode } = encodings[0];
3836
+ const match = SCALABILITY_MODE_REGEX.exec(scalabilityMode || "");
3837
+ if (!match) {
3838
+ if (scalabilityMode) {
3839
+ logger$4.warn("getTopSpatialLayer() unrecognized scalabilityMode %s, using a single spatial layer", scalabilityMode);
3840
+ }
3841
+ return 0;
3842
+ }
3843
+ const spatialLayers = Number(match[2]) || 1;
3844
+ return spatialLayers - 1;
3845
+ }
3846
+ function getInitialHighestPreferredLayer(encodings) {
3847
+ return Math.min(getTopSpatialLayer(encodings), INITIAL_HIGHEST_PREFERRED_LAYER);
3848
+ }
3849
+ function getReducedSvcEncodingParams(originalScalabilityMode, spatialLayer, originalMaxBitrate) {
3850
+ const match = SCALABILITY_MODE_REGEX.exec(originalScalabilityMode || "");
3851
+ if (!match)
3852
+ return undefined;
3853
+ const [, mode, originalSpatialLayers, temporalLayers, key = ""] = match;
3854
+ const topLayerIndex = Number(originalSpatialLayers) - 1;
3855
+ if (topLayerIndex === 0)
3856
+ return undefined;
3857
+ const preferredLayerIndex = Math.min(Math.max(spatialLayer, 0), topLayerIndex);
3858
+ const onlyLowestLayerPreferred = preferredLayerIndex === 0;
3859
+ const middleLayerPreferred = preferredLayerIndex > 0 && preferredLayerIndex < topLayerIndex;
3860
+ let maxBitrate = originalMaxBitrate;
3861
+ if (onlyLowestLayerPreferred) {
3862
+ maxBitrate = Math.min(LOWEST_SVC_LAYER_MAX_BITRATE, originalMaxBitrate !== null && originalMaxBitrate !== void 0 ? originalMaxBitrate : Infinity);
3863
+ }
3864
+ else if (middleLayerPreferred) {
3865
+ maxBitrate = Math.min(MIDDLE_SVC_LAYER_MAX_BITRATE, originalMaxBitrate !== null && originalMaxBitrate !== void 0 ? originalMaxBitrate : Infinity);
3866
+ }
3867
+ const scalabilityMode = onlyLowestLayerPreferred
3868
+ ? `L1T${temporalLayers}`
3869
+ : `${mode}${preferredLayerIndex + 1}T${temporalLayers}${key}`;
3870
+ return {
3871
+ scalabilityMode,
3872
+ scaleResolutionDownBy: Math.pow(2, (topLayerIndex - preferredLayerIndex)),
3873
+ maxBitrate,
3874
+ };
3875
+ }
3757
3876
  function addProducerCpuOveruseWatch({ producer, onOveruse }) {
3758
3877
  var _a;
3759
3878
  const encodings = (_a = producer.rtpParameters) === null || _a === void 0 ? void 0 : _a.encodings;
@@ -4210,6 +4329,7 @@ const RESTARTICE_ERROR_RETRY_THRESHOLD_IN_MS = 3500;
4210
4329
  const RESTARTICE_ERROR_MAX_RETRY_COUNT = 5;
4211
4330
  const OUTBOUND_CAM_OUTBOUND_STREAM_ID = v4$1();
4212
4331
  const OUTBOUND_SCREEN_OUTBOUND_STREAM_ID = v4$1();
4332
+ const getFrameArea = (frameSize) => { var _a, _b; return ((_a = frameSize === null || frameSize === void 0 ? void 0 : frameSize.width) !== null && _a !== void 0 ? _a : 0) * ((_b = frameSize === null || frameSize === void 0 ? void 0 : frameSize.height) !== null && _b !== void 0 ? _b : 0); };
4213
4333
  if (browserName === "chrome")
4214
4334
  window.document.addEventListener("beforeunload", () => (unloading = true));
4215
4335
  class VegaRtcManager {
@@ -4247,6 +4367,11 @@ class VegaRtcManager {
4247
4367
  this._micScoreProducer = null;
4248
4368
  this._micScoreProducerPromise = null;
4249
4369
  this._webcamProducer = null;
4370
+ this._webcamProducerOriginalSvcScalabilityMode = undefined;
4371
+ this._webcamProducerOriginalSvcMaxBitrate = undefined;
4372
+ this._webcamProducerHighestPreferredLayer = undefined;
4373
+ this._highestPreferredLayerUpdate = null;
4374
+ this._highestPreferredLayerUpdatePending = false;
4250
4375
  this._webcamProducerPromise = null;
4251
4376
  this._webcamPaused = false;
4252
4377
  this._screenVideoProducer = null;
@@ -4288,12 +4413,19 @@ class VegaRtcManager {
4288
4413
  };
4289
4414
  (_a = window === null || window === void 0 ? void 0 : window.addEventListener) === null || _a === void 0 ? void 0 : _a.call(window, "offline", this._sfuZombie.onBrowserOffline);
4290
4415
  this.analytics = {
4416
+ avgPreferredLayerSwitchLatencyMs: undefined,
4417
+ camOutboundCongestedFraction: undefined,
4418
+ camOutboundRttInflationMs: undefined,
4291
4419
  camTrackEndedCount: 0,
4420
+ highestPreferredLayerChangeCounts: {},
4292
4421
  micTrackEndedCount: 0,
4422
+ numHighestPreferredLayerChanges: 0,
4293
4423
  numIceConnected: 0,
4294
4424
  numIceDisconnected: 0,
4295
4425
  numIceFailed: 0,
4296
4426
  numNewPc: 0,
4427
+ numPreferredSpatialLayerChanges: 0,
4428
+ preferredSpatialLayerChangeCounts: {},
4297
4429
  sfuMsFromOfflineToClose: 0,
4298
4430
  sfuOfflineToCloseCount: 0,
4299
4431
  sfuOfflineWhileConnectedCount: 0,
@@ -4313,6 +4445,15 @@ class VegaRtcManager {
4313
4445
  vegaUnknownResponse: 0,
4314
4446
  vegaWebcamProducerFailed: 0,
4315
4447
  };
4448
+ this._preferredLayerSwitchLatencyStats = createMetricStats();
4449
+ this._preferredLayerSwitchWatches = new Map();
4450
+ this._lastSeenRemoteReportTimestamps = new Map();
4451
+ this._camOutboundCandidatePairId = undefined;
4452
+ this._camOutboundSamplesToSkip = 0;
4453
+ this._camOutboundPathRtt = { sumMs: 0, count: 0, minMs: undefined };
4454
+ this._camOutboundRttInflation = { sumMs: 0, count: 0 };
4455
+ this._camOutboundSamples = { total: 0, congested: 0 };
4456
+ this._statsSubscription = null;
4316
4457
  }
4317
4458
  _updateAndScheduleMediaServersRefresh({ iceServers, turnServers, sfuServer, mediaserverConfigTtlSeconds, }) {
4318
4459
  var _a, _b, _c, _d;
@@ -4482,7 +4623,6 @@ class VegaRtcManager {
4482
4623
  this._sendTransport = null;
4483
4624
  this._receiveTransport = null;
4484
4625
  this._streamIdToVideoConsumerId.clear();
4485
- this._streamIdToVideoResolution.clear();
4486
4626
  if (this._reconnect) {
4487
4627
  this._reconnectTimeOut = setTimeout(() => this._connect(), 1000);
4488
4628
  }
@@ -4905,6 +5045,14 @@ class VegaRtcManager {
4905
5045
  const simulcastLayer3ShouldBeActive = !this._cpuOveruseDetected;
4906
5046
  const params = this._webcamProducer.rtpParameters;
4907
5047
  if (((_a = params === null || params === void 0 ? void 0 : params.encodings) === null || _a === void 0 ? void 0 : _a.length) === 3) {
5048
+ if (this._features.sfuHighestPreferredLayerTrackingOn) {
5049
+ this._syncWebcamEncoderToHighestPreferredLayer();
5050
+ rtcStats.sendEvent("simulcast_layer_activation_changed", {
5051
+ layerIndex: 2,
5052
+ active: simulcastLayer3ShouldBeActive,
5053
+ });
5054
+ return;
5055
+ }
4908
5056
  const targetMaxSpatialLayer = simulcastLayer3ShouldBeActive ? 2 : 1;
4909
5057
  if (this._webcamProducer.maxSpatialLayer !== targetMaxSpatialLayer) {
4910
5058
  this._webcamProducer.setMaxSpatialLayer(targetMaxSpatialLayer);
@@ -4927,7 +5075,7 @@ class VegaRtcManager {
4927
5075
  return;
4928
5076
  }
4929
5077
  this._webcamProducerPromise = (() => __awaiter(this, void 0, void 0, function* () {
4930
- var _a;
5078
+ var _a, _b, _c;
4931
5079
  try {
4932
5080
  const currentPaused = this._webcamPaused;
4933
5081
  if (!this._sendTransport) {
@@ -4953,6 +5101,16 @@ class VegaRtcManager {
4953
5101
  })
4954
5102
  : () => { };
4955
5103
  this._webcamProducer = producer;
5104
+ if (this._features.sfuHighestPreferredLayerTrackingOn) {
5105
+ const originalWebcamEncodings = (_b = (_a = producer.rtpSender) === null || _a === void 0 ? void 0 : _a.getParameters()) === null || _b === void 0 ? void 0 : _b.encodings;
5106
+ const svcEncoding = (originalWebcamEncodings === null || originalWebcamEncodings === void 0 ? void 0 : originalWebcamEncodings.length) === 1 ? originalWebcamEncodings[0] : undefined;
5107
+ this._webcamProducerOriginalSvcScalabilityMode = svcEncoding === null || svcEncoding === void 0 ? void 0 : svcEncoding.scalabilityMode;
5108
+ this._webcamProducerOriginalSvcMaxBitrate = svcEncoding === null || svcEncoding === void 0 ? void 0 : svcEncoding.maxBitrate;
5109
+ this._webcamProducerHighestPreferredLayer = (originalWebcamEncodings === null || originalWebcamEncodings === void 0 ? void 0 : originalWebcamEncodings.length)
5110
+ ? getInitialHighestPreferredLayer(originalWebcamEncodings)
5111
+ : undefined;
5112
+ this._syncWebcamEncoderToHighestPreferredLayer();
5113
+ }
4956
5114
  this._qualityMonitor.addProducer(this._selfId, producer.id);
4957
5115
  producer.observer.once("close", () => {
4958
5116
  var _a;
@@ -4960,11 +5118,16 @@ class VegaRtcManager {
4960
5118
  if (producer.appData.localClosed)
4961
5119
  (_a = this._vegaConnection) === null || _a === void 0 ? void 0 : _a.message("closeProducers", { producerIds: [producer.id] });
4962
5120
  cleanUpCpuWatch();
5121
+ this._stopWebcamStatsSubscription();
4963
5122
  this._webcamProducer = null;
5123
+ this._webcamProducerOriginalSvcScalabilityMode = undefined;
5124
+ this._webcamProducerOriginalSvcMaxBitrate = undefined;
5125
+ this._webcamProducerHighestPreferredLayer = undefined;
4964
5126
  this._webcamProducerPromise = null;
4965
5127
  this._qualityMonitor.removeProducer(this._selfId, producer.id);
4966
5128
  });
4967
- if (this._webcamTrack && this._webcamTrack !== ((_a = this._webcamProducer) === null || _a === void 0 ? void 0 : _a.track)) {
5129
+ this._startWebcamStatsSubscription();
5130
+ if (this._webcamTrack && this._webcamTrack !== ((_c = this._webcamProducer) === null || _c === void 0 ? void 0 : _c.track)) {
4968
5131
  this._webcamProducerPromise = null;
4969
5132
  this._replaceWebcamTrack();
4970
5133
  }
@@ -4981,6 +5144,9 @@ class VegaRtcManager {
4981
5144
  if (!this._webcamTrack) {
4982
5145
  this._stopProducer(this._webcamProducer);
4983
5146
  this._webcamProducer = null;
5147
+ this._webcamProducerOriginalSvcScalabilityMode = undefined;
5148
+ this._webcamProducerOriginalSvcMaxBitrate = undefined;
5149
+ this._webcamProducerHighestPreferredLayer = undefined;
4984
5150
  }
4985
5151
  }
4986
5152
  }))();
@@ -5232,6 +5398,7 @@ class VegaRtcManager {
5232
5398
  if (clientState) {
5233
5399
  clientState.hasAcceptedWebcamStream = false;
5234
5400
  clientState.hasAcceptedScreenStream = false;
5401
+ [clientState.webcamStream, clientState.screenStream].forEach((stream) => stream && this._streamIdToVideoResolution.delete(stream.id));
5235
5402
  this._syncIncomingStreamsWithPWA(clientId);
5236
5403
  }
5237
5404
  if (eventClaim) {
@@ -5355,6 +5522,9 @@ class VegaRtcManager {
5355
5522
  if (this._webcamProducer && !this._webcamProducer.closed && this._webcamProducer.track === track) {
5356
5523
  this._stopProducer(this._webcamProducer);
5357
5524
  this._webcamProducer = null;
5525
+ this._webcamProducerOriginalSvcScalabilityMode = undefined;
5526
+ this._webcamProducerOriginalSvcMaxBitrate = undefined;
5527
+ this._webcamProducerHighestPreferredLayer = undefined;
5358
5528
  this._webcamTrack = null;
5359
5529
  }
5360
5530
  }
@@ -5382,14 +5552,18 @@ class VegaRtcManager {
5382
5552
  this._syncIncomingStreamsWithPWA(clientId);
5383
5553
  }
5384
5554
  updateStreamResolution(streamId, _ignored, { width, height, }) {
5385
- var _a, _b, _c;
5386
5555
  logger$2.info("updateStreamResolution()", { streamId, width, height });
5556
+ this._streamIdToVideoResolution.set(streamId, { width, height });
5557
+ this._applyStreamResolution(streamId);
5558
+ }
5559
+ _applyStreamResolution(streamId) {
5560
+ var _a, _b, _c;
5561
+ const resolution = this._streamIdToVideoResolution.get(streamId);
5387
5562
  const consumerId = this._streamIdToVideoConsumerId.get(streamId);
5388
5563
  const consumer = this._consumers.get(consumerId);
5389
- if (!consumer) {
5390
- this._streamIdToVideoResolution.set(streamId, { width, height });
5564
+ if (!resolution || !consumer)
5391
5565
  return;
5392
- }
5566
+ const { width, height } = resolution;
5393
5567
  updateRenderedDimensions((_a = consumer.track) === null || _a === void 0 ? void 0 : _a.id, { width, height, time: Date.now() });
5394
5568
  const numberOfActiveVideos = getNumberOfActiveVideos(this._consumers);
5395
5569
  const numberOfTemporalLayers = getNumberOfTemporalLayers(consumer);
@@ -5399,6 +5573,12 @@ class VegaRtcManager {
5399
5573
  uncappedSingleRemoteVideoOn: (_b = this._features) === null || _b === void 0 ? void 0 : _b.uncappedSingleRemoteVideoOn,
5400
5574
  });
5401
5575
  if (consumer.appData.spatialLayer !== spatialLayer || consumer.appData.temporalLayer !== temporalLayer) {
5576
+ const previousSpatialLayer = consumer.appData.spatialLayer;
5577
+ const spatialLayerChanged = previousSpatialLayer !== spatialLayer;
5578
+ if (spatialLayerChanged) {
5579
+ this.analytics.numPreferredSpatialLayerChanges++;
5580
+ this._incrementHistogramCount(this.analytics.preferredSpatialLayerChangeCounts, `${previousSpatialLayer}->${spatialLayer}`);
5581
+ }
5402
5582
  consumer.appData.spatialLayer = spatialLayer;
5403
5583
  consumer.appData.temporalLayer = temporalLayer;
5404
5584
  (_c = this._vegaConnection) === null || _c === void 0 ? void 0 : _c.message("setConsumersPreferredLayers", {
@@ -5406,7 +5586,178 @@ class VegaRtcManager {
5406
5586
  spatialLayer,
5407
5587
  temporalLayer,
5408
5588
  });
5589
+ if (spatialLayerChanged) {
5590
+ this._watchForPreferredLayerSwitch(consumerId, consumer, {
5591
+ toHigherLayer: spatialLayer > previousSpatialLayer,
5592
+ });
5593
+ }
5594
+ }
5595
+ }
5596
+ _watchForPreferredLayerSwitch(consumerId, consumer, { toHigherLayer }) {
5597
+ const previousWatch = this._preferredLayerSwitchWatches.get(consumerId);
5598
+ if (!previousWatch && this._preferredLayerSwitchWatches.size >= MAX_CONCURRENT_PREFERRED_LAYER_SWITCH_WATCHES) {
5599
+ return;
5600
+ }
5601
+ previousWatch === null || previousWatch === void 0 ? void 0 : previousWatch.stop();
5602
+ let stopped = false;
5603
+ let intervalId;
5604
+ const stop = () => {
5605
+ if (stopped)
5606
+ return;
5607
+ stopped = true;
5608
+ clearInterval(intervalId);
5609
+ clearTimeout(timeoutId);
5610
+ this._preferredLayerSwitchWatches.delete(consumerId);
5611
+ };
5612
+ this._preferredLayerSwitchWatches.set(consumerId, { stop });
5613
+ const timeoutId = setTimeout(stop, PREFERRED_LAYER_SWITCH_WATCH_TIMEOUT_MS);
5614
+ (() => __awaiter(this, void 0, void 0, function* () {
5615
+ const sentAt = Date.now();
5616
+ const baseline = yield this._getConsumerFrameSize(consumer);
5617
+ if (stopped || !(baseline === null || baseline === void 0 ? void 0 : baseline.width) || !(baseline === null || baseline === void 0 ? void 0 : baseline.height)) {
5618
+ stop();
5619
+ return;
5620
+ }
5621
+ let polling = false;
5622
+ intervalId = setInterval(() => __awaiter(this, void 0, void 0, function* () {
5623
+ if (stopped || consumer.closed) {
5624
+ stop();
5625
+ return;
5626
+ }
5627
+ if (polling)
5628
+ return;
5629
+ polling = true;
5630
+ const current = yield this._getConsumerFrameSize(consumer);
5631
+ polling = false;
5632
+ if (stopped)
5633
+ return;
5634
+ const switched = toHigherLayer
5635
+ ? getFrameArea(current) > getFrameArea(baseline)
5636
+ : getFrameArea(current) < getFrameArea(baseline);
5637
+ if (current && switched) {
5638
+ this._recordPreferredLayerSwitchLatency(Date.now() - sentAt);
5639
+ stop();
5640
+ }
5641
+ }), PREFERRED_LAYER_SWITCH_POLL_INTERVAL_MS);
5642
+ }))();
5643
+ }
5644
+ _getConsumerFrameSize(consumer) {
5645
+ return __awaiter(this, void 0, void 0, function* () {
5646
+ try {
5647
+ const stats = yield consumer.getStats();
5648
+ let frameSize;
5649
+ stats.forEach((report) => {
5650
+ if (report.type === "inbound-rtp") {
5651
+ frameSize = { width: report.frameWidth, height: report.frameHeight };
5652
+ }
5653
+ });
5654
+ return frameSize;
5655
+ }
5656
+ catch (error) {
5657
+ logger$2.warn("_getConsumerFrameSize() failed to read stats", { error });
5658
+ return undefined;
5659
+ }
5660
+ });
5661
+ }
5662
+ _recordPreferredLayerSwitchLatency(latencyMs) {
5663
+ recordMetricSample(this._preferredLayerSwitchLatencyStats, latencyMs);
5664
+ const { avg } = aggregateMetricStats(this._preferredLayerSwitchLatencyStats);
5665
+ this.analytics.avgPreferredLayerSwitchLatencyMs = avg;
5666
+ }
5667
+ _onUpdatedStats(statsByView) {
5668
+ var _a, _b, _c, _d;
5669
+ const webcamProducerMid = (_b = (_a = this._webcamProducer) === null || _a === void 0 ? void 0 : _a.rtpParameters) === null || _b === void 0 ? void 0 : _b.mid;
5670
+ if (webcamProducerMid === undefined)
5671
+ return;
5672
+ const sendTransportPc = (_d = (_c = this._sendTransport) === null || _c === void 0 ? void 0 : _c.handler) === null || _d === void 0 ? void 0 : _d._pc;
5673
+ const sendTransportPcIndex = sendTransportPc ? getPeerConnectionIndex(sendTransportPc) : undefined;
5674
+ const newRemoteReports = [];
5675
+ Object.values(statsByView).forEach((viewStats) => {
5676
+ Object.values(viewStats.tracks || {}).forEach((trackStats) => {
5677
+ Object.entries(trackStats.ssrcs || {}).forEach(([ssrc, ssrcMetrics]) => {
5678
+ if (ssrcMetrics.direction !== "out" || String(ssrcMetrics.mid) !== webcamProducerMid)
5679
+ return;
5680
+ if (sendTransportPcIndex !== undefined && ssrcMetrics.pcIndex !== sendTransportPcIndex)
5681
+ return;
5682
+ this._followCamOutboundCandidatePair(ssrcMetrics);
5683
+ const { remoteReportTimestamp } = ssrcMetrics;
5684
+ if (remoteReportTimestamp === undefined)
5685
+ return;
5686
+ if (remoteReportTimestamp === this._lastSeenRemoteReportTimestamps.get(ssrc))
5687
+ return;
5688
+ this._lastSeenRemoteReportTimestamps.set(ssrc, remoteReportTimestamp);
5689
+ newRemoteReports.push(ssrcMetrics);
5690
+ });
5691
+ });
5692
+ });
5693
+ if (!newRemoteReports.length)
5694
+ return;
5695
+ if (this._camOutboundSamplesToSkip > 0) {
5696
+ this._camOutboundSamplesToSkip--;
5697
+ return;
5409
5698
  }
5699
+ this._recordCamOutboundSample(newRemoteReports);
5700
+ this._updateCamOutboundAnalytics();
5701
+ }
5702
+ _recordCamOutboundSample(newRemoteReports) {
5703
+ var _a, _b;
5704
+ const rttsMs = newRemoteReports.map(({ roundTripTime }) => (roundTripTime || 0) * 1000).filter((ms) => ms > 0);
5705
+ const rttMs = rttsMs.length ? Math.max(...rttsMs) : undefined;
5706
+ const fractionLost = getPacketWeightedFractionLost(newRemoteReports);
5707
+ const path = this._camOutboundPathRtt;
5708
+ if (rttMs !== undefined) {
5709
+ path.sumMs += rttMs;
5710
+ path.count++;
5711
+ path.minMs = Math.min((_a = path.minMs) !== null && _a !== void 0 ? _a : Infinity, rttMs);
5712
+ }
5713
+ const congested = (rttMs !== undefined && rttMs - ((_b = path.minMs) !== null && _b !== void 0 ? _b : rttMs) > CONGESTED_RTT_INFLATION_MS) ||
5714
+ fractionLost > CONGESTED_FRACTION_LOST;
5715
+ this._camOutboundSamples.total++;
5716
+ if (congested)
5717
+ this._camOutboundSamples.congested++;
5718
+ }
5719
+ _followCamOutboundCandidatePair({ selectedCandidatePairId }) {
5720
+ if (!selectedCandidatePairId || selectedCandidatePairId === this._camOutboundCandidatePairId)
5721
+ return;
5722
+ if (this._camOutboundCandidatePairId !== undefined) {
5723
+ this._finishCamOutboundRttPath();
5724
+ this._camOutboundSamplesToSkip = CAM_SAMPLES_SKIPPED_AFTER_CANDIDATE_PAIR_CHANGE;
5725
+ }
5726
+ this._camOutboundCandidatePairId = selectedCandidatePairId;
5727
+ }
5728
+ _finishCamOutboundRttPath() {
5729
+ const path = this._camOutboundPathRtt;
5730
+ if (path.count && path.minMs !== undefined) {
5731
+ this._camOutboundRttInflation.sumMs += path.sumMs - path.count * path.minMs;
5732
+ this._camOutboundRttInflation.count += path.count;
5733
+ }
5734
+ this._camOutboundPathRtt = { sumMs: 0, count: 0, minMs: undefined };
5735
+ }
5736
+ _updateCamOutboundAnalytics() {
5737
+ const path = this._camOutboundPathRtt;
5738
+ const inflationSumMs = this._camOutboundRttInflation.sumMs + (path.minMs !== undefined ? path.sumMs - path.count * path.minMs : 0);
5739
+ const inflationCount = this._camOutboundRttInflation.count + path.count;
5740
+ this.analytics.camOutboundRttInflationMs = inflationCount
5741
+ ? Math.round(inflationSumMs / inflationCount)
5742
+ : undefined;
5743
+ const { congested, total } = this._camOutboundSamples;
5744
+ this.analytics.camOutboundCongestedFraction = total ? congested / total : undefined;
5745
+ }
5746
+ _startWebcamStatsSubscription() {
5747
+ if (this._statsSubscription)
5748
+ return;
5749
+ this._statsSubscription = subscribeStats({
5750
+ onUpdatedStats: (statsByView) => this._onUpdatedStats(statsByView),
5751
+ });
5752
+ }
5753
+ _stopWebcamStatsSubscription() {
5754
+ var _a;
5755
+ (_a = this._statsSubscription) === null || _a === void 0 ? void 0 : _a.stop();
5756
+ this._statsSubscription = null;
5757
+ this._lastSeenRemoteReportTimestamps.clear();
5758
+ this._finishCamOutboundRttPath();
5759
+ this._camOutboundCandidatePairId = undefined;
5760
+ this._camOutboundSamplesToSkip = 0;
5410
5761
  }
5411
5762
  close() {
5412
5763
  this.disconnectAll();
@@ -5437,8 +5788,11 @@ class VegaRtcManager {
5437
5788
  this._screenVideoTrack = null;
5438
5789
  this._screenAudioTrack = null;
5439
5790
  this._streamIdToVideoConsumerId.clear();
5791
+ this._streamIdToVideoResolution.clear();
5440
5792
  this._mediasoupDeviceInitializedAsync = Promise.resolve(null);
5441
5793
  this._qualityMonitor.close();
5794
+ this._stopWebcamStatsSubscription();
5795
+ this._preferredLayerSwitchWatches.forEach(({ stop }) => stop());
5442
5796
  }
5443
5797
  sendStatsCustomEvent(eventName, data) {
5444
5798
  rtcStats.sendEvent(eventName, data);
@@ -5496,6 +5850,8 @@ class VegaRtcManager {
5496
5850
  return this._onConsumerScore(data);
5497
5851
  case "producerScore":
5498
5852
  return this._onProducerScore(data);
5853
+ case "changedHighestPreferredLayer":
5854
+ return this._onChangedHighestPreferredLayer(data);
5499
5855
  default:
5500
5856
  logger$2.info(`unknown message method "${method}"`);
5501
5857
  return;
@@ -5523,13 +5879,16 @@ class VegaRtcManager {
5523
5879
  }
5524
5880
  consumer.pause();
5525
5881
  consumer.appData.localPaused = true;
5526
- consumer.appData.spatialLayer = 2;
5882
+ consumer.appData.spatialLayer = INITIAL_CONSUMER_SPATIAL_LAYER;
5527
5883
  this._consumers.set(consumer.id, consumer);
5528
5884
  this._qualityMonitor.addConsumer(consumer.appData.sourceClientId, consumer.id);
5529
5885
  consumer.observer.once("close", () => {
5530
5886
  this._consumers.delete(consumer.id);
5531
5887
  this._qualityMonitor.removeConsumer(consumer.appData.sourceClientId, consumer.id);
5532
5888
  this._consumerClosedCleanup(consumer);
5889
+ if (consumer.kind === "video" && this._receiveTransport && !this._receiveTransport.closed) {
5890
+ this._reapplyStreamResolutions();
5891
+ }
5533
5892
  });
5534
5893
  if (this._features.increaseIncomingMediaBufferOn && consumer.rtpReceiver) {
5535
5894
  try {
@@ -5561,13 +5920,12 @@ class VegaRtcManager {
5561
5920
  }
5562
5921
  stream.addTrack(consumer.track);
5563
5922
  this._syncIncomingStreamsWithPWA(clientId);
5564
- const resolution = this._streamIdToVideoResolution.get(stream.id);
5565
- if (resolution) {
5566
- this.updateStreamResolution(stream.id, null, resolution);
5567
- this._streamIdToVideoResolution.delete(stream.id);
5568
- }
5923
+ this._reapplyStreamResolutions();
5569
5924
  });
5570
5925
  }
5926
+ _reapplyStreamResolutions() {
5927
+ this._streamIdToVideoResolution.forEach((_resolution, streamId) => this._applyStreamResolution(streamId));
5928
+ }
5571
5929
  _onConsumerClosed(_a) {
5572
5930
  return __awaiter(this, arguments, void 0, function* ({ consumerId, reason }) {
5573
5931
  var _b;
@@ -5582,6 +5940,8 @@ class VegaRtcManager {
5582
5940
  return;
5583
5941
  consumer.appData.remotePaused = true;
5584
5942
  consumer.pause();
5943
+ if (consumer.kind === "video")
5944
+ this._reapplyStreamResolutions();
5585
5945
  }
5586
5946
  _onConsumerResumed({ consumerId }) {
5587
5947
  logger$2.info("_onConsumerResumed()", { consumerId });
@@ -5592,6 +5952,8 @@ class VegaRtcManager {
5592
5952
  if (!consumer.appData.localPaused) {
5593
5953
  consumer.resume();
5594
5954
  }
5955
+ if (consumer.kind === "video")
5956
+ this._reapplyStreamResolutions();
5595
5957
  }
5596
5958
  _onConsumerScore({ consumerId, kind, score }) {
5597
5959
  logger$2.info("_onConsumerScore()", { consumerId, kind, score });
@@ -5608,6 +5970,90 @@ class VegaRtcManager {
5608
5970
  }
5609
5971
  });
5610
5972
  }
5973
+ _getSvcEncodingUpdate(encoding, spatialLayer) {
5974
+ var _a;
5975
+ const reduced = getReducedSvcEncodingParams(this._webcamProducerOriginalSvcScalabilityMode, spatialLayer, this._webcamProducerOriginalSvcMaxBitrate);
5976
+ if (!reduced)
5977
+ return undefined;
5978
+ const changed = reduced.scalabilityMode !== encoding.scalabilityMode ||
5979
+ reduced.scaleResolutionDownBy !== ((_a = encoding.scaleResolutionDownBy) !== null && _a !== void 0 ? _a : 1) ||
5980
+ reduced.maxBitrate !== encoding.maxBitrate;
5981
+ return changed ? reduced : undefined;
5982
+ }
5983
+ _onChangedHighestPreferredLayer(_a) {
5984
+ return __awaiter(this, arguments, void 0, function* ({ producerId, spatialLayer }) {
5985
+ var _b;
5986
+ if (!this._features.sfuHighestPreferredLayerTrackingOn)
5987
+ return;
5988
+ if (((_b = this._webcamProducer) === null || _b === void 0 ? void 0 : _b.id) !== producerId)
5989
+ return;
5990
+ if (!Number.isFinite(spatialLayer)) {
5991
+ logger$2.warn("_onChangedHighestPreferredLayer() ignoring invalid spatialLayer", {
5992
+ producerId,
5993
+ spatialLayer,
5994
+ });
5995
+ return;
5996
+ }
5997
+ if (this._webcamProducerHighestPreferredLayer !== undefined &&
5998
+ this._webcamProducerHighestPreferredLayer !== spatialLayer) {
5999
+ this.analytics.numHighestPreferredLayerChanges++;
6000
+ this._incrementHistogramCount(this.analytics.highestPreferredLayerChangeCounts, `${this._webcamProducerHighestPreferredLayer}->${spatialLayer}`);
6001
+ }
6002
+ this._webcamProducerHighestPreferredLayer = spatialLayer;
6003
+ logger$2.info("_onChangedHighestPreferredLayer()", { producerId, spatialLayer });
6004
+ return this._syncWebcamEncoderToHighestPreferredLayer();
6005
+ });
6006
+ }
6007
+ _syncWebcamEncoderToHighestPreferredLayer() {
6008
+ this._highestPreferredLayerUpdatePending = true;
6009
+ if (!this._highestPreferredLayerUpdate) {
6010
+ this._highestPreferredLayerUpdate = this._applyPendingHighestPreferredLayerUpdates();
6011
+ }
6012
+ return this._highestPreferredLayerUpdate;
6013
+ }
6014
+ _applyPendingHighestPreferredLayerUpdates() {
6015
+ return __awaiter(this, void 0, void 0, function* () {
6016
+ while (this._highestPreferredLayerUpdatePending) {
6017
+ this._highestPreferredLayerUpdatePending = false;
6018
+ try {
6019
+ yield this._applyHighestPreferredLayerToWebcamEncoder();
6020
+ }
6021
+ catch (error) {
6022
+ logger$2.error("Failed to apply highest preferred layer: %o", error);
6023
+ }
6024
+ }
6025
+ this._highestPreferredLayerUpdate = null;
6026
+ });
6027
+ }
6028
+ _applyHighestPreferredLayerToWebcamEncoder() {
6029
+ return __awaiter(this, void 0, void 0, function* () {
6030
+ const producer = this._webcamProducer;
6031
+ const highestPreferredLayer = this._webcamProducerHighestPreferredLayer;
6032
+ if (!producer || highestPreferredLayer === undefined)
6033
+ return;
6034
+ const encodings = producer.rtpSender.getParameters().encodings;
6035
+ if (encodings.length > 1) {
6036
+ const cpuOveruseLimit = this._cpuOveruseDetected && encodings.length === 3 ? 1 : Infinity;
6037
+ const spatialLayer = Math.max(0, Math.min(highestPreferredLayer, cpuOveruseLimit, encodings.length - 1));
6038
+ if (producer.maxSpatialLayer === spatialLayer)
6039
+ return;
6040
+ yield producer.setMaxSpatialLayer(spatialLayer);
6041
+ const applied = producer.rtpSender
6042
+ .getParameters()
6043
+ .encodings.every((encoding, index) => encoding.active === index <= spatialLayer);
6044
+ if (!applied)
6045
+ logger$2.error("setMaxSpatialLayer(%d) was not applied to the encodings", spatialLayer);
6046
+ }
6047
+ else if (encodings.length === 1 && this._webcamProducerOriginalSvcScalabilityMode) {
6048
+ const update = this._getSvcEncodingUpdate(encodings[0], highestPreferredLayer);
6049
+ if (update)
6050
+ yield producer.setRtpEncodingParameters(update);
6051
+ }
6052
+ });
6053
+ }
6054
+ _incrementHistogramCount(histogram, key) {
6055
+ histogram[key] = (histogram[key] || 0) + 1;
6056
+ }
5611
6057
  _onDataConsumerReady(options) {
5612
6058
  return __awaiter(this, void 0, void 0, function* () {
5613
6059
  logger$2.info("_onDataConsumerReady()", { id: options.id, dataProducerId: options.dataProducerId });
@@ -5657,8 +6103,8 @@ class VegaRtcManager {
5657
6103
  stream.removeTrack(consumer.track);
5658
6104
  if (stream.getTracks().length === 0) {
5659
6105
  this._streamIdToVideoConsumerId.delete(stream.id);
5660
- this._streamIdToVideoResolution.delete(stream.id);
5661
6106
  if (screenShare) {
6107
+ this._streamIdToVideoResolution.delete(stream.id);
5662
6108
  clientState.screenStream = undefined;
5663
6109
  clientState.hasEmittedScreenStream = false;
5664
6110
  clientState.screenShareStreamId = undefined;
@@ -5704,6 +6150,8 @@ class VegaRtcManager {
5704
6150
  consumerIds: toResumeConsumers,
5705
6151
  });
5706
6152
  }
6153
+ if (toPauseConsumers.length > 0 || toResumeConsumers.length > 0)
6154
+ this._reapplyStreamResolutions();
5707
6155
  if (webcamStream && !hasEmittedWebcamStream && hasAcceptedWebcamStream) {
5708
6156
  this._emitToPWA(EVENTS.STREAM_ADDED, {
5709
6157
  clientId,
@@ -7468,5 +7916,5 @@ var RtcEventNames;
7468
7916
  RtcEventNames["stream_added"] = "stream_added";
7469
7917
  })(RtcEventNames || (RtcEventNames = {}));
7470
7918
 
7471
- export { ADDITIONAL_SCREEN_SHARE_SETTINGS, AUDIO_SETTINGS, BandwidthTester, CAMERA_STREAM_ID, EVENTS, FILE_SHARE_ERROR_CODES, KNOCK_MESSAGES, KalmanFilter, Logger, MEDIA_JITTER_BUFFER_TARGET, NoDevicesError, P2pRtcManager, PROTOCOL_ERRORS, PROTOCOL_EVENTS, PROTOCOL_REQUESTS, PROTOCOL_RESPONSES, RELAY_MESSAGES, ReconnectManager, RtcEventNames, RtcManagerDispatcher, SCREEN_SHARE_SETTINGS, SCREEN_SHARE_SIMULCAST_SETTINGS, STREAM_TYPES, ServerSocket, Session, SfuV2Parser, TYPES, VIDEO_SETTINGS_HD, VIDEO_SETTINGS_SD, VIDEO_SETTINGS_VP9, VIDEO_SETTINGS_VP9_LOW_BANDWIDTH, VegaConnection, VegaMediaQualityMonitor, VegaRtcManager, addAbsCaptureTimeExtMap, addExtMap, assert, buildDeviceList, calculateStd, captureAudioSsrcMetrics, captureCandidatePairInfoMetrics, captureCommonSsrcMetrics, captureSsrcInfo, captureVideoSsrcMetrics, cleanSdp, compareLocalDevices, createACFCalculator, createMicAnalyser, createWorker, deprioritizeH264, enumerate, external_stun_servers, filterMidExtension, filterMsidSemantic, fromLocation, generateByteString, getConstraints, getCurrentPeerConnections, getDeviceData, getDisplayMedia, getInitialStream, getIssuesAndMetrics, getMediaConstraints, getMediaSettings, getMediasoupDeviceAsync, getNumFailedStatsReports, getNumFailedTrackSsrcLookups, getNumMissingTrackSsrcLookups, getPeerConnectionIndex, getStats, getStream, getUpdatedDevices, getUpdatedStats, getUserMedia, hasGetDisplayMedia, ipRegex, isFileShareError, isMobile, issueDetectorOrMetricEnabled, maybeTurnOnly, modifyMediaCapabilities, removePeerConnection, replaceTracksInStream, rtcManagerEvents, rtcStats, setClientProvider, setCodecPreferenceSDP, setPeerConnectionsForTests, setVideoBandwidthUsingSetParameters, sortCodecs, standardDeviation, startPerformanceMonitor, stopStreamTracks, subscribeIssues, subscribeStats, trackAnnotations, turnServerOverride, updateRenderedDimensions, variance };
7919
+ export { ADDITIONAL_SCREEN_SHARE_SETTINGS, AUDIO_SETTINGS, BandwidthTester, CAMERA_STREAM_ID, CAM_SAMPLES_SKIPPED_AFTER_CANDIDATE_PAIR_CHANGE, CONGESTED_FRACTION_LOST, CONGESTED_RTT_INFLATION_MS, EVENTS, FILE_SHARE_ERROR_CODES, INITIAL_CONSUMER_SPATIAL_LAYER, INITIAL_HIGHEST_PREFERRED_LAYER, KNOCK_MESSAGES, KalmanFilter, LOWEST_SVC_LAYER_MAX_BITRATE, Logger, MAX_CONCURRENT_PREFERRED_LAYER_SWITCH_WATCHES, MEDIA_JITTER_BUFFER_TARGET, MIDDLE_SVC_LAYER_MAX_BITRATE, NoDevicesError, P2pRtcManager, PREFERRED_LAYER_SWITCH_POLL_INTERVAL_MS, PREFERRED_LAYER_SWITCH_WATCH_TIMEOUT_MS, PROTOCOL_ERRORS, PROTOCOL_EVENTS, PROTOCOL_REQUESTS, PROTOCOL_RESPONSES, RELAY_MESSAGES, ROOM_INTEGRATION_ERROR_CODES, ReconnectManager, RtcEventNames, RtcManagerDispatcher, SCREEN_SHARE_SETTINGS, SCREEN_SHARE_SIMULCAST_SETTINGS, STREAM_TYPES, ServerSocket, Session, SfuV2Parser, TYPES, VIDEO_SETTINGS_HD, VIDEO_SETTINGS_SD, VIDEO_SETTINGS_VP9, VIDEO_SETTINGS_VP9_LOW_BANDWIDTH, VegaConnection, VegaMediaQualityMonitor, VegaRtcManager, addAbsCaptureTimeExtMap, addExtMap, assert, buildDeviceList, calculateStd, captureAudioSsrcMetrics, captureCandidatePairInfoMetrics, captureCommonSsrcMetrics, captureSsrcInfo, captureVideoSsrcMetrics, cleanSdp, compareLocalDevices, createACFCalculator, createMicAnalyser, createWorker, deprioritizeH264, enumerate, external_stun_servers, filterMidExtension, filterMsidSemantic, fromLocation, generateByteString, getConstraints, getCurrentPeerConnections, getDeviceData, getDisplayMedia, getInitialStream, getIssuesAndMetrics, getMediaConstraints, getMediaSettings, getMediasoupDeviceAsync, getNumFailedStatsReports, getNumFailedTrackSsrcLookups, getNumMissingTrackSsrcLookups, getPeerConnectionIndex, getSelectedCandidatePairId, getStats, getStream, getUpdatedDevices, getUpdatedStats, getUserMedia, hasGetDisplayMedia, ipRegex, isFileShareError, isMobile, isRoomIntegrationErrorCode, issueDetectorOrMetricEnabled, maybeTurnOnly, modifyMediaCapabilities, removePeerConnection, replaceTracksInStream, rtcManagerEvents, rtcStats, setClientProvider, setCodecPreferenceSDP, setPeerConnectionsForTests, setVideoBandwidthUsingSetParameters, sortCodecs, standardDeviation, startPerformanceMonitor, stopStreamTracks, subscribeIssues, subscribeStats, trackAnnotations, turnServerOverride, updateRenderedDimensions, variance };
7472
7920
  //# sourceMappingURL=legacy-esm.js.map