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