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