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