livekit-client 2.22.2 → 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 +486 -437
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +398 -100
- 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/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 +26 -0
- package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
- package/dist/src/e2ee/types.d.ts +15 -1
- 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 +1 -18
- 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/RTCEngine.d.ts +1 -0
- package/dist/src/room/RTCEngine.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 +26 -0
- package/dist/ts4.2/e2ee/types.d.ts +15 -1
- package/dist/ts4.2/e2ee/worker/ErrorRateLimiter.d.ts +21 -0
- package/dist/ts4.2/e2ee/worker/FrameCryptor.d.ts +1 -18
- package/dist/ts4.2/logger.d.ts +4 -0
- package/dist/ts4.2/room/RTCEngine.d.ts +1 -0
- 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/WebSocketStream.ts +3 -8
- package/src/api/utils.ts +10 -0
- package/src/e2ee/E2eeManager.test.ts +196 -0
- package/src/e2ee/E2eeManager.ts +114 -19
- package/src/e2ee/types.ts +19 -1
- 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.ts +20 -70
- package/src/e2ee/worker/e2ee.worker.ts +34 -11
- package/src/logger.ts +22 -0
- package/src/room/RTCEngine.ts +28 -7
- package/src/room/Room.ts +1 -1
- 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,6 +14945,15 @@ 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;
|
|
@@ -15775,10 +15905,18 @@ function isElementInViewport(el, win) {
|
|
|
15775
15905
|
* @experimental
|
|
15776
15906
|
*/
|
|
15777
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
|
+
}
|
|
15778
15915
|
constructor(options, dcEncryptionEnabled) {
|
|
15779
15916
|
super();
|
|
15780
15917
|
this.decryptDataRequests = new Map();
|
|
15781
15918
|
this.encryptDataRequests = new Map();
|
|
15919
|
+
this.log = getLogger(LoggerNames.E2EE, () => this.logContext);
|
|
15782
15920
|
this.onWorkerMessage = ev => {
|
|
15783
15921
|
var _a, _b;
|
|
15784
15922
|
const _ev$data = ev.data,
|
|
@@ -15786,22 +15924,22 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
15786
15924
|
data = _ev$data.data;
|
|
15787
15925
|
switch (kind) {
|
|
15788
15926
|
case 'error':
|
|
15789
|
-
|
|
15790
|
-
//
|
|
15791
|
-
//
|
|
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.
|
|
15792
15930
|
if (data.uuid) {
|
|
15793
15931
|
const decryptFuture = this.decryptDataRequests.get(data.uuid);
|
|
15794
15932
|
if (decryptFuture === null || decryptFuture === void 0 ? void 0 : decryptFuture.reject) {
|
|
15795
15933
|
decryptFuture.reject(data.error);
|
|
15796
|
-
break;
|
|
15934
|
+
break;
|
|
15797
15935
|
}
|
|
15798
15936
|
const encryptFuture = this.encryptDataRequests.get(data.uuid);
|
|
15799
15937
|
if (encryptFuture === null || encryptFuture === void 0 ? void 0 : encryptFuture.reject) {
|
|
15800
15938
|
encryptFuture.reject(data.error);
|
|
15801
|
-
break;
|
|
15939
|
+
break;
|
|
15802
15940
|
}
|
|
15803
15941
|
}
|
|
15804
|
-
|
|
15942
|
+
this.log.error(data.error.message);
|
|
15805
15943
|
this.emit(EncryptionEvent.EncryptionError, data.error, data.participantIdentity);
|
|
15806
15944
|
break;
|
|
15807
15945
|
case 'initAck':
|
|
@@ -15846,10 +15984,13 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
15846
15984
|
case 'packetTrailerMetadata':
|
|
15847
15985
|
this.handleFrameMetadata(data.trackId, data.rtpTimestamp, data.ssrc, data.metadata);
|
|
15848
15986
|
break;
|
|
15987
|
+
case 'log':
|
|
15988
|
+
workerLogger[data.level](data.msg, data.context);
|
|
15989
|
+
break;
|
|
15849
15990
|
}
|
|
15850
15991
|
};
|
|
15851
15992
|
this.onWorkerError = ev => {
|
|
15852
|
-
|
|
15993
|
+
this.log.error('e2ee worker encountered an error:', {
|
|
15853
15994
|
error: ev.error
|
|
15854
15995
|
});
|
|
15855
15996
|
this.emit(EncryptionEvent.EncryptionError, ev.error, undefined);
|
|
@@ -15872,7 +16013,7 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
15872
16013
|
if (!isE2EESupported()) {
|
|
15873
16014
|
throw new DeviceUnsupportedError('tried to setup end-to-end encryption on an unsupported browser');
|
|
15874
16015
|
}
|
|
15875
|
-
|
|
16016
|
+
this.log.info('setting up e2ee');
|
|
15876
16017
|
if (room !== this.room) {
|
|
15877
16018
|
this.room = room;
|
|
15878
16019
|
this.setupEventListeners(room, this.keyProvider);
|
|
@@ -15885,20 +16026,94 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
15885
16026
|
}
|
|
15886
16027
|
};
|
|
15887
16028
|
if (this.worker) {
|
|
15888
|
-
|
|
16029
|
+
this.log.info("initializing worker", {
|
|
15889
16030
|
worker: this.worker
|
|
15890
16031
|
});
|
|
15891
16032
|
this.worker.onmessage = this.onWorkerMessage;
|
|
15892
16033
|
this.worker.onerror = this.onWorkerError;
|
|
15893
16034
|
this.worker.postMessage(msg);
|
|
16035
|
+
this.subscribeToLogLevelChanges();
|
|
15894
16036
|
}
|
|
15895
16037
|
}
|
|
15896
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
|
+
}
|
|
15897
16112
|
/**
|
|
15898
16113
|
* @internal
|
|
15899
16114
|
*/
|
|
15900
16115
|
setParticipantCryptorEnabled(enabled, participantIdentity) {
|
|
15901
|
-
|
|
16116
|
+
this.log.debug("set e2ee to ".concat(enabled, " for participant ").concat(participantIdentity));
|
|
15902
16117
|
this.postEnable(enabled, participantIdentity);
|
|
15903
16118
|
}
|
|
15904
16119
|
/**
|
|
@@ -15906,7 +16121,7 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
15906
16121
|
*/
|
|
15907
16122
|
setSifTrailer(trailer) {
|
|
15908
16123
|
if (!trailer || trailer.length === 0) {
|
|
15909
|
-
|
|
16124
|
+
this.log.warn("ignoring server sent trailer as it's empty");
|
|
15910
16125
|
} else {
|
|
15911
16126
|
this.postSifTrailer(trailer);
|
|
15912
16127
|
}
|
|
@@ -16113,8 +16328,7 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
16113
16328
|
*/
|
|
16114
16329
|
setParticipantCryptorEnabledForPublication(pub, participantIdentity) {
|
|
16115
16330
|
if (!pub.trackInfo) {
|
|
16116
|
-
|
|
16117
|
-
participant: participantIdentity,
|
|
16331
|
+
this.log.warn('skipping e2ee enabled update for publication without trackInfo', {
|
|
16118
16332
|
trackSid: pub.trackSid
|
|
16119
16333
|
});
|
|
16120
16334
|
return;
|
|
@@ -16134,7 +16348,7 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
16134
16348
|
setupE2EESender(track, sender) {
|
|
16135
16349
|
var _a, _b, _c;
|
|
16136
16350
|
if (!isLocalTrack(track) || !sender) {
|
|
16137
|
-
if (!sender)
|
|
16351
|
+
if (!sender) this.log.warn('early return because sender is not ready');
|
|
16138
16352
|
return;
|
|
16139
16353
|
}
|
|
16140
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);
|
|
@@ -16227,7 +16441,7 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
16227
16441
|
throw TypeError('local identity needs to be known in order to set up encrypted sender');
|
|
16228
16442
|
}
|
|
16229
16443
|
if (isScriptTransformSupportedForWorker()) {
|
|
16230
|
-
|
|
16444
|
+
this.log.info('initialize script transform');
|
|
16231
16445
|
const options = {
|
|
16232
16446
|
kind: 'encode',
|
|
16233
16447
|
participantIdentity: this.room.localParticipant.identity,
|
|
@@ -16239,7 +16453,7 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
16239
16453
|
// @ts-ignore
|
|
16240
16454
|
sender.transform = new RTCRtpScriptTransform(this.worker, options);
|
|
16241
16455
|
} else {
|
|
16242
|
-
|
|
16456
|
+
this.log.info('initialize encoded streams');
|
|
16243
16457
|
// @ts-ignore
|
|
16244
16458
|
const senderStreams = sender.createEncodedStreams();
|
|
16245
16459
|
const msg = {
|
|
@@ -16259,7 +16473,15 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
16259
16473
|
// @ts-ignore
|
|
16260
16474
|
sender[E2EE_FLAG] = true;
|
|
16261
16475
|
}
|
|
16262
|
-
}
|
|
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;
|
|
16263
16485
|
/**
|
|
16264
16486
|
* Caches frame metadata extracted from received video frames,
|
|
16265
16487
|
* keyed by RTP timestamp so it can be looked up when the frame is displayed.
|
|
@@ -18070,9 +18292,9 @@ class WebSocketStream {
|
|
|
18070
18292
|
let data = _ref2.data;
|
|
18071
18293
|
return controller.enqueue(data);
|
|
18072
18294
|
};
|
|
18073
|
-
ws.onerror = e => controller.error(ConnectionError.websocket(
|
|
18295
|
+
ws.onerror = e => controller.error(ConnectionError.websocket(getErrorDescription(e, 'websocket')));
|
|
18074
18296
|
ws.onclose = ev => {
|
|
18075
|
-
if (ev.wasClean) {
|
|
18297
|
+
if (ev.wasClean || ev.code === 1000) {
|
|
18076
18298
|
controller.close();
|
|
18077
18299
|
} else {
|
|
18078
18300
|
controller.error(ConnectionError.websocket("WS closed unexpectedly with code ".concat(ev.code)));
|
|
@@ -22962,6 +23184,8 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
|
|
|
22962
23184
|
const useSimulcast = options === null || options === void 0 ? void 0 : options.simulcast;
|
|
22963
23185
|
const scalabilityMode = options === null || options === void 0 ? void 0 : options.scalabilityMode;
|
|
22964
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);
|
|
22965
23189
|
if (!videoEncoding && !useSimulcast && !scalabilityMode || !width || !height) {
|
|
22966
23190
|
// when we aren't simulcasting or svc, will need to return a single encoding without
|
|
22967
23191
|
// capping bandwidth. we always require a encoding for dynacast
|
|
@@ -22974,23 +23198,16 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
|
|
|
22974
23198
|
}
|
|
22975
23199
|
const sourceFramerate = videoEncoding.maxFramerate;
|
|
22976
23200
|
const original = new VideoPreset(width, height, videoEncoding.maxBitrate, videoEncoding.maxFramerate, videoEncoding.priority);
|
|
22977
|
-
if (scalabilityMode && isSVCCodec(videoCodec)) {
|
|
23201
|
+
if (scalabilityMode && isSVCCodec(videoCodec) && !useSVCSimulcast) {
|
|
22978
23202
|
const sm = new ScalabilityMode(scalabilityMode);
|
|
22979
23203
|
const encodings = [];
|
|
22980
23204
|
if (sm.spatial > 3) {
|
|
22981
23205
|
throw new Error("unsupported scalabilityMode: ".concat(scalabilityMode));
|
|
22982
23206
|
}
|
|
22983
|
-
//
|
|
22984
|
-
//
|
|
22985
|
-
// This is a bit confusing but is due to how libwebrtc interpreted the encodings field
|
|
22986
|
-
// before M113.
|
|
22987
|
-
// 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
|
|
22988
23209
|
const browser = getBrowser();
|
|
22989
|
-
if (
|
|
22990
|
-
// Even tho RN runs M114, it does not produce SVC layers when a single encoding
|
|
22991
|
-
// is provided. So we'll use the legacy SVC specification for now.
|
|
22992
|
-
// TODO: when we upstream libwebrtc, this will need additional verification
|
|
22993
|
-
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()) {
|
|
22994
23211
|
const bitratesRatio = sm.suffix == 'h' ? 2 : 3;
|
|
22995
23212
|
// safari 18.4 uses a different svc API that requires scaleResolutionDownBy to be set.
|
|
22996
23213
|
const requireScale = isSafariSvcApi(browser);
|
|
@@ -23026,6 +23243,18 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
|
|
|
23026
23243
|
if (!useSimulcast) {
|
|
23027
23244
|
return [videoEncoding];
|
|
23028
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
|
+
};
|
|
23029
23258
|
let presets;
|
|
23030
23259
|
if (isScreenShare) {
|
|
23031
23260
|
presets = (_a = sortPresets(options === null || options === void 0 ? void 0 : options.screenShareSimulcastLayers)) !== null && _a !== void 0 ? _a : defaultSimulcastLayers(isScreenShare, original);
|
|
@@ -23051,13 +23280,38 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
|
|
|
23051
23280
|
// based on other conditions.
|
|
23052
23281
|
const size = Math.max(width, height);
|
|
23053
23282
|
if (size >= 960 && midPreset) {
|
|
23054
|
-
return encodingsFromPresets(width, height, [lowPreset, midPreset, original], sourceFramerate);
|
|
23283
|
+
return applySVCSimulcastMode(encodingsFromPresets(width, height, [lowPreset, midPreset, original], sourceFramerate));
|
|
23055
23284
|
}
|
|
23056
23285
|
if (size >= 480) {
|
|
23057
|
-
return encodingsFromPresets(width, height, [lowPreset, original], sourceFramerate);
|
|
23286
|
+
return applySVCSimulcastMode(encodingsFromPresets(width, height, [lowPreset, original], sourceFramerate));
|
|
23058
23287
|
}
|
|
23059
23288
|
}
|
|
23060
|
-
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);
|
|
23061
23315
|
}
|
|
23062
23316
|
function computeTrackBackupEncodings(track, videoCodec, opts) {
|
|
23063
23317
|
var _a, _b, _c, _d;
|
|
@@ -23511,6 +23765,15 @@ class LocalVideoTrack extends LocalTrack {
|
|
|
23511
23765
|
return items;
|
|
23512
23766
|
});
|
|
23513
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
|
+
}
|
|
23514
23777
|
setPublishingQuality(maxQuality) {
|
|
23515
23778
|
const qualities = [];
|
|
23516
23779
|
for (let q = VideoQuality.LOW; q <= VideoQuality.HIGH; q += 1) {
|
|
@@ -23520,7 +23783,7 @@ class LocalVideoTrack extends LocalTrack {
|
|
|
23520
23783
|
}));
|
|
23521
23784
|
}
|
|
23522
23785
|
this.log.debug("setting publishing quality. max quality ".concat(maxQuality), this.logContext);
|
|
23523
|
-
this.setPublishingLayers(
|
|
23786
|
+
this.setPublishingLayers(this.isSvcPublish(this.codec), qualities);
|
|
23524
23787
|
}
|
|
23525
23788
|
restartTrack(options) {
|
|
23526
23789
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -23785,7 +24048,7 @@ class LocalVideoTrack extends LocalTrack {
|
|
|
23785
24048
|
}));
|
|
23786
24049
|
// only enable simulcast codec for preference codec setted
|
|
23787
24050
|
if (!this.codec && codecs.length > 0) {
|
|
23788
|
-
yield this.setPublishingLayers(
|
|
24051
|
+
yield this.setPublishingLayers(this.isSvcPublish(codecs[0].codec), codecs[0].qualities);
|
|
23789
24052
|
return [];
|
|
23790
24053
|
}
|
|
23791
24054
|
this.subscribedCodecs = codecs;
|
|
@@ -23796,7 +24059,7 @@ class LocalVideoTrack extends LocalTrack {
|
|
|
23796
24059
|
_a = false;
|
|
23797
24060
|
const codec = _d;
|
|
23798
24061
|
if (!this.codec || this.codec === codec.codec) {
|
|
23799
|
-
yield this.setPublishingLayers(
|
|
24062
|
+
yield this.setPublishingLayers(this.isSvcPublish(codec.codec), codec.qualities);
|
|
23800
24063
|
} else {
|
|
23801
24064
|
const simulcastCodecInfo = this.simulcastCodecs.get(codec.codec);
|
|
23802
24065
|
this.log.debug("try setPublishingCodec for ".concat(codec.codec), Object.assign(Object.assign({}, this.logContext), {
|
|
@@ -23811,7 +24074,7 @@ class LocalVideoTrack extends LocalTrack {
|
|
|
23811
24074
|
}
|
|
23812
24075
|
} else if (simulcastCodecInfo.encodings) {
|
|
23813
24076
|
this.log.debug("try setPublishingLayersForSender ".concat(codec.codec), this.logContext);
|
|
23814
|
-
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);
|
|
23815
24078
|
}
|
|
23816
24079
|
}
|
|
23817
24080
|
}
|
|
@@ -24071,6 +24334,10 @@ class RTCEngine extends eventsExports.EventEmitter {
|
|
|
24071
24334
|
get pendingReconnect() {
|
|
24072
24335
|
return !!this.reconnectTimeout;
|
|
24073
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
|
+
}
|
|
24074
24341
|
get reliableChannel() {
|
|
24075
24342
|
return this.dataChannels.reliable;
|
|
24076
24343
|
}
|
|
@@ -24123,7 +24390,7 @@ class RTCEngine extends eventsExports.EventEmitter {
|
|
|
24123
24390
|
}();
|
|
24124
24391
|
});
|
|
24125
24392
|
this.handleDataMessage = message => __awaiter(this, void 0, void 0, function* () {
|
|
24126
|
-
var _a, _b, _c, _d
|
|
24393
|
+
var _a, _b, _c, _d;
|
|
24127
24394
|
// make sure to respect incoming data message order by processing message events one after the other
|
|
24128
24395
|
const unlock = yield this.dataProcessLock.lock();
|
|
24129
24396
|
try {
|
|
@@ -24148,20 +24415,29 @@ class RTCEngine extends eventsExports.EventEmitter {
|
|
|
24148
24415
|
this.log.error('Received encrypted packet but E2EE not set up');
|
|
24149
24416
|
return;
|
|
24150
24417
|
}
|
|
24151
|
-
|
|
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
|
+
}
|
|
24152
24428
|
const decryptedPacket = EncryptedPacketPayload.fromBinary(decryptedData.payload);
|
|
24153
24429
|
const newDp = new DataPacket({
|
|
24154
24430
|
value: decryptedPacket.value,
|
|
24155
24431
|
participantIdentity: dp.participantIdentity,
|
|
24156
24432
|
participantSid: dp.participantSid
|
|
24157
24433
|
});
|
|
24158
|
-
if (((
|
|
24434
|
+
if (((_c = newDp.value) === null || _c === void 0 ? void 0 : _c.case) === 'user') {
|
|
24159
24435
|
// compatibility
|
|
24160
24436
|
applyUserDataCompat(newDp, newDp.value.value);
|
|
24161
24437
|
}
|
|
24162
24438
|
this.emit(EngineEvent.DataPacketReceived, newDp, dp.value.value.encryptionType);
|
|
24163
24439
|
} else {
|
|
24164
|
-
if (((
|
|
24440
|
+
if (((_d = dp.value) === null || _d === void 0 ? void 0 : _d.case) === 'user') {
|
|
24165
24441
|
// compatibility
|
|
24166
24442
|
applyUserDataCompat(dp, dp.value.value);
|
|
24167
24443
|
}
|
|
@@ -24662,7 +24938,11 @@ class RTCEngine extends eventsExports.EventEmitter {
|
|
|
24662
24938
|
sdp: sd.sdp,
|
|
24663
24939
|
midToTrackId
|
|
24664
24940
|
});
|
|
24665
|
-
|
|
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
|
+
}
|
|
24666
24946
|
yield this.pcManager.setPublisherAnswer(sd, offerId);
|
|
24667
24947
|
});
|
|
24668
24948
|
// add candidate on trickle
|
|
@@ -31773,7 +32053,7 @@ class Participant extends eventsExports.EventEmitter {
|
|
|
31773
32053
|
}
|
|
31774
32054
|
publish(track, opts, isStereo) {
|
|
31775
32055
|
return __awaiter(this, void 0, void 0, function* () {
|
|
31776
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
32056
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
31777
32057
|
if (!this.hasPermissionsToPublish(track)) {
|
|
31778
32058
|
throw new PublishTrackError('failed to publish track, insufficient permissions', 403);
|
|
31779
32059
|
}
|
|
@@ -31876,7 +32156,12 @@ class Participant extends eventsExports.EventEmitter {
|
|
|
31876
32156
|
req.height = dims.height;
|
|
31877
32157
|
// for svc codecs, disable simulcast and use vp8 for backup codec
|
|
31878
32158
|
if (isLocalVideoTrack(track)) {
|
|
31879
|
-
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) {
|
|
31880
32165
|
if (track.source === Track.Source.ScreenShare) {
|
|
31881
32166
|
// vp9 svc with screenshare cannot encode multiple spatial layers
|
|
31882
32167
|
// doing so reduces publish resolution to minimal resolution
|
|
@@ -31892,12 +32177,16 @@ class Participant extends eventsExports.EventEmitter {
|
|
|
31892
32177
|
}
|
|
31893
32178
|
}
|
|
31894
32179
|
// set scalabilityMode to 'L3T3_KEY' by default
|
|
31895
|
-
opts.scalabilityMode = (
|
|
32180
|
+
opts.scalabilityMode = (_f = opts.scalabilityMode) !== null && _f !== void 0 ? _f : 'L3T3_KEY';
|
|
31896
32181
|
}
|
|
31897
|
-
|
|
32182
|
+
const primaryCodec = new SimulcastCodec({
|
|
31898
32183
|
codec: videoCodec,
|
|
31899
32184
|
cid: track.mediaStreamTrack.id
|
|
31900
|
-
})
|
|
32185
|
+
});
|
|
32186
|
+
if (svcSimulcast) {
|
|
32187
|
+
primaryCodec.videoLayerMode = VideoLayer_Mode.ONE_SPATIAL_LAYER_PER_STREAM;
|
|
32188
|
+
}
|
|
32189
|
+
req.simulcastCodecs = [primaryCodec];
|
|
31901
32190
|
// set up backup
|
|
31902
32191
|
if (opts.backupCodec === true) {
|
|
31903
32192
|
opts.backupCodec = {
|
|
@@ -31918,19 +32207,19 @@ class Participant extends eventsExports.EventEmitter {
|
|
|
31918
32207
|
}
|
|
31919
32208
|
}
|
|
31920
32209
|
encodings = computeVideoEncodings(track.source === Track.Source.ScreenShare, req.width, req.height, opts);
|
|
31921
|
-
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));
|
|
31922
32211
|
} else if (track.kind === Track.Kind.Audio) {
|
|
31923
32212
|
encodings = [{
|
|
31924
|
-
maxBitrate: (
|
|
31925
|
-
priority: (
|
|
31926
|
-
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'
|
|
31927
32216
|
}];
|
|
31928
32217
|
}
|
|
31929
32218
|
if (!this.engine || this.engine.isClosed) {
|
|
31930
32219
|
throw new UnexpectedConnectionState('cannot publish track when not connected');
|
|
31931
32220
|
}
|
|
31932
32221
|
const negotiate = () => __awaiter(this, void 0, void 0, function* () {
|
|
31933
|
-
var _a, _b
|
|
32222
|
+
var _a, _b;
|
|
31934
32223
|
if (!this.engine.pcManager) {
|
|
31935
32224
|
throw new UnexpectedConnectionState('pcManager is not ready');
|
|
31936
32225
|
}
|
|
@@ -31967,13 +32256,9 @@ class Participant extends eventsExports.EventEmitter {
|
|
|
31967
32256
|
});
|
|
31968
32257
|
}
|
|
31969
32258
|
} else if (track.codec && isVideoCodec(track.codec)) {
|
|
31970
|
-
// Apply start bitrate for all video codecs to prevent initial blurriness
|
|
31971
|
-
//
|
|
31972
|
-
|
|
31973
|
-
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) => {
|
|
31974
|
-
var _a;
|
|
31975
|
-
return sum + ((_a = enc.maxBitrate) !== null && _a !== void 0 ? _a : 0);
|
|
31976
|
-
}, 0);
|
|
32259
|
+
// Apply start bitrate for all video codecs to prevent initial blurriness,
|
|
32260
|
+
// see computeStartTargetBitrate
|
|
32261
|
+
const targetBitrate = computeStartTargetBitrate(track.codec, opts, encodings);
|
|
31977
32262
|
if (targetBitrate > 0) {
|
|
31978
32263
|
this.engine.pcManager.publisher.setTrackCodecBitrate({
|
|
31979
32264
|
cid: req.cid,
|
|
@@ -34212,8 +34497,8 @@ class Room extends eventsExports.EventEmitter {
|
|
|
34212
34497
|
});
|
|
34213
34498
|
this.registerRpcDataStreamHandler();
|
|
34214
34499
|
this.rpcClientManager = new RpcClientManager(this.log, this.outgoingDataStreamManager, this.getRemoteParticipantClientProtocol, () => {
|
|
34215
|
-
var _a
|
|
34216
|
-
return (
|
|
34500
|
+
var _a;
|
|
34501
|
+
return (_a = this.engine) === null || _a === void 0 ? void 0 : _a.serverVersion;
|
|
34217
34502
|
});
|
|
34218
34503
|
this.rpcClientManager.on('sendDataPacket', _ref2 => {
|
|
34219
34504
|
let packet = _ref2.packet;
|
|
@@ -36368,33 +36653,10 @@ class TokenSourceFixed {}
|
|
|
36368
36653
|
* and {@link TokenSourceCustom}.
|
|
36369
36654
|
*/
|
|
36370
36655
|
class TokenSourceConfigurable {}new TextEncoder();
|
|
36371
|
-
const decoder = new TextDecoder();
|
|
36372
|
-
|
|
36373
|
-
|
|
36374
|
-
|
|
36375
|
-
const binary = atob(encoded);
|
|
36376
|
-
const bytes = new Uint8Array(binary.length);
|
|
36377
|
-
for (let i = 0; i < binary.length; i++) {
|
|
36378
|
-
bytes[i] = binary.charCodeAt(i);
|
|
36379
|
-
}
|
|
36380
|
-
return bytes;
|
|
36381
|
-
}function decode(input) {
|
|
36382
|
-
if (Uint8Array.fromBase64) {
|
|
36383
|
-
return Uint8Array.fromBase64(typeof input === 'string' ? input : decoder.decode(input), {
|
|
36384
|
-
alphabet: 'base64url'
|
|
36385
|
-
});
|
|
36386
|
-
}
|
|
36387
|
-
let encoded = input;
|
|
36388
|
-
if (encoded instanceof Uint8Array) {
|
|
36389
|
-
encoded = decoder.decode(encoded);
|
|
36390
|
-
}
|
|
36391
|
-
encoded = encoded.replace(/-/g, '+').replace(/_/g, '/');
|
|
36392
|
-
try {
|
|
36393
|
-
return decodeBase64(encoded);
|
|
36394
|
-
} catch (_unused) {
|
|
36395
|
-
throw new TypeError('The input to be decoded is not correctly encoded.');
|
|
36396
|
-
}
|
|
36397
|
-
}class JOSEError extends Error {
|
|
36656
|
+
const decoder = new TextDecoder();
|
|
36657
|
+
const strictDecoder = new TextDecoder('utf-8', {
|
|
36658
|
+
fatal: true
|
|
36659
|
+
});class JOSEError extends Error {
|
|
36398
36660
|
constructor(message, options) {
|
|
36399
36661
|
var _Error$captureStackTr;
|
|
36400
36662
|
super(message, options);
|
|
@@ -36518,7 +36780,7 @@ class JWKSMultipleMatchingKeys extends JOSEError {
|
|
|
36518
36780
|
let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'multiple matching keys found in the JSON Web Key Set';
|
|
36519
36781
|
let options = arguments.length > 1 ? arguments[1] : undefined;
|
|
36520
36782
|
super(message, options);
|
|
36521
|
-
_defineProperty(this, Symbol.asyncIterator,
|
|
36783
|
+
_defineProperty(this, Symbol.asyncIterator, _wrapAsyncGenerator(function* () {}));
|
|
36522
36784
|
_defineProperty(this, "code", 'ERR_JWKS_MULTIPLE_MATCHING_KEYS');
|
|
36523
36785
|
}
|
|
36524
36786
|
}
|
|
@@ -36540,19 +36802,55 @@ class JWSSignatureVerificationFailed extends JOSEError {
|
|
|
36540
36802
|
_defineProperty(this, "code", 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED');
|
|
36541
36803
|
}
|
|
36542
36804
|
}
|
|
36543
|
-
_defineProperty(JWSSignatureVerificationFailed, "code", 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED');
|
|
36544
|
-
|
|
36545
|
-
|
|
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]') {
|
|
36546
36843
|
return false;
|
|
36547
36844
|
}
|
|
36548
|
-
|
|
36845
|
+
const prototype = Object.getPrototypeOf(input);
|
|
36846
|
+
if (prototype === null) {
|
|
36549
36847
|
return true;
|
|
36550
36848
|
}
|
|
36551
|
-
let proto =
|
|
36849
|
+
let proto = prototype;
|
|
36552
36850
|
while (Object.getPrototypeOf(proto) !== null) {
|
|
36553
36851
|
proto = Object.getPrototypeOf(proto);
|
|
36554
36852
|
}
|
|
36555
|
-
return
|
|
36853
|
+
return prototype === proto;
|
|
36556
36854
|
}function decodeJwt(jwt) {
|
|
36557
36855
|
if (typeof jwt !== 'string') throw new JWTInvalid('JWTs must use Compact JWS serialization, JWT must be a string');
|
|
36558
36856
|
const _jwt$split = jwt.split('.'),
|
|
@@ -36569,7 +36867,7 @@ function isObject(input) {
|
|
|
36569
36867
|
}
|
|
36570
36868
|
let result;
|
|
36571
36869
|
try {
|
|
36572
|
-
result = JSON.parse(
|
|
36870
|
+
result = JSON.parse(strictDecoder.decode(decoded));
|
|
36573
36871
|
} catch (_unused2) {
|
|
36574
36872
|
throw new JWTInvalid('Failed to parse the decoded payload as JSON');
|
|
36575
36873
|
}
|