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