livekit-client 2.22.1 → 2.22.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/livekit-client.e2ee.worker.js +1 -1
- package/dist/livekit-client.e2ee.worker.js.map +1 -1
- package/dist/livekit-client.e2ee.worker.mjs +663 -476
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +480 -157
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.fm.worker.js +1 -1
- package/dist/livekit-client.fm.worker.js.map +1 -1
- package/dist/livekit-client.fm.worker.mjs +8 -1
- package/dist/livekit-client.fm.worker.mjs.map +1 -1
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/src/api/SignalClient.d.ts.map +1 -1
- package/dist/src/api/WebSocketStream.d.ts.map +1 -1
- package/dist/src/api/utils.d.ts +1 -0
- package/dist/src/api/utils.d.ts.map +1 -1
- package/dist/src/e2ee/E2eeManager.d.ts +33 -0
- package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
- package/dist/src/e2ee/constants.d.ts +5 -0
- package/dist/src/e2ee/constants.d.ts.map +1 -1
- package/dist/src/e2ee/types.d.ts +24 -3
- package/dist/src/e2ee/types.d.ts.map +1 -1
- package/dist/src/e2ee/worker/DataCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/ErrorRateLimiter.d.ts +21 -0
- package/dist/src/e2ee/worker/ErrorRateLimiter.d.ts.map +1 -0
- package/dist/src/e2ee/worker/FrameCryptor.d.ts +43 -19
- package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
- package/dist/src/logger.d.ts +4 -0
- package/dist/src/logger.d.ts.map +1 -1
- package/dist/src/room/PCTransportManager.d.ts +12 -0
- package/dist/src/room/PCTransportManager.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +1 -0
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/data-stream/incoming/StreamReader.d.ts +17 -17
- package/dist/src/room/data-stream/incoming/StreamReader.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/publishUtils.d.ts +16 -0
- package/dist/src/room/participant/publishUtils.d.ts.map +1 -1
- package/dist/src/room/track/LocalVideoTrack.d.ts +7 -0
- package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +1 -1
- package/dist/src/room/utils.d.ts +34 -0
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/ts4.2/api/utils.d.ts +1 -0
- package/dist/ts4.2/e2ee/E2eeManager.d.ts +33 -0
- package/dist/ts4.2/e2ee/constants.d.ts +5 -0
- package/dist/ts4.2/e2ee/types.d.ts +24 -3
- package/dist/ts4.2/e2ee/worker/ErrorRateLimiter.d.ts +21 -0
- package/dist/ts4.2/e2ee/worker/FrameCryptor.d.ts +43 -19
- package/dist/ts4.2/logger.d.ts +4 -0
- package/dist/ts4.2/room/PCTransportManager.d.ts +12 -0
- package/dist/ts4.2/room/RTCEngine.d.ts +1 -0
- package/dist/ts4.2/room/data-stream/incoming/StreamReader.d.ts +17 -17
- package/dist/ts4.2/room/participant/publishUtils.d.ts +16 -0
- package/dist/ts4.2/room/track/LocalVideoTrack.d.ts +7 -0
- package/dist/ts4.2/room/track/options.d.ts +1 -1
- package/dist/ts4.2/room/utils.d.ts +34 -0
- package/package.json +1 -1
- package/src/api/SignalClient.ts +2 -1
- package/src/api/WebSocketStream.ts +3 -8
- package/src/api/utils.ts +10 -0
- package/src/e2ee/E2eeManager.test.ts +196 -0
- package/src/e2ee/E2eeManager.ts +150 -31
- package/src/e2ee/constants.ts +6 -0
- package/src/e2ee/subscriberBlackScreen.test.ts +544 -0
- package/src/e2ee/types.ts +28 -3
- package/src/e2ee/worker/DataCryptor.ts +2 -1
- package/src/e2ee/worker/ErrorRateLimiter.test.ts +53 -0
- package/src/e2ee/worker/ErrorRateLimiter.ts +52 -0
- package/src/e2ee/worker/FrameCryptor.race.test.ts +9 -26
- package/src/e2ee/worker/FrameCryptor.test.ts +0 -1
- package/src/e2ee/worker/FrameCryptor.ts +202 -119
- package/src/e2ee/worker/e2ee.worker.ts +72 -17
- package/src/logger.ts +22 -0
- package/src/room/PCTransportManager.test.ts +35 -0
- package/src/room/PCTransportManager.ts +12 -4
- package/src/room/RTCEngine.ts +28 -7
- package/src/room/Room.ts +1 -1
- package/src/room/data-stream/incoming/IncomingDataStreamManager.test.ts +171 -0
- package/src/room/data-stream/incoming/IncomingDataStreamManager.ts +17 -18
- package/src/room/data-stream/incoming/StreamReader.ts +20 -50
- package/src/room/participant/LocalParticipant.ts +30 -14
- package/src/room/participant/publishUtils.test.ts +133 -0
- package/src/room/participant/publishUtils.ts +54 -19
- package/src/room/track/LocalVideoTrack.ts +15 -5
- package/src/room/track/options.ts +1 -1
- package/src/room/utils.test.ts +87 -0
- package/src/room/utils.ts +59 -0
|
@@ -930,7 +930,10 @@ function isScalarZeroValue(type, value) {
|
|
|
930
930
|
return value == 0;
|
|
931
931
|
// Loose comparison matches 0n, 0 and "0"
|
|
932
932
|
}
|
|
933
|
-
}function
|
|
933
|
+
}function _OverloadYield(e, d) {
|
|
934
|
+
this.v = e, this.k = d;
|
|
935
|
+
}
|
|
936
|
+
function _arrayLikeToArray(r, a) {
|
|
934
937
|
(null == a || a > r.length) && (a = r.length);
|
|
935
938
|
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
|
|
936
939
|
return n;
|
|
@@ -1046,7 +1049,61 @@ function _unsupportedIterableToArray(r, a) {
|
|
|
1046
1049
|
var t = {}.toString.call(r).slice(8, -1);
|
|
1047
1050
|
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
|
|
1048
1051
|
}
|
|
1049
|
-
}
|
|
1052
|
+
}
|
|
1053
|
+
function _wrapAsyncGenerator(e) {
|
|
1054
|
+
return function () {
|
|
1055
|
+
return new AsyncGenerator(e.apply(this, arguments));
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
function AsyncGenerator(e) {
|
|
1059
|
+
var t, n;
|
|
1060
|
+
function resume(t, n) {
|
|
1061
|
+
try {
|
|
1062
|
+
var r = e[t](n),
|
|
1063
|
+
o = r.value,
|
|
1064
|
+
u = o instanceof _OverloadYield;
|
|
1065
|
+
Promise.resolve(u ? o.v : o).then(function (n) {
|
|
1066
|
+
if (u) {
|
|
1067
|
+
var i = "return" === t && o.k ? t : "next";
|
|
1068
|
+
if (!o.k || n.done) return resume(i, n);
|
|
1069
|
+
n = e[i](n).value;
|
|
1070
|
+
}
|
|
1071
|
+
settle(!!r.done, n);
|
|
1072
|
+
}, function (e) {
|
|
1073
|
+
resume("throw", e);
|
|
1074
|
+
});
|
|
1075
|
+
} catch (e) {
|
|
1076
|
+
settle(2, e);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
function settle(e, r) {
|
|
1080
|
+
2 === e ? t.reject(r) : t.resolve({
|
|
1081
|
+
value: r,
|
|
1082
|
+
done: e
|
|
1083
|
+
}), (t = t.next) ? resume(t.key, t.arg) : n = null;
|
|
1084
|
+
}
|
|
1085
|
+
this._invoke = function (e, r) {
|
|
1086
|
+
return new Promise(function (o, u) {
|
|
1087
|
+
var i = {
|
|
1088
|
+
key: e,
|
|
1089
|
+
arg: r,
|
|
1090
|
+
resolve: o,
|
|
1091
|
+
reject: u,
|
|
1092
|
+
next: null
|
|
1093
|
+
};
|
|
1094
|
+
n ? n = n.next = i : (t = n = i, resume(e, r));
|
|
1095
|
+
});
|
|
1096
|
+
}, "function" != typeof e.return && (this.return = void 0);
|
|
1097
|
+
}
|
|
1098
|
+
AsyncGenerator.prototype["function" == typeof Symbol && Symbol.asyncIterator || "@@asyncIterator"] = function () {
|
|
1099
|
+
return this;
|
|
1100
|
+
}, AsyncGenerator.prototype.next = function (e) {
|
|
1101
|
+
return this._invoke("next", e);
|
|
1102
|
+
}, AsyncGenerator.prototype.throw = function (e) {
|
|
1103
|
+
return this._invoke("throw", e);
|
|
1104
|
+
}, AsyncGenerator.prototype.return = function (e) {
|
|
1105
|
+
return this._invoke("return", e);
|
|
1106
|
+
};/* eslint-disable prefer-const,no-case-declarations,@typescript-eslint/restrict-plus-operands */
|
|
1050
1107
|
/**
|
|
1051
1108
|
* Protobuf binary format wire types.
|
|
1052
1109
|
*
|
|
@@ -8625,7 +8682,21 @@ function setLogExtension(extension, logger) {
|
|
|
8625
8682
|
logR.setLevel(logR.getLevel());
|
|
8626
8683
|
});
|
|
8627
8684
|
}
|
|
8628
|
-
const workerLogger = loglevelExports.getLogger(LoggerNames.E2EE);
|
|
8685
|
+
const workerLogger = loglevelExports.getLogger(LoggerNames.E2EE);
|
|
8686
|
+
const workerLogLevelListeners = new Set();
|
|
8687
|
+
const originalWorkerSetLevel = workerLogger.setLevel.bind(workerLogger);
|
|
8688
|
+
workerLogger.setLevel = (level, persist) => {
|
|
8689
|
+
originalWorkerSetLevel(level, persist);
|
|
8690
|
+
const numeric = workerLogger.getLevel();
|
|
8691
|
+
workerLogLevelListeners.forEach(cb => cb(numeric));
|
|
8692
|
+
};
|
|
8693
|
+
/** @internal Subscribe to workerLogger level changes (so E2EE workers can be kept in sync). */
|
|
8694
|
+
function onWorkerLogLevelChanged(cb) {
|
|
8695
|
+
workerLogLevelListeners.add(cb);
|
|
8696
|
+
return () => {
|
|
8697
|
+
workerLogLevelListeners.delete(cb);
|
|
8698
|
+
};
|
|
8699
|
+
}const maxRetryDelay = 7000;
|
|
8629
8700
|
const DEFAULT_RETRY_DELAYS_IN_MS = [0, 300, 2 * 2 * 300, 3 * 3 * 300, 4 * 4 * 300, maxRetryDelay, maxRetryDelay, maxRetryDelay, maxRetryDelay, maxRetryDelay];
|
|
8630
8701
|
class DefaultReconnectPolicy {
|
|
8631
8702
|
constructor(retryDelays) {
|
|
@@ -12208,7 +12279,7 @@ function getMatch(exp, ua) {
|
|
|
12208
12279
|
}
|
|
12209
12280
|
function getOSVersion(ua) {
|
|
12210
12281
|
return ua.includes('mac os') ? getMatch(/\(.+?(\d+_\d+(:?_\d+)?)/, ua, 1).replace(/_/g, '.') : undefined;
|
|
12211
|
-
}var version$1 = "2.22.
|
|
12282
|
+
}var version$1 = "2.22.3";const version = version$1;
|
|
12212
12283
|
const protocolVersion = 17;
|
|
12213
12284
|
/** Initial client protocol. */
|
|
12214
12285
|
const CLIENT_PROTOCOL_DEFAULT = 0;
|
|
@@ -14216,6 +14287,56 @@ function negotiateDependencyDescriptor(transceiver) {
|
|
|
14216
14287
|
return false;
|
|
14217
14288
|
}
|
|
14218
14289
|
}
|
|
14290
|
+
/**
|
|
14291
|
+
* VP9 and AV1 are published as SVC (a single RTP stream carrying every spatial layer)
|
|
14292
|
+
* by default. They can instead be published as real, rid based simulcast — one
|
|
14293
|
+
* independent stream per rid, each carrying a single spatial layer — when the caller
|
|
14294
|
+
* opts in with `simulcast: true` and a single spatial layer scalability mode (`L1Tx`).
|
|
14295
|
+
*
|
|
14296
|
+
* The SFU has to be told about this: without an explicit
|
|
14297
|
+
* `SimulcastCodec.videoLayerMode` it assumes `MULTIPLE_SPATIAL_LAYERS_PER_STREAM` for
|
|
14298
|
+
* any SVC capable codec.
|
|
14299
|
+
*/
|
|
14300
|
+
function isSVCSimulcast(codec, options) {
|
|
14301
|
+
var _a;
|
|
14302
|
+
return isSVCCodec(codec) && !!(options === null || options === void 0 ? void 0 : options.simulcast) && !!((_a = options.scalabilityMode) === null || _a === void 0 ? void 0 : _a.startsWith('L1T'));
|
|
14303
|
+
}
|
|
14304
|
+
/**
|
|
14305
|
+
* Whether the browser reads multiple encodings on an SVC capable codec as *legacy SVC*
|
|
14306
|
+
* rather than as real simulcast.
|
|
14307
|
+
*
|
|
14308
|
+
* Before Chrome M113, supplying more than one encoding for VP9/AV1 selected SVC mode;
|
|
14309
|
+
* only from M113 does libwebrtc treat such encodings as simulcast, and only when each
|
|
14310
|
+
* one carries its own scalabilityMode. Safari (and anything WebKit based, i. e. every
|
|
14311
|
+
* browser on iOS) still uses the old interpretation, as does React Native's libwebrtc.
|
|
14312
|
+
* Announced at https://groups.google.com/g/discuss-webrtc/c/-QQ3pxrl-fw
|
|
14313
|
+
*
|
|
14314
|
+
* Where this is true the rids would not exist on the wire, so VP9/AV1 must be published
|
|
14315
|
+
* as SVC no matter what the caller asked for.
|
|
14316
|
+
*/
|
|
14317
|
+
function usesLegacySVCEncodings() {
|
|
14318
|
+
const browser = getBrowser();
|
|
14319
|
+
return isSafariBased() ||
|
|
14320
|
+
// Even tho RN runs M114, it does not produce SVC layers when a single encoding
|
|
14321
|
+
// is provided. So we'll use the legacy SVC specification for now.
|
|
14322
|
+
// TODO: when we upstream libwebrtc, this will need additional verification
|
|
14323
|
+
isReactNative() || (browser === null || browser === void 0 ? void 0 : browser.name) === 'Chrome' && compareVersions(browser.version, '113') < 0;
|
|
14324
|
+
}
|
|
14325
|
+
/**
|
|
14326
|
+
* Last server version that doesn't support vp9/av1 simulcast.
|
|
14327
|
+
*/
|
|
14328
|
+
const svcSimulcastMinServerVersion = '1.13.6';
|
|
14329
|
+
/**
|
|
14330
|
+
* Whether the connected server honours `SimulcastCodec.videoLayerMode`, i. e. whether
|
|
14331
|
+
* VP9/AV1 can be published as rid based simulcast. An unknown version is treated as
|
|
14332
|
+
* unsupported so the publish falls back to SVC.
|
|
14333
|
+
*/
|
|
14334
|
+
function isSVCSimulcastSupportedByServer(serverVersion) {
|
|
14335
|
+
if (!serverVersion) {
|
|
14336
|
+
return false;
|
|
14337
|
+
}
|
|
14338
|
+
return compareVersions(serverVersion, svcSimulcastMinServerVersion) > 0;
|
|
14339
|
+
}
|
|
14219
14340
|
function supportsSetSinkId(elm) {
|
|
14220
14341
|
if (!document || isSafariBased()) {
|
|
14221
14342
|
return false;
|
|
@@ -14824,11 +14945,25 @@ function getAbortReasonAsString(signal) {
|
|
|
14824
14945
|
default:
|
|
14825
14946
|
return 'toString' in reason ? reason.toString() : defaultMessage;
|
|
14826
14947
|
}
|
|
14948
|
+
}
|
|
14949
|
+
function getErrorDescription(error, errorCategory) {
|
|
14950
|
+
if (error instanceof Error) {
|
|
14951
|
+
if (error.name && error.message) {
|
|
14952
|
+
return "".concat(error.name, ": ").concat(error.message);
|
|
14953
|
+
}
|
|
14954
|
+
return error.name;
|
|
14955
|
+
}
|
|
14956
|
+
return "Encountered unknown ".concat(errorCategory, " error: ").concat(String(error));
|
|
14827
14957
|
}const ENCRYPTION_ALGORITHM = 'AES-GCM';
|
|
14828
14958
|
// How many consecutive frames can fail decrypting before a particular key gets marked as invalid
|
|
14829
14959
|
const DECRYPTION_FAILURE_TOLERANCE = 10;
|
|
14830
14960
|
// flag set to indicate that e2ee has been setup for sender/receiver;
|
|
14831
14961
|
const E2EE_FLAG = 'lk_e2ee';
|
|
14962
|
+
/**
|
|
14963
|
+
* trackId a receiver's/sender's encoded stream pipeline was last set up for.
|
|
14964
|
+
* Needed to recover the right cryptor when a transceiver gets reused.
|
|
14965
|
+
*/
|
|
14966
|
+
const E2EE_TRACK_ID = 'lk_e2ee_track_id';
|
|
14832
14967
|
const SALT = 'LKFrameEncryptionKey';
|
|
14833
14968
|
const KEY_PROVIDER_DEFAULTS = {
|
|
14834
14969
|
sharedKey: false,
|
|
@@ -15770,10 +15905,18 @@ function isElementInViewport(el, win) {
|
|
|
15770
15905
|
* @experimental
|
|
15771
15906
|
*/
|
|
15772
15907
|
class E2EEManager extends eventsExports.EventEmitter {
|
|
15908
|
+
get logContext() {
|
|
15909
|
+
var _a, _b;
|
|
15910
|
+
return {
|
|
15911
|
+
room: (_a = this.room) === null || _a === void 0 ? void 0 : _a.name,
|
|
15912
|
+
participant: (_b = this.room) === null || _b === void 0 ? void 0 : _b.localParticipant.identity
|
|
15913
|
+
};
|
|
15914
|
+
}
|
|
15773
15915
|
constructor(options, dcEncryptionEnabled) {
|
|
15774
15916
|
super();
|
|
15775
15917
|
this.decryptDataRequests = new Map();
|
|
15776
15918
|
this.encryptDataRequests = new Map();
|
|
15919
|
+
this.log = getLogger(LoggerNames.E2EE, () => this.logContext);
|
|
15777
15920
|
this.onWorkerMessage = ev => {
|
|
15778
15921
|
var _a, _b;
|
|
15779
15922
|
const _ev$data = ev.data,
|
|
@@ -15781,22 +15924,22 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
15781
15924
|
data = _ev$data.data;
|
|
15782
15925
|
switch (kind) {
|
|
15783
15926
|
case 'error':
|
|
15784
|
-
|
|
15785
|
-
//
|
|
15786
|
-
//
|
|
15927
|
+
// If error has uuid, it's from an async operation (encrypt/decrypt).
|
|
15928
|
+
// Reject the corresponding future and let the caller decide how to log/handle;
|
|
15929
|
+
// logging here would duplicate whatever the caller does.
|
|
15787
15930
|
if (data.uuid) {
|
|
15788
15931
|
const decryptFuture = this.decryptDataRequests.get(data.uuid);
|
|
15789
15932
|
if (decryptFuture === null || decryptFuture === void 0 ? void 0 : decryptFuture.reject) {
|
|
15790
15933
|
decryptFuture.reject(data.error);
|
|
15791
|
-
break;
|
|
15934
|
+
break;
|
|
15792
15935
|
}
|
|
15793
15936
|
const encryptFuture = this.encryptDataRequests.get(data.uuid);
|
|
15794
15937
|
if (encryptFuture === null || encryptFuture === void 0 ? void 0 : encryptFuture.reject) {
|
|
15795
15938
|
encryptFuture.reject(data.error);
|
|
15796
|
-
break;
|
|
15939
|
+
break;
|
|
15797
15940
|
}
|
|
15798
15941
|
}
|
|
15799
|
-
|
|
15942
|
+
this.log.error(data.error.message);
|
|
15800
15943
|
this.emit(EncryptionEvent.EncryptionError, data.error, data.participantIdentity);
|
|
15801
15944
|
break;
|
|
15802
15945
|
case 'initAck':
|
|
@@ -15841,10 +15984,13 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
15841
15984
|
case 'packetTrailerMetadata':
|
|
15842
15985
|
this.handleFrameMetadata(data.trackId, data.rtpTimestamp, data.ssrc, data.metadata);
|
|
15843
15986
|
break;
|
|
15987
|
+
case 'log':
|
|
15988
|
+
workerLogger[data.level](data.msg, data.context);
|
|
15989
|
+
break;
|
|
15844
15990
|
}
|
|
15845
15991
|
};
|
|
15846
15992
|
this.onWorkerError = ev => {
|
|
15847
|
-
|
|
15993
|
+
this.log.error('e2ee worker encountered an error:', {
|
|
15848
15994
|
error: ev.error
|
|
15849
15995
|
});
|
|
15850
15996
|
this.emit(EncryptionEvent.EncryptionError, ev.error, undefined);
|
|
@@ -15867,7 +16013,7 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
15867
16013
|
if (!isE2EESupported()) {
|
|
15868
16014
|
throw new DeviceUnsupportedError('tried to setup end-to-end encryption on an unsupported browser');
|
|
15869
16015
|
}
|
|
15870
|
-
|
|
16016
|
+
this.log.info('setting up e2ee');
|
|
15871
16017
|
if (room !== this.room) {
|
|
15872
16018
|
this.room = room;
|
|
15873
16019
|
this.setupEventListeners(room, this.keyProvider);
|
|
@@ -15880,20 +16026,94 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
15880
16026
|
}
|
|
15881
16027
|
};
|
|
15882
16028
|
if (this.worker) {
|
|
15883
|
-
|
|
16029
|
+
this.log.info("initializing worker", {
|
|
15884
16030
|
worker: this.worker
|
|
15885
16031
|
});
|
|
15886
16032
|
this.worker.onmessage = this.onWorkerMessage;
|
|
15887
16033
|
this.worker.onerror = this.onWorkerError;
|
|
15888
16034
|
this.worker.postMessage(msg);
|
|
16035
|
+
this.subscribeToLogLevelChanges();
|
|
15889
16036
|
}
|
|
15890
16037
|
}
|
|
15891
16038
|
}
|
|
16039
|
+
/**
|
|
16040
|
+
* Subscribe the current worker to main-thread `workerLogger` level changes,
|
|
16041
|
+
* without strongly retaining `this` or `this.worker` from the module-global
|
|
16042
|
+
* listener Set on the logger. See {@link disposeRegistry}.
|
|
16043
|
+
*/
|
|
16044
|
+
subscribeToLogLevelChanges() {
|
|
16045
|
+
var _a;
|
|
16046
|
+
// Guard against duplicate registration on re-setup.
|
|
16047
|
+
(_a = this.unsubscribeLogLevel) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
16048
|
+
let unsub;
|
|
16049
|
+
if (E2EEManager.disposeRegistry) {
|
|
16050
|
+
// Modern engines: hold the worker weakly so the module-global listener Set
|
|
16051
|
+
// on the logger can't retain this manager, and clean up the entry on GC.
|
|
16052
|
+
const workerRef = new WeakRef(this.worker);
|
|
16053
|
+
unsub = onWorkerLogLevelChanged(level => {
|
|
16054
|
+
const worker = workerRef.deref();
|
|
16055
|
+
if (!worker) {
|
|
16056
|
+
unsub === null || unsub === void 0 ? void 0 : unsub();
|
|
16057
|
+
return;
|
|
16058
|
+
}
|
|
16059
|
+
worker.postMessage({
|
|
16060
|
+
kind: 'setLogLevel',
|
|
16061
|
+
data: {
|
|
16062
|
+
level
|
|
16063
|
+
}
|
|
16064
|
+
});
|
|
16065
|
+
});
|
|
16066
|
+
E2EEManager.disposeRegistry.register(this, unsub, this);
|
|
16067
|
+
} else {
|
|
16068
|
+
// Safari <14.1 and similar: no WeakRef. Fall back to a strong reference;
|
|
16069
|
+
// the leak lives until the consumer calls `dispose()`.
|
|
16070
|
+
const worker = this.worker;
|
|
16071
|
+
unsub = onWorkerLogLevelChanged(level => {
|
|
16072
|
+
worker.postMessage({
|
|
16073
|
+
kind: 'setLogLevel',
|
|
16074
|
+
data: {
|
|
16075
|
+
level
|
|
16076
|
+
}
|
|
16077
|
+
});
|
|
16078
|
+
});
|
|
16079
|
+
}
|
|
16080
|
+
this.unsubscribeLogLevel = unsub;
|
|
16081
|
+
}
|
|
16082
|
+
/**
|
|
16083
|
+
* @internal
|
|
16084
|
+
* Release the log-level subscription, reject any pending encrypt/decrypt
|
|
16085
|
+
* futures, and detach the worker message handlers. The worker itself is
|
|
16086
|
+
* caller-owned and is not terminated. Idempotent.
|
|
16087
|
+
*/
|
|
16088
|
+
dispose() {
|
|
16089
|
+
var _a, _b, _c;
|
|
16090
|
+
(_a = this.unsubscribeLogLevel) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
16091
|
+
this.unsubscribeLogLevel = undefined;
|
|
16092
|
+
if (E2EEManager.disposeRegistry) {
|
|
16093
|
+
E2EEManager.disposeRegistry.unregister(this);
|
|
16094
|
+
}
|
|
16095
|
+
// Reject pending futures BEFORE detaching worker handlers, so any late
|
|
16096
|
+
// response can't resolve one after we've cut the pipe. Each future's
|
|
16097
|
+
// `onFinally` deletes its own map entry, so both maps drain themselves.
|
|
16098
|
+
// Snapshot before iterating in case a rejection handler mutates the map.
|
|
16099
|
+
const disposalError = new CryptorError('E2EEManager disposed', CryptorErrorReason.InternalError);
|
|
16100
|
+
for (const future of [...this.encryptDataRequests.values()]) {
|
|
16101
|
+
(_b = future.reject) === null || _b === void 0 ? void 0 : _b.call(future, disposalError);
|
|
16102
|
+
}
|
|
16103
|
+
for (const future of [...this.decryptDataRequests.values()]) {
|
|
16104
|
+
(_c = future.reject) === null || _c === void 0 ? void 0 : _c.call(future, disposalError);
|
|
16105
|
+
}
|
|
16106
|
+
if (this.worker) {
|
|
16107
|
+
this.worker.onmessage = null;
|
|
16108
|
+
this.worker.onerror = null;
|
|
16109
|
+
}
|
|
16110
|
+
this.removeAllListeners();
|
|
16111
|
+
}
|
|
15892
16112
|
/**
|
|
15893
16113
|
* @internal
|
|
15894
16114
|
*/
|
|
15895
16115
|
setParticipantCryptorEnabled(enabled, participantIdentity) {
|
|
15896
|
-
|
|
16116
|
+
this.log.debug("set e2ee to ".concat(enabled, " for participant ").concat(participantIdentity));
|
|
15897
16117
|
this.postEnable(enabled, participantIdentity);
|
|
15898
16118
|
}
|
|
15899
16119
|
/**
|
|
@@ -15901,7 +16121,7 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
15901
16121
|
*/
|
|
15902
16122
|
setSifTrailer(trailer) {
|
|
15903
16123
|
if (!trailer || trailer.length === 0) {
|
|
15904
|
-
|
|
16124
|
+
this.log.warn("ignoring server sent trailer as it's empty");
|
|
15905
16125
|
} else {
|
|
15906
16126
|
this.postSifTrailer(trailer);
|
|
15907
16127
|
}
|
|
@@ -15925,12 +16145,12 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
15925
16145
|
});
|
|
15926
16146
|
}
|
|
15927
16147
|
setupEventListeners(room, keyProvider) {
|
|
15928
|
-
room.on(RoomEvent.TrackPublished, (pub, participant) => this.
|
|
16148
|
+
room.on(RoomEvent.TrackPublished, (pub, participant) => this.setParticipantCryptorEnabledForPublication(pub, participant.identity));
|
|
15929
16149
|
room.on(RoomEvent.ConnectionStateChanged, state => {
|
|
15930
16150
|
if (state === ConnectionState.Connected) {
|
|
15931
16151
|
room.remoteParticipants.forEach(participant => {
|
|
15932
16152
|
participant.trackPublications.forEach(pub => {
|
|
15933
|
-
this.
|
|
16153
|
+
this.setParticipantCryptorEnabledForPublication(pub, participant.identity);
|
|
15934
16154
|
});
|
|
15935
16155
|
});
|
|
15936
16156
|
}
|
|
@@ -16100,6 +16320,21 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
16100
16320
|
};
|
|
16101
16321
|
this.worker.postMessage(msg);
|
|
16102
16322
|
}
|
|
16323
|
+
/**
|
|
16324
|
+
* Derive the participant's encryption state from one of its publications.
|
|
16325
|
+
* Publications without trackInfo are skipped rather than thrown on: throwing
|
|
16326
|
+
* inside the forEach above would leave every remaining participant without an
|
|
16327
|
+
* encryption state, and a cryptor with unknown state can no longer decrypt.
|
|
16328
|
+
*/
|
|
16329
|
+
setParticipantCryptorEnabledForPublication(pub, participantIdentity) {
|
|
16330
|
+
if (!pub.trackInfo) {
|
|
16331
|
+
this.log.warn('skipping e2ee enabled update for publication without trackInfo', {
|
|
16332
|
+
trackSid: pub.trackSid
|
|
16333
|
+
});
|
|
16334
|
+
return;
|
|
16335
|
+
}
|
|
16336
|
+
this.setParticipantCryptorEnabled(pub.trackInfo.encryption !== Encryption_Type.NONE, participantIdentity);
|
|
16337
|
+
}
|
|
16103
16338
|
setupE2EEReceiver(track, remoteId, trackInfo) {
|
|
16104
16339
|
if (!track.receiver) {
|
|
16105
16340
|
return;
|
|
@@ -16113,7 +16348,7 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
16113
16348
|
setupE2EESender(track, sender) {
|
|
16114
16349
|
var _a, _b, _c;
|
|
16115
16350
|
if (!isLocalTrack(track) || !sender) {
|
|
16116
|
-
if (!sender)
|
|
16351
|
+
if (!sender) this.log.warn('early return because sender is not ready');
|
|
16117
16352
|
return;
|
|
16118
16353
|
}
|
|
16119
16354
|
this.handleSender(sender, track.mediaStreamID, undefined, isVideoTrack(track) ? (_b = (_a = track.publishOptions) === null || _a === void 0 ? void 0 : _a.frameMetadata) !== null && _b !== void 0 ? _b : (_c = track.publishOptions) === null || _c === void 0 ? void 0 : _c.packetTrailer : undefined);
|
|
@@ -16136,21 +16371,27 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
16136
16371
|
codec,
|
|
16137
16372
|
hasPacketTrailer
|
|
16138
16373
|
};
|
|
16139
|
-
// @ts-ignore
|
|
16140
16374
|
receiver.transform = new RTCRtpScriptTransform(this.worker, options);
|
|
16141
16375
|
} else {
|
|
16142
|
-
if (E2EE_FLAG in receiver &&
|
|
16143
|
-
//
|
|
16376
|
+
if (E2EE_FLAG in receiver && E2EE_TRACK_ID in receiver) {
|
|
16377
|
+
// The transceiver is being reused for a new track. We cannot set up a new
|
|
16378
|
+
// pipeline from here: this receiver's encoded streams were transferred to
|
|
16379
|
+
// the worker on first setup and a transferred stream can't be transferred
|
|
16380
|
+
// again, while createEncodedStreams() may only be called once per receiver.
|
|
16381
|
+
// So hand the worker the new track/participant and let it re-point (and if
|
|
16382
|
+
// necessary rebuild) the cryptor that still owns those streams.
|
|
16144
16383
|
const msg = {
|
|
16145
16384
|
kind: 'updateCodec',
|
|
16146
16385
|
data: {
|
|
16147
16386
|
trackId,
|
|
16387
|
+
previousTrackId: receiver[E2EE_TRACK_ID],
|
|
16148
16388
|
codec,
|
|
16149
16389
|
participantIdentity,
|
|
16150
16390
|
hasPacketTrailer
|
|
16151
16391
|
}
|
|
16152
16392
|
};
|
|
16153
16393
|
this.worker.postMessage(msg);
|
|
16394
|
+
receiver[E2EE_TRACK_ID] = trackId;
|
|
16154
16395
|
return;
|
|
16155
16396
|
}
|
|
16156
16397
|
// @ts-ignore
|
|
@@ -16175,7 +16416,6 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
16175
16416
|
trackId: trackId,
|
|
16176
16417
|
codec,
|
|
16177
16418
|
participantIdentity: participantIdentity,
|
|
16178
|
-
isReuse: E2EE_FLAG in receiver,
|
|
16179
16419
|
hasPacketTrailer
|
|
16180
16420
|
}
|
|
16181
16421
|
};
|
|
@@ -16183,6 +16423,8 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
16183
16423
|
}
|
|
16184
16424
|
// @ts-ignore
|
|
16185
16425
|
receiver[E2EE_FLAG] = true;
|
|
16426
|
+
// @ts-ignore
|
|
16427
|
+
receiver[E2EE_TRACK_ID] = trackId;
|
|
16186
16428
|
});
|
|
16187
16429
|
}
|
|
16188
16430
|
/**
|
|
@@ -16199,7 +16441,7 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
16199
16441
|
throw TypeError('local identity needs to be known in order to set up encrypted sender');
|
|
16200
16442
|
}
|
|
16201
16443
|
if (isScriptTransformSupportedForWorker()) {
|
|
16202
|
-
|
|
16444
|
+
this.log.info('initialize script transform');
|
|
16203
16445
|
const options = {
|
|
16204
16446
|
kind: 'encode',
|
|
16205
16447
|
participantIdentity: this.room.localParticipant.identity,
|
|
@@ -16211,7 +16453,7 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
16211
16453
|
// @ts-ignore
|
|
16212
16454
|
sender.transform = new RTCRtpScriptTransform(this.worker, options);
|
|
16213
16455
|
} else {
|
|
16214
|
-
|
|
16456
|
+
this.log.info('initialize encoded streams');
|
|
16215
16457
|
// @ts-ignore
|
|
16216
16458
|
const senderStreams = sender.createEncodedStreams();
|
|
16217
16459
|
const msg = {
|
|
@@ -16222,7 +16464,6 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
16222
16464
|
codec,
|
|
16223
16465
|
trackId,
|
|
16224
16466
|
participantIdentity: this.room.localParticipant.identity,
|
|
16225
|
-
isReuse: false,
|
|
16226
16467
|
hasPacketTrailer: hasFrameMetadataPublishOptions(frameMetadata),
|
|
16227
16468
|
packetTrailer: frameMetadata
|
|
16228
16469
|
}
|
|
@@ -16232,7 +16473,15 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
16232
16473
|
// @ts-ignore
|
|
16233
16474
|
sender[E2EE_FLAG] = true;
|
|
16234
16475
|
}
|
|
16235
|
-
}
|
|
16476
|
+
}
|
|
16477
|
+
/**
|
|
16478
|
+
* Runs a cleanup callback once this manager is garbage collected. Lets the
|
|
16479
|
+
* log-level listener (held in a module-global Set on the main-thread logger)
|
|
16480
|
+
* fall out of scope even when the consumer forgets to call `dispose()`.
|
|
16481
|
+
*/
|
|
16482
|
+
E2EEManager.disposeRegistry = typeof FinalizationRegistry !== 'undefined' && typeof WeakRef !== 'undefined' && new FinalizationRegistry(cleanup => {
|
|
16483
|
+
cleanup();
|
|
16484
|
+
});const MAX_ENTRIES = 300;
|
|
16236
16485
|
/**
|
|
16237
16486
|
* Caches frame metadata extracted from received video frames,
|
|
16238
16487
|
* keyed by RTP timestamp so it can be looked up when the frame is displayed.
|
|
@@ -18043,9 +18292,9 @@ class WebSocketStream {
|
|
|
18043
18292
|
let data = _ref2.data;
|
|
18044
18293
|
return controller.enqueue(data);
|
|
18045
18294
|
};
|
|
18046
|
-
ws.onerror = e => controller.error(ConnectionError.websocket(
|
|
18295
|
+
ws.onerror = e => controller.error(ConnectionError.websocket(getErrorDescription(e, 'websocket')));
|
|
18047
18296
|
ws.onclose = ev => {
|
|
18048
|
-
if (ev.wasClean) {
|
|
18297
|
+
if (ev.wasClean || ev.code === 1000) {
|
|
18049
18298
|
controller.close();
|
|
18050
18299
|
} else {
|
|
18051
18300
|
controller.error(ConnectionError.websocket("WS closed unexpectedly with code ".concat(ev.code)));
|
|
@@ -18500,6 +18749,7 @@ class SignalClient {
|
|
|
18500
18749
|
if (firstMessage) {
|
|
18501
18750
|
this.handleSignalResponse(firstMessage);
|
|
18502
18751
|
}
|
|
18752
|
+
const attemptId = this.attemptId;
|
|
18503
18753
|
while (true) {
|
|
18504
18754
|
if (this.signalLatency) {
|
|
18505
18755
|
yield sleep(this.signalLatency);
|
|
@@ -18517,7 +18767,7 @@ class SignalClient {
|
|
|
18517
18767
|
this.log.error("error reading from signal stream", {
|
|
18518
18768
|
error: e
|
|
18519
18769
|
});
|
|
18520
|
-
yield this.
|
|
18770
|
+
yield this.handleOnClose('error in reading loop', attemptId);
|
|
18521
18771
|
break;
|
|
18522
18772
|
}
|
|
18523
18773
|
}
|
|
@@ -21074,13 +21324,21 @@ class PCTransportManager {
|
|
|
21074
21324
|
this.updateState();
|
|
21075
21325
|
});
|
|
21076
21326
|
}
|
|
21327
|
+
/**
|
|
21328
|
+
* Restarts ICE on the transports that need it. Only the publisher: the server restarts the
|
|
21329
|
+
* subscriber's ICE itself and follows with a fresh offer.
|
|
21330
|
+
*
|
|
21331
|
+
* The subscriber deliberately does NOT enter `restartingIce` here. Queueing its remote
|
|
21332
|
+
* candidates would guard against candidates for a new generation arriving before the offer
|
|
21333
|
+
* that introduces it, but the server does not send them in that order -- on a same-node
|
|
21334
|
+
* resume it buffers them until the offer has gone out, and on a reconnect that lands on
|
|
21335
|
+
* another node it withholds subscriber candidates until immediately before creating the
|
|
21336
|
+
* offer. Setting the flag only risks withholding candidates during the window that decides
|
|
21337
|
+
* whether the reconnect succeeded.
|
|
21338
|
+
*/
|
|
21077
21339
|
triggerIceRestart() {
|
|
21078
21340
|
return __awaiter(this, void 0, void 0, function* () {
|
|
21079
21341
|
this.iceLog.warn('triggering ICE restart');
|
|
21080
|
-
if (this.subscriber) {
|
|
21081
|
-
this.subscriber.restartingIce = true;
|
|
21082
|
-
}
|
|
21083
|
-
// only restart publisher if it's needed
|
|
21084
21342
|
if (this.needsPublisher) {
|
|
21085
21343
|
yield this.createAndSendPublisherOffer({
|
|
21086
21344
|
iceRestart: true
|
|
@@ -22926,6 +23184,8 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
|
|
|
22926
23184
|
const useSimulcast = options === null || options === void 0 ? void 0 : options.simulcast;
|
|
22927
23185
|
const scalabilityMode = options === null || options === void 0 ? void 0 : options.scalabilityMode;
|
|
22928
23186
|
const videoCodec = options === null || options === void 0 ? void 0 : options.videoCodec;
|
|
23187
|
+
// VP9/AV1 published as rid based simulcast rather than SVC, see isSVCSimulcast
|
|
23188
|
+
const useSVCSimulcast = isSVCSimulcast(videoCodec, options);
|
|
22929
23189
|
if (!videoEncoding && !useSimulcast && !scalabilityMode || !width || !height) {
|
|
22930
23190
|
// when we aren't simulcasting or svc, will need to return a single encoding without
|
|
22931
23191
|
// capping bandwidth. we always require a encoding for dynacast
|
|
@@ -22938,23 +23198,16 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
|
|
|
22938
23198
|
}
|
|
22939
23199
|
const sourceFramerate = videoEncoding.maxFramerate;
|
|
22940
23200
|
const original = new VideoPreset(width, height, videoEncoding.maxBitrate, videoEncoding.maxFramerate, videoEncoding.priority);
|
|
22941
|
-
if (scalabilityMode && isSVCCodec(videoCodec)) {
|
|
23201
|
+
if (scalabilityMode && isSVCCodec(videoCodec) && !useSVCSimulcast) {
|
|
22942
23202
|
const sm = new ScalabilityMode(scalabilityMode);
|
|
22943
23203
|
const encodings = [];
|
|
22944
23204
|
if (sm.spatial > 3) {
|
|
22945
23205
|
throw new Error("unsupported scalabilityMode: ".concat(scalabilityMode));
|
|
22946
23206
|
}
|
|
22947
|
-
//
|
|
22948
|
-
//
|
|
22949
|
-
// This is a bit confusing but is due to how libwebrtc interpreted the encodings field
|
|
22950
|
-
// before M113.
|
|
22951
|
-
// Announced here: https://groups.google.com/g/discuss-webrtc/c/-QQ3pxrl-fw?pli=1
|
|
23207
|
+
// Browsers that read multiple encodings on an SVC codec as SVC rather than as
|
|
23208
|
+
// simulcast, see usesLegacySVCEncodings
|
|
22952
23209
|
const browser = getBrowser();
|
|
22953
|
-
if (
|
|
22954
|
-
// Even tho RN runs M114, it does not produce SVC layers when a single encoding
|
|
22955
|
-
// is provided. So we'll use the legacy SVC specification for now.
|
|
22956
|
-
// TODO: when we upstream libwebrtc, this will need additional verification
|
|
22957
|
-
isReactNative() || (browser === null || browser === void 0 ? void 0 : browser.name) === 'Chrome' && compareVersions(browser === null || browser === void 0 ? void 0 : browser.version, '113') < 0) {
|
|
23210
|
+
if (usesLegacySVCEncodings()) {
|
|
22958
23211
|
const bitratesRatio = sm.suffix == 'h' ? 2 : 3;
|
|
22959
23212
|
// safari 18.4 uses a different svc API that requires scaleResolutionDownBy to be set.
|
|
22960
23213
|
const requireScale = isSafariSvcApi(browser);
|
|
@@ -22990,6 +23243,18 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
|
|
|
22990
23243
|
if (!useSimulcast) {
|
|
22991
23244
|
return [videoEncoding];
|
|
22992
23245
|
}
|
|
23246
|
+
// Chrome M113+ only treats multiple encodings on an SVC capable codec as real
|
|
23247
|
+
// simulcast when every encoding carries an explicit scalabilityMode next to its
|
|
23248
|
+
// scaleResolutionDownBy. Without it the encodings are interpreted as legacy SVC.
|
|
23249
|
+
const applySVCSimulcastMode = encodings => {
|
|
23250
|
+
if (useSVCSimulcast) {
|
|
23251
|
+
encodings.forEach(encoding => {
|
|
23252
|
+
/* @ts-ignore */
|
|
23253
|
+
encoding.scalabilityMode = scalabilityMode;
|
|
23254
|
+
});
|
|
23255
|
+
}
|
|
23256
|
+
return encodings;
|
|
23257
|
+
};
|
|
22993
23258
|
let presets;
|
|
22994
23259
|
if (isScreenShare) {
|
|
22995
23260
|
presets = (_a = sortPresets(options === null || options === void 0 ? void 0 : options.screenShareSimulcastLayers)) !== null && _a !== void 0 ? _a : defaultSimulcastLayers(isScreenShare, original);
|
|
@@ -23015,13 +23280,38 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
|
|
|
23015
23280
|
// based on other conditions.
|
|
23016
23281
|
const size = Math.max(width, height);
|
|
23017
23282
|
if (size >= 960 && midPreset) {
|
|
23018
|
-
return encodingsFromPresets(width, height, [lowPreset, midPreset, original], sourceFramerate);
|
|
23283
|
+
return applySVCSimulcastMode(encodingsFromPresets(width, height, [lowPreset, midPreset, original], sourceFramerate));
|
|
23019
23284
|
}
|
|
23020
23285
|
if (size >= 480) {
|
|
23021
|
-
return encodingsFromPresets(width, height, [lowPreset, original], sourceFramerate);
|
|
23286
|
+
return applySVCSimulcastMode(encodingsFromPresets(width, height, [lowPreset, original], sourceFramerate));
|
|
23022
23287
|
}
|
|
23023
23288
|
}
|
|
23024
|
-
return encodingsFromPresets(width, height, [original]);
|
|
23289
|
+
return applySVCSimulcastMode(encodingsFromPresets(width, height, [original]));
|
|
23290
|
+
}
|
|
23291
|
+
/**
|
|
23292
|
+
* Bitrate to hint to the bandwidth estimator through `x-google-start-bitrate`, so that
|
|
23293
|
+
* a publish does not spend its first seconds ramping up from a very low rate.
|
|
23294
|
+
*
|
|
23295
|
+
* It has to be the total the encoder will put on the wire, which means picking the
|
|
23296
|
+
* encoding that carries the inclusive bitrate:
|
|
23297
|
+
* - SVC publishes a single stream with the layers built in. `encodings[0]` holds the
|
|
23298
|
+
* full bitrate — the legacy SVC shape orders its encodings `f`..`q`, so that holds
|
|
23299
|
+
* for both SVC shapes.
|
|
23300
|
+
* - Simulcast publishes independent streams ordered `q`..`f`, so the total is the sum.
|
|
23301
|
+
* This includes VP9/AV1 published as rid based simulcast, where `encodings[0]` is
|
|
23302
|
+
* the *smallest* layer even though the codec is SVC capable.
|
|
23303
|
+
*
|
|
23304
|
+
* @internal
|
|
23305
|
+
*/
|
|
23306
|
+
function computeStartTargetBitrate(codec, options, encodings) {
|
|
23307
|
+
var _a, _b;
|
|
23308
|
+
if (isSVCCodec(codec) && !isSVCSimulcast(codec, options)) {
|
|
23309
|
+
return (_b = (_a = encodings[0]) === null || _a === void 0 ? void 0 : _a.maxBitrate) !== null && _b !== void 0 ? _b : 0;
|
|
23310
|
+
}
|
|
23311
|
+
return encodings.reduce((sum, enc) => {
|
|
23312
|
+
var _a;
|
|
23313
|
+
return sum + ((_a = enc.maxBitrate) !== null && _a !== void 0 ? _a : 0);
|
|
23314
|
+
}, 0);
|
|
23025
23315
|
}
|
|
23026
23316
|
function computeTrackBackupEncodings(track, videoCodec, opts) {
|
|
23027
23317
|
var _a, _b, _c, _d;
|
|
@@ -23475,6 +23765,15 @@ class LocalVideoTrack extends LocalTrack {
|
|
|
23475
23765
|
return items;
|
|
23476
23766
|
});
|
|
23477
23767
|
}
|
|
23768
|
+
/**
|
|
23769
|
+
* Whether `codec` is being published as SVC (a single stream carrying all spatial
|
|
23770
|
+
* layers) as opposed to rid based simulcast. VP9/AV1 are SVC unless the publisher
|
|
23771
|
+
* opted into simulcast, in which case each rid is an independent stream and the
|
|
23772
|
+
* layers can be enabled/disabled individually.
|
|
23773
|
+
*/
|
|
23774
|
+
isSvcPublish(codec) {
|
|
23775
|
+
return isSVCCodec(codec) && !isSVCSimulcast(codec, this.publishOptions);
|
|
23776
|
+
}
|
|
23478
23777
|
setPublishingQuality(maxQuality) {
|
|
23479
23778
|
const qualities = [];
|
|
23480
23779
|
for (let q = VideoQuality.LOW; q <= VideoQuality.HIGH; q += 1) {
|
|
@@ -23484,7 +23783,7 @@ class LocalVideoTrack extends LocalTrack {
|
|
|
23484
23783
|
}));
|
|
23485
23784
|
}
|
|
23486
23785
|
this.log.debug("setting publishing quality. max quality ".concat(maxQuality), this.logContext);
|
|
23487
|
-
this.setPublishingLayers(
|
|
23786
|
+
this.setPublishingLayers(this.isSvcPublish(this.codec), qualities);
|
|
23488
23787
|
}
|
|
23489
23788
|
restartTrack(options) {
|
|
23490
23789
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -23749,7 +24048,7 @@ class LocalVideoTrack extends LocalTrack {
|
|
|
23749
24048
|
}));
|
|
23750
24049
|
// only enable simulcast codec for preference codec setted
|
|
23751
24050
|
if (!this.codec && codecs.length > 0) {
|
|
23752
|
-
yield this.setPublishingLayers(
|
|
24051
|
+
yield this.setPublishingLayers(this.isSvcPublish(codecs[0].codec), codecs[0].qualities);
|
|
23753
24052
|
return [];
|
|
23754
24053
|
}
|
|
23755
24054
|
this.subscribedCodecs = codecs;
|
|
@@ -23760,7 +24059,7 @@ class LocalVideoTrack extends LocalTrack {
|
|
|
23760
24059
|
_a = false;
|
|
23761
24060
|
const codec = _d;
|
|
23762
24061
|
if (!this.codec || this.codec === codec.codec) {
|
|
23763
|
-
yield this.setPublishingLayers(
|
|
24062
|
+
yield this.setPublishingLayers(this.isSvcPublish(codec.codec), codec.qualities);
|
|
23764
24063
|
} else {
|
|
23765
24064
|
const simulcastCodecInfo = this.simulcastCodecs.get(codec.codec);
|
|
23766
24065
|
this.log.debug("try setPublishingCodec for ".concat(codec.codec), Object.assign(Object.assign({}, this.logContext), {
|
|
@@ -23775,7 +24074,7 @@ class LocalVideoTrack extends LocalTrack {
|
|
|
23775
24074
|
}
|
|
23776
24075
|
} else if (simulcastCodecInfo.encodings) {
|
|
23777
24076
|
this.log.debug("try setPublishingLayersForSender ".concat(codec.codec), this.logContext);
|
|
23778
|
-
yield setPublishingLayersForSender(simulcastCodecInfo.sender, simulcastCodecInfo.encodings, codec.qualities, this.senderLock,
|
|
24077
|
+
yield setPublishingLayersForSender(simulcastCodecInfo.sender, simulcastCodecInfo.encodings, codec.qualities, this.senderLock, this.isSvcPublish(codec.codec), this.log, this.logContext);
|
|
23779
24078
|
}
|
|
23780
24079
|
}
|
|
23781
24080
|
}
|
|
@@ -24035,6 +24334,10 @@ class RTCEngine extends eventsExports.EventEmitter {
|
|
|
24035
24334
|
get pendingReconnect() {
|
|
24036
24335
|
return !!this.reconnectTimeout;
|
|
24037
24336
|
}
|
|
24337
|
+
get serverVersion() {
|
|
24338
|
+
var _a, _b, _c;
|
|
24339
|
+
return ((_b = (_a = this.latestJoinResponse) === null || _a === void 0 ? void 0 : _a.serverInfo) === null || _b === void 0 ? void 0 : _b.version) || ((_c = this.latestJoinResponse) === null || _c === void 0 ? void 0 : _c.serverVersion) || undefined;
|
|
24340
|
+
}
|
|
24038
24341
|
get reliableChannel() {
|
|
24039
24342
|
return this.dataChannels.reliable;
|
|
24040
24343
|
}
|
|
@@ -24087,7 +24390,7 @@ class RTCEngine extends eventsExports.EventEmitter {
|
|
|
24087
24390
|
}();
|
|
24088
24391
|
});
|
|
24089
24392
|
this.handleDataMessage = message => __awaiter(this, void 0, void 0, function* () {
|
|
24090
|
-
var _a, _b, _c, _d
|
|
24393
|
+
var _a, _b, _c, _d;
|
|
24091
24394
|
// make sure to respect incoming data message order by processing message events one after the other
|
|
24092
24395
|
const unlock = yield this.dataProcessLock.lock();
|
|
24093
24396
|
try {
|
|
@@ -24112,20 +24415,29 @@ class RTCEngine extends eventsExports.EventEmitter {
|
|
|
24112
24415
|
this.log.error('Received encrypted packet but E2EE not set up');
|
|
24113
24416
|
return;
|
|
24114
24417
|
}
|
|
24115
|
-
|
|
24418
|
+
let decryptedData;
|
|
24419
|
+
try {
|
|
24420
|
+
decryptedData = yield this.e2eeManager.handleEncryptedData(dp.value.value.encryptedValue, dp.value.value.iv, dp.participantIdentity, dp.value.value.keyIndex);
|
|
24421
|
+
} catch (err) {
|
|
24422
|
+
this.log.debug('failed to decrypt data packet', {
|
|
24423
|
+
error: err,
|
|
24424
|
+
participantIdentity: dp.participantIdentity
|
|
24425
|
+
});
|
|
24426
|
+
return;
|
|
24427
|
+
}
|
|
24116
24428
|
const decryptedPacket = EncryptedPacketPayload.fromBinary(decryptedData.payload);
|
|
24117
24429
|
const newDp = new DataPacket({
|
|
24118
24430
|
value: decryptedPacket.value,
|
|
24119
24431
|
participantIdentity: dp.participantIdentity,
|
|
24120
24432
|
participantSid: dp.participantSid
|
|
24121
24433
|
});
|
|
24122
|
-
if (((
|
|
24434
|
+
if (((_c = newDp.value) === null || _c === void 0 ? void 0 : _c.case) === 'user') {
|
|
24123
24435
|
// compatibility
|
|
24124
24436
|
applyUserDataCompat(newDp, newDp.value.value);
|
|
24125
24437
|
}
|
|
24126
24438
|
this.emit(EngineEvent.DataPacketReceived, newDp, dp.value.value.encryptionType);
|
|
24127
24439
|
} else {
|
|
24128
|
-
if (((
|
|
24440
|
+
if (((_d = dp.value) === null || _d === void 0 ? void 0 : _d.case) === 'user') {
|
|
24129
24441
|
// compatibility
|
|
24130
24442
|
applyUserDataCompat(dp, dp.value.value);
|
|
24131
24443
|
}
|
|
@@ -24626,7 +24938,11 @@ class RTCEngine extends eventsExports.EventEmitter {
|
|
|
24626
24938
|
sdp: sd.sdp,
|
|
24627
24939
|
midToTrackId
|
|
24628
24940
|
});
|
|
24629
|
-
|
|
24941
|
+
// in dual PC mode the publisher answer carries no mapping (the server's publisher
|
|
24942
|
+
// transport has no sending tracks) and must not clobber the subscriber offer mapping
|
|
24943
|
+
if (this.pcManager.mode === 'publisher-only') {
|
|
24944
|
+
this.midToTrackId = midToTrackId;
|
|
24945
|
+
}
|
|
24630
24946
|
yield this.pcManager.setPublisherAnswer(sd, offerId);
|
|
24631
24947
|
});
|
|
24632
24948
|
// add candidate on trickle
|
|
@@ -25911,8 +26227,11 @@ const DEFAULT_MAX_PAYLOAD_BYTE_LENGTH = 5000000000;class BaseStreamReader {
|
|
|
25911
26227
|
this._info = info;
|
|
25912
26228
|
this.bytesReceived = 0;
|
|
25913
26229
|
}
|
|
25914
|
-
|
|
25915
|
-
|
|
26230
|
+
/**
|
|
26231
|
+
* Counts a chunk's bytes against `totalByteSize` and reports progress. Chunk ordering and
|
|
26232
|
+
* de-duplication happen upstream in the manager's `ensureOrderedChunks`, so every chunk reaching
|
|
26233
|
+
* here is new and in order.
|
|
26234
|
+
*/
|
|
25916
26235
|
handleChunkReceived(chunk) {
|
|
25917
26236
|
var _a;
|
|
25918
26237
|
this.bytesReceived += chunk.content.byteLength;
|
|
@@ -25920,6 +26239,8 @@ class ByteStreamReader extends BaseStreamReader {
|
|
|
25920
26239
|
const currentProgress = this.totalByteSize ? this.bytesReceived / this.totalByteSize : undefined;
|
|
25921
26240
|
(_a = this.onProgress) === null || _a === void 0 ? void 0 : _a.call(this, currentProgress);
|
|
25922
26241
|
}
|
|
26242
|
+
}
|
|
26243
|
+
class ByteStreamReader extends BaseStreamReader {
|
|
25923
26244
|
[Symbol.asyncIterator]() {
|
|
25924
26245
|
const reader = this.reader.getReader();
|
|
25925
26246
|
// Suppress unhandled rejection on reader.closed — errors are
|
|
@@ -26027,35 +26348,18 @@ class ByteStreamReader extends BaseStreamReader {
|
|
|
26027
26348
|
}
|
|
26028
26349
|
}
|
|
26029
26350
|
/**
|
|
26030
|
-
* A class to read chunks from a ReadableStream and
|
|
26351
|
+
* A class to read chunks from a ReadableStream and decode them as UTF-8 text.
|
|
26352
|
+
*
|
|
26353
|
+
* NOTE: chunk-level `version` (resending a chunk at an already-received `chunkIndex` to supersede
|
|
26354
|
+
* it) is not supported. The reader used to rebuild the whole string from a per-index chunk map and
|
|
26355
|
+
* yield it as `TextStreamChunk.collected`, which made superseding work; 5d4a6346 (#1410, text auto
|
|
26356
|
+
* chunking) changed the iterator to yield each chunk's text as it arrives, and a streaming reader
|
|
26357
|
+
* cannot retract text it has already handed to the consumer. No sender emits a versioned chunk.
|
|
26031
26358
|
*/
|
|
26032
26359
|
class TextStreamReader extends BaseStreamReader {
|
|
26033
|
-
/**
|
|
26034
|
-
* A TextStreamReader instance can be used as an AsyncIterator that returns the entire string
|
|
26035
|
-
* that has been received up to the current point in time.
|
|
26036
|
-
*/
|
|
26037
|
-
constructor(info, stream, totalChunkCount) {
|
|
26038
|
-
super(info, stream, totalChunkCount);
|
|
26039
|
-
this.receivedChunks = new Map();
|
|
26040
|
-
}
|
|
26041
|
-
handleChunkReceived(chunk) {
|
|
26042
|
-
var _a;
|
|
26043
|
-
const index = bigIntToNumber(chunk.chunkIndex);
|
|
26044
|
-
const previousChunkAtIndex = this.receivedChunks.get(index);
|
|
26045
|
-
if (previousChunkAtIndex && previousChunkAtIndex.version > chunk.version) {
|
|
26046
|
-
// we have a newer version already, dropping the old one
|
|
26047
|
-
return;
|
|
26048
|
-
}
|
|
26049
|
-
this.receivedChunks.set(index, chunk);
|
|
26050
|
-
this.bytesReceived += chunk.content.byteLength;
|
|
26051
|
-
this.validateBytesReceived();
|
|
26052
|
-
const currentProgress = this.totalByteSize ? this.bytesReceived / this.totalByteSize : undefined;
|
|
26053
|
-
(_a = this.onProgress) === null || _a === void 0 ? void 0 : _a.call(this, currentProgress);
|
|
26054
|
-
}
|
|
26055
26360
|
/**
|
|
26056
26361
|
* Async iterator implementation to allow usage of `for await...of` syntax.
|
|
26057
|
-
* Yields
|
|
26058
|
-
*
|
|
26362
|
+
* Yields each chunk's decoded text as it arrives - a delta, not the string accumulated so far.
|
|
26059
26363
|
*/
|
|
26060
26364
|
[Symbol.asyncIterator]() {
|
|
26061
26365
|
const reader = this.reader.getReader();
|
|
@@ -26326,7 +26630,7 @@ class TextStreamReader extends BaseStreamReader {
|
|
|
26326
26630
|
});
|
|
26327
26631
|
}
|
|
26328
26632
|
});
|
|
26329
|
-
streamHandlerCallback(new ByteStreamReader(info, compressed ? inflateRawByteChunkStream(stream, streamHeader.streamId, this.maxPayloadByteLength) : stream,
|
|
26633
|
+
streamHandlerCallback(new ByteStreamReader(info, compressed ? inflateRawByteChunkStream(stream, streamHeader.streamId, this.maxPayloadByteLength) : stream.pipeThrough(ensureOrderedChunks(streamHeader.streamId)),
|
|
26330
26634
|
// `totalLength` is the pre-compression size, and the reader counts decompressed bytes,
|
|
26331
26635
|
// so it applies to both paths (mirrors text).
|
|
26332
26636
|
bigIntToNumber(streamHeader.totalLength)), {
|
|
@@ -26398,7 +26702,7 @@ class TextStreamReader extends BaseStreamReader {
|
|
|
26398
26702
|
});
|
|
26399
26703
|
}
|
|
26400
26704
|
});
|
|
26401
|
-
streamHandlerCallback(new TextStreamReader(info, compressed ? inflateRawChunkStream(stream, streamHeader.streamId, this.maxPayloadByteLength) : stream,
|
|
26705
|
+
streamHandlerCallback(new TextStreamReader(info, compressed ? inflateRawChunkStream(stream, streamHeader.streamId, this.maxPayloadByteLength) : stream.pipeThrough(ensureOrderedChunks(streamHeader.streamId)),
|
|
26402
26706
|
// `totalLength` is the pre-compression size, and the reader sees decompressed bytes, so
|
|
26403
26707
|
// it applies to both paths.
|
|
26404
26708
|
bigIntToNumber(streamHeader.totalLength)), {
|
|
@@ -26414,7 +26718,7 @@ class TextStreamReader extends BaseStreamReader {
|
|
|
26414
26718
|
if (fileBuffer.info.encryptionType !== encryptionType) {
|
|
26415
26719
|
fileBuffer.controller.error(new DataStreamError("Encryption type mismatch for stream ".concat(chunk.streamId, ". Expected ").concat(encryptionType, ", got ").concat(fileBuffer.info.encryptionType), DataStreamErrorReason.EncryptionTypeMismatch));
|
|
26416
26720
|
this.byteStreamControllers.delete(chunk.streamId);
|
|
26417
|
-
} else
|
|
26721
|
+
} else {
|
|
26418
26722
|
fileBuffer.controller.enqueue(chunk);
|
|
26419
26723
|
}
|
|
26420
26724
|
}
|
|
@@ -26423,7 +26727,7 @@ class TextStreamReader extends BaseStreamReader {
|
|
|
26423
26727
|
if (textBuffer.info.encryptionType !== encryptionType) {
|
|
26424
26728
|
textBuffer.controller.error(new DataStreamError("Encryption type mismatch for stream ".concat(chunk.streamId, ". Expected ").concat(encryptionType, ", got ").concat(textBuffer.info.encryptionType), DataStreamErrorReason.EncryptionTypeMismatch));
|
|
26425
26729
|
this.textStreamControllers.delete(chunk.streamId);
|
|
26426
|
-
} else
|
|
26730
|
+
} else {
|
|
26427
26731
|
textBuffer.controller.enqueue(chunk);
|
|
26428
26732
|
}
|
|
26429
26733
|
}
|
|
@@ -26471,26 +26775,24 @@ class TextStreamReader extends BaseStreamReader {
|
|
|
26471
26775
|
function createInlineStream(streamId, content) {
|
|
26472
26776
|
return new ReadableStream({
|
|
26473
26777
|
start: controller => __awaiter(this, void 0, void 0, function* () {
|
|
26474
|
-
|
|
26475
|
-
|
|
26476
|
-
|
|
26477
|
-
|
|
26478
|
-
|
|
26479
|
-
|
|
26480
|
-
|
|
26481
|
-
controller.close();
|
|
26482
|
-
} catch (err) {
|
|
26483
|
-
controller.error(err);
|
|
26484
|
-
}
|
|
26778
|
+
const bytes = yield content;
|
|
26779
|
+
controller.enqueue(new DataStream_Chunk({
|
|
26780
|
+
streamId,
|
|
26781
|
+
chunkIndex: BigInt(0),
|
|
26782
|
+
content: bytes
|
|
26783
|
+
}));
|
|
26784
|
+
controller.close();
|
|
26485
26785
|
})
|
|
26486
26786
|
});
|
|
26487
26787
|
}
|
|
26488
26788
|
/**
|
|
26489
26789
|
* Validates that chunks are received in order, dropping duplicates and throwing if gaps are found.
|
|
26490
26790
|
*
|
|
26491
|
-
*
|
|
26492
|
-
* dropped (with a warning - in-order delivery is expected
|
|
26493
|
-
* handling may replay) and a gap is a hard error.
|
|
26791
|
+
* Reassembly (and, for compressed streams, a stateful decompressor) silently corrupts on duplicated
|
|
26792
|
+
* or out-of-order input, so duplicates are dropped (with a warning - in-order delivery is expected
|
|
26793
|
+
* on the reliable channel, but reconnect handling may replay) and a gap is a hard error. Empty
|
|
26794
|
+
* chunks consume their index and are then dropped, so they never reach the reader. Applied to every
|
|
26795
|
+
* chunked stream, compressed or not.
|
|
26494
26796
|
*/
|
|
26495
26797
|
function ensureOrderedChunks(streamId) {
|
|
26496
26798
|
let lastChunkIndex = -1;
|
|
@@ -26498,13 +26800,16 @@ function ensureOrderedChunks(streamId) {
|
|
|
26498
26800
|
transform: (value, controller) => {
|
|
26499
26801
|
const index = bigIntToNumber(value.chunkIndex);
|
|
26500
26802
|
if (index <= lastChunkIndex) {
|
|
26501
|
-
livekitLogger.warn("ignoring duplicate chunk ".concat(index, " for
|
|
26803
|
+
livekitLogger.warn("ignoring duplicate chunk ".concat(index, " ").concat(value.version > 0 ? "(version ".concat(value.version, ")") : '', " for data stream ").concat(streamId, " (last processed: ").concat(lastChunkIndex, ")"));
|
|
26502
26804
|
return;
|
|
26503
26805
|
}
|
|
26504
26806
|
if (index > lastChunkIndex + 1) {
|
|
26505
|
-
throw new DataStreamError("Missing chunk(s) ".concat(lastChunkIndex + 1, "..").concat(index - 1, " for
|
|
26807
|
+
throw new DataStreamError("Missing chunk(s) ".concat(lastChunkIndex + 1, "..").concat(index - 1, " for data stream ").concat(streamId, " - cannot reassemble payload"), DataStreamErrorReason.Incomplete);
|
|
26506
26808
|
}
|
|
26507
26809
|
lastChunkIndex = index;
|
|
26810
|
+
if (value.content.length === 0) {
|
|
26811
|
+
return;
|
|
26812
|
+
}
|
|
26508
26813
|
controller.enqueue(value);
|
|
26509
26814
|
}
|
|
26510
26815
|
});
|
|
@@ -31748,7 +32053,7 @@ class Participant extends eventsExports.EventEmitter {
|
|
|
31748
32053
|
}
|
|
31749
32054
|
publish(track, opts, isStereo) {
|
|
31750
32055
|
return __awaiter(this, void 0, void 0, function* () {
|
|
31751
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
32056
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
31752
32057
|
if (!this.hasPermissionsToPublish(track)) {
|
|
31753
32058
|
throw new PublishTrackError('failed to publish track, insufficient permissions', 403);
|
|
31754
32059
|
}
|
|
@@ -31851,7 +32156,12 @@ class Participant extends eventsExports.EventEmitter {
|
|
|
31851
32156
|
req.height = dims.height;
|
|
31852
32157
|
// for svc codecs, disable simulcast and use vp8 for backup codec
|
|
31853
32158
|
if (isLocalVideoTrack(track)) {
|
|
31854
|
-
if (
|
|
32159
|
+
if (isSVCSimulcast(videoCodec, opts) && (usesLegacySVCEncodings() || !isSVCSimulcastSupportedByServer((_e = this.engine) === null || _e === void 0 ? void 0 : _e.serverVersion))) {
|
|
32160
|
+
opts.simulcast = false;
|
|
32161
|
+
this.log.info('SVC simulcast is not supported, disabling simulcast.', getLogContextFromTrack(track));
|
|
32162
|
+
}
|
|
32163
|
+
const svcSimulcast = isSVCSimulcast(videoCodec, opts);
|
|
32164
|
+
if (isSVCCodec(videoCodec) && !svcSimulcast) {
|
|
31855
32165
|
if (track.source === Track.Source.ScreenShare) {
|
|
31856
32166
|
// vp9 svc with screenshare cannot encode multiple spatial layers
|
|
31857
32167
|
// doing so reduces publish resolution to minimal resolution
|
|
@@ -31867,12 +32177,16 @@ class Participant extends eventsExports.EventEmitter {
|
|
|
31867
32177
|
}
|
|
31868
32178
|
}
|
|
31869
32179
|
// set scalabilityMode to 'L3T3_KEY' by default
|
|
31870
|
-
opts.scalabilityMode = (
|
|
32180
|
+
opts.scalabilityMode = (_f = opts.scalabilityMode) !== null && _f !== void 0 ? _f : 'L3T3_KEY';
|
|
31871
32181
|
}
|
|
31872
|
-
|
|
32182
|
+
const primaryCodec = new SimulcastCodec({
|
|
31873
32183
|
codec: videoCodec,
|
|
31874
32184
|
cid: track.mediaStreamTrack.id
|
|
31875
|
-
})
|
|
32185
|
+
});
|
|
32186
|
+
if (svcSimulcast) {
|
|
32187
|
+
primaryCodec.videoLayerMode = VideoLayer_Mode.ONE_SPATIAL_LAYER_PER_STREAM;
|
|
32188
|
+
}
|
|
32189
|
+
req.simulcastCodecs = [primaryCodec];
|
|
31876
32190
|
// set up backup
|
|
31877
32191
|
if (opts.backupCodec === true) {
|
|
31878
32192
|
opts.backupCodec = {
|
|
@@ -31893,19 +32207,19 @@ class Participant extends eventsExports.EventEmitter {
|
|
|
31893
32207
|
}
|
|
31894
32208
|
}
|
|
31895
32209
|
encodings = computeVideoEncodings(track.source === Track.Source.ScreenShare, req.width, req.height, opts);
|
|
31896
|
-
req.layers = videoLayersFromEncodings(req.width, req.height, encodings, isSVCCodec(opts.videoCodec));
|
|
32210
|
+
req.layers = videoLayersFromEncodings(req.width, req.height, encodings, isSVCCodec(opts.videoCodec) && !isSVCSimulcast(opts.videoCodec, opts));
|
|
31897
32211
|
} else if (track.kind === Track.Kind.Audio) {
|
|
31898
32212
|
encodings = [{
|
|
31899
|
-
maxBitrate: (
|
|
31900
|
-
priority: (
|
|
31901
|
-
networkPriority: (
|
|
32213
|
+
maxBitrate: (_g = opts.audioPreset) === null || _g === void 0 ? void 0 : _g.maxBitrate,
|
|
32214
|
+
priority: (_j = (_h = opts.audioPreset) === null || _h === void 0 ? void 0 : _h.priority) !== null && _j !== void 0 ? _j : 'high',
|
|
32215
|
+
networkPriority: (_l = (_k = opts.audioPreset) === null || _k === void 0 ? void 0 : _k.priority) !== null && _l !== void 0 ? _l : 'high'
|
|
31902
32216
|
}];
|
|
31903
32217
|
}
|
|
31904
32218
|
if (!this.engine || this.engine.isClosed) {
|
|
31905
32219
|
throw new UnexpectedConnectionState('cannot publish track when not connected');
|
|
31906
32220
|
}
|
|
31907
32221
|
const negotiate = () => __awaiter(this, void 0, void 0, function* () {
|
|
31908
|
-
var _a, _b
|
|
32222
|
+
var _a, _b;
|
|
31909
32223
|
if (!this.engine.pcManager) {
|
|
31910
32224
|
throw new UnexpectedConnectionState('pcManager is not ready');
|
|
31911
32225
|
}
|
|
@@ -31942,13 +32256,9 @@ class Participant extends eventsExports.EventEmitter {
|
|
|
31942
32256
|
});
|
|
31943
32257
|
}
|
|
31944
32258
|
} else if (track.codec && isVideoCodec(track.codec)) {
|
|
31945
|
-
// Apply start bitrate for all video codecs to prevent initial blurriness
|
|
31946
|
-
//
|
|
31947
|
-
|
|
31948
|
-
const targetBitrate = isSVCCodec(track.codec) ? (_d = (_c = encodings[0]) === null || _c === void 0 ? void 0 : _c.maxBitrate) !== null && _d !== void 0 ? _d : 0 : encodings.reduce((sum, enc) => {
|
|
31949
|
-
var _a;
|
|
31950
|
-
return sum + ((_a = enc.maxBitrate) !== null && _a !== void 0 ? _a : 0);
|
|
31951
|
-
}, 0);
|
|
32259
|
+
// Apply start bitrate for all video codecs to prevent initial blurriness,
|
|
32260
|
+
// see computeStartTargetBitrate
|
|
32261
|
+
const targetBitrate = computeStartTargetBitrate(track.codec, opts, encodings);
|
|
31952
32262
|
if (targetBitrate > 0) {
|
|
31953
32263
|
this.engine.pcManager.publisher.setTrackCodecBitrate({
|
|
31954
32264
|
cid: req.cid,
|
|
@@ -34187,8 +34497,8 @@ class Room extends eventsExports.EventEmitter {
|
|
|
34187
34497
|
});
|
|
34188
34498
|
this.registerRpcDataStreamHandler();
|
|
34189
34499
|
this.rpcClientManager = new RpcClientManager(this.log, this.outgoingDataStreamManager, this.getRemoteParticipantClientProtocol, () => {
|
|
34190
|
-
var _a
|
|
34191
|
-
return (
|
|
34500
|
+
var _a;
|
|
34501
|
+
return (_a = this.engine) === null || _a === void 0 ? void 0 : _a.serverVersion;
|
|
34192
34502
|
});
|
|
34193
34503
|
this.rpcClientManager.on('sendDataPacket', _ref2 => {
|
|
34194
34504
|
let packet = _ref2.packet;
|
|
@@ -36343,33 +36653,10 @@ class TokenSourceFixed {}
|
|
|
36343
36653
|
* and {@link TokenSourceCustom}.
|
|
36344
36654
|
*/
|
|
36345
36655
|
class TokenSourceConfigurable {}new TextEncoder();
|
|
36346
|
-
const decoder = new TextDecoder();
|
|
36347
|
-
|
|
36348
|
-
|
|
36349
|
-
|
|
36350
|
-
const binary = atob(encoded);
|
|
36351
|
-
const bytes = new Uint8Array(binary.length);
|
|
36352
|
-
for (let i = 0; i < binary.length; i++) {
|
|
36353
|
-
bytes[i] = binary.charCodeAt(i);
|
|
36354
|
-
}
|
|
36355
|
-
return bytes;
|
|
36356
|
-
}function decode(input) {
|
|
36357
|
-
if (Uint8Array.fromBase64) {
|
|
36358
|
-
return Uint8Array.fromBase64(typeof input === 'string' ? input : decoder.decode(input), {
|
|
36359
|
-
alphabet: 'base64url'
|
|
36360
|
-
});
|
|
36361
|
-
}
|
|
36362
|
-
let encoded = input;
|
|
36363
|
-
if (encoded instanceof Uint8Array) {
|
|
36364
|
-
encoded = decoder.decode(encoded);
|
|
36365
|
-
}
|
|
36366
|
-
encoded = encoded.replace(/-/g, '+').replace(/_/g, '/');
|
|
36367
|
-
try {
|
|
36368
|
-
return decodeBase64(encoded);
|
|
36369
|
-
} catch (_unused) {
|
|
36370
|
-
throw new TypeError('The input to be decoded is not correctly encoded.');
|
|
36371
|
-
}
|
|
36372
|
-
}class JOSEError extends Error {
|
|
36656
|
+
const decoder = new TextDecoder();
|
|
36657
|
+
const strictDecoder = new TextDecoder('utf-8', {
|
|
36658
|
+
fatal: true
|
|
36659
|
+
});class JOSEError extends Error {
|
|
36373
36660
|
constructor(message, options) {
|
|
36374
36661
|
var _Error$captureStackTr;
|
|
36375
36662
|
super(message, options);
|
|
@@ -36493,7 +36780,7 @@ class JWKSMultipleMatchingKeys extends JOSEError {
|
|
|
36493
36780
|
let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'multiple matching keys found in the JSON Web Key Set';
|
|
36494
36781
|
let options = arguments.length > 1 ? arguments[1] : undefined;
|
|
36495
36782
|
super(message, options);
|
|
36496
|
-
_defineProperty(this, Symbol.asyncIterator,
|
|
36783
|
+
_defineProperty(this, Symbol.asyncIterator, _wrapAsyncGenerator(function* () {}));
|
|
36497
36784
|
_defineProperty(this, "code", 'ERR_JWKS_MULTIPLE_MATCHING_KEYS');
|
|
36498
36785
|
}
|
|
36499
36786
|
}
|
|
@@ -36515,19 +36802,55 @@ class JWSSignatureVerificationFailed extends JOSEError {
|
|
|
36515
36802
|
_defineProperty(this, "code", 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED');
|
|
36516
36803
|
}
|
|
36517
36804
|
}
|
|
36518
|
-
_defineProperty(JWSSignatureVerificationFailed, "code", 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED');
|
|
36519
|
-
|
|
36520
|
-
|
|
36805
|
+
_defineProperty(JWSSignatureVerificationFailed, "code", 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED');function decodeBase64(encoded) {
|
|
36806
|
+
if (Uint8Array.fromBase64) {
|
|
36807
|
+
return Uint8Array.fromBase64(encoded);
|
|
36808
|
+
}
|
|
36809
|
+
const binary = atob(encoded);
|
|
36810
|
+
const bytes = new Uint8Array(binary.length);
|
|
36811
|
+
for (let i = 0; i < binary.length; i++) {
|
|
36812
|
+
bytes[i] = binary.charCodeAt(i);
|
|
36813
|
+
}
|
|
36814
|
+
return bytes;
|
|
36815
|
+
}const invalid = 'The input to be decoded is not correctly encoded.';
|
|
36816
|
+
function decode(input) {
|
|
36817
|
+
if (Uint8Array.fromBase64) {
|
|
36818
|
+
try {
|
|
36819
|
+
return Uint8Array.fromBase64(typeof input === 'string' ? input : decoder.decode(input), {
|
|
36820
|
+
alphabet: 'base64url'
|
|
36821
|
+
});
|
|
36822
|
+
} catch (cause) {
|
|
36823
|
+
throw new TypeError(invalid, {
|
|
36824
|
+
cause
|
|
36825
|
+
});
|
|
36826
|
+
}
|
|
36827
|
+
}
|
|
36828
|
+
let encoded = input;
|
|
36829
|
+
if (encoded instanceof Uint8Array) {
|
|
36830
|
+
encoded = decoder.decode(encoded);
|
|
36831
|
+
}
|
|
36832
|
+
if (encoded.includes('+') || encoded.includes('/')) {
|
|
36833
|
+
throw new TypeError(invalid);
|
|
36834
|
+
}
|
|
36835
|
+
encoded = encoded.replace(/-/g, '+').replace(/_/g, '/');
|
|
36836
|
+
try {
|
|
36837
|
+
return decodeBase64(encoded);
|
|
36838
|
+
} catch (_unused) {
|
|
36839
|
+
throw new TypeError(invalid);
|
|
36840
|
+
}
|
|
36841
|
+
}function isObject(input) {
|
|
36842
|
+
if (typeof input !== 'object' || input === null || Object.prototype.toString.call(input) !== '[object Object]') {
|
|
36521
36843
|
return false;
|
|
36522
36844
|
}
|
|
36523
|
-
|
|
36845
|
+
const prototype = Object.getPrototypeOf(input);
|
|
36846
|
+
if (prototype === null) {
|
|
36524
36847
|
return true;
|
|
36525
36848
|
}
|
|
36526
|
-
let proto =
|
|
36849
|
+
let proto = prototype;
|
|
36527
36850
|
while (Object.getPrototypeOf(proto) !== null) {
|
|
36528
36851
|
proto = Object.getPrototypeOf(proto);
|
|
36529
36852
|
}
|
|
36530
|
-
return
|
|
36853
|
+
return prototype === proto;
|
|
36531
36854
|
}function decodeJwt(jwt) {
|
|
36532
36855
|
if (typeof jwt !== 'string') throw new JWTInvalid('JWTs must use Compact JWS serialization, JWT must be a string');
|
|
36533
36856
|
const _jwt$split = jwt.split('.'),
|
|
@@ -36544,7 +36867,7 @@ function isObject(input) {
|
|
|
36544
36867
|
}
|
|
36545
36868
|
let result;
|
|
36546
36869
|
try {
|
|
36547
|
-
result = JSON.parse(
|
|
36870
|
+
result = JSON.parse(strictDecoder.decode(decoded));
|
|
36548
36871
|
} catch (_unused2) {
|
|
36549
36872
|
throw new JWTInvalid('Failed to parse the decoded payload as JSON');
|
|
36550
36873
|
}
|