livekit-client 2.17.1 → 2.17.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/README.md +7 -5
- 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 +21 -14
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +2087 -1920
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/src/e2ee/E2eeManager.d.ts +2 -0
- package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
- package/dist/src/e2ee/KeyProvider.d.ts +2 -0
- package/dist/src/e2ee/KeyProvider.d.ts.map +1 -1
- package/dist/src/e2ee/events.d.ts +1 -1
- package/dist/src/e2ee/events.d.ts.map +1 -1
- package/dist/src/e2ee/types.d.ts +1 -0
- package/dist/src/e2ee/types.d.ts.map +1 -1
- package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts +2 -2
- package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts.map +1 -1
- package/dist/src/index.d.ts +7 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/logger.d.ts +2 -1
- package/dist/src/logger.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +1 -4
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/PCTransportManager.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts.map +1 -1
- package/dist/src/room/data-stream/incoming/StreamReader.d.ts +2 -4
- package/dist/src/room/data-stream/incoming/StreamReader.d.ts.map +1 -1
- package/dist/src/room/data-track/depacketizer.d.ts +51 -0
- package/dist/src/room/data-track/depacketizer.d.ts.map +1 -0
- package/dist/src/room/data-track/e2ee.d.ts +12 -0
- package/dist/src/room/data-track/e2ee.d.ts.map +1 -0
- package/dist/src/room/data-track/frame.d.ts +7 -0
- package/dist/src/room/data-track/frame.d.ts.map +1 -0
- package/dist/src/room/data-track/handle.d.ts +6 -7
- package/dist/src/room/data-track/handle.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +76 -0
- package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts.map +1 -0
- package/dist/src/room/data-track/outgoing/errors.d.ts +64 -0
- package/dist/src/room/data-track/outgoing/errors.d.ts.map +1 -0
- package/dist/src/room/data-track/outgoing/pipeline.d.ts +22 -0
- package/dist/src/room/data-track/outgoing/pipeline.d.ts.map +1 -0
- package/dist/src/room/data-track/outgoing/types.d.ts +31 -0
- package/dist/src/room/data-track/outgoing/types.d.ts.map +1 -0
- package/dist/src/room/data-track/packet/index.d.ts +3 -3
- package/dist/src/room/data-track/packet/index.d.ts.map +1 -1
- package/dist/src/room/data-track/packetizer.d.ts +43 -0
- package/dist/src/room/data-track/packetizer.d.ts.map +1 -0
- package/dist/src/room/data-track/track.d.ts +30 -0
- package/dist/src/room/data-track/track.d.ts.map +1 -0
- package/dist/src/room/data-track/utils.d.ts +34 -2
- package/dist/src/room/data-track/utils.d.ts.map +1 -1
- package/dist/src/room/debounce.d.ts +11 -0
- package/dist/src/room/debounce.d.ts.map +1 -0
- package/dist/src/room/events.d.ts +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts +1 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +2 -1
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/types.d.ts +0 -2
- package/dist/src/room/types.d.ts.map +1 -1
- package/dist/src/room/utils.d.ts +6 -1
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/src/utils/subscribeToEvents.d.ts +12 -0
- package/dist/src/utils/subscribeToEvents.d.ts.map +1 -0
- package/dist/src/utils/throws.d.ts +4 -2
- package/dist/src/utils/throws.d.ts.map +1 -1
- package/dist/ts4.2/e2ee/E2eeManager.d.ts +2 -0
- package/dist/ts4.2/e2ee/KeyProvider.d.ts +2 -0
- package/dist/ts4.2/e2ee/events.d.ts +1 -1
- package/dist/ts4.2/e2ee/types.d.ts +1 -0
- package/dist/ts4.2/e2ee/worker/ParticipantKeyHandler.d.ts +2 -2
- package/dist/ts4.2/index.d.ts +7 -3
- package/dist/ts4.2/logger.d.ts +2 -1
- package/dist/ts4.2/room/PCTransport.d.ts +1 -6
- package/dist/ts4.2/room/data-stream/incoming/StreamReader.d.ts +2 -4
- package/dist/ts4.2/room/data-track/depacketizer.d.ts +51 -0
- package/dist/ts4.2/room/data-track/e2ee.d.ts +12 -0
- package/dist/ts4.2/room/data-track/frame.d.ts +7 -0
- package/dist/ts4.2/room/data-track/handle.d.ts +6 -7
- package/dist/ts4.2/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +77 -0
- package/dist/ts4.2/room/data-track/outgoing/errors.d.ts +64 -0
- package/dist/ts4.2/room/data-track/outgoing/pipeline.d.ts +22 -0
- package/dist/ts4.2/room/data-track/outgoing/types.d.ts +31 -0
- package/dist/ts4.2/room/data-track/packet/index.d.ts +3 -3
- package/dist/ts4.2/room/data-track/packetizer.d.ts +43 -0
- package/dist/ts4.2/room/data-track/track.d.ts +30 -0
- package/dist/ts4.2/room/data-track/utils.d.ts +34 -2
- package/dist/ts4.2/room/debounce.d.ts +11 -0
- package/dist/ts4.2/room/events.d.ts +1 -1
- package/dist/ts4.2/room/track/LocalAudioTrack.d.ts +1 -1
- package/dist/ts4.2/room/track/LocalTrack.d.ts +2 -1
- package/dist/ts4.2/room/types.d.ts +0 -2
- package/dist/ts4.2/room/utils.d.ts +6 -1
- package/dist/ts4.2/utils/subscribeToEvents.d.ts +12 -0
- package/dist/ts4.2/utils/throws.d.ts +4 -2
- package/package.json +4 -5
- package/src/e2ee/E2eeManager.ts +9 -5
- package/src/e2ee/KeyProvider.ts +10 -1
- package/src/e2ee/events.ts +1 -1
- package/src/e2ee/types.ts +1 -0
- package/src/e2ee/worker/ParticipantKeyHandler.ts +7 -4
- package/src/e2ee/worker/e2ee.worker.ts +20 -10
- package/src/index.ts +15 -5
- package/src/logger.ts +1 -0
- package/src/room/PCTransport.ts +2 -1
- package/src/room/PCTransportManager.ts +27 -9
- package/src/room/RTCEngine.ts +13 -2
- package/src/room/Room.ts +11 -5
- package/src/room/data-stream/incoming/IncomingDataStreamManager.ts +5 -25
- package/src/room/data-stream/incoming/StreamReader.ts +56 -73
- package/src/room/data-track/depacketizer.test.ts +442 -0
- package/src/room/data-track/depacketizer.ts +298 -0
- package/src/room/data-track/e2ee.ts +14 -0
- package/src/room/data-track/frame.ts +8 -0
- package/src/room/data-track/handle.test.ts +1 -1
- package/src/room/data-track/handle.ts +9 -14
- package/src/room/data-track/outgoing/OutgoingDataTrackManager.test.ts +392 -0
- package/src/room/data-track/outgoing/OutgoingDataTrackManager.ts +302 -0
- package/src/room/data-track/outgoing/errors.ts +157 -0
- package/src/room/data-track/outgoing/pipeline.ts +76 -0
- package/src/room/data-track/outgoing/types.ts +37 -0
- package/src/room/data-track/packet/index.test.ts +9 -9
- package/src/room/data-track/packet/index.ts +11 -9
- package/src/room/data-track/packet/serializable.ts +1 -1
- package/src/room/data-track/packetizer.test.ts +131 -0
- package/src/room/data-track/packetizer.ts +132 -0
- package/src/room/data-track/track.ts +50 -0
- package/src/room/data-track/utils.test.ts +27 -1
- package/src/room/data-track/utils.ts +125 -5
- package/src/room/debounce.ts +115 -0
- package/src/room/events.ts +1 -1
- package/src/room/participant/LocalParticipant.ts +2 -0
- package/src/room/track/LocalAudioTrack.ts +10 -10
- package/src/room/track/LocalTrack.ts +14 -5
- package/src/room/track/LocalVideoTrack.ts +1 -1
- package/src/room/track/RemoteVideoTrack.ts +1 -1
- package/src/room/types.ts +0 -2
- package/src/room/utils.ts +7 -2
- package/src/utils/subscribeToEvents.ts +63 -0
- package/src/utils/throws.ts +3 -1
|
@@ -8073,6 +8073,7 @@ var LoggerNames;
|
|
|
8073
8073
|
LoggerNames["PCManager"] = "livekit-pc-manager";
|
|
8074
8074
|
LoggerNames["PCTransport"] = "livekit-pc-transport";
|
|
8075
8075
|
LoggerNames["E2EE"] = "lk-e2ee";
|
|
8076
|
+
LoggerNames["DataTracks"] = "livekit-data-tracks";
|
|
8076
8077
|
})(LoggerNames || (LoggerNames = {}));
|
|
8077
8078
|
let livekitLogger = loglevelExports.getLogger('livekit');
|
|
8078
8079
|
const livekitLoggers = Object.values(LoggerNames).map(name => loglevelExports.getLogger(name));
|
|
@@ -11605,7 +11606,7 @@ function getMatch(exp, ua) {
|
|
|
11605
11606
|
}
|
|
11606
11607
|
function getOSVersion(ua) {
|
|
11607
11608
|
return ua.includes('mac os') ? getMatch(/\(.+?(\d+_\d+(:?_\d+)?)/, ua, 1).replace(/_/g, '.') : undefined;
|
|
11608
|
-
}var version$1 = "2.17.
|
|
11609
|
+
}var version$1 = "2.17.3";const version = version$1;
|
|
11609
11610
|
const protocolVersion = 16;/** Base error that all LiveKit specific custom errors inherit from. */
|
|
11610
11611
|
class LivekitError extends Error {
|
|
11611
11612
|
constructor(code, message, options) {
|
|
@@ -11834,7 +11835,7 @@ var RoomEvent;
|
|
|
11834
11835
|
RoomEvent["Reconnected"] = "reconnected";
|
|
11835
11836
|
/**
|
|
11836
11837
|
* When disconnected from room. This fires when room.disconnect() is called or
|
|
11837
|
-
* when an unrecoverable connection issue had
|
|
11838
|
+
* when an unrecoverable connection issue had occurred.
|
|
11838
11839
|
*
|
|
11839
11840
|
* DisconnectReason can be used to determine why the participant was disconnected. Notable reasons are
|
|
11840
11841
|
* - DUPLICATE_IDENTITY: another client with the same identity has joined the room
|
|
@@ -13567,6 +13568,10 @@ function getEmptyAudioStreamTrack() {
|
|
|
13567
13568
|
}
|
|
13568
13569
|
return emptyAudioStreamTrack.clone();
|
|
13569
13570
|
}
|
|
13571
|
+
/** An object that represents a serialized version of a `new Promise((resolve, reject) => {})`
|
|
13572
|
+
* constructor. Wait for a promise resolution with `await future.promise` and explicitly resolve or
|
|
13573
|
+
* reject the inner promise with `future.resolve(...)` or `future.reject(...)`.
|
|
13574
|
+
*/
|
|
13570
13575
|
class Future {
|
|
13571
13576
|
get isResolved() {
|
|
13572
13577
|
return this._isResolved;
|
|
@@ -14051,6 +14056,7 @@ class BaseKeyProvider extends eventsExports.EventEmitter {
|
|
|
14051
14056
|
constructor() {
|
|
14052
14057
|
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
14053
14058
|
super();
|
|
14059
|
+
this.latestManuallySetKeyIndex = 0;
|
|
14054
14060
|
/**
|
|
14055
14061
|
* Callback being invoked after a key has been ratcheted.
|
|
14056
14062
|
* Can happen when:
|
|
@@ -14087,11 +14093,17 @@ class BaseKeyProvider extends eventsExports.EventEmitter {
|
|
|
14087
14093
|
throw new Error('participant identity needs to be passed for encryption key if sharedKey option is false');
|
|
14088
14094
|
}
|
|
14089
14095
|
this.keyInfoMap.set("".concat(participantIdentity !== null && participantIdentity !== void 0 ? participantIdentity : 'shared', "-").concat(keyIndex !== null && keyIndex !== void 0 ? keyIndex : 0), keyInfo);
|
|
14090
|
-
|
|
14096
|
+
if (keyIndex !== undefined) {
|
|
14097
|
+
this.latestManuallySetKeyIndex = keyIndex;
|
|
14098
|
+
}
|
|
14099
|
+
this.emit(KeyProviderEvent.SetKey, keyInfo, keyIndex !== undefined);
|
|
14091
14100
|
}
|
|
14092
14101
|
getKeys() {
|
|
14093
14102
|
return Array.from(this.keyInfoMap.values());
|
|
14094
14103
|
}
|
|
14104
|
+
getLatestManuallySetKeyIndex() {
|
|
14105
|
+
return this.latestManuallySetKeyIndex;
|
|
14106
|
+
}
|
|
14095
14107
|
getOptions() {
|
|
14096
14108
|
return this.options;
|
|
14097
14109
|
}
|
|
@@ -14182,14 +14194,14 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
14182
14194
|
case 'initAck':
|
|
14183
14195
|
if (data.enabled) {
|
|
14184
14196
|
this.keyProvider.getKeys().forEach(keyInfo => {
|
|
14185
|
-
this.postKey(keyInfo);
|
|
14197
|
+
this.postKey(keyInfo, false);
|
|
14186
14198
|
});
|
|
14187
14199
|
}
|
|
14188
14200
|
break;
|
|
14189
14201
|
case 'enable':
|
|
14190
14202
|
if (data.enabled) {
|
|
14191
14203
|
this.keyProvider.getKeys().forEach(keyInfo => {
|
|
14192
|
-
this.postKey(keyInfo);
|
|
14204
|
+
this.postKey(keyInfo, false);
|
|
14193
14205
|
});
|
|
14194
14206
|
}
|
|
14195
14207
|
if (this.encryptionEnabled !== data.enabled && data.participantIdentity === ((_a = this.room) === null || _a === void 0 ? void 0 : _a.localParticipant.identity)) {
|
|
@@ -14314,8 +14326,10 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
14314
14326
|
if (!this.room) {
|
|
14315
14327
|
throw new TypeError("expected room to be present on signal connect");
|
|
14316
14328
|
}
|
|
14329
|
+
const latestKeyIndex = keyProvider.getLatestManuallySetKeyIndex();
|
|
14317
14330
|
keyProvider.getKeys().forEach(keyInfo => {
|
|
14318
|
-
|
|
14331
|
+
var _a;
|
|
14332
|
+
this.postKey(keyInfo, latestKeyIndex === ((_a = keyInfo.keyIndex) !== null && _a !== void 0 ? _a : 0));
|
|
14319
14333
|
});
|
|
14320
14334
|
this.setParticipantCryptorEnabled(this.room.localParticipant.isE2EEEnabled, this.room.localParticipant.identity);
|
|
14321
14335
|
});
|
|
@@ -14337,7 +14351,7 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
14337
14351
|
};
|
|
14338
14352
|
this.worker.postMessage(msg);
|
|
14339
14353
|
});
|
|
14340
|
-
keyProvider.on(KeyProviderEvent.SetKey, keyInfo => this.postKey(keyInfo)).on(KeyProviderEvent.RatchetRequest, (participantId, keyIndex) => this.postRatchetRequest(participantId, keyIndex));
|
|
14354
|
+
keyProvider.on(KeyProviderEvent.SetKey, (keyInfo, updateCurrentKeyIndex) => this.postKey(keyInfo, updateCurrentKeyIndex !== null && updateCurrentKeyIndex !== void 0 ? updateCurrentKeyIndex : true)).on(KeyProviderEvent.RatchetRequest, (participantId, keyIndex) => this.postRatchetRequest(participantId, keyIndex));
|
|
14341
14355
|
}
|
|
14342
14356
|
encryptData(data) {
|
|
14343
14357
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -14398,7 +14412,7 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
14398
14412
|
};
|
|
14399
14413
|
this.worker.postMessage(msg);
|
|
14400
14414
|
}
|
|
14401
|
-
postKey(_ref) {
|
|
14415
|
+
postKey(_ref, updateCurrentKeyIndex) {
|
|
14402
14416
|
let {
|
|
14403
14417
|
key,
|
|
14404
14418
|
participantIdentity,
|
|
@@ -14414,7 +14428,8 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
|
14414
14428
|
participantIdentity: participantIdentity,
|
|
14415
14429
|
isPublisher: participantIdentity === ((_a = this.room) === null || _a === void 0 ? void 0 : _a.localParticipant.identity),
|
|
14416
14430
|
key,
|
|
14417
|
-
keyIndex
|
|
14431
|
+
keyIndex,
|
|
14432
|
+
updateCurrentKeyIndex
|
|
14418
14433
|
}
|
|
14419
14434
|
};
|
|
14420
14435
|
this.worker.postMessage(msg);
|
|
@@ -16530,48 +16545,106 @@ function requireLib() {
|
|
|
16530
16545
|
lib.parseImageAttributes = parser.parseImageAttributes;
|
|
16531
16546
|
lib.parseSimulcastStreamList = parser.parseSimulcastStreamList;
|
|
16532
16547
|
return lib;
|
|
16533
|
-
}var libExports = requireLib()
|
|
16534
|
-
|
|
16535
|
-
|
|
16536
|
-
|
|
16537
|
-
|
|
16538
|
-
|
|
16539
|
-
|
|
16540
|
-
|
|
16541
|
-
|
|
16542
|
-
|
|
16543
|
-
|
|
16544
|
-
|
|
16545
|
-
|
|
16546
|
-
|
|
16547
|
-
|
|
16548
|
-
|
|
16549
|
-
|
|
16550
|
-
|
|
16551
|
-
|
|
16552
|
-
|
|
16553
|
-
|
|
16554
|
-
|
|
16555
|
-
|
|
16556
|
-
|
|
16557
|
-
|
|
16558
|
-
|
|
16559
|
-
|
|
16560
|
-
|
|
16561
|
-
|
|
16562
|
-
|
|
16563
|
-
|
|
16564
|
-
|
|
16565
|
-
|
|
16566
|
-
|
|
16548
|
+
}var libExports = requireLib();/**
|
|
16549
|
+
* Originally from ts-debounce (https://github.com/chodorowicz/ts-debounce)
|
|
16550
|
+
* with the following license:
|
|
16551
|
+
*
|
|
16552
|
+
* MIT License
|
|
16553
|
+
*
|
|
16554
|
+
* Copyright (c) 2017 Jakub Chodorowicz
|
|
16555
|
+
*
|
|
16556
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
16557
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
16558
|
+
* in the Software without restriction, including without limitation the rights
|
|
16559
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16560
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
16561
|
+
* furnished to do so, subject to the following conditions:
|
|
16562
|
+
*
|
|
16563
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
16564
|
+
* copies or substantial portions of the Software.
|
|
16565
|
+
*
|
|
16566
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16567
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16568
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16569
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
16570
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
16571
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
16572
|
+
* SOFTWARE.
|
|
16573
|
+
*
|
|
16574
|
+
* Modified to use CriticalTimers for reliable timer execution.
|
|
16575
|
+
*/
|
|
16576
|
+
/* eslint-disable @typescript-eslint/no-this-alias, @typescript-eslint/no-unused-expressions, @typescript-eslint/no-shadow */
|
|
16577
|
+
function debounce(func) {
|
|
16578
|
+
let waitMilliseconds = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 50;
|
|
16579
|
+
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
16580
|
+
var _a, _b;
|
|
16581
|
+
let timeoutId;
|
|
16582
|
+
const isImmediate = (_a = options.isImmediate) !== null && _a !== void 0 ? _a : false;
|
|
16583
|
+
const callback = (_b = options.callback) !== null && _b !== void 0 ? _b : false;
|
|
16584
|
+
const maxWait = options.maxWait;
|
|
16585
|
+
let lastInvokeTime = Date.now();
|
|
16586
|
+
let promises = [];
|
|
16587
|
+
function nextInvokeTimeout() {
|
|
16588
|
+
if (maxWait !== undefined) {
|
|
16589
|
+
const timeSinceLastInvocation = Date.now() - lastInvokeTime;
|
|
16590
|
+
if (timeSinceLastInvocation + waitMilliseconds >= maxWait) {
|
|
16591
|
+
return maxWait - timeSinceLastInvocation;
|
|
16592
|
+
}
|
|
16593
|
+
}
|
|
16594
|
+
return waitMilliseconds;
|
|
16595
|
+
}
|
|
16596
|
+
const debouncedFunction = function () {
|
|
16597
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
16598
|
+
args[_key] = arguments[_key];
|
|
16599
|
+
}
|
|
16600
|
+
const context = this;
|
|
16601
|
+
return new Promise((resolve, reject) => {
|
|
16602
|
+
const invokeFunction = function () {
|
|
16603
|
+
timeoutId = undefined;
|
|
16604
|
+
lastInvokeTime = Date.now();
|
|
16605
|
+
if (!isImmediate) {
|
|
16606
|
+
const result = func.apply(context, args);
|
|
16607
|
+
callback && callback(result);
|
|
16608
|
+
// biome-ignore lint/suspicious/useIterableCallbackReturn: vendored code
|
|
16609
|
+
promises.forEach(_ref => {
|
|
16610
|
+
let {
|
|
16611
|
+
resolve
|
|
16612
|
+
} = _ref;
|
|
16613
|
+
return resolve(result);
|
|
16614
|
+
});
|
|
16615
|
+
promises = [];
|
|
16616
|
+
}
|
|
16617
|
+
};
|
|
16618
|
+
const shouldCallNow = isImmediate && timeoutId === undefined;
|
|
16619
|
+
if (timeoutId !== undefined) {
|
|
16620
|
+
CriticalTimers.clearTimeout(timeoutId);
|
|
16621
|
+
}
|
|
16622
|
+
timeoutId = CriticalTimers.setTimeout(invokeFunction, nextInvokeTimeout());
|
|
16623
|
+
if (shouldCallNow) {
|
|
16624
|
+
const result = func.apply(context, args);
|
|
16625
|
+
callback && callback(result);
|
|
16626
|
+
return resolve(result);
|
|
16627
|
+
}
|
|
16628
|
+
promises.push({
|
|
16629
|
+
resolve,
|
|
16630
|
+
reject
|
|
16567
16631
|
});
|
|
16568
16632
|
});
|
|
16569
16633
|
};
|
|
16570
|
-
|
|
16571
|
-
|
|
16572
|
-
|
|
16573
|
-
}
|
|
16574
|
-
|
|
16634
|
+
debouncedFunction.cancel = function (reason) {
|
|
16635
|
+
if (timeoutId !== undefined) {
|
|
16636
|
+
CriticalTimers.clearTimeout(timeoutId);
|
|
16637
|
+
}
|
|
16638
|
+
// biome-ignore lint/suspicious/useIterableCallbackReturn: vendored code
|
|
16639
|
+
promises.forEach(_ref2 => {
|
|
16640
|
+
let {
|
|
16641
|
+
reject
|
|
16642
|
+
} = _ref2;
|
|
16643
|
+
return reject(reason);
|
|
16644
|
+
});
|
|
16645
|
+
promises = [];
|
|
16646
|
+
};
|
|
16647
|
+
return debouncedFunction;
|
|
16575
16648
|
}/* The svc codec (av1/vp9) would use a very low bitrate at the begining and
|
|
16576
16649
|
increase slowly by the bandwidth estimator until it reach the target bitrate. The
|
|
16577
16650
|
process commonly cost more than 10 seconds cause subscriber will get blur video at
|
|
@@ -16607,7 +16680,7 @@ class PCTransport extends eventsExports.EventEmitter {
|
|
|
16607
16680
|
this.remoteStereoMids = [];
|
|
16608
16681
|
this.remoteNackMids = [];
|
|
16609
16682
|
// debounced negotiate interface
|
|
16610
|
-
this.negotiate =
|
|
16683
|
+
this.negotiate = debounce(onError => __awaiter(this, void 0, void 0, function* () {
|
|
16611
16684
|
this.emit(PCEvents.NegotiationStarted);
|
|
16612
16685
|
try {
|
|
16613
16686
|
yield this.createAndSendOffer();
|
|
@@ -16800,6 +16873,7 @@ class PCTransport extends eventsExports.EventEmitter {
|
|
|
16800
16873
|
yield this._pc.setRemoteDescription(currentSD);
|
|
16801
16874
|
} else {
|
|
16802
16875
|
this.renegotiate = true;
|
|
16876
|
+
this.log.debug('requesting renegotiation', Object.assign({}, this.logContext));
|
|
16803
16877
|
return;
|
|
16804
16878
|
}
|
|
16805
16879
|
} else if (!this._pc || this._pc.signalingState === 'closed') {
|
|
@@ -17400,25 +17474,41 @@ class PCTransportManager {
|
|
|
17400
17474
|
negotiate(abortController) {
|
|
17401
17475
|
return __awaiter(this, void 0, void 0, function* () {
|
|
17402
17476
|
return new TypedPromise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
17403
|
-
|
|
17477
|
+
let negotiationTimeout = setTimeout(() => {
|
|
17404
17478
|
reject(new NegotiationError('negotiation timed out'));
|
|
17405
17479
|
}, this.peerConnectionTimeout);
|
|
17406
|
-
const
|
|
17480
|
+
const cleanup = () => {
|
|
17407
17481
|
clearTimeout(negotiationTimeout);
|
|
17482
|
+
this.publisher.off(PCEvents.NegotiationStarted, onNegotiationStarted);
|
|
17483
|
+
abortController.signal.removeEventListener('abort', abortHandler);
|
|
17484
|
+
};
|
|
17485
|
+
const abortHandler = () => {
|
|
17486
|
+
cleanup();
|
|
17408
17487
|
reject(new NegotiationError('negotiation aborted'));
|
|
17409
17488
|
};
|
|
17410
|
-
|
|
17411
|
-
|
|
17489
|
+
// Reset the timeout each time a renegotiation cycle starts. This
|
|
17490
|
+
// prevents premature timeouts when the negotiation machinery is
|
|
17491
|
+
// actively renegotiating (offers going out, answers coming back) but
|
|
17492
|
+
// NegotiationComplete hasn't fired yet because new requirements keep
|
|
17493
|
+
// arriving between offer/answer round-trips.
|
|
17494
|
+
const onNegotiationStarted = () => {
|
|
17412
17495
|
if (abortController.signal.aborted) {
|
|
17413
17496
|
return;
|
|
17414
17497
|
}
|
|
17415
|
-
|
|
17416
|
-
|
|
17417
|
-
|
|
17418
|
-
|
|
17498
|
+
clearTimeout(negotiationTimeout);
|
|
17499
|
+
negotiationTimeout = setTimeout(() => {
|
|
17500
|
+
cleanup();
|
|
17501
|
+
reject(new NegotiationError('negotiation timed out'));
|
|
17502
|
+
}, this.peerConnectionTimeout);
|
|
17503
|
+
};
|
|
17504
|
+
abortController.signal.addEventListener('abort', abortHandler);
|
|
17505
|
+
this.publisher.on(PCEvents.NegotiationStarted, onNegotiationStarted);
|
|
17506
|
+
this.publisher.once(PCEvents.NegotiationComplete, () => {
|
|
17507
|
+
cleanup();
|
|
17508
|
+
resolve();
|
|
17419
17509
|
});
|
|
17420
17510
|
yield this.publisher.negotiate(e => {
|
|
17421
|
-
|
|
17511
|
+
cleanup();
|
|
17422
17512
|
if (e instanceof Error) {
|
|
17423
17513
|
reject(e);
|
|
17424
17514
|
} else {
|
|
@@ -17914,9 +18004,10 @@ class LocalTrack extends Track {
|
|
|
17914
18004
|
let loggerOptions = arguments.length > 4 ? arguments[4] : undefined;
|
|
17915
18005
|
super(mediaTrack, kind, loggerOptions);
|
|
17916
18006
|
this.manuallyStopped = false;
|
|
18007
|
+
this.pendingDeviceChange = false;
|
|
17917
18008
|
this._isUpstreamPaused = false;
|
|
17918
18009
|
this.handleTrackMuteEvent = () => this.debouncedTrackMuteHandler().catch(() => this.log.debug('track mute bounce got cancelled by an unmute event', this.logContext));
|
|
17919
|
-
this.debouncedTrackMuteHandler =
|
|
18010
|
+
this.debouncedTrackMuteHandler = debounce(() => __awaiter(this, void 0, void 0, function* () {
|
|
17920
18011
|
yield this.pauseUpstream();
|
|
17921
18012
|
}), 5000);
|
|
17922
18013
|
this.handleTrackUnmuteEvent = () => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -17988,7 +18079,7 @@ class LocalTrack extends Track {
|
|
|
17988
18079
|
getSourceTrackSettings() {
|
|
17989
18080
|
return this._mediaStreamTrack.getSettings();
|
|
17990
18081
|
}
|
|
17991
|
-
setMediaStreamTrack(newTrack, force) {
|
|
18082
|
+
setMediaStreamTrack(newTrack, force, isUnmuting) {
|
|
17992
18083
|
return __awaiter(this, void 0, void 0, function* () {
|
|
17993
18084
|
var _a;
|
|
17994
18085
|
if (newTrack === this._mediaStreamTrack && !force) {
|
|
@@ -18045,7 +18136,8 @@ class LocalTrack extends Track {
|
|
|
18045
18136
|
this._mediaStreamTrack = newTrack;
|
|
18046
18137
|
if (newTrack) {
|
|
18047
18138
|
// sync muted state with the enabled state of the newly provided track
|
|
18048
|
-
|
|
18139
|
+
// if restarting as part of an unmute, set enabled to true directly to avoid mute cycling
|
|
18140
|
+
this._mediaStreamTrack.enabled = isUnmuting ? true : !this.isMuted;
|
|
18049
18141
|
// when a valid track is replace, we'd want to start producing
|
|
18050
18142
|
yield this.resumeUpstream();
|
|
18051
18143
|
this.attachedElements.forEach(el => {
|
|
@@ -18089,6 +18181,7 @@ class LocalTrack extends Track {
|
|
|
18089
18181
|
// when track is muted, underlying media stream track is stopped and
|
|
18090
18182
|
// will be restarted later
|
|
18091
18183
|
if (this.isMuted) {
|
|
18184
|
+
this.pendingDeviceChange = true;
|
|
18092
18185
|
return true;
|
|
18093
18186
|
}
|
|
18094
18187
|
yield this.restartTrack();
|
|
@@ -18157,7 +18250,7 @@ class LocalTrack extends Track {
|
|
|
18157
18250
|
}
|
|
18158
18251
|
});
|
|
18159
18252
|
}
|
|
18160
|
-
restart(constraints) {
|
|
18253
|
+
restart(constraints, isUnmuting) {
|
|
18161
18254
|
return __awaiter(this, void 0, void 0, function* () {
|
|
18162
18255
|
this.manuallyStopped = false;
|
|
18163
18256
|
const unlock = yield this.trackChangeLock.lock();
|
|
@@ -18206,8 +18299,9 @@ class LocalTrack extends Track {
|
|
|
18206
18299
|
}
|
|
18207
18300
|
newTrack.addEventListener('ended', this.handleEnded);
|
|
18208
18301
|
this.log.debug('re-acquired MediaStreamTrack', this.logContext);
|
|
18209
|
-
yield this.setMediaStreamTrack(newTrack);
|
|
18302
|
+
yield this.setMediaStreamTrack(newTrack, false, isUnmuting);
|
|
18210
18303
|
this._constraints = constraints;
|
|
18304
|
+
this.pendingDeviceChange = false;
|
|
18211
18305
|
this.emit(TrackEvent.Restarted, this);
|
|
18212
18306
|
if (this.manuallyStopped) {
|
|
18213
18307
|
this.log.warn('track was stopped during a restart, stopping restarted track', this.logContext);
|
|
@@ -18586,10 +18680,9 @@ class LocalTrack extends Track {
|
|
|
18586
18680
|
this.log.debug('Track already unmuted', this.logContext);
|
|
18587
18681
|
return this;
|
|
18588
18682
|
}
|
|
18589
|
-
|
|
18590
|
-
if (this.source === Track.Source.Microphone && (this.stopOnMute || this._mediaStreamTrack.readyState === 'ended' || deviceHasChanged) && !this.isUserProvided) {
|
|
18683
|
+
if (this.source === Track.Source.Microphone && (this.stopOnMute || this._mediaStreamTrack.readyState === 'ended' || this.pendingDeviceChange) && !this.isUserProvided) {
|
|
18591
18684
|
this.log.debug('reacquiring mic track', this.logContext);
|
|
18592
|
-
yield this.
|
|
18685
|
+
yield this.restart(undefined, true);
|
|
18593
18686
|
}
|
|
18594
18687
|
yield _super.unmute.call(this);
|
|
18595
18688
|
return this;
|
|
@@ -18612,14 +18705,14 @@ class LocalTrack extends Track {
|
|
|
18612
18705
|
yield this.restart(constraints);
|
|
18613
18706
|
});
|
|
18614
18707
|
}
|
|
18615
|
-
restart(constraints) {
|
|
18708
|
+
restart(constraints, isUnmuting) {
|
|
18616
18709
|
const _super = Object.create(null, {
|
|
18617
18710
|
restart: {
|
|
18618
18711
|
get: () => super.restart
|
|
18619
18712
|
}
|
|
18620
18713
|
});
|
|
18621
18714
|
return __awaiter(this, void 0, void 0, function* () {
|
|
18622
|
-
const track = yield _super.restart.call(this, constraints);
|
|
18715
|
+
const track = yield _super.restart.call(this, constraints, isUnmuting);
|
|
18623
18716
|
this.checkForSilence();
|
|
18624
18717
|
return track;
|
|
18625
18718
|
});
|
|
@@ -19252,7 +19345,7 @@ class LocalVideoTrack extends LocalTrack {
|
|
|
19252
19345
|
}
|
|
19253
19346
|
if (this.source === Track.Source.Camera && !this.isUserProvided) {
|
|
19254
19347
|
this.log.debug('reacquiring camera track', this.logContext);
|
|
19255
|
-
yield this.
|
|
19348
|
+
yield this.restart(undefined, true);
|
|
19256
19349
|
}
|
|
19257
19350
|
yield _super.unmute.call(this);
|
|
19258
19351
|
return this;
|
|
@@ -20914,8 +21007,8 @@ class RTCEngine extends eventsExports.EventEmitter {
|
|
|
20914
21007
|
if (!this.pcManager) {
|
|
20915
21008
|
return false;
|
|
20916
21009
|
}
|
|
20917
|
-
|
|
20918
|
-
if (this.pcManager.currentState
|
|
21010
|
+
const allowedConnectionStates = [PCTransportState.CONNECTING, PCTransportState.CONNECTED];
|
|
21011
|
+
if (!allowedConnectionStates.includes(this.pcManager.currentState)) {
|
|
20919
21012
|
return false;
|
|
20920
21013
|
}
|
|
20921
21014
|
// ensure signal is connected
|
|
@@ -20949,6 +21042,7 @@ class RTCEngine extends eventsExports.EventEmitter {
|
|
|
20949
21042
|
reject(new NegotiationError('cannot negotiate on closed engine'));
|
|
20950
21043
|
}
|
|
20951
21044
|
this.on(EngineEvent.Closing, handleClosed);
|
|
21045
|
+
this.on(EngineEvent.Restarting, handleClosed);
|
|
20952
21046
|
this.pcManager.publisher.once(PCEvents.RTPVideoPayloadTypes, rtpTypes => {
|
|
20953
21047
|
const rtpMap = new Map();
|
|
20954
21048
|
rtpTypes.forEach(rtp => {
|
|
@@ -20963,6 +21057,12 @@ class RTCEngine extends eventsExports.EventEmitter {
|
|
|
20963
21057
|
yield this.pcManager.negotiate(abortController);
|
|
20964
21058
|
resolve();
|
|
20965
21059
|
} catch (e) {
|
|
21060
|
+
if (abortController.signal.aborted) {
|
|
21061
|
+
// negotiation was aborted due to engine close or restart, resolve
|
|
21062
|
+
// cleanly to avoid triggering a cascading reconnect loop
|
|
21063
|
+
resolve();
|
|
21064
|
+
return;
|
|
21065
|
+
}
|
|
20966
21066
|
if (e instanceof NegotiationError) {
|
|
20967
21067
|
this.fullReconnectOnNext = true;
|
|
20968
21068
|
}
|
|
@@ -20974,6 +21074,7 @@ class RTCEngine extends eventsExports.EventEmitter {
|
|
|
20974
21074
|
}
|
|
20975
21075
|
} finally {
|
|
20976
21076
|
this.off(EngineEvent.Closing, handleClosed);
|
|
21077
|
+
this.off(EngineEvent.Restarting, handleClosed);
|
|
20977
21078
|
}
|
|
20978
21079
|
}));
|
|
20979
21080
|
});
|
|
@@ -21136,12 +21237,11 @@ function applyUserDataCompat(newObj, oldObj) {
|
|
|
21136
21237
|
throw new DataStreamError("Extra chunk(s) received - expected ".concat(this.totalByteSize, " bytes of data total, received ").concat(this.bytesReceived, " bytes"), DataStreamErrorReason.LengthExceeded);
|
|
21137
21238
|
}
|
|
21138
21239
|
}
|
|
21139
|
-
constructor(info, stream, totalByteSize
|
|
21240
|
+
constructor(info, stream, totalByteSize) {
|
|
21140
21241
|
this.reader = stream;
|
|
21141
21242
|
this.totalByteSize = totalByteSize;
|
|
21142
21243
|
this._info = info;
|
|
21143
21244
|
this.bytesReceived = 0;
|
|
21144
|
-
this.outOfBandFailureRejectingFuture = outOfBandFailureRejectingFuture;
|
|
21145
21245
|
}
|
|
21146
21246
|
}
|
|
21147
21247
|
class ByteStreamReader extends BaseStreamReader {
|
|
@@ -21154,50 +21254,44 @@ class ByteStreamReader extends BaseStreamReader {
|
|
|
21154
21254
|
}
|
|
21155
21255
|
[Symbol.asyncIterator]() {
|
|
21156
21256
|
const reader = this.reader.getReader();
|
|
21157
|
-
|
|
21158
|
-
|
|
21159
|
-
|
|
21160
|
-
if (this.signal) {
|
|
21161
|
-
const signal = this.signal;
|
|
21162
|
-
onAbort = () => {
|
|
21163
|
-
var _a;
|
|
21164
|
-
(_a = rejectingSignalFuture.reject) === null || _a === void 0 ? void 0 : _a.call(rejectingSignalFuture, signal.reason);
|
|
21165
|
-
};
|
|
21166
|
-
signal.addEventListener('abort', onAbort);
|
|
21167
|
-
activeSignal = signal;
|
|
21168
|
-
}
|
|
21257
|
+
// Suppress unhandled rejection on reader.closed — errors are
|
|
21258
|
+
// already propagated through reader.read() to the consumer.
|
|
21259
|
+
reader.closed.catch(() => {});
|
|
21169
21260
|
const cleanup = () => {
|
|
21170
21261
|
reader.releaseLock();
|
|
21171
|
-
if (activeSignal && onAbort) {
|
|
21172
|
-
activeSignal.removeEventListener('abort', onAbort);
|
|
21173
|
-
}
|
|
21174
21262
|
this.signal = undefined;
|
|
21175
21263
|
};
|
|
21176
21264
|
return {
|
|
21177
21265
|
next: () => __awaiter(this, void 0, void 0, function* () {
|
|
21178
|
-
var _a, _b;
|
|
21179
21266
|
try {
|
|
21180
|
-
const
|
|
21181
|
-
|
|
21182
|
-
|
|
21183
|
-
}
|
|
21184
|
-
|
|
21185
|
-
|
|
21186
|
-
|
|
21187
|
-
|
|
21188
|
-
|
|
21189
|
-
|
|
21190
|
-
|
|
21267
|
+
const signal = this.signal;
|
|
21268
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
21269
|
+
throw signal.reason;
|
|
21270
|
+
}
|
|
21271
|
+
const result = yield new Promise((resolve, reject) => {
|
|
21272
|
+
if (signal) {
|
|
21273
|
+
const onAbort = () => reject(signal.reason);
|
|
21274
|
+
signal.addEventListener('abort', onAbort, {
|
|
21275
|
+
once: true
|
|
21276
|
+
});
|
|
21277
|
+
reader.read().then(resolve, reject).finally(() => {
|
|
21278
|
+
signal.removeEventListener('abort', onAbort);
|
|
21279
|
+
});
|
|
21280
|
+
} else {
|
|
21281
|
+
reader.read().then(resolve, reject);
|
|
21282
|
+
}
|
|
21283
|
+
});
|
|
21284
|
+
if (result.done) {
|
|
21191
21285
|
this.validateBytesReceived(true);
|
|
21192
21286
|
return {
|
|
21193
21287
|
done: true,
|
|
21194
21288
|
value: undefined
|
|
21195
21289
|
};
|
|
21196
21290
|
} else {
|
|
21197
|
-
this.handleChunkReceived(value);
|
|
21291
|
+
this.handleChunkReceived(result.value);
|
|
21198
21292
|
return {
|
|
21199
21293
|
done: false,
|
|
21200
|
-
value: value.content
|
|
21294
|
+
value: result.value.content
|
|
21201
21295
|
};
|
|
21202
21296
|
}
|
|
21203
21297
|
} catch (err) {
|
|
@@ -21268,8 +21362,8 @@ class TextStreamReader extends BaseStreamReader {
|
|
|
21268
21362
|
* A TextStreamReader instance can be used as an AsyncIterator that returns the entire string
|
|
21269
21363
|
* that has been received up to the current point in time.
|
|
21270
21364
|
*/
|
|
21271
|
-
constructor(info, stream, totalChunkCount
|
|
21272
|
-
super(info, stream, totalChunkCount
|
|
21365
|
+
constructor(info, stream, totalChunkCount) {
|
|
21366
|
+
super(info, stream, totalChunkCount);
|
|
21273
21367
|
this.receivedChunks = new Map();
|
|
21274
21368
|
}
|
|
21275
21369
|
handleChunkReceived(chunk) {
|
|
@@ -21293,55 +21387,49 @@ class TextStreamReader extends BaseStreamReader {
|
|
|
21293
21387
|
*/
|
|
21294
21388
|
[Symbol.asyncIterator]() {
|
|
21295
21389
|
const reader = this.reader.getReader();
|
|
21390
|
+
// Suppress unhandled rejection on reader.closed — errors are
|
|
21391
|
+
// already propagated through reader.read() to the consumer.
|
|
21392
|
+
reader.closed.catch(() => {});
|
|
21296
21393
|
const decoder = new TextDecoder('utf-8', {
|
|
21297
21394
|
fatal: true
|
|
21298
21395
|
});
|
|
21299
|
-
|
|
21300
|
-
let activeSignal = null;
|
|
21301
|
-
let onAbort = null;
|
|
21302
|
-
if (this.signal) {
|
|
21303
|
-
const signal = this.signal;
|
|
21304
|
-
onAbort = () => {
|
|
21305
|
-
var _a;
|
|
21306
|
-
(_a = rejectingSignalFuture.reject) === null || _a === void 0 ? void 0 : _a.call(rejectingSignalFuture, signal.reason);
|
|
21307
|
-
};
|
|
21308
|
-
signal.addEventListener('abort', onAbort);
|
|
21309
|
-
activeSignal = signal;
|
|
21310
|
-
}
|
|
21396
|
+
const signal = this.signal;
|
|
21311
21397
|
const cleanup = () => {
|
|
21312
21398
|
reader.releaseLock();
|
|
21313
|
-
if (activeSignal && onAbort) {
|
|
21314
|
-
activeSignal.removeEventListener('abort', onAbort);
|
|
21315
|
-
}
|
|
21316
21399
|
this.signal = undefined;
|
|
21317
21400
|
};
|
|
21318
21401
|
return {
|
|
21319
21402
|
next: () => __awaiter(this, void 0, void 0, function* () {
|
|
21320
|
-
var _a, _b;
|
|
21321
21403
|
try {
|
|
21322
|
-
|
|
21323
|
-
|
|
21324
|
-
|
|
21325
|
-
|
|
21326
|
-
|
|
21327
|
-
|
|
21328
|
-
|
|
21329
|
-
|
|
21330
|
-
|
|
21331
|
-
|
|
21332
|
-
|
|
21404
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
21405
|
+
throw signal.reason;
|
|
21406
|
+
}
|
|
21407
|
+
const result = yield new Promise((resolve, reject) => {
|
|
21408
|
+
if (signal) {
|
|
21409
|
+
const onAbort = () => reject(signal.reason);
|
|
21410
|
+
signal.addEventListener('abort', onAbort, {
|
|
21411
|
+
once: true
|
|
21412
|
+
});
|
|
21413
|
+
reader.read().then(resolve, reject).finally(() => {
|
|
21414
|
+
signal.removeEventListener('abort', onAbort);
|
|
21415
|
+
});
|
|
21416
|
+
} else {
|
|
21417
|
+
reader.read().then(resolve, reject);
|
|
21418
|
+
}
|
|
21419
|
+
});
|
|
21420
|
+
if (result.done) {
|
|
21333
21421
|
this.validateBytesReceived(true);
|
|
21334
21422
|
return {
|
|
21335
21423
|
done: true,
|
|
21336
21424
|
value: undefined
|
|
21337
21425
|
};
|
|
21338
21426
|
} else {
|
|
21339
|
-
this.handleChunkReceived(value);
|
|
21427
|
+
this.handleChunkReceived(result.value);
|
|
21340
21428
|
let decodedResult;
|
|
21341
21429
|
try {
|
|
21342
|
-
decodedResult = decoder.decode(value.content);
|
|
21430
|
+
decodedResult = decoder.decode(result.value.content);
|
|
21343
21431
|
} catch (err) {
|
|
21344
|
-
throw new DataStreamError("Cannot decode datastream chunk ".concat(value.chunkIndex, " as text: ").concat(err), DataStreamErrorReason.DecodeFailed);
|
|
21432
|
+
throw new DataStreamError("Cannot decode datastream chunk ".concat(result.value.chunkIndex, " as text: ").concat(err), DataStreamErrorReason.DecodeFailed);
|
|
21345
21433
|
}
|
|
21346
21434
|
return {
|
|
21347
21435
|
done: false,
|
|
@@ -21438,18 +21526,17 @@ class TextStreamReader extends BaseStreamReader {
|
|
|
21438
21526
|
this.textStreamControllers.clear();
|
|
21439
21527
|
}
|
|
21440
21528
|
validateParticipantHasNoActiveDataStreams(participantIdentity) {
|
|
21441
|
-
var _a, _b, _c, _d;
|
|
21442
21529
|
// Terminate any in flight data stream receives from the given participant
|
|
21443
21530
|
const textStreamsBeingSentByDisconnectingParticipant = Array.from(this.textStreamControllers.entries()).filter(entry => entry[1].sendingParticipantIdentity === participantIdentity);
|
|
21444
21531
|
const byteStreamsBeingSentByDisconnectingParticipant = Array.from(this.byteStreamControllers.entries()).filter(entry => entry[1].sendingParticipantIdentity === participantIdentity);
|
|
21445
21532
|
if (textStreamsBeingSentByDisconnectingParticipant.length > 0 || byteStreamsBeingSentByDisconnectingParticipant.length > 0) {
|
|
21446
21533
|
const abnormalEndError = new DataStreamError("Participant ".concat(participantIdentity, " unexpectedly disconnected in the middle of sending data"), DataStreamErrorReason.AbnormalEnd);
|
|
21447
21534
|
for (const [id, controller] of byteStreamsBeingSentByDisconnectingParticipant) {
|
|
21448
|
-
|
|
21535
|
+
controller.controller.error(abnormalEndError);
|
|
21449
21536
|
this.byteStreamControllers.delete(id);
|
|
21450
21537
|
}
|
|
21451
21538
|
for (const [id, controller] of textStreamsBeingSentByDisconnectingParticipant) {
|
|
21452
|
-
|
|
21539
|
+
controller.controller.error(abnormalEndError);
|
|
21453
21540
|
this.textStreamControllers.delete(id);
|
|
21454
21541
|
}
|
|
21455
21542
|
}
|
|
@@ -21478,10 +21565,6 @@ class TextStreamReader extends BaseStreamReader {
|
|
|
21478
21565
|
return;
|
|
21479
21566
|
}
|
|
21480
21567
|
let streamController;
|
|
21481
|
-
const outOfBandFailureRejectingFuture = new Future();
|
|
21482
|
-
outOfBandFailureRejectingFuture.promise.catch(err => {
|
|
21483
|
-
this.log.error(err);
|
|
21484
|
-
});
|
|
21485
21568
|
const info = {
|
|
21486
21569
|
id: streamHeader.streamId,
|
|
21487
21570
|
name: (_a = streamHeader.contentHeader.value.name) !== null && _a !== void 0 ? _a : 'unknown',
|
|
@@ -21502,12 +21585,11 @@ class TextStreamReader extends BaseStreamReader {
|
|
|
21502
21585
|
info,
|
|
21503
21586
|
controller: streamController,
|
|
21504
21587
|
startTime: Date.now(),
|
|
21505
|
-
sendingParticipantIdentity: participantIdentity
|
|
21506
|
-
outOfBandFailureRejectingFuture
|
|
21588
|
+
sendingParticipantIdentity: participantIdentity
|
|
21507
21589
|
});
|
|
21508
21590
|
}
|
|
21509
21591
|
});
|
|
21510
|
-
streamHandlerCallback(new ByteStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength)
|
|
21592
|
+
streamHandlerCallback(new ByteStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength)), {
|
|
21511
21593
|
identity: participantIdentity
|
|
21512
21594
|
});
|
|
21513
21595
|
} else if (streamHeader.contentHeader.case === 'textHeader') {
|
|
@@ -21517,10 +21599,6 @@ class TextStreamReader extends BaseStreamReader {
|
|
|
21517
21599
|
return;
|
|
21518
21600
|
}
|
|
21519
21601
|
let streamController;
|
|
21520
|
-
const outOfBandFailureRejectingFuture = new Future();
|
|
21521
|
-
outOfBandFailureRejectingFuture.promise.catch(err => {
|
|
21522
|
-
this.log.error(err);
|
|
21523
|
-
});
|
|
21524
21602
|
const info = {
|
|
21525
21603
|
id: streamHeader.streamId,
|
|
21526
21604
|
mimeType: streamHeader.mimeType,
|
|
@@ -21541,12 +21619,11 @@ class TextStreamReader extends BaseStreamReader {
|
|
|
21541
21619
|
info,
|
|
21542
21620
|
controller: streamController,
|
|
21543
21621
|
startTime: Date.now(),
|
|
21544
|
-
sendingParticipantIdentity: participantIdentity
|
|
21545
|
-
outOfBandFailureRejectingFuture
|
|
21622
|
+
sendingParticipantIdentity: participantIdentity
|
|
21546
21623
|
});
|
|
21547
21624
|
}
|
|
21548
21625
|
});
|
|
21549
|
-
streamHandlerCallback(new TextStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength)
|
|
21626
|
+
streamHandlerCallback(new TextStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength)), {
|
|
21550
21627
|
identity: participantIdentity
|
|
21551
21628
|
});
|
|
21552
21629
|
}
|
|
@@ -22226,7 +22303,7 @@ class RemoteVideoTrack extends RemoteTrack {
|
|
|
22226
22303
|
}
|
|
22227
22304
|
this.prevStats = stats;
|
|
22228
22305
|
});
|
|
22229
|
-
this.debouncedHandleResize =
|
|
22306
|
+
this.debouncedHandleResize = debounce(() => {
|
|
22230
22307
|
this.updateDimensions();
|
|
22231
22308
|
}, REACTION_DELAY);
|
|
22232
22309
|
this.adaptiveStreamSettings = adaptiveStreamSettings;
|
|
@@ -23245,6 +23322,8 @@ class Participant extends eventsExports.EventEmitter {
|
|
|
23245
23322
|
this.handleClosing = () => {
|
|
23246
23323
|
var _a, _b, _c, _d, _e, _f;
|
|
23247
23324
|
if (this.reconnectFuture) {
|
|
23325
|
+
// @throws-transformer ignore - introduced due to adding Throws into Future, investigate this
|
|
23326
|
+
// further
|
|
23248
23327
|
this.reconnectFuture.promise.catch(e => this.log.warn(e.message, this.logContext));
|
|
23249
23328
|
(_b = (_a = this.reconnectFuture) === null || _a === void 0 ? void 0 : _a.reject) === null || _b === void 0 ? void 0 : _b.call(_a, new Error('Got disconnected during reconnection attempt'));
|
|
23250
23329
|
this.reconnectFuture = undefined;
|
|
@@ -25602,7 +25681,7 @@ class Room extends eventsExports.EventEmitter {
|
|
|
25602
25681
|
}
|
|
25603
25682
|
if (nextUrl && !((_b = this.abortController) === null || _b === void 0 ? void 0 : _b.signal.aborted)) {
|
|
25604
25683
|
this.log.info("Initial connection failed with ConnectionError: ".concat(error.message, ". Retrying with another region: ").concat(nextUrl), this.logContext);
|
|
25605
|
-
this.recreateEngine();
|
|
25684
|
+
this.recreateEngine(true);
|
|
25606
25685
|
yield connectFn(resolve, reject, nextUrl);
|
|
25607
25686
|
} else {
|
|
25608
25687
|
this.handleDisconnect(this.options.stopLocalTrackOnUnpublish, getDisconnectReasonFromConnectionError(error));
|
|
@@ -25687,7 +25766,7 @@ class Room extends eventsExports.EventEmitter {
|
|
|
25687
25766
|
if (this.state === ConnectionState.Reconnecting || this.isResuming || ((_a = this.engine) === null || _a === void 0 ? void 0 : _a.pendingReconnect)) {
|
|
25688
25767
|
this.log.info('Reconnection attempt replaced by new connection attempt', this.logContext);
|
|
25689
25768
|
// make sure we close and recreate the existing engine in order to get rid of any potentially ongoing reconnection attempts
|
|
25690
|
-
this.recreateEngine();
|
|
25769
|
+
this.recreateEngine(true);
|
|
25691
25770
|
} else {
|
|
25692
25771
|
// create engine if previously disconnected
|
|
25693
25772
|
this.maybeCreateEngine();
|
|
@@ -26800,9 +26879,13 @@ class Room extends eventsExports.EventEmitter {
|
|
|
26800
26879
|
setupLocalParticipantEvents() {
|
|
26801
26880
|
this.localParticipant.on(ParticipantEvent.ParticipantMetadataChanged, this.onLocalParticipantMetadataChanged).on(ParticipantEvent.ParticipantNameChanged, this.onLocalParticipantNameChanged).on(ParticipantEvent.AttributesChanged, this.onLocalAttributesChanged).on(ParticipantEvent.TrackMuted, this.onLocalTrackMuted).on(ParticipantEvent.TrackUnmuted, this.onLocalTrackUnmuted).on(ParticipantEvent.LocalTrackPublished, this.onLocalTrackPublished).on(ParticipantEvent.LocalTrackUnpublished, this.onLocalTrackUnpublished).on(ParticipantEvent.ConnectionQualityChanged, this.onLocalConnectionQualityChanged).on(ParticipantEvent.MediaDevicesError, this.onMediaDevicesError).on(ParticipantEvent.AudioStreamAcquired, this.startAudio).on(ParticipantEvent.ChatMessage, this.onLocalChatMessageSent).on(ParticipantEvent.ParticipantPermissionsChanged, this.onLocalParticipantPermissionsChanged);
|
|
26802
26881
|
}
|
|
26803
|
-
recreateEngine() {
|
|
26804
|
-
|
|
26805
|
-
(
|
|
26882
|
+
recreateEngine(sendLeave) {
|
|
26883
|
+
const oldEngine = this.engine;
|
|
26884
|
+
if (sendLeave && oldEngine && !oldEngine.client.isDisconnected) {
|
|
26885
|
+
oldEngine.client.sendLeave().finally(() => oldEngine.close());
|
|
26886
|
+
} else {
|
|
26887
|
+
oldEngine === null || oldEngine === void 0 ? void 0 : oldEngine.close();
|
|
26888
|
+
}
|
|
26806
26889
|
/* @ts-ignore */
|
|
26807
26890
|
this.engine = undefined;
|
|
26808
26891
|
this.isResuming = false;
|
|
@@ -27223,7 +27306,7 @@ class Room extends eventsExports.EventEmitter {
|
|
|
27223
27306
|
numFailures: consecutiveFailures,
|
|
27224
27307
|
engine: this.engine ? {
|
|
27225
27308
|
closed: this.engine.isClosed,
|
|
27226
|
-
|
|
27309
|
+
transportsConnectedOrConnecting: this.engine.verifyTransport()
|
|
27227
27310
|
} : undefined
|
|
27228
27311
|
}));
|
|
27229
27312
|
if (consecutiveFailures >= 3) {
|
|
@@ -27441,1946 +27524,2030 @@ class Convert {
|
|
|
27441
27524
|
static transcriptionAttributesToJson(value) {
|
|
27442
27525
|
return JSON.stringify(value);
|
|
27443
27526
|
}
|
|
27444
|
-
}var attributeTypings=/*#__PURE__*/Object.freeze({__proto__:null,Convert:Convert});
|
|
27445
|
-
|
|
27446
|
-
|
|
27447
|
-
|
|
27448
|
-
|
|
27449
|
-
|
|
27450
|
-
|
|
27451
|
-
|
|
27452
|
-
class
|
|
27453
|
-
|
|
27454
|
-
|
|
27455
|
-
super();
|
|
27456
|
-
this.status = CheckStatus.IDLE;
|
|
27457
|
-
this.logs = [];
|
|
27458
|
-
this.options = {};
|
|
27459
|
-
this.url = url;
|
|
27460
|
-
this.token = token;
|
|
27461
|
-
this.name = this.constructor.name;
|
|
27462
|
-
this.room = new Room(options.roomOptions);
|
|
27463
|
-
this.connectOptions = options.connectOptions;
|
|
27464
|
-
this.options = options;
|
|
27527
|
+
}var attributeTypings=/*#__PURE__*/Object.freeze({__proto__:null,Convert:Convert});const U16_MAX_SIZE = 0xffff;
|
|
27528
|
+
const U32_MAX_SIZE = 0xffffffff;
|
|
27529
|
+
/**
|
|
27530
|
+
* A number of fields withing the data tracks packet specification assume wrap around behavior when
|
|
27531
|
+
* an unsigned type is incremented beyond its max size (ie, the packet `sequence` field). This
|
|
27532
|
+
* wrapper type manually reimplements this wrap around behavior given javascript's lack of fixed
|
|
27533
|
+
* size integer types.
|
|
27534
|
+
*/
|
|
27535
|
+
class WrapAroundUnsignedInt {
|
|
27536
|
+
static u16(raw) {
|
|
27537
|
+
return new WrapAroundUnsignedInt(raw, U16_MAX_SIZE);
|
|
27465
27538
|
}
|
|
27466
|
-
|
|
27467
|
-
return
|
|
27468
|
-
if (this.status !== CheckStatus.IDLE) {
|
|
27469
|
-
throw Error('check is running already');
|
|
27470
|
-
}
|
|
27471
|
-
this.setStatus(CheckStatus.RUNNING);
|
|
27472
|
-
try {
|
|
27473
|
-
yield this.perform();
|
|
27474
|
-
} catch (err) {
|
|
27475
|
-
if (err instanceof Error) {
|
|
27476
|
-
if (this.options.errorsAsWarnings) {
|
|
27477
|
-
this.appendWarning(err.message);
|
|
27478
|
-
} else {
|
|
27479
|
-
this.appendError(err.message);
|
|
27480
|
-
}
|
|
27481
|
-
}
|
|
27482
|
-
}
|
|
27483
|
-
yield this.disconnect();
|
|
27484
|
-
// sleep for a bit to ensure disconnect
|
|
27485
|
-
yield new Promise(resolve => setTimeout(resolve, 500));
|
|
27486
|
-
// @ts-ignore
|
|
27487
|
-
if (this.status !== CheckStatus.SKIPPED) {
|
|
27488
|
-
this.setStatus(this.isSuccess() ? CheckStatus.SUCCESS : CheckStatus.FAILED);
|
|
27489
|
-
}
|
|
27490
|
-
if (onComplete) {
|
|
27491
|
-
onComplete();
|
|
27492
|
-
}
|
|
27493
|
-
return this.getInfo();
|
|
27494
|
-
});
|
|
27539
|
+
static u32(raw) {
|
|
27540
|
+
return new WrapAroundUnsignedInt(raw, U32_MAX_SIZE);
|
|
27495
27541
|
}
|
|
27496
|
-
|
|
27497
|
-
|
|
27542
|
+
constructor(raw, maxSize) {
|
|
27543
|
+
this.value = raw;
|
|
27544
|
+
if (raw < 0) {
|
|
27545
|
+
throw new Error('WrapAroundUnsignedInt: cannot faithfully represent an integer smaller than 0');
|
|
27546
|
+
}
|
|
27547
|
+
if (maxSize > Number.MAX_SAFE_INTEGER) {
|
|
27548
|
+
throw new Error('WrapAroundUnsignedInt: cannot faithfully represent an integer bigger than MAX_SAFE_INTEGER.');
|
|
27549
|
+
}
|
|
27550
|
+
this.maxSize = maxSize;
|
|
27551
|
+
this.clamp();
|
|
27498
27552
|
}
|
|
27499
|
-
|
|
27500
|
-
|
|
27501
|
-
|
|
27502
|
-
|
|
27503
|
-
|
|
27504
|
-
|
|
27505
|
-
|
|
27506
|
-
|
|
27507
|
-
|
|
27508
|
-
return this.room;
|
|
27509
|
-
});
|
|
27553
|
+
/** Manually clamp the given containing value according to the wrap around max size bounds. Use
|
|
27554
|
+
* this after out of bounds modification to the contained value by external code. */
|
|
27555
|
+
clamp() {
|
|
27556
|
+
while (this.value > this.maxSize) {
|
|
27557
|
+
this.value -= this.maxSize + 1;
|
|
27558
|
+
}
|
|
27559
|
+
while (this.value < 0) {
|
|
27560
|
+
this.value += this.maxSize + 1;
|
|
27561
|
+
}
|
|
27510
27562
|
}
|
|
27511
|
-
|
|
27512
|
-
return
|
|
27513
|
-
if (this.room && this.room.state !== ConnectionState.Disconnected) {
|
|
27514
|
-
yield this.room.disconnect();
|
|
27515
|
-
// wait for it to go through
|
|
27516
|
-
yield new Promise(resolve => setTimeout(resolve, 500));
|
|
27517
|
-
}
|
|
27518
|
-
});
|
|
27563
|
+
clone() {
|
|
27564
|
+
return new WrapAroundUnsignedInt(this.value, this.maxSize);
|
|
27519
27565
|
}
|
|
27520
|
-
|
|
27521
|
-
|
|
27566
|
+
/** When called, maps the containing value to a new containing value. After mapping, the wrap
|
|
27567
|
+
* around external max size bounds are applied. Note that this is a mutative operation. */
|
|
27568
|
+
update(updateFn) {
|
|
27569
|
+
this.value = updateFn(this.value);
|
|
27570
|
+
this.clamp();
|
|
27522
27571
|
}
|
|
27523
|
-
|
|
27524
|
-
|
|
27525
|
-
|
|
27526
|
-
|
|
27527
|
-
this.room.on(RoomEvent.Reconnecting, () => {
|
|
27528
|
-
hasReconnecting = true;
|
|
27529
|
-
});
|
|
27530
|
-
this.room.once(RoomEvent.Reconnected, () => {
|
|
27531
|
-
hasReconnected = true;
|
|
27532
|
-
});
|
|
27533
|
-
this.room.simulateScenario("force-".concat(protocol));
|
|
27534
|
-
yield new Promise(resolve => setTimeout(resolve, 1000));
|
|
27535
|
-
if (!hasReconnecting) {
|
|
27536
|
-
// no need to wait for reconnection
|
|
27537
|
-
return;
|
|
27538
|
-
}
|
|
27539
|
-
// wait for 10 seconds for reconnection
|
|
27540
|
-
const timeout = Date.now() + 10000;
|
|
27541
|
-
while (Date.now() < timeout) {
|
|
27542
|
-
if (hasReconnected) {
|
|
27543
|
-
return;
|
|
27544
|
-
}
|
|
27545
|
-
yield sleep(100);
|
|
27546
|
-
}
|
|
27547
|
-
throw new Error("Could not reconnect using ".concat(protocol, " protocol after 10 seconds"));
|
|
27548
|
-
});
|
|
27572
|
+
/** Increments the given `n` to the inner value. Note that this is a mutative operation. */
|
|
27573
|
+
increment() {
|
|
27574
|
+
let n = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
|
|
27575
|
+
this.update(value => value + n);
|
|
27549
27576
|
}
|
|
27550
|
-
|
|
27551
|
-
|
|
27552
|
-
|
|
27553
|
-
|
|
27554
|
-
});
|
|
27555
|
-
this.emit('update', this.getInfo());
|
|
27577
|
+
/** Decrements the given `n` from the inner value. Note that this is a mutative operation. */
|
|
27578
|
+
decrement() {
|
|
27579
|
+
let n = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
|
|
27580
|
+
this.update(value => value - n);
|
|
27556
27581
|
}
|
|
27557
|
-
|
|
27558
|
-
this.
|
|
27559
|
-
|
|
27560
|
-
|
|
27561
|
-
});
|
|
27562
|
-
this.emit('update', this.getInfo());
|
|
27582
|
+
getThenIncrement() {
|
|
27583
|
+
const previousValue = this.value;
|
|
27584
|
+
this.increment();
|
|
27585
|
+
return new WrapAroundUnsignedInt(previousValue, this.maxSize);
|
|
27563
27586
|
}
|
|
27564
|
-
|
|
27565
|
-
|
|
27566
|
-
|
|
27567
|
-
|
|
27568
|
-
|
|
27569
|
-
this.
|
|
27587
|
+
/** Returns true if {@link this} is before the passed other {@link WrapAroundUnsignedInt}. */
|
|
27588
|
+
isBefore(other) {
|
|
27589
|
+
const a = this.value >>> 0;
|
|
27590
|
+
const b = other.value >>> 0;
|
|
27591
|
+
const diff = b - a >>> 0;
|
|
27592
|
+
return diff !== 0 && diff < this.maxSize + 1;
|
|
27570
27593
|
}
|
|
27571
|
-
|
|
27572
|
-
|
|
27573
|
-
|
|
27594
|
+
}
|
|
27595
|
+
class DataTrackTimestamp {
|
|
27596
|
+
static fromRtpTicks(rtpTicks) {
|
|
27597
|
+
return new DataTrackTimestamp(rtpTicks, 90000);
|
|
27574
27598
|
}
|
|
27575
|
-
|
|
27576
|
-
|
|
27577
|
-
|
|
27599
|
+
/** Generates a timestamp initialized to a non cryptographically secure random value, so that
|
|
27600
|
+
* different streams are more difficult to correlate in packet capture. */
|
|
27601
|
+
static rtpRandom() {
|
|
27602
|
+
const randomValue = Math.round(Math.random() * U32_MAX_SIZE);
|
|
27603
|
+
return DataTrackTimestamp.fromRtpTicks(randomValue);
|
|
27578
27604
|
}
|
|
27579
|
-
|
|
27580
|
-
|
|
27581
|
-
|
|
27582
|
-
name: this.name,
|
|
27583
|
-
status: this.status,
|
|
27584
|
-
description: this.description
|
|
27585
|
-
};
|
|
27605
|
+
constructor(raw, rateInHz) {
|
|
27606
|
+
this.timestamp = WrapAroundUnsignedInt.u32(raw);
|
|
27607
|
+
this.rateInHz = rateInHz;
|
|
27586
27608
|
}
|
|
27587
|
-
|
|
27588
|
-
|
|
27589
|
-
*/
|
|
27590
|
-
class CloudRegionCheck extends Checker {
|
|
27591
|
-
get description() {
|
|
27592
|
-
return 'Cloud regions';
|
|
27609
|
+
asTicks() {
|
|
27610
|
+
return this.timestamp.value;
|
|
27593
27611
|
}
|
|
27594
|
-
|
|
27595
|
-
return
|
|
27596
|
-
const regionProvider = new RegionUrlProvider(this.url, this.token);
|
|
27597
|
-
if (!regionProvider.isCloud()) {
|
|
27598
|
-
this.skip();
|
|
27599
|
-
return;
|
|
27600
|
-
}
|
|
27601
|
-
const regionStats = [];
|
|
27602
|
-
const seenUrls = new Set();
|
|
27603
|
-
for (let i = 0; i < 3; i++) {
|
|
27604
|
-
const regionUrl = yield regionProvider.getNextBestRegionUrl();
|
|
27605
|
-
if (!regionUrl) {
|
|
27606
|
-
break;
|
|
27607
|
-
}
|
|
27608
|
-
if (seenUrls.has(regionUrl)) {
|
|
27609
|
-
continue;
|
|
27610
|
-
}
|
|
27611
|
-
seenUrls.add(regionUrl);
|
|
27612
|
-
const stats = yield this.checkCloudRegion(regionUrl);
|
|
27613
|
-
this.appendMessage("".concat(stats.region, " RTT: ").concat(stats.rtt, "ms, duration: ").concat(stats.duration, "ms"));
|
|
27614
|
-
regionStats.push(stats);
|
|
27615
|
-
}
|
|
27616
|
-
regionStats.sort((a, b) => {
|
|
27617
|
-
return (a.duration - b.duration) * 0.5 + (a.rtt - b.rtt) * 0.5;
|
|
27618
|
-
});
|
|
27619
|
-
const bestRegion = regionStats[0];
|
|
27620
|
-
this.bestStats = bestRegion;
|
|
27621
|
-
this.appendMessage("best Cloud region: ".concat(bestRegion.region));
|
|
27622
|
-
});
|
|
27612
|
+
clone() {
|
|
27613
|
+
return new DataTrackTimestamp(this.timestamp.value, this.rateInHz);
|
|
27623
27614
|
}
|
|
27624
|
-
|
|
27625
|
-
|
|
27626
|
-
info.data = this.bestStats;
|
|
27627
|
-
return info;
|
|
27615
|
+
wrappingAdd(n) {
|
|
27616
|
+
this.timestamp.increment(n);
|
|
27628
27617
|
}
|
|
27629
|
-
|
|
27630
|
-
|
|
27631
|
-
|
|
27632
|
-
yield this.connect(url);
|
|
27633
|
-
if (this.options.protocol === 'tcp') {
|
|
27634
|
-
yield this.switchProtocol('tcp');
|
|
27635
|
-
}
|
|
27636
|
-
const region = (_a = this.room.serverInfo) === null || _a === void 0 ? void 0 : _a.region;
|
|
27637
|
-
if (!region) {
|
|
27638
|
-
throw new Error('Region not found');
|
|
27639
|
-
}
|
|
27640
|
-
const writer = yield this.room.localParticipant.streamText({
|
|
27641
|
-
topic: 'test'
|
|
27642
|
-
});
|
|
27643
|
-
const chunkSize = 1000; // each chunk is about 1000 bytes
|
|
27644
|
-
const totalSize = 1000000; // approximately 1MB of data
|
|
27645
|
-
const numChunks = totalSize / chunkSize; // will yield 1000 chunks
|
|
27646
|
-
const chunkData = 'A'.repeat(chunkSize); // create a string of 1000 'A' characters
|
|
27647
|
-
const startTime = Date.now();
|
|
27648
|
-
for (let i = 0; i < numChunks; i++) {
|
|
27649
|
-
yield writer.write(chunkData);
|
|
27650
|
-
}
|
|
27651
|
-
yield writer.close();
|
|
27652
|
-
const endTime = Date.now();
|
|
27653
|
-
const stats = yield (_b = this.room.engine.pcManager) === null || _b === void 0 ? void 0 : _b.publisher.getStats();
|
|
27654
|
-
const regionStats = {
|
|
27655
|
-
region: region,
|
|
27656
|
-
rtt: 10000,
|
|
27657
|
-
duration: endTime - startTime
|
|
27658
|
-
};
|
|
27659
|
-
stats === null || stats === void 0 ? void 0 : stats.forEach(stat => {
|
|
27660
|
-
if (stat.type === 'candidate-pair' && stat.nominated) {
|
|
27661
|
-
regionStats.rtt = stat.currentRoundTripTime * 1000;
|
|
27662
|
-
}
|
|
27663
|
-
});
|
|
27664
|
-
yield this.disconnect();
|
|
27665
|
-
return regionStats;
|
|
27666
|
-
});
|
|
27618
|
+
/** Returns true if {@link this} is before the passed other {@link DataTrackTimestamp}. */
|
|
27619
|
+
isBefore(other) {
|
|
27620
|
+
return this.timestamp.isBefore(other.timestamp);
|
|
27667
27621
|
}
|
|
27668
|
-
}
|
|
27669
|
-
|
|
27670
|
-
|
|
27671
|
-
return
|
|
27622
|
+
}
|
|
27623
|
+
function coerceToDataView(input) {
|
|
27624
|
+
if (input instanceof DataView) {
|
|
27625
|
+
return input;
|
|
27626
|
+
} else if (input instanceof ArrayBuffer) {
|
|
27627
|
+
return new DataView(input);
|
|
27628
|
+
} else if (input instanceof Uint8Array) {
|
|
27629
|
+
return new DataView(input.buffer, input.byteOffset, input.byteLength);
|
|
27630
|
+
} else {
|
|
27631
|
+
throw new Error("Error coercing ".concat(input, " to DataView - input was not DataView, ArrayBuffer, or Uint8Array."));
|
|
27672
27632
|
}
|
|
27673
|
-
|
|
27674
|
-
|
|
27675
|
-
|
|
27676
|
-
|
|
27677
|
-
|
|
27678
|
-
|
|
27679
|
-
|
|
27680
|
-
|
|
27681
|
-
|
|
27682
|
-
|
|
27683
|
-
|
|
27684
|
-
|
|
27685
|
-
|
|
27686
|
-
|
|
27687
|
-
|
|
27688
|
-
|
|
27689
|
-
|
|
27690
|
-
|
|
27691
|
-
|
|
27692
|
-
|
|
27693
|
-
|
|
27694
|
-
|
|
27695
|
-
|
|
27696
|
-
|
|
27697
|
-
|
|
27698
|
-
|
|
27699
|
-
|
|
27700
|
-
|
|
27633
|
+
}// Number type sizes
|
|
27634
|
+
const U8_LENGTH_BYTES = 1;
|
|
27635
|
+
const U16_LENGTH_BYTES = 2;
|
|
27636
|
+
const U32_LENGTH_BYTES = 4;
|
|
27637
|
+
const U64_LENGTH_BYTES = 8;
|
|
27638
|
+
/// Constants used for serialization and deserialization.
|
|
27639
|
+
const SUPPORTED_VERSION = 0;
|
|
27640
|
+
const BASE_HEADER_LEN = 12;
|
|
27641
|
+
// Bitfield shifts and masks for header flags
|
|
27642
|
+
const VERSION_SHIFT = 5;
|
|
27643
|
+
const VERSION_MASK = 0x07;
|
|
27644
|
+
const FRAME_MARKER_SHIFT = 3;
|
|
27645
|
+
const FRAME_MARKER_MASK = 0x3;
|
|
27646
|
+
const FRAME_MARKER_START = 0x2;
|
|
27647
|
+
const FRAME_MARKER_FINAL = 0x1;
|
|
27648
|
+
const FRAME_MARKER_INTER = 0x0;
|
|
27649
|
+
const FRAME_MARKER_SINGLE = 0x3;
|
|
27650
|
+
const EXT_WORDS_INDICATOR_SIZE = 2;
|
|
27651
|
+
const EXT_FLAG_SHIFT = 0x2;
|
|
27652
|
+
const EXT_FLAG_MASK = 0x1;
|
|
27653
|
+
const EXT_TAG_PADDING = 0;var DataTrackDeserializeErrorReason;
|
|
27654
|
+
(function (DataTrackDeserializeErrorReason) {
|
|
27655
|
+
DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["TooShort"] = 0] = "TooShort";
|
|
27656
|
+
DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["HeaderOverrun"] = 1] = "HeaderOverrun";
|
|
27657
|
+
DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["MissingExtWords"] = 2] = "MissingExtWords";
|
|
27658
|
+
DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["UnsupportedVersion"] = 3] = "UnsupportedVersion";
|
|
27659
|
+
DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["InvalidHandle"] = 4] = "InvalidHandle";
|
|
27660
|
+
DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["MalformedExt"] = 5] = "MalformedExt";
|
|
27661
|
+
})(DataTrackDeserializeErrorReason || (DataTrackDeserializeErrorReason = {}));
|
|
27662
|
+
class DataTrackDeserializeError extends LivekitReasonedError {
|
|
27663
|
+
constructor(message, reason, options) {
|
|
27664
|
+
super(19, message, options);
|
|
27665
|
+
this.name = 'DataTrackDeserializeError';
|
|
27666
|
+
this.reason = reason;
|
|
27667
|
+
this.reasonName = DataTrackDeserializeErrorReason[reason];
|
|
27701
27668
|
}
|
|
27702
|
-
|
|
27703
|
-
|
|
27704
|
-
info.data = this.bestStats;
|
|
27705
|
-
return info;
|
|
27669
|
+
static tooShort() {
|
|
27670
|
+
return new DataTrackDeserializeError('Too short to contain a valid header', DataTrackDeserializeErrorReason.TooShort);
|
|
27706
27671
|
}
|
|
27707
|
-
|
|
27708
|
-
return
|
|
27709
|
-
yield this.connect();
|
|
27710
|
-
if (protocol === 'tcp') {
|
|
27711
|
-
yield this.switchProtocol('tcp');
|
|
27712
|
-
} else {
|
|
27713
|
-
yield this.switchProtocol('udp');
|
|
27714
|
-
}
|
|
27715
|
-
// create a canvas with animated content
|
|
27716
|
-
const canvas = document.createElement('canvas');
|
|
27717
|
-
canvas.width = 1280;
|
|
27718
|
-
canvas.height = 720;
|
|
27719
|
-
const ctx = canvas.getContext('2d');
|
|
27720
|
-
if (!ctx) {
|
|
27721
|
-
throw new Error('Could not get canvas context');
|
|
27722
|
-
}
|
|
27723
|
-
let hue = 0;
|
|
27724
|
-
const animate = () => {
|
|
27725
|
-
hue = (hue + 1) % 360;
|
|
27726
|
-
ctx.fillStyle = "hsl(".concat(hue, ", 100%, 50%)");
|
|
27727
|
-
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
27728
|
-
requestAnimationFrame(animate);
|
|
27729
|
-
};
|
|
27730
|
-
animate();
|
|
27731
|
-
// create video track from canvas
|
|
27732
|
-
const stream = canvas.captureStream(30); // 30fps
|
|
27733
|
-
const videoTrack = stream.getVideoTracks()[0];
|
|
27734
|
-
// publish to room
|
|
27735
|
-
const pub = yield this.room.localParticipant.publishTrack(videoTrack, {
|
|
27736
|
-
simulcast: false,
|
|
27737
|
-
degradationPreference: 'maintain-resolution',
|
|
27738
|
-
videoEncoding: {
|
|
27739
|
-
maxBitrate: 2000000
|
|
27740
|
-
}
|
|
27741
|
-
});
|
|
27742
|
-
const track = pub.track;
|
|
27743
|
-
const protocolStats = {
|
|
27744
|
-
protocol,
|
|
27745
|
-
packetsLost: 0,
|
|
27746
|
-
packetsSent: 0,
|
|
27747
|
-
qualityLimitationDurations: {},
|
|
27748
|
-
rttTotal: 0,
|
|
27749
|
-
jitterTotal: 0,
|
|
27750
|
-
bitrateTotal: 0,
|
|
27751
|
-
count: 0
|
|
27752
|
-
};
|
|
27753
|
-
// gather stats once a second
|
|
27754
|
-
const interval = setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
27755
|
-
const stats = yield track.getRTCStatsReport();
|
|
27756
|
-
stats === null || stats === void 0 ? void 0 : stats.forEach(stat => {
|
|
27757
|
-
if (stat.type === 'outbound-rtp') {
|
|
27758
|
-
protocolStats.packetsSent = stat.packetsSent;
|
|
27759
|
-
protocolStats.qualityLimitationDurations = stat.qualityLimitationDurations;
|
|
27760
|
-
protocolStats.bitrateTotal += stat.targetBitrate;
|
|
27761
|
-
protocolStats.count++;
|
|
27762
|
-
} else if (stat.type === 'remote-inbound-rtp') {
|
|
27763
|
-
protocolStats.packetsLost = stat.packetsLost;
|
|
27764
|
-
protocolStats.rttTotal += stat.roundTripTime;
|
|
27765
|
-
protocolStats.jitterTotal += stat.jitter;
|
|
27766
|
-
}
|
|
27767
|
-
});
|
|
27768
|
-
}), 1000);
|
|
27769
|
-
// wait a bit to gather stats
|
|
27770
|
-
yield new Promise(resolve => setTimeout(resolve, TEST_DURATION));
|
|
27771
|
-
clearInterval(interval);
|
|
27772
|
-
videoTrack.stop();
|
|
27773
|
-
canvas.remove();
|
|
27774
|
-
yield this.disconnect();
|
|
27775
|
-
return protocolStats;
|
|
27776
|
-
});
|
|
27672
|
+
static headerOverrun() {
|
|
27673
|
+
return new DataTrackDeserializeError('Header exceeds total packet length', DataTrackDeserializeErrorReason.HeaderOverrun);
|
|
27777
27674
|
}
|
|
27778
|
-
|
|
27779
|
-
|
|
27780
|
-
return 'Can publish audio';
|
|
27675
|
+
static missingExtWords() {
|
|
27676
|
+
return new DataTrackDeserializeError('Extension word indicator is missing', DataTrackDeserializeErrorReason.MissingExtWords);
|
|
27781
27677
|
}
|
|
27782
|
-
|
|
27783
|
-
return
|
|
27784
|
-
|
|
27785
|
-
|
|
27786
|
-
|
|
27787
|
-
|
|
27788
|
-
if (trackIsSilent) {
|
|
27789
|
-
throw new Error('unable to detect audio from microphone');
|
|
27790
|
-
}
|
|
27791
|
-
this.appendMessage('detected audio from microphone');
|
|
27792
|
-
room.localParticipant.publishTrack(track);
|
|
27793
|
-
// wait for a few seconds to publish
|
|
27794
|
-
yield new Promise(resolve => setTimeout(resolve, 3000));
|
|
27795
|
-
// verify RTC stats that it's publishing
|
|
27796
|
-
const stats = yield (_a = track.sender) === null || _a === void 0 ? void 0 : _a.getStats();
|
|
27797
|
-
if (!stats) {
|
|
27798
|
-
throw new Error('Could not get RTCStats');
|
|
27799
|
-
}
|
|
27800
|
-
let numPackets = 0;
|
|
27801
|
-
stats.forEach(stat => {
|
|
27802
|
-
if (stat.type === 'outbound-rtp' && (stat.kind === 'audio' || !stat.kind && stat.mediaType === 'audio')) {
|
|
27803
|
-
numPackets = stat.packetsSent;
|
|
27804
|
-
}
|
|
27805
|
-
});
|
|
27806
|
-
if (numPackets === 0) {
|
|
27807
|
-
throw new Error('Could not determine packets are sent');
|
|
27808
|
-
}
|
|
27809
|
-
this.appendMessage("published ".concat(numPackets, " audio packets"));
|
|
27678
|
+
static unsupportedVersion(version) {
|
|
27679
|
+
return new DataTrackDeserializeError("Unsupported version ".concat(version), DataTrackDeserializeErrorReason.UnsupportedVersion);
|
|
27680
|
+
}
|
|
27681
|
+
static invalidHandle(cause) {
|
|
27682
|
+
return new DataTrackDeserializeError("invalid track handle: ".concat(cause.message), DataTrackDeserializeErrorReason.InvalidHandle, {
|
|
27683
|
+
cause
|
|
27810
27684
|
});
|
|
27811
27685
|
}
|
|
27812
|
-
|
|
27813
|
-
|
|
27814
|
-
return 'Can publish video';
|
|
27686
|
+
static malformedExt(tag) {
|
|
27687
|
+
return new DataTrackDeserializeError("Extension with tag ".concat(tag, " is malformed"), DataTrackDeserializeErrorReason.MalformedExt);
|
|
27815
27688
|
}
|
|
27816
|
-
|
|
27817
|
-
|
|
27818
|
-
|
|
27819
|
-
|
|
27820
|
-
|
|
27821
|
-
|
|
27822
|
-
|
|
27823
|
-
|
|
27824
|
-
|
|
27825
|
-
|
|
27826
|
-
|
|
27827
|
-
|
|
27828
|
-
if (!stats) {
|
|
27829
|
-
throw new Error('Could not get RTCStats');
|
|
27830
|
-
}
|
|
27831
|
-
let numPackets = 0;
|
|
27832
|
-
stats.forEach(stat => {
|
|
27833
|
-
if (stat.type === 'outbound-rtp' && (stat.kind === 'video' || !stat.kind && stat.mediaType === 'video')) {
|
|
27834
|
-
numPackets += stat.packetsSent;
|
|
27835
|
-
}
|
|
27836
|
-
});
|
|
27837
|
-
if (numPackets === 0) {
|
|
27838
|
-
throw new Error('Could not determine packets are sent');
|
|
27839
|
-
}
|
|
27840
|
-
this.appendMessage("published ".concat(numPackets, " video packets"));
|
|
27841
|
-
});
|
|
27689
|
+
}
|
|
27690
|
+
var DataTrackSerializeErrorReason;
|
|
27691
|
+
(function (DataTrackSerializeErrorReason) {
|
|
27692
|
+
DataTrackSerializeErrorReason[DataTrackSerializeErrorReason["TooSmallForHeader"] = 0] = "TooSmallForHeader";
|
|
27693
|
+
DataTrackSerializeErrorReason[DataTrackSerializeErrorReason["TooSmallForPayload"] = 1] = "TooSmallForPayload";
|
|
27694
|
+
})(DataTrackSerializeErrorReason || (DataTrackSerializeErrorReason = {}));
|
|
27695
|
+
class DataTrackSerializeError extends LivekitReasonedError {
|
|
27696
|
+
constructor(message, reason, options) {
|
|
27697
|
+
super(19, message, options);
|
|
27698
|
+
this.name = 'DataTrackSerializeError';
|
|
27699
|
+
this.reason = reason;
|
|
27700
|
+
this.reasonName = DataTrackSerializeErrorReason[reason];
|
|
27842
27701
|
}
|
|
27843
|
-
|
|
27844
|
-
return
|
|
27845
|
-
const stream = new MediaStream();
|
|
27846
|
-
stream.addTrack(track.clone());
|
|
27847
|
-
// Create video element to check frames
|
|
27848
|
-
const video = document.createElement('video');
|
|
27849
|
-
video.srcObject = stream;
|
|
27850
|
-
video.muted = true;
|
|
27851
|
-
video.autoplay = true;
|
|
27852
|
-
video.playsInline = true;
|
|
27853
|
-
// For iOS Safari
|
|
27854
|
-
video.setAttribute('playsinline', 'true');
|
|
27855
|
-
document.body.appendChild(video);
|
|
27856
|
-
yield new Promise(resolve => {
|
|
27857
|
-
video.onplay = () => {
|
|
27858
|
-
setTimeout(() => {
|
|
27859
|
-
var _a, _b, _c, _d;
|
|
27860
|
-
const canvas = document.createElement('canvas');
|
|
27861
|
-
const settings = track.getSettings();
|
|
27862
|
-
const width = (_b = (_a = settings.width) !== null && _a !== void 0 ? _a : video.videoWidth) !== null && _b !== void 0 ? _b : 1280;
|
|
27863
|
-
const height = (_d = (_c = settings.height) !== null && _c !== void 0 ? _c : video.videoHeight) !== null && _d !== void 0 ? _d : 720;
|
|
27864
|
-
canvas.width = width;
|
|
27865
|
-
canvas.height = height;
|
|
27866
|
-
const ctx = canvas.getContext('2d');
|
|
27867
|
-
// Draw video frame to canvas
|
|
27868
|
-
ctx.drawImage(video, 0, 0);
|
|
27869
|
-
// Get image data and check if all pixels are black
|
|
27870
|
-
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
27871
|
-
const data = imageData.data;
|
|
27872
|
-
let isAllBlack = true;
|
|
27873
|
-
for (let i = 0; i < data.length; i += 4) {
|
|
27874
|
-
if (data[i] !== 0 || data[i + 1] !== 0 || data[i + 2] !== 0) {
|
|
27875
|
-
isAllBlack = false;
|
|
27876
|
-
break;
|
|
27877
|
-
}
|
|
27878
|
-
}
|
|
27879
|
-
if (isAllBlack) {
|
|
27880
|
-
this.appendError('camera appears to be producing only black frames');
|
|
27881
|
-
} else {
|
|
27882
|
-
this.appendMessage('received video frames');
|
|
27883
|
-
}
|
|
27884
|
-
resolve();
|
|
27885
|
-
}, 1000);
|
|
27886
|
-
};
|
|
27887
|
-
video.play();
|
|
27888
|
-
});
|
|
27889
|
-
stream.getTracks().forEach(t => t.stop());
|
|
27890
|
-
video.remove();
|
|
27891
|
-
});
|
|
27702
|
+
static tooSmallForHeader() {
|
|
27703
|
+
return new DataTrackSerializeError('Buffer cannot fit header', DataTrackSerializeErrorReason.TooSmallForHeader);
|
|
27892
27704
|
}
|
|
27893
|
-
|
|
27894
|
-
|
|
27895
|
-
return 'Resuming connection after interruption';
|
|
27705
|
+
static tooSmallForPayload() {
|
|
27706
|
+
return new DataTrackSerializeError('Buffer cannot fit payload', DataTrackSerializeErrorReason.TooSmallForPayload);
|
|
27896
27707
|
}
|
|
27897
|
-
|
|
27898
|
-
|
|
27899
|
-
|
|
27900
|
-
|
|
27901
|
-
|
|
27902
|
-
|
|
27903
|
-
|
|
27904
|
-
|
|
27905
|
-
|
|
27906
|
-
|
|
27907
|
-
|
|
27908
|
-
|
|
27909
|
-
|
|
27910
|
-
};
|
|
27911
|
-
room.on(RoomEvent.SignalReconnecting, handleReconnecting).on(RoomEvent.Reconnecting, handleReconnecting).on(RoomEvent.Reconnected, () => {
|
|
27912
|
-
reconnected = true;
|
|
27913
|
-
reconnectResolver(true);
|
|
27914
|
-
});
|
|
27915
|
-
(_a = room.engine.client.ws) === null || _a === void 0 ? void 0 : _a.close();
|
|
27916
|
-
const onClose = room.engine.client.onClose;
|
|
27917
|
-
if (onClose) {
|
|
27918
|
-
onClose('');
|
|
27919
|
-
}
|
|
27920
|
-
yield reconnectTimeout;
|
|
27921
|
-
if (!reconnectingTriggered) {
|
|
27922
|
-
throw new Error('Did not attempt to reconnect');
|
|
27923
|
-
} else if (!reconnected || room.state !== ConnectionState.Connected) {
|
|
27924
|
-
this.appendWarning('reconnection is only possible in Redis-based configurations');
|
|
27925
|
-
throw new Error('Not able to reconnect');
|
|
27926
|
-
}
|
|
27927
|
-
});
|
|
27708
|
+
}/** An abstract class implementing common behavior related to data track binary serialization. */
|
|
27709
|
+
class Serializable {
|
|
27710
|
+
/** Encodes the instance as binary and returns the data as a Uint8Array. */
|
|
27711
|
+
toBinary() {
|
|
27712
|
+
const lengthBytes = this.toBinaryLengthBytes();
|
|
27713
|
+
const output = new ArrayBuffer(lengthBytes);
|
|
27714
|
+
const view = new DataView(output);
|
|
27715
|
+
const writtenBytes = this.toBinaryInto(view);
|
|
27716
|
+
if (lengthBytes !== writtenBytes) {
|
|
27717
|
+
// @throws-transformer ignore - this should be treated as a "panic" and not be caught
|
|
27718
|
+
throw new Error("".concat(this.constructor.name, ".toBinary: written bytes (").concat(writtenBytes, " bytes) not equal to allocated array buffer length (").concat(lengthBytes, " bytes)."));
|
|
27719
|
+
}
|
|
27720
|
+
return new Uint8Array(output);
|
|
27928
27721
|
}
|
|
27929
|
-
}
|
|
27930
|
-
|
|
27931
|
-
|
|
27722
|
+
}var DataTrackExtensionTag;
|
|
27723
|
+
(function (DataTrackExtensionTag) {
|
|
27724
|
+
DataTrackExtensionTag[DataTrackExtensionTag["UserTimestamp"] = 2] = "UserTimestamp";
|
|
27725
|
+
DataTrackExtensionTag[DataTrackExtensionTag["E2ee"] = 1] = "E2ee";
|
|
27726
|
+
})(DataTrackExtensionTag || (DataTrackExtensionTag = {}));
|
|
27727
|
+
class DataTrackExtension extends Serializable {}
|
|
27728
|
+
class DataTrackUserTimestampExtension extends DataTrackExtension {
|
|
27729
|
+
constructor(timestamp) {
|
|
27730
|
+
super();
|
|
27731
|
+
this.timestamp = timestamp;
|
|
27932
27732
|
}
|
|
27933
|
-
|
|
27934
|
-
return
|
|
27935
|
-
var _a, _b, _c;
|
|
27936
|
-
if (isCloud(new URL(this.url))) {
|
|
27937
|
-
this.appendMessage('Using region specific url');
|
|
27938
|
-
this.url = (_a = yield new RegionUrlProvider(this.url, this.token).getNextBestRegionUrl()) !== null && _a !== void 0 ? _a : this.url;
|
|
27939
|
-
}
|
|
27940
|
-
const signalClient = new SignalClient();
|
|
27941
|
-
const joinRes = yield signalClient.join(this.url, this.token, {
|
|
27942
|
-
autoSubscribe: true,
|
|
27943
|
-
maxRetries: 0,
|
|
27944
|
-
e2eeEnabled: false,
|
|
27945
|
-
websocketTimeout: 15000
|
|
27946
|
-
}, undefined, true);
|
|
27947
|
-
let hasTLS = false;
|
|
27948
|
-
let hasTURN = false;
|
|
27949
|
-
let hasSTUN = false;
|
|
27950
|
-
for (let iceServer of joinRes.iceServers) {
|
|
27951
|
-
for (let url of iceServer.urls) {
|
|
27952
|
-
if (url.startsWith('turn:')) {
|
|
27953
|
-
hasTURN = true;
|
|
27954
|
-
hasSTUN = true;
|
|
27955
|
-
} else if (url.startsWith('turns:')) {
|
|
27956
|
-
hasTURN = true;
|
|
27957
|
-
hasSTUN = true;
|
|
27958
|
-
hasTLS = true;
|
|
27959
|
-
}
|
|
27960
|
-
if (url.startsWith('stun:')) {
|
|
27961
|
-
hasSTUN = true;
|
|
27962
|
-
}
|
|
27963
|
-
}
|
|
27964
|
-
}
|
|
27965
|
-
if (!hasSTUN) {
|
|
27966
|
-
this.appendWarning('No STUN servers configured on server side.');
|
|
27967
|
-
} else if (hasTURN && !hasTLS) {
|
|
27968
|
-
this.appendWarning('TURN is configured server side, but TURN/TLS is unavailable.');
|
|
27969
|
-
}
|
|
27970
|
-
yield signalClient.close();
|
|
27971
|
-
if (((_c = (_b = this.connectOptions) === null || _b === void 0 ? void 0 : _b.rtcConfig) === null || _c === void 0 ? void 0 : _c.iceServers) || hasTURN) {
|
|
27972
|
-
yield this.room.connect(this.url, this.token, {
|
|
27973
|
-
rtcConfig: {
|
|
27974
|
-
iceTransportPolicy: 'relay'
|
|
27975
|
-
}
|
|
27976
|
-
});
|
|
27977
|
-
} else {
|
|
27978
|
-
this.appendWarning('No TURN servers configured.');
|
|
27979
|
-
this.skip();
|
|
27980
|
-
yield new Promise(resolve => setTimeout(resolve, 0));
|
|
27981
|
-
}
|
|
27982
|
-
});
|
|
27733
|
+
toBinaryLengthBytes() {
|
|
27734
|
+
return U16_LENGTH_BYTES /* tag */ + U16_LENGTH_BYTES /* length */ + DataTrackUserTimestampExtension.lengthBytes;
|
|
27983
27735
|
}
|
|
27984
|
-
|
|
27985
|
-
|
|
27986
|
-
|
|
27736
|
+
toBinaryInto(dataView) {
|
|
27737
|
+
let byteIndex = 0;
|
|
27738
|
+
dataView.setUint16(byteIndex, DataTrackUserTimestampExtension.tag);
|
|
27739
|
+
byteIndex += U16_LENGTH_BYTES;
|
|
27740
|
+
const rtpOrientedLength = DataTrackUserTimestampExtension.lengthBytes - 1;
|
|
27741
|
+
dataView.setUint16(byteIndex, rtpOrientedLength);
|
|
27742
|
+
byteIndex += U16_LENGTH_BYTES;
|
|
27743
|
+
dataView.setBigUint64(byteIndex, this.timestamp);
|
|
27744
|
+
byteIndex += U64_LENGTH_BYTES;
|
|
27745
|
+
const totalLengthBytes = this.toBinaryLengthBytes();
|
|
27746
|
+
if (byteIndex !== totalLengthBytes) {
|
|
27747
|
+
// @throws-transformer ignore - this should be treated as a "panic" and not be caught
|
|
27748
|
+
throw new Error("DataTrackUserTimestampExtension.toBinaryInto: Wrote ".concat(byteIndex, " bytes but expected length was ").concat(totalLengthBytes, " bytes"));
|
|
27749
|
+
}
|
|
27750
|
+
return byteIndex;
|
|
27751
|
+
}
|
|
27752
|
+
toJSON() {
|
|
27753
|
+
return {
|
|
27754
|
+
tag: DataTrackUserTimestampExtension.tag,
|
|
27755
|
+
lengthBytes: DataTrackUserTimestampExtension.lengthBytes,
|
|
27756
|
+
timestamp: this.timestamp
|
|
27757
|
+
};
|
|
27758
|
+
}
|
|
27759
|
+
}
|
|
27760
|
+
DataTrackUserTimestampExtension.tag = DataTrackExtensionTag.UserTimestamp;
|
|
27761
|
+
DataTrackUserTimestampExtension.lengthBytes = 8;
|
|
27762
|
+
class DataTrackE2eeExtension extends DataTrackExtension {
|
|
27763
|
+
constructor(keyIndex, iv) {
|
|
27764
|
+
super();
|
|
27765
|
+
this.keyIndex = keyIndex;
|
|
27766
|
+
this.iv = iv;
|
|
27767
|
+
}
|
|
27768
|
+
toBinaryLengthBytes() {
|
|
27769
|
+
return U16_LENGTH_BYTES /* tag */ + U16_LENGTH_BYTES /* length */ + DataTrackE2eeExtension.lengthBytes;
|
|
27987
27770
|
}
|
|
27988
|
-
|
|
27989
|
-
|
|
27990
|
-
|
|
27991
|
-
|
|
27992
|
-
|
|
27993
|
-
|
|
27994
|
-
|
|
27995
|
-
|
|
27996
|
-
|
|
27997
|
-
|
|
27998
|
-
|
|
27999
|
-
|
|
28000
|
-
|
|
28001
|
-
|
|
28002
|
-
|
|
28003
|
-
|
|
28004
|
-
|
|
28005
|
-
|
|
28006
|
-
|
|
28007
|
-
|
|
28008
|
-
|
|
28009
|
-
|
|
28010
|
-
|
|
28011
|
-
|
|
28012
|
-
|
|
28013
|
-
|
|
28014
|
-
|
|
28015
|
-
}
|
|
28016
|
-
};
|
|
28017
|
-
if ((_a = this.room.engine.pcManager) === null || _a === void 0 ? void 0 : _a.subscriber) {
|
|
28018
|
-
this.room.engine.pcManager.subscriber.onIceCandidateError = ev => {
|
|
28019
|
-
if (ev instanceof RTCPeerConnectionIceErrorEvent) {
|
|
28020
|
-
this.appendWarning("error with ICE candidate: ".concat(ev.errorCode, " ").concat(ev.errorText, " ").concat(ev.url));
|
|
28021
|
-
}
|
|
28022
|
-
};
|
|
28023
|
-
}
|
|
28024
|
-
});
|
|
28025
|
-
try {
|
|
28026
|
-
yield this.connect();
|
|
28027
|
-
livekitLogger.info('now the room is connected');
|
|
28028
|
-
} catch (err) {
|
|
28029
|
-
this.appendWarning('ports need to be open on firewall in order to connect.');
|
|
28030
|
-
throw err;
|
|
28031
|
-
}
|
|
28032
|
-
if (!hasTcp) {
|
|
28033
|
-
this.appendWarning('Server is not configured for ICE/TCP');
|
|
28034
|
-
}
|
|
28035
|
-
if (!hasIpv4Udp) {
|
|
28036
|
-
this.appendWarning('No public IPv4 UDP candidates were found. Your server is likely not configured correctly');
|
|
28037
|
-
}
|
|
28038
|
-
});
|
|
27771
|
+
toBinaryInto(dataView) {
|
|
27772
|
+
let byteIndex = 0;
|
|
27773
|
+
dataView.setUint16(byteIndex, DataTrackE2eeExtension.tag);
|
|
27774
|
+
byteIndex += U16_LENGTH_BYTES;
|
|
27775
|
+
const rtpOrientedLength = DataTrackE2eeExtension.lengthBytes - 1;
|
|
27776
|
+
dataView.setUint16(byteIndex, rtpOrientedLength);
|
|
27777
|
+
byteIndex += U16_LENGTH_BYTES;
|
|
27778
|
+
dataView.setUint8(byteIndex, this.keyIndex);
|
|
27779
|
+
byteIndex += U8_LENGTH_BYTES;
|
|
27780
|
+
for (let i = 0; i < this.iv.length; i += 1) {
|
|
27781
|
+
dataView.setUint8(byteIndex, this.iv[i]);
|
|
27782
|
+
byteIndex += U8_LENGTH_BYTES;
|
|
27783
|
+
}
|
|
27784
|
+
const totalLengthBytes = this.toBinaryLengthBytes();
|
|
27785
|
+
if (byteIndex !== totalLengthBytes) {
|
|
27786
|
+
// @throws-transformer ignore - this should be treated as a "panic" and not be caught
|
|
27787
|
+
throw new Error("DataTrackE2eeExtension.toBinaryInto: Wrote ".concat(byteIndex, " bytes but expected length was ").concat(totalLengthBytes, " bytes"));
|
|
27788
|
+
}
|
|
27789
|
+
return byteIndex;
|
|
27790
|
+
}
|
|
27791
|
+
toJSON() {
|
|
27792
|
+
return {
|
|
27793
|
+
tag: DataTrackE2eeExtension.tag,
|
|
27794
|
+
lengthBytes: DataTrackE2eeExtension.lengthBytes,
|
|
27795
|
+
keyIndex: this.keyIndex,
|
|
27796
|
+
iv: this.iv
|
|
27797
|
+
};
|
|
28039
27798
|
}
|
|
28040
27799
|
}
|
|
28041
|
-
|
|
28042
|
-
|
|
28043
|
-
|
|
28044
|
-
|
|
28045
|
-
|
|
28046
|
-
|
|
28047
|
-
|
|
28048
|
-
|
|
28049
|
-
|
|
28050
|
-
|
|
28051
|
-
|
|
28052
|
-
|
|
27800
|
+
DataTrackE2eeExtension.tag = DataTrackExtensionTag.E2ee;
|
|
27801
|
+
DataTrackE2eeExtension.lengthBytes = 13;
|
|
27802
|
+
class DataTrackExtensions extends Serializable {
|
|
27803
|
+
constructor() {
|
|
27804
|
+
let opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
27805
|
+
super();
|
|
27806
|
+
this.userTimestamp = opts.userTimestamp;
|
|
27807
|
+
this.e2ee = opts.e2ee;
|
|
27808
|
+
}
|
|
27809
|
+
toBinaryLengthBytes() {
|
|
27810
|
+
let lengthBytes = 0;
|
|
27811
|
+
if (this.userTimestamp) {
|
|
27812
|
+
lengthBytes += this.userTimestamp.toBinaryLengthBytes();
|
|
27813
|
+
}
|
|
27814
|
+
if (this.e2ee) {
|
|
27815
|
+
lengthBytes += this.e2ee.toBinaryLengthBytes();
|
|
28053
27816
|
}
|
|
27817
|
+
return lengthBytes;
|
|
28054
27818
|
}
|
|
28055
|
-
|
|
28056
|
-
|
|
28057
|
-
|
|
28058
|
-
|
|
27819
|
+
toBinaryInto(dataView) {
|
|
27820
|
+
let byteIndex = 0;
|
|
27821
|
+
if (this.e2ee) {
|
|
27822
|
+
const e2eeBytes = this.e2ee.toBinaryInto(dataView);
|
|
27823
|
+
byteIndex += e2eeBytes;
|
|
27824
|
+
}
|
|
27825
|
+
if (this.userTimestamp) {
|
|
27826
|
+
const userTimestampBytes = this.userTimestamp.toBinaryInto(new DataView(dataView.buffer, dataView.byteOffset + byteIndex));
|
|
27827
|
+
byteIndex += userTimestampBytes;
|
|
27828
|
+
}
|
|
27829
|
+
const totalLengthBytes = this.toBinaryLengthBytes();
|
|
27830
|
+
if (byteIndex !== totalLengthBytes) {
|
|
27831
|
+
// @throws-transformer ignore - this should be treated as a "panic" and not be caught
|
|
27832
|
+
throw new Error("DataTrackExtensions.toBinaryInto: Wrote ".concat(byteIndex, " bytes but expected length was ").concat(totalLengthBytes, " bytes"));
|
|
27833
|
+
}
|
|
27834
|
+
return byteIndex;
|
|
28059
27835
|
}
|
|
28060
|
-
|
|
28061
|
-
|
|
28062
|
-
|
|
28063
|
-
|
|
28064
|
-
|
|
27836
|
+
static fromBinary(input) {
|
|
27837
|
+
const dataView = coerceToDataView(input);
|
|
27838
|
+
let userTimestamp;
|
|
27839
|
+
let e2ee;
|
|
27840
|
+
let byteIndex = 0;
|
|
27841
|
+
while (dataView.byteLength - byteIndex >= U16_LENGTH_BYTES + U16_LENGTH_BYTES) {
|
|
27842
|
+
const tag = dataView.getUint16(byteIndex);
|
|
27843
|
+
byteIndex += U16_LENGTH_BYTES;
|
|
27844
|
+
const rtpOrientedLength = dataView.getUint16(byteIndex);
|
|
27845
|
+
const lengthBytes = rtpOrientedLength + 1;
|
|
27846
|
+
byteIndex += U16_LENGTH_BYTES;
|
|
27847
|
+
if (tag === EXT_TAG_PADDING) {
|
|
27848
|
+
// Skip padding
|
|
27849
|
+
continue;
|
|
28065
27850
|
}
|
|
28066
|
-
|
|
28067
|
-
|
|
28068
|
-
|
|
28069
|
-
|
|
28070
|
-
autoSubscribe: true,
|
|
28071
|
-
maxRetries: 0,
|
|
28072
|
-
e2eeEnabled: false,
|
|
28073
|
-
websocketTimeout: 15000
|
|
28074
|
-
}, undefined, true);
|
|
28075
|
-
} catch (e) {
|
|
28076
|
-
if (isCloud(new URL(this.url))) {
|
|
28077
|
-
this.appendMessage("Initial connection failed with error ".concat(e.message, ". Retrying with region fallback"));
|
|
28078
|
-
const regionProvider = new RegionUrlProvider(this.url, this.token);
|
|
28079
|
-
const regionUrl = yield regionProvider.getNextBestRegionUrl();
|
|
28080
|
-
if (regionUrl) {
|
|
28081
|
-
joinRes = yield signalClient.join(regionUrl, this.token, {
|
|
28082
|
-
autoSubscribe: true,
|
|
28083
|
-
maxRetries: 0,
|
|
28084
|
-
e2eeEnabled: false,
|
|
28085
|
-
websocketTimeout: 15000
|
|
28086
|
-
}, undefined, true);
|
|
28087
|
-
this.appendMessage("Fallback to region worked. To avoid initial connections failing, ensure you're calling room.prepareConnection() ahead of time");
|
|
27851
|
+
switch (tag) {
|
|
27852
|
+
case DataTrackExtensionTag.UserTimestamp:
|
|
27853
|
+
if (dataView.byteLength - byteIndex < DataTrackUserTimestampExtension.lengthBytes) {
|
|
27854
|
+
throw DataTrackDeserializeError.malformedExt(tag);
|
|
28088
27855
|
}
|
|
28089
|
-
|
|
28090
|
-
|
|
28091
|
-
|
|
28092
|
-
|
|
28093
|
-
|
|
28094
|
-
|
|
28095
|
-
|
|
28096
|
-
|
|
28097
|
-
|
|
27856
|
+
userTimestamp = new DataTrackUserTimestampExtension(dataView.getBigUint64(byteIndex));
|
|
27857
|
+
byteIndex += lengthBytes;
|
|
27858
|
+
break;
|
|
27859
|
+
case DataTrackExtensionTag.E2ee:
|
|
27860
|
+
if (dataView.byteLength - byteIndex < DataTrackE2eeExtension.lengthBytes) {
|
|
27861
|
+
throw DataTrackDeserializeError.malformedExt(tag);
|
|
27862
|
+
}
|
|
27863
|
+
const keyIndex = dataView.getUint8(byteIndex);
|
|
27864
|
+
const iv = new Uint8Array(12);
|
|
27865
|
+
for (let i = 0; i < iv.length; i += 1) {
|
|
27866
|
+
let byteIndexForIv = byteIndex;
|
|
27867
|
+
byteIndexForIv += U8_LENGTH_BYTES; // key index
|
|
27868
|
+
byteIndexForIv += i * U8_LENGTH_BYTES; // Index into iv array
|
|
27869
|
+
iv[i] = dataView.getUint8(byteIndexForIv);
|
|
27870
|
+
}
|
|
27871
|
+
e2ee = new DataTrackE2eeExtension(keyIndex, iv);
|
|
27872
|
+
byteIndex += lengthBytes;
|
|
27873
|
+
break;
|
|
27874
|
+
default:
|
|
27875
|
+
// Skip over unknown extensions (forward compatible).
|
|
27876
|
+
if (dataView.byteLength - byteIndex < lengthBytes) {
|
|
27877
|
+
throw DataTrackDeserializeError.malformedExt(tag);
|
|
27878
|
+
}
|
|
27879
|
+
byteIndex += lengthBytes;
|
|
27880
|
+
break;
|
|
28098
27881
|
}
|
|
28099
|
-
|
|
28100
|
-
|
|
28101
|
-
|
|
28102
|
-
|
|
28103
|
-
|
|
28104
|
-
|
|
28105
|
-
super();
|
|
28106
|
-
this.options = {};
|
|
28107
|
-
this.checkResults = new Map();
|
|
28108
|
-
this.url = url;
|
|
28109
|
-
this.token = token;
|
|
28110
|
-
this.options = options;
|
|
28111
|
-
}
|
|
28112
|
-
getNextCheckId() {
|
|
28113
|
-
const nextId = this.checkResults.size;
|
|
28114
|
-
this.checkResults.set(nextId, {
|
|
28115
|
-
logs: [],
|
|
28116
|
-
status: CheckStatus.IDLE,
|
|
28117
|
-
name: '',
|
|
28118
|
-
description: ''
|
|
28119
|
-
});
|
|
28120
|
-
return nextId;
|
|
28121
|
-
}
|
|
28122
|
-
updateCheck(checkId, info) {
|
|
28123
|
-
this.checkResults.set(checkId, info);
|
|
28124
|
-
this.emit('checkUpdate', checkId, info);
|
|
27882
|
+
}
|
|
27883
|
+
// NOTE: padding bytes after extension data is intentionally not being processed
|
|
27884
|
+
return [new DataTrackExtensions({
|
|
27885
|
+
userTimestamp,
|
|
27886
|
+
e2ee
|
|
27887
|
+
}), dataView.byteLength];
|
|
28125
27888
|
}
|
|
28126
|
-
|
|
28127
|
-
|
|
27889
|
+
toJSON() {
|
|
27890
|
+
var _a, _b, _c, _d;
|
|
27891
|
+
return {
|
|
27892
|
+
userTimestamp: (_b = (_a = this.userTimestamp) === null || _a === void 0 ? void 0 : _a.toJSON()) !== null && _b !== void 0 ? _b : null,
|
|
27893
|
+
e2ee: (_d = (_c = this.e2ee) === null || _c === void 0 ? void 0 : _c.toJSON()) !== null && _d !== void 0 ? _d : null
|
|
27894
|
+
};
|
|
28128
27895
|
}
|
|
28129
|
-
|
|
28130
|
-
|
|
27896
|
+
}var DataTrackHandleErrorReason;
|
|
27897
|
+
(function (DataTrackHandleErrorReason) {
|
|
27898
|
+
DataTrackHandleErrorReason[DataTrackHandleErrorReason["Reserved"] = 0] = "Reserved";
|
|
27899
|
+
DataTrackHandleErrorReason[DataTrackHandleErrorReason["TooLarge"] = 1] = "TooLarge";
|
|
27900
|
+
})(DataTrackHandleErrorReason || (DataTrackHandleErrorReason = {}));
|
|
27901
|
+
class DataTrackHandleError extends LivekitReasonedError {
|
|
27902
|
+
constructor(message, reason) {
|
|
27903
|
+
super(19, message);
|
|
27904
|
+
this.name = 'DataTrackHandleError';
|
|
27905
|
+
this.reason = reason;
|
|
27906
|
+
this.reasonName = DataTrackHandleErrorReason[reason];
|
|
28131
27907
|
}
|
|
28132
|
-
|
|
28133
|
-
return
|
|
28134
|
-
const checkId = this.getNextCheckId();
|
|
28135
|
-
const test = new check(this.url, this.token, this.options);
|
|
28136
|
-
const handleUpdate = info => {
|
|
28137
|
-
this.updateCheck(checkId, info);
|
|
28138
|
-
};
|
|
28139
|
-
test.on('update', handleUpdate);
|
|
28140
|
-
const result = yield test.run();
|
|
28141
|
-
test.off('update', handleUpdate);
|
|
28142
|
-
return result;
|
|
28143
|
-
});
|
|
27908
|
+
isReason(reason) {
|
|
27909
|
+
return this.reason === reason;
|
|
28144
27910
|
}
|
|
28145
|
-
|
|
28146
|
-
return
|
|
28147
|
-
return this.createAndRunCheck(WebSocketCheck);
|
|
28148
|
-
});
|
|
27911
|
+
static tooLarge() {
|
|
27912
|
+
return new DataTrackHandleError('Value too large to be a valid track handle', DataTrackHandleErrorReason.TooLarge);
|
|
28149
27913
|
}
|
|
28150
|
-
|
|
28151
|
-
return
|
|
28152
|
-
return this.createAndRunCheck(WebRTCCheck);
|
|
28153
|
-
});
|
|
27914
|
+
static reserved(value) {
|
|
27915
|
+
return new DataTrackHandleError("0x".concat(value.toString(16), " is a reserved value."), DataTrackHandleErrorReason.Reserved);
|
|
28154
27916
|
}
|
|
28155
|
-
|
|
28156
|
-
|
|
28157
|
-
|
|
28158
|
-
|
|
27917
|
+
}
|
|
27918
|
+
const DataTrackHandle = {
|
|
27919
|
+
fromNumber(raw) {
|
|
27920
|
+
if (raw === 0) {
|
|
27921
|
+
throw DataTrackHandleError.reserved(raw);
|
|
27922
|
+
}
|
|
27923
|
+
if (raw > U16_MAX_SIZE) {
|
|
27924
|
+
throw DataTrackHandleError.tooLarge();
|
|
27925
|
+
}
|
|
27926
|
+
return raw;
|
|
28159
27927
|
}
|
|
28160
|
-
|
|
28161
|
-
|
|
28162
|
-
|
|
28163
|
-
|
|
27928
|
+
};/** A class for serializing / deserializing data track packet header sections. */
|
|
27929
|
+
class DataTrackPacketHeader extends Serializable {
|
|
27930
|
+
constructor(opts) {
|
|
27931
|
+
var _a;
|
|
27932
|
+
super();
|
|
27933
|
+
this.marker = opts.marker;
|
|
27934
|
+
this.trackHandle = opts.trackHandle;
|
|
27935
|
+
this.sequence = opts.sequence;
|
|
27936
|
+
this.frameNumber = opts.frameNumber;
|
|
27937
|
+
this.timestamp = opts.timestamp;
|
|
27938
|
+
this.extensions = (_a = opts.extensions) !== null && _a !== void 0 ? _a : new DataTrackExtensions();
|
|
28164
27939
|
}
|
|
28165
|
-
|
|
28166
|
-
|
|
28167
|
-
|
|
28168
|
-
|
|
27940
|
+
extensionsMetrics() {
|
|
27941
|
+
const lengthBytes = this.extensions.toBinaryLengthBytes();
|
|
27942
|
+
const lengthWords = Math.ceil(lengthBytes / 4);
|
|
27943
|
+
const paddingLengthBytes = lengthWords * 4 - lengthBytes;
|
|
27944
|
+
return {
|
|
27945
|
+
lengthBytes,
|
|
27946
|
+
lengthWords,
|
|
27947
|
+
paddingLengthBytes
|
|
27948
|
+
};
|
|
28169
27949
|
}
|
|
28170
|
-
|
|
28171
|
-
|
|
28172
|
-
|
|
28173
|
-
|
|
27950
|
+
toBinaryLengthBytes() {
|
|
27951
|
+
const {
|
|
27952
|
+
lengthBytes: extLengthBytes,
|
|
27953
|
+
paddingLengthBytes: extPaddingLengthBytes
|
|
27954
|
+
} = this.extensionsMetrics();
|
|
27955
|
+
let totalLengthBytes = BASE_HEADER_LEN;
|
|
27956
|
+
if (extLengthBytes > 0) {
|
|
27957
|
+
totalLengthBytes += EXT_WORDS_INDICATOR_SIZE + extLengthBytes + extPaddingLengthBytes;
|
|
27958
|
+
}
|
|
27959
|
+
return totalLengthBytes;
|
|
28174
27960
|
}
|
|
28175
|
-
|
|
28176
|
-
|
|
28177
|
-
|
|
28178
|
-
|
|
28179
|
-
|
|
28180
|
-
|
|
27961
|
+
toBinaryInto(dataView) {
|
|
27962
|
+
if (dataView.byteLength < this.toBinaryLengthBytes()) {
|
|
27963
|
+
throw DataTrackSerializeError.tooSmallForHeader();
|
|
27964
|
+
}
|
|
27965
|
+
let initial = SUPPORTED_VERSION << VERSION_SHIFT;
|
|
27966
|
+
let marker;
|
|
27967
|
+
switch (this.marker) {
|
|
27968
|
+
case FrameMarker.Inter:
|
|
27969
|
+
marker = FRAME_MARKER_INTER;
|
|
27970
|
+
break;
|
|
27971
|
+
case FrameMarker.Final:
|
|
27972
|
+
marker = FRAME_MARKER_FINAL;
|
|
27973
|
+
break;
|
|
27974
|
+
case FrameMarker.Start:
|
|
27975
|
+
marker = FRAME_MARKER_START;
|
|
27976
|
+
break;
|
|
27977
|
+
case FrameMarker.Single:
|
|
27978
|
+
marker = FRAME_MARKER_SINGLE;
|
|
27979
|
+
break;
|
|
27980
|
+
}
|
|
27981
|
+
initial |= marker << FRAME_MARKER_SHIFT;
|
|
27982
|
+
const {
|
|
27983
|
+
lengthBytes: extensionsLengthBytes,
|
|
27984
|
+
lengthWords: extensionsLengthWords,
|
|
27985
|
+
paddingLengthBytes: extensionsPaddingLengthBytes
|
|
27986
|
+
} = this.extensionsMetrics();
|
|
27987
|
+
if (extensionsLengthBytes > 0) {
|
|
27988
|
+
initial |= 1 << EXT_FLAG_SHIFT;
|
|
27989
|
+
}
|
|
27990
|
+
let byteIndex = 0;
|
|
27991
|
+
dataView.setUint8(byteIndex, initial);
|
|
27992
|
+
byteIndex += U8_LENGTH_BYTES;
|
|
27993
|
+
dataView.setUint8(byteIndex, 0); // Reserved
|
|
27994
|
+
byteIndex += U8_LENGTH_BYTES;
|
|
27995
|
+
dataView.setUint16(byteIndex, this.trackHandle);
|
|
27996
|
+
byteIndex += U16_LENGTH_BYTES;
|
|
27997
|
+
dataView.setUint16(byteIndex, this.sequence.value);
|
|
27998
|
+
byteIndex += U16_LENGTH_BYTES;
|
|
27999
|
+
dataView.setUint16(byteIndex, this.frameNumber.value);
|
|
28000
|
+
byteIndex += U16_LENGTH_BYTES;
|
|
28001
|
+
dataView.setUint32(byteIndex, this.timestamp.asTicks());
|
|
28002
|
+
byteIndex += U32_LENGTH_BYTES;
|
|
28003
|
+
if (extensionsLengthBytes > 0) {
|
|
28004
|
+
// NOTE: The protocol is implemented in a way where if the extension bit is set, any
|
|
28005
|
+
// deserializer assumes the extensions section is at least one byte long, and the "length"
|
|
28006
|
+
// field represents the "number of additional bytes" long the extensions section is. This is
|
|
28007
|
+
// potentially unintuitive so I wanted to call it out.
|
|
28008
|
+
const rtpOrientedExtensionLengthWords = extensionsLengthWords - 1;
|
|
28009
|
+
dataView.setUint16(byteIndex, rtpOrientedExtensionLengthWords);
|
|
28010
|
+
byteIndex += U16_LENGTH_BYTES;
|
|
28011
|
+
const extensionBytes = this.extensions.toBinaryInto(new DataView(dataView.buffer, dataView.byteOffset + byteIndex));
|
|
28012
|
+
byteIndex += extensionBytes;
|
|
28013
|
+
for (let i = 0; i < extensionsPaddingLengthBytes; i += 1) {
|
|
28014
|
+
dataView.setUint8(byteIndex, 0);
|
|
28015
|
+
byteIndex += U8_LENGTH_BYTES;
|
|
28181
28016
|
}
|
|
28182
|
-
|
|
28183
|
-
|
|
28184
|
-
|
|
28185
|
-
|
|
28186
|
-
|
|
28187
|
-
|
|
28188
|
-
|
|
28017
|
+
}
|
|
28018
|
+
const totalLengthBytes = this.toBinaryLengthBytes();
|
|
28019
|
+
if (byteIndex !== totalLengthBytes) {
|
|
28020
|
+
// @throws-transformer ignore - this should be treated as a "panic" and not be caught
|
|
28021
|
+
throw new Error("DataTrackPacketHeader.toBinaryInto: Wrote ".concat(byteIndex, " bytes but expected length was ").concat(totalLengthBytes, " bytes"));
|
|
28022
|
+
}
|
|
28023
|
+
return totalLengthBytes;
|
|
28189
28024
|
}
|
|
28190
|
-
|
|
28191
|
-
|
|
28192
|
-
|
|
28193
|
-
|
|
28194
|
-
|
|
28195
|
-
|
|
28196
|
-
|
|
28197
|
-
|
|
28198
|
-
|
|
28199
|
-
|
|
28200
|
-
|
|
28201
|
-
|
|
28202
|
-
|
|
28203
|
-
|
|
28204
|
-
|
|
28205
|
-
|
|
28206
|
-
|
|
28207
|
-
|
|
28208
|
-
|
|
28209
|
-
|
|
28210
|
-
|
|
28211
|
-
|
|
28212
|
-
|
|
28213
|
-
|
|
28214
|
-
|
|
28215
|
-
|
|
28216
|
-
|
|
28217
|
-
|
|
28218
|
-
|
|
28219
|
-
|
|
28220
|
-
|
|
28221
|
-
|
|
28025
|
+
static fromBinary(input) {
|
|
28026
|
+
const dataView = coerceToDataView(input);
|
|
28027
|
+
if (dataView.byteLength < BASE_HEADER_LEN) {
|
|
28028
|
+
throw DataTrackDeserializeError.tooShort();
|
|
28029
|
+
}
|
|
28030
|
+
let byteIndex = 0;
|
|
28031
|
+
const initial = dataView.getUint8(byteIndex);
|
|
28032
|
+
byteIndex += U8_LENGTH_BYTES;
|
|
28033
|
+
const version = initial >> VERSION_SHIFT & VERSION_MASK;
|
|
28034
|
+
if (version > SUPPORTED_VERSION) {
|
|
28035
|
+
throw DataTrackDeserializeError.unsupportedVersion(version);
|
|
28036
|
+
}
|
|
28037
|
+
let marker;
|
|
28038
|
+
switch (initial >> FRAME_MARKER_SHIFT & FRAME_MARKER_MASK) {
|
|
28039
|
+
case FRAME_MARKER_START:
|
|
28040
|
+
marker = FrameMarker.Start;
|
|
28041
|
+
break;
|
|
28042
|
+
case FRAME_MARKER_FINAL:
|
|
28043
|
+
marker = FrameMarker.Final;
|
|
28044
|
+
break;
|
|
28045
|
+
case FRAME_MARKER_SINGLE:
|
|
28046
|
+
marker = FrameMarker.Single;
|
|
28047
|
+
break;
|
|
28048
|
+
case FRAME_MARKER_INTER:
|
|
28049
|
+
default:
|
|
28050
|
+
marker = FrameMarker.Inter;
|
|
28051
|
+
break;
|
|
28052
|
+
}
|
|
28053
|
+
const extensionsFlag = (initial >> EXT_FLAG_SHIFT & EXT_FLAG_MASK) > 0;
|
|
28054
|
+
byteIndex += U8_LENGTH_BYTES; // Reserved
|
|
28055
|
+
let trackHandle;
|
|
28056
|
+
try {
|
|
28057
|
+
trackHandle = DataTrackHandle.fromNumber(dataView.getUint16(byteIndex));
|
|
28058
|
+
} catch (e) {
|
|
28059
|
+
if (e instanceof DataTrackHandleError && (e.isReason(DataTrackHandleErrorReason.Reserved) || e.isReason(DataTrackHandleErrorReason.TooLarge))) {
|
|
28060
|
+
throw DataTrackDeserializeError.invalidHandle(e);
|
|
28061
|
+
} else {
|
|
28062
|
+
throw e;
|
|
28063
|
+
}
|
|
28064
|
+
}
|
|
28065
|
+
byteIndex += U16_LENGTH_BYTES;
|
|
28066
|
+
const sequence = WrapAroundUnsignedInt.u16(dataView.getUint16(byteIndex));
|
|
28067
|
+
byteIndex += U16_LENGTH_BYTES;
|
|
28068
|
+
const frameNumber = WrapAroundUnsignedInt.u16(dataView.getUint16(byteIndex));
|
|
28069
|
+
byteIndex += U16_LENGTH_BYTES;
|
|
28070
|
+
const timestamp = DataTrackTimestamp.fromRtpTicks(dataView.getUint32(byteIndex));
|
|
28071
|
+
byteIndex += U32_LENGTH_BYTES;
|
|
28072
|
+
let extensions = new DataTrackExtensions();
|
|
28073
|
+
if (extensionsFlag) {
|
|
28074
|
+
if (dataView.byteLength - byteIndex < U16_LENGTH_BYTES) {
|
|
28075
|
+
throw DataTrackDeserializeError.missingExtWords();
|
|
28076
|
+
}
|
|
28077
|
+
let rtpOrientedExtensionWords = dataView.getUint16(byteIndex);
|
|
28078
|
+
byteIndex += U16_LENGTH_BYTES;
|
|
28079
|
+
// NOTE: The protocol is implemented in a way where if the extension bit is set, any
|
|
28080
|
+
// deserializer assumes the extensions section is at least one byte long, and the "length"
|
|
28081
|
+
// field represents the "number of additional bytes" long the extensions section is. This is
|
|
28082
|
+
// potentially unintuitive so I wanted to call it out.
|
|
28083
|
+
const extensionWords = rtpOrientedExtensionWords + 1;
|
|
28084
|
+
let extensionLengthBytes = 4 * extensionWords;
|
|
28085
|
+
if (byteIndex + extensionLengthBytes > dataView.byteLength) {
|
|
28086
|
+
throw DataTrackDeserializeError.headerOverrun();
|
|
28087
|
+
}
|
|
28088
|
+
let extensionDataView = new DataView(dataView.buffer, dataView.byteOffset + byteIndex, extensionLengthBytes);
|
|
28089
|
+
const [result, readBytes] = DataTrackExtensions.fromBinary(extensionDataView);
|
|
28090
|
+
extensions = result;
|
|
28091
|
+
byteIndex += readBytes;
|
|
28092
|
+
}
|
|
28093
|
+
return [new DataTrackPacketHeader({
|
|
28094
|
+
marker,
|
|
28095
|
+
trackHandle: trackHandle,
|
|
28096
|
+
sequence,
|
|
28097
|
+
frameNumber,
|
|
28098
|
+
timestamp,
|
|
28099
|
+
extensions
|
|
28100
|
+
}), byteIndex];
|
|
28101
|
+
}
|
|
28102
|
+
toJSON() {
|
|
28103
|
+
return {
|
|
28104
|
+
marker: this.marker,
|
|
28105
|
+
trackHandle: this.trackHandle,
|
|
28106
|
+
sequence: this.sequence.value,
|
|
28107
|
+
frameNumber: this.frameNumber.value,
|
|
28108
|
+
timestamp: this.timestamp.asTicks(),
|
|
28109
|
+
extensions: this.extensions.toJSON()
|
|
28110
|
+
};
|
|
28222
28111
|
}
|
|
28223
|
-
return ("string" === r ? String : Number)(t);
|
|
28224
28112
|
}
|
|
28225
|
-
|
|
28226
|
-
|
|
28227
|
-
|
|
28228
|
-
|
|
28229
|
-
|
|
28230
|
-
|
|
28231
|
-
|
|
28113
|
+
/** Marker indicating a packet's position in relation to a frame. */
|
|
28114
|
+
var FrameMarker;
|
|
28115
|
+
(function (FrameMarker) {
|
|
28116
|
+
/** Packet is the first in a frame. */
|
|
28117
|
+
FrameMarker[FrameMarker["Start"] = 0] = "Start";
|
|
28118
|
+
/** Packet is within a frame. */
|
|
28119
|
+
FrameMarker[FrameMarker["Inter"] = 1] = "Inter";
|
|
28120
|
+
/** Packet is the last in a frame. */
|
|
28121
|
+
FrameMarker[FrameMarker["Final"] = 2] = "Final";
|
|
28122
|
+
/** Packet is the only one in a frame. */
|
|
28123
|
+
FrameMarker[FrameMarker["Single"] = 3] = "Single";
|
|
28124
|
+
})(FrameMarker || (FrameMarker = {}));
|
|
28125
|
+
/** A class for serializing / deserializing data track packets. */
|
|
28126
|
+
class DataTrackPacket extends Serializable {
|
|
28127
|
+
constructor(header, payload) {
|
|
28128
|
+
super();
|
|
28129
|
+
this.header = header;
|
|
28130
|
+
this.payload = payload;
|
|
28232
28131
|
}
|
|
28233
|
-
|
|
28234
|
-
|
|
28235
|
-
for (let i = 0; i < binary.length; i++) {
|
|
28236
|
-
bytes[i] = binary.charCodeAt(i);
|
|
28132
|
+
toBinaryLengthBytes() {
|
|
28133
|
+
return this.header.toBinaryLengthBytes() + this.payload.byteLength;
|
|
28237
28134
|
}
|
|
28238
|
-
|
|
28239
|
-
|
|
28240
|
-
|
|
28241
|
-
|
|
28242
|
-
|
|
28243
|
-
|
|
28135
|
+
toBinaryInto(dataView) {
|
|
28136
|
+
let byteIndex = 0;
|
|
28137
|
+
const headerLengthBytes = this.header.toBinaryInto(dataView);
|
|
28138
|
+
byteIndex += headerLengthBytes;
|
|
28139
|
+
if (dataView.byteLength - byteIndex < this.payload.byteLength) {
|
|
28140
|
+
throw DataTrackSerializeError.tooSmallForPayload();
|
|
28141
|
+
}
|
|
28142
|
+
for (let index = 0; index < this.payload.length; index += 1) {
|
|
28143
|
+
dataView.setUint8(byteIndex, this.payload[index]);
|
|
28144
|
+
byteIndex += U8_LENGTH_BYTES;
|
|
28145
|
+
}
|
|
28146
|
+
const totalLengthBytes = this.toBinaryLengthBytes();
|
|
28147
|
+
if (byteIndex !== totalLengthBytes) {
|
|
28148
|
+
// @throws-transformer ignore - this should be treated as a "panic" and not be caught
|
|
28149
|
+
throw new Error("DataTrackPacket.toBinaryInto: Wrote ".concat(byteIndex, " bytes but expected length was ").concat(totalLengthBytes, " bytes"));
|
|
28150
|
+
}
|
|
28151
|
+
return totalLengthBytes;
|
|
28244
28152
|
}
|
|
28245
|
-
|
|
28246
|
-
|
|
28247
|
-
|
|
28153
|
+
static fromBinary(input) {
|
|
28154
|
+
const dataView = coerceToDataView(input);
|
|
28155
|
+
const [header, headerByteLength] = DataTrackPacketHeader.fromBinary(dataView);
|
|
28156
|
+
const payload = dataView.buffer.slice(dataView.byteOffset + headerByteLength, dataView.byteOffset + dataView.byteLength);
|
|
28157
|
+
return [new DataTrackPacket(header, new Uint8Array(payload)), dataView.byteLength];
|
|
28248
28158
|
}
|
|
28249
|
-
|
|
28250
|
-
|
|
28251
|
-
|
|
28252
|
-
|
|
28253
|
-
|
|
28159
|
+
toJSON() {
|
|
28160
|
+
return {
|
|
28161
|
+
header: this.header.toJSON(),
|
|
28162
|
+
payload: this.payload
|
|
28163
|
+
};
|
|
28254
28164
|
}
|
|
28255
|
-
}
|
|
28256
|
-
|
|
28257
|
-
|
|
28258
|
-
|
|
28259
|
-
|
|
28165
|
+
}var DataTrackPacketizerReason;
|
|
28166
|
+
(function (DataTrackPacketizerReason) {
|
|
28167
|
+
DataTrackPacketizerReason[DataTrackPacketizerReason["MtuTooShort"] = 0] = "MtuTooShort";
|
|
28168
|
+
})(DataTrackPacketizerReason || (DataTrackPacketizerReason = {}));getLogger(LoggerNames.DataTracks);
|
|
28169
|
+
/** Reason why a frame was dropped. */
|
|
28170
|
+
var DataTrackDepacketizerDropReason;
|
|
28171
|
+
(function (DataTrackDepacketizerDropReason) {
|
|
28172
|
+
DataTrackDepacketizerDropReason[DataTrackDepacketizerDropReason["Interrupted"] = 0] = "Interrupted";
|
|
28173
|
+
DataTrackDepacketizerDropReason[DataTrackDepacketizerDropReason["UnknownFrame"] = 1] = "UnknownFrame";
|
|
28174
|
+
DataTrackDepacketizerDropReason[DataTrackDepacketizerDropReason["BufferFull"] = 2] = "BufferFull";
|
|
28175
|
+
DataTrackDepacketizerDropReason[DataTrackDepacketizerDropReason["Incomplete"] = 3] = "Incomplete";
|
|
28176
|
+
})(DataTrackDepacketizerDropReason || (DataTrackDepacketizerDropReason = {}));var DataTrackPublishErrorReason;
|
|
28177
|
+
(function (DataTrackPublishErrorReason) {
|
|
28178
|
+
/**
|
|
28179
|
+
* Local participant does not have permission to publish data tracks.
|
|
28180
|
+
*
|
|
28181
|
+
* Ensure the participant's token contains the `canPublishData` grant.
|
|
28182
|
+
*/
|
|
28183
|
+
DataTrackPublishErrorReason[DataTrackPublishErrorReason["NotAllowed"] = 0] = "NotAllowed";
|
|
28184
|
+
/** A track with the same name is already published by the local participant. */
|
|
28185
|
+
DataTrackPublishErrorReason[DataTrackPublishErrorReason["DuplicateName"] = 1] = "DuplicateName";
|
|
28186
|
+
/** Request to publish the track took long to complete. */
|
|
28187
|
+
DataTrackPublishErrorReason[DataTrackPublishErrorReason["Timeout"] = 2] = "Timeout";
|
|
28188
|
+
/** No additional data tracks can be published by the local participant. */
|
|
28189
|
+
DataTrackPublishErrorReason[DataTrackPublishErrorReason["LimitReached"] = 3] = "LimitReached";
|
|
28190
|
+
/** Cannot publish data track when the room is disconnected. */
|
|
28191
|
+
DataTrackPublishErrorReason[DataTrackPublishErrorReason["Disconnected"] = 4] = "Disconnected";
|
|
28192
|
+
// NOTE: this was introduced by web / there isn't a corresponding case in the rust version.
|
|
28193
|
+
DataTrackPublishErrorReason[DataTrackPublishErrorReason["Cancelled"] = 5] = "Cancelled";
|
|
28194
|
+
})(DataTrackPublishErrorReason || (DataTrackPublishErrorReason = {}));
|
|
28195
|
+
var DataTrackPushFrameErrorReason;
|
|
28196
|
+
(function (DataTrackPushFrameErrorReason) {
|
|
28197
|
+
/** Track is no longer published. */
|
|
28198
|
+
DataTrackPushFrameErrorReason[DataTrackPushFrameErrorReason["TrackUnpublished"] = 0] = "TrackUnpublished";
|
|
28199
|
+
/** Frame was dropped. */
|
|
28200
|
+
// NOTE: this should become a web specific error, the rust version of this "dropped" error means
|
|
28201
|
+
// something different and will be renamed to "QueueFull".
|
|
28202
|
+
DataTrackPushFrameErrorReason[DataTrackPushFrameErrorReason["Dropped"] = 1] = "Dropped";
|
|
28203
|
+
})(DataTrackPushFrameErrorReason || (DataTrackPushFrameErrorReason = {}));
|
|
28204
|
+
var DataTrackOutgoingPipelineErrorReason;
|
|
28205
|
+
(function (DataTrackOutgoingPipelineErrorReason) {
|
|
28206
|
+
DataTrackOutgoingPipelineErrorReason[DataTrackOutgoingPipelineErrorReason["Packetizer"] = 0] = "Packetizer";
|
|
28207
|
+
DataTrackOutgoingPipelineErrorReason[DataTrackOutgoingPipelineErrorReason["Encryption"] = 1] = "Encryption";
|
|
28208
|
+
})(DataTrackOutgoingPipelineErrorReason || (DataTrackOutgoingPipelineErrorReason = {}));getLogger(LoggerNames.DataTracks);var CheckStatus;
|
|
28209
|
+
(function (CheckStatus) {
|
|
28210
|
+
CheckStatus[CheckStatus["IDLE"] = 0] = "IDLE";
|
|
28211
|
+
CheckStatus[CheckStatus["RUNNING"] = 1] = "RUNNING";
|
|
28212
|
+
CheckStatus[CheckStatus["SKIPPED"] = 2] = "SKIPPED";
|
|
28213
|
+
CheckStatus[CheckStatus["SUCCESS"] = 3] = "SUCCESS";
|
|
28214
|
+
CheckStatus[CheckStatus["FAILED"] = 4] = "FAILED";
|
|
28215
|
+
})(CheckStatus || (CheckStatus = {}));
|
|
28216
|
+
class Checker extends eventsExports.EventEmitter {
|
|
28217
|
+
constructor(url, token) {
|
|
28218
|
+
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
28219
|
+
super();
|
|
28220
|
+
this.status = CheckStatus.IDLE;
|
|
28221
|
+
this.logs = [];
|
|
28222
|
+
this.options = {};
|
|
28223
|
+
this.url = url;
|
|
28224
|
+
this.token = token;
|
|
28260
28225
|
this.name = this.constructor.name;
|
|
28261
|
-
|
|
28226
|
+
this.room = new Room(options.roomOptions);
|
|
28227
|
+
this.connectOptions = options.connectOptions;
|
|
28228
|
+
this.options = options;
|
|
28262
28229
|
}
|
|
28263
|
-
|
|
28264
|
-
|
|
28265
|
-
|
|
28266
|
-
|
|
28267
|
-
let claim = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'unspecified';
|
|
28268
|
-
let reason = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'unspecified';
|
|
28269
|
-
super(message, {
|
|
28270
|
-
cause: {
|
|
28271
|
-
claim,
|
|
28272
|
-
reason,
|
|
28273
|
-
payload
|
|
28230
|
+
run(onComplete) {
|
|
28231
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28232
|
+
if (this.status !== CheckStatus.IDLE) {
|
|
28233
|
+
throw Error('check is running already');
|
|
28274
28234
|
}
|
|
28275
|
-
|
|
28276
|
-
|
|
28277
|
-
|
|
28278
|
-
|
|
28279
|
-
|
|
28280
|
-
|
|
28281
|
-
|
|
28282
|
-
|
|
28283
|
-
|
|
28284
|
-
}
|
|
28285
|
-
|
|
28286
|
-
|
|
28287
|
-
|
|
28288
|
-
|
|
28289
|
-
|
|
28290
|
-
|
|
28291
|
-
|
|
28292
|
-
|
|
28293
|
-
|
|
28294
|
-
|
|
28235
|
+
this.setStatus(CheckStatus.RUNNING);
|
|
28236
|
+
try {
|
|
28237
|
+
yield this.perform();
|
|
28238
|
+
} catch (err) {
|
|
28239
|
+
if (err instanceof Error) {
|
|
28240
|
+
if (this.options.errorsAsWarnings) {
|
|
28241
|
+
this.appendWarning(err.message);
|
|
28242
|
+
} else {
|
|
28243
|
+
this.appendError(err.message);
|
|
28244
|
+
}
|
|
28245
|
+
}
|
|
28246
|
+
}
|
|
28247
|
+
yield this.disconnect();
|
|
28248
|
+
// sleep for a bit to ensure disconnect
|
|
28249
|
+
yield new Promise(resolve => setTimeout(resolve, 500));
|
|
28250
|
+
// @ts-ignore
|
|
28251
|
+
if (this.status !== CheckStatus.SKIPPED) {
|
|
28252
|
+
this.setStatus(this.isSuccess() ? CheckStatus.SUCCESS : CheckStatus.FAILED);
|
|
28253
|
+
}
|
|
28254
|
+
if (onComplete) {
|
|
28255
|
+
onComplete();
|
|
28295
28256
|
}
|
|
28257
|
+
return this.getInfo();
|
|
28296
28258
|
});
|
|
28297
|
-
_defineProperty(this, "code", 'ERR_JWT_EXPIRED');
|
|
28298
|
-
_defineProperty(this, "claim", void 0);
|
|
28299
|
-
_defineProperty(this, "reason", void 0);
|
|
28300
|
-
_defineProperty(this, "payload", void 0);
|
|
28301
|
-
this.claim = claim;
|
|
28302
|
-
this.reason = reason;
|
|
28303
|
-
this.payload = payload;
|
|
28304
|
-
}
|
|
28305
|
-
}
|
|
28306
|
-
_defineProperty(JWTExpired, "code", 'ERR_JWT_EXPIRED');
|
|
28307
|
-
class JOSEAlgNotAllowed extends JOSEError {
|
|
28308
|
-
constructor() {
|
|
28309
|
-
super(...arguments);
|
|
28310
|
-
_defineProperty(this, "code", 'ERR_JOSE_ALG_NOT_ALLOWED');
|
|
28311
28259
|
}
|
|
28312
|
-
|
|
28313
|
-
|
|
28314
|
-
class JOSENotSupported extends JOSEError {
|
|
28315
|
-
constructor() {
|
|
28316
|
-
super(...arguments);
|
|
28317
|
-
_defineProperty(this, "code", 'ERR_JOSE_NOT_SUPPORTED');
|
|
28318
|
-
}
|
|
28319
|
-
}
|
|
28320
|
-
_defineProperty(JOSENotSupported, "code", 'ERR_JOSE_NOT_SUPPORTED');
|
|
28321
|
-
class JWEDecryptionFailed extends JOSEError {
|
|
28322
|
-
constructor() {
|
|
28323
|
-
let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'decryption operation failed';
|
|
28324
|
-
let options = arguments.length > 1 ? arguments[1] : undefined;
|
|
28325
|
-
super(message, options);
|
|
28326
|
-
_defineProperty(this, "code", 'ERR_JWE_DECRYPTION_FAILED');
|
|
28260
|
+
isSuccess() {
|
|
28261
|
+
return !this.logs.some(l => l.level === 'error');
|
|
28327
28262
|
}
|
|
28328
|
-
|
|
28329
|
-
|
|
28330
|
-
|
|
28331
|
-
|
|
28332
|
-
|
|
28333
|
-
|
|
28263
|
+
connect(url) {
|
|
28264
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28265
|
+
if (this.room.state === ConnectionState.Connected) {
|
|
28266
|
+
return this.room;
|
|
28267
|
+
}
|
|
28268
|
+
if (!url) {
|
|
28269
|
+
url = this.url;
|
|
28270
|
+
}
|
|
28271
|
+
yield this.room.connect(url, this.token, this.connectOptions);
|
|
28272
|
+
return this.room;
|
|
28273
|
+
});
|
|
28334
28274
|
}
|
|
28335
|
-
|
|
28336
|
-
|
|
28337
|
-
|
|
28338
|
-
|
|
28339
|
-
|
|
28340
|
-
|
|
28275
|
+
disconnect() {
|
|
28276
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28277
|
+
if (this.room && this.room.state !== ConnectionState.Disconnected) {
|
|
28278
|
+
yield this.room.disconnect();
|
|
28279
|
+
// wait for it to go through
|
|
28280
|
+
yield new Promise(resolve => setTimeout(resolve, 500));
|
|
28281
|
+
}
|
|
28282
|
+
});
|
|
28341
28283
|
}
|
|
28342
|
-
|
|
28343
|
-
|
|
28344
|
-
class JWTInvalid extends JOSEError {
|
|
28345
|
-
constructor() {
|
|
28346
|
-
super(...arguments);
|
|
28347
|
-
_defineProperty(this, "code", 'ERR_JWT_INVALID');
|
|
28284
|
+
skip() {
|
|
28285
|
+
this.setStatus(CheckStatus.SKIPPED);
|
|
28348
28286
|
}
|
|
28349
|
-
|
|
28350
|
-
|
|
28351
|
-
|
|
28352
|
-
|
|
28353
|
-
|
|
28354
|
-
|
|
28287
|
+
switchProtocol(protocol) {
|
|
28288
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28289
|
+
let hasReconnecting = false;
|
|
28290
|
+
let hasReconnected = false;
|
|
28291
|
+
this.room.on(RoomEvent.Reconnecting, () => {
|
|
28292
|
+
hasReconnecting = true;
|
|
28293
|
+
});
|
|
28294
|
+
this.room.once(RoomEvent.Reconnected, () => {
|
|
28295
|
+
hasReconnected = true;
|
|
28296
|
+
});
|
|
28297
|
+
this.room.simulateScenario("force-".concat(protocol));
|
|
28298
|
+
yield new Promise(resolve => setTimeout(resolve, 1000));
|
|
28299
|
+
if (!hasReconnecting) {
|
|
28300
|
+
// no need to wait for reconnection
|
|
28301
|
+
return;
|
|
28302
|
+
}
|
|
28303
|
+
// wait for 10 seconds for reconnection
|
|
28304
|
+
const timeout = Date.now() + 10000;
|
|
28305
|
+
while (Date.now() < timeout) {
|
|
28306
|
+
if (hasReconnected) {
|
|
28307
|
+
return;
|
|
28308
|
+
}
|
|
28309
|
+
yield sleep(100);
|
|
28310
|
+
}
|
|
28311
|
+
throw new Error("Could not reconnect using ".concat(protocol, " protocol after 10 seconds"));
|
|
28312
|
+
});
|
|
28355
28313
|
}
|
|
28356
|
-
|
|
28357
|
-
|
|
28358
|
-
|
|
28359
|
-
|
|
28360
|
-
|
|
28361
|
-
|
|
28314
|
+
appendMessage(message) {
|
|
28315
|
+
this.logs.push({
|
|
28316
|
+
level: 'info',
|
|
28317
|
+
message
|
|
28318
|
+
});
|
|
28319
|
+
this.emit('update', this.getInfo());
|
|
28362
28320
|
}
|
|
28363
|
-
|
|
28364
|
-
|
|
28365
|
-
|
|
28366
|
-
|
|
28367
|
-
|
|
28368
|
-
|
|
28369
|
-
super(message, options);
|
|
28370
|
-
_defineProperty(this, "code", 'ERR_JWKS_NO_MATCHING_KEY');
|
|
28321
|
+
appendWarning(message) {
|
|
28322
|
+
this.logs.push({
|
|
28323
|
+
level: 'warning',
|
|
28324
|
+
message
|
|
28325
|
+
});
|
|
28326
|
+
this.emit('update', this.getInfo());
|
|
28371
28327
|
}
|
|
28372
|
-
|
|
28373
|
-
|
|
28374
|
-
|
|
28375
|
-
|
|
28376
|
-
|
|
28377
|
-
|
|
28378
|
-
super(message, options);
|
|
28379
|
-
_defineProperty(this, Symbol.asyncIterator, void 0);
|
|
28380
|
-
_defineProperty(this, "code", 'ERR_JWKS_MULTIPLE_MATCHING_KEYS');
|
|
28328
|
+
appendError(message) {
|
|
28329
|
+
this.logs.push({
|
|
28330
|
+
level: 'error',
|
|
28331
|
+
message
|
|
28332
|
+
});
|
|
28333
|
+
this.emit('update', this.getInfo());
|
|
28381
28334
|
}
|
|
28382
|
-
|
|
28383
|
-
|
|
28384
|
-
|
|
28385
|
-
constructor() {
|
|
28386
|
-
let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'request timed out';
|
|
28387
|
-
let options = arguments.length > 1 ? arguments[1] : undefined;
|
|
28388
|
-
super(message, options);
|
|
28389
|
-
_defineProperty(this, "code", 'ERR_JWKS_TIMEOUT');
|
|
28335
|
+
setStatus(status) {
|
|
28336
|
+
this.status = status;
|
|
28337
|
+
this.emit('update', this.getInfo());
|
|
28390
28338
|
}
|
|
28391
|
-
|
|
28392
|
-
|
|
28393
|
-
|
|
28394
|
-
constructor() {
|
|
28395
|
-
let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'signature verification failed';
|
|
28396
|
-
let options = arguments.length > 1 ? arguments[1] : undefined;
|
|
28397
|
-
super(message, options);
|
|
28398
|
-
_defineProperty(this, "code", 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED');
|
|
28339
|
+
get engine() {
|
|
28340
|
+
var _a;
|
|
28341
|
+
return (_a = this.room) === null || _a === void 0 ? void 0 : _a.engine;
|
|
28399
28342
|
}
|
|
28400
|
-
|
|
28401
|
-
|
|
28402
|
-
|
|
28403
|
-
|
|
28404
|
-
|
|
28343
|
+
getInfo() {
|
|
28344
|
+
return {
|
|
28345
|
+
logs: this.logs,
|
|
28346
|
+
name: this.name,
|
|
28347
|
+
status: this.status,
|
|
28348
|
+
description: this.description
|
|
28349
|
+
};
|
|
28405
28350
|
}
|
|
28406
|
-
|
|
28407
|
-
|
|
28351
|
+
}/**
|
|
28352
|
+
* Checks for connections quality to closests Cloud regions and determining the best quality
|
|
28353
|
+
*/
|
|
28354
|
+
class CloudRegionCheck extends Checker {
|
|
28355
|
+
get description() {
|
|
28356
|
+
return 'Cloud regions';
|
|
28408
28357
|
}
|
|
28409
|
-
|
|
28410
|
-
|
|
28411
|
-
|
|
28358
|
+
perform() {
|
|
28359
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28360
|
+
const regionProvider = new RegionUrlProvider(this.url, this.token);
|
|
28361
|
+
if (!regionProvider.isCloud()) {
|
|
28362
|
+
this.skip();
|
|
28363
|
+
return;
|
|
28364
|
+
}
|
|
28365
|
+
const regionStats = [];
|
|
28366
|
+
const seenUrls = new Set();
|
|
28367
|
+
for (let i = 0; i < 3; i++) {
|
|
28368
|
+
const regionUrl = yield regionProvider.getNextBestRegionUrl();
|
|
28369
|
+
if (!regionUrl) {
|
|
28370
|
+
break;
|
|
28371
|
+
}
|
|
28372
|
+
if (seenUrls.has(regionUrl)) {
|
|
28373
|
+
continue;
|
|
28374
|
+
}
|
|
28375
|
+
seenUrls.add(regionUrl);
|
|
28376
|
+
const stats = yield this.checkCloudRegion(regionUrl);
|
|
28377
|
+
this.appendMessage("".concat(stats.region, " RTT: ").concat(stats.rtt, "ms, duration: ").concat(stats.duration, "ms"));
|
|
28378
|
+
regionStats.push(stats);
|
|
28379
|
+
}
|
|
28380
|
+
regionStats.sort((a, b) => {
|
|
28381
|
+
return (a.duration - b.duration) * 0.5 + (a.rtt - b.rtt) * 0.5;
|
|
28382
|
+
});
|
|
28383
|
+
const bestRegion = regionStats[0];
|
|
28384
|
+
this.bestStats = bestRegion;
|
|
28385
|
+
this.appendMessage("best Cloud region: ".concat(bestRegion.region));
|
|
28386
|
+
});
|
|
28412
28387
|
}
|
|
28413
|
-
|
|
28414
|
-
|
|
28415
|
-
|
|
28416
|
-
|
|
28417
|
-
1: payload,
|
|
28418
|
-
length
|
|
28419
|
-
} = jwt.split('.');
|
|
28420
|
-
if (length === 5) throw new JWTInvalid('Only JWTs using Compact JWS serialization can be decoded');
|
|
28421
|
-
if (length !== 3) throw new JWTInvalid('Invalid JWT');
|
|
28422
|
-
if (!payload) throw new JWTInvalid('JWTs must contain a payload');
|
|
28423
|
-
let decoded;
|
|
28424
|
-
try {
|
|
28425
|
-
decoded = decode(payload);
|
|
28426
|
-
} catch (_unused) {
|
|
28427
|
-
throw new JWTInvalid('Failed to base64url decode the payload');
|
|
28388
|
+
getInfo() {
|
|
28389
|
+
const info = super.getInfo();
|
|
28390
|
+
info.data = this.bestStats;
|
|
28391
|
+
return info;
|
|
28428
28392
|
}
|
|
28429
|
-
|
|
28430
|
-
|
|
28431
|
-
|
|
28432
|
-
|
|
28433
|
-
|
|
28393
|
+
checkCloudRegion(url) {
|
|
28394
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28395
|
+
var _a, _b;
|
|
28396
|
+
yield this.connect(url);
|
|
28397
|
+
if (this.options.protocol === 'tcp') {
|
|
28398
|
+
yield this.switchProtocol('tcp');
|
|
28399
|
+
}
|
|
28400
|
+
const region = (_a = this.room.serverInfo) === null || _a === void 0 ? void 0 : _a.region;
|
|
28401
|
+
if (!region) {
|
|
28402
|
+
throw new Error('Region not found');
|
|
28403
|
+
}
|
|
28404
|
+
const writer = yield this.room.localParticipant.streamText({
|
|
28405
|
+
topic: 'test'
|
|
28406
|
+
});
|
|
28407
|
+
const chunkSize = 1000; // each chunk is about 1000 bytes
|
|
28408
|
+
const totalSize = 1000000; // approximately 1MB of data
|
|
28409
|
+
const numChunks = totalSize / chunkSize; // will yield 1000 chunks
|
|
28410
|
+
const chunkData = 'A'.repeat(chunkSize); // create a string of 1000 'A' characters
|
|
28411
|
+
const startTime = Date.now();
|
|
28412
|
+
for (let i = 0; i < numChunks; i++) {
|
|
28413
|
+
yield writer.write(chunkData);
|
|
28414
|
+
}
|
|
28415
|
+
yield writer.close();
|
|
28416
|
+
const endTime = Date.now();
|
|
28417
|
+
const stats = yield (_b = this.room.engine.pcManager) === null || _b === void 0 ? void 0 : _b.publisher.getStats();
|
|
28418
|
+
const regionStats = {
|
|
28419
|
+
region: region,
|
|
28420
|
+
rtt: 10000,
|
|
28421
|
+
duration: endTime - startTime
|
|
28422
|
+
};
|
|
28423
|
+
stats === null || stats === void 0 ? void 0 : stats.forEach(stat => {
|
|
28424
|
+
if (stat.type === 'candidate-pair' && stat.nominated) {
|
|
28425
|
+
regionStats.rtt = stat.currentRoundTripTime * 1000;
|
|
28426
|
+
}
|
|
28427
|
+
});
|
|
28428
|
+
yield this.disconnect();
|
|
28429
|
+
return regionStats;
|
|
28430
|
+
});
|
|
28434
28431
|
}
|
|
28435
|
-
|
|
28436
|
-
|
|
28437
|
-
|
|
28438
|
-
|
|
28439
|
-
function isResponseTokenValid(response) {
|
|
28440
|
-
const jwtPayload = decodeTokenPayload(response.participantToken);
|
|
28441
|
-
if (!(jwtPayload === null || jwtPayload === void 0 ? void 0 : jwtPayload.nbf) || !(jwtPayload === null || jwtPayload === void 0 ? void 0 : jwtPayload.exp)) {
|
|
28442
|
-
return true;
|
|
28432
|
+
}const TEST_DURATION = 10000;
|
|
28433
|
+
class ConnectionProtocolCheck extends Checker {
|
|
28434
|
+
get description() {
|
|
28435
|
+
return 'Connection via UDP vs TCP';
|
|
28443
28436
|
}
|
|
28444
|
-
|
|
28445
|
-
|
|
28446
|
-
|
|
28447
|
-
|
|
28448
|
-
|
|
28449
|
-
|
|
28450
|
-
|
|
28451
|
-
|
|
28452
|
-
|
|
28453
|
-
|
|
28454
|
-
|
|
28455
|
-
|
|
28456
|
-
|
|
28457
|
-
|
|
28458
|
-
|
|
28459
|
-
|
|
28460
|
-
|
|
28461
|
-
|
|
28462
|
-
|
|
28463
|
-
|
|
28464
|
-
|
|
28465
|
-
|
|
28466
|
-
|
|
28467
|
-
|
|
28468
|
-
|
|
28469
|
-
|
|
28470
|
-
|
|
28471
|
-
|
|
28472
|
-
case 'participantAttributes':
|
|
28473
|
-
case 'agentName':
|
|
28474
|
-
case 'agentMetadata':
|
|
28475
|
-
if (a[key] !== b[key]) {
|
|
28476
|
-
return false;
|
|
28477
|
-
}
|
|
28478
|
-
break;
|
|
28479
|
-
default:
|
|
28480
|
-
// ref: https://stackoverflow.com/a/58009992
|
|
28481
|
-
const exhaustiveCheckedKey = key;
|
|
28482
|
-
throw new Error("Options key ".concat(exhaustiveCheckedKey, " not being checked for equality!"));
|
|
28483
|
-
}
|
|
28437
|
+
perform() {
|
|
28438
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28439
|
+
const udpStats = yield this.checkConnectionProtocol('udp');
|
|
28440
|
+
const tcpStats = yield this.checkConnectionProtocol('tcp');
|
|
28441
|
+
this.bestStats = udpStats;
|
|
28442
|
+
// udp should is the better protocol typically. however, we'd prefer TCP when either of these conditions are true:
|
|
28443
|
+
// 1. the bandwidth limitation is worse on UDP by 500ms
|
|
28444
|
+
// 2. the packet loss is higher on UDP by 1%
|
|
28445
|
+
if (udpStats.qualityLimitationDurations.bandwidth - tcpStats.qualityLimitationDurations.bandwidth > 0.5 || (udpStats.packetsLost - tcpStats.packetsLost) / udpStats.packetsSent > 0.01) {
|
|
28446
|
+
this.appendMessage('best connection quality via tcp');
|
|
28447
|
+
this.bestStats = tcpStats;
|
|
28448
|
+
} else {
|
|
28449
|
+
this.appendMessage('best connection quality via udp');
|
|
28450
|
+
}
|
|
28451
|
+
const stats = this.bestStats;
|
|
28452
|
+
this.appendMessage("upstream bitrate: ".concat((stats.bitrateTotal / stats.count / 1000 / 1000).toFixed(2), " mbps"));
|
|
28453
|
+
this.appendMessage("RTT: ".concat((stats.rttTotal / stats.count * 1000).toFixed(2), " ms"));
|
|
28454
|
+
this.appendMessage("jitter: ".concat((stats.jitterTotal / stats.count * 1000).toFixed(2), " ms"));
|
|
28455
|
+
if (stats.packetsLost > 0) {
|
|
28456
|
+
this.appendWarning("packets lost: ".concat((stats.packetsLost / stats.packetsSent * 100).toFixed(2), "%"));
|
|
28457
|
+
}
|
|
28458
|
+
if (stats.qualityLimitationDurations.bandwidth > 1) {
|
|
28459
|
+
this.appendWarning("bandwidth limited ".concat((stats.qualityLimitationDurations.bandwidth / (TEST_DURATION / 1000) * 100).toFixed(2), "%"));
|
|
28460
|
+
}
|
|
28461
|
+
if (stats.qualityLimitationDurations.cpu > 0) {
|
|
28462
|
+
this.appendWarning("cpu limited ".concat((stats.qualityLimitationDurations.cpu / (TEST_DURATION / 1000) * 100).toFixed(2), "%"));
|
|
28463
|
+
}
|
|
28464
|
+
});
|
|
28484
28465
|
}
|
|
28485
|
-
|
|
28486
|
-
|
|
28487
|
-
|
|
28488
|
-
|
|
28489
|
-
constructor() {
|
|
28490
|
-
super(...arguments);
|
|
28491
|
-
this.cachedFetchOptions = null;
|
|
28492
|
-
this.cachedResponse = null;
|
|
28493
|
-
this.fetchMutex = new _();
|
|
28466
|
+
getInfo() {
|
|
28467
|
+
const info = super.getInfo();
|
|
28468
|
+
info.data = this.bestStats;
|
|
28469
|
+
return info;
|
|
28494
28470
|
}
|
|
28495
|
-
|
|
28496
|
-
|
|
28497
|
-
|
|
28498
|
-
|
|
28499
|
-
|
|
28500
|
-
|
|
28501
|
-
|
|
28502
|
-
case 'participantName':
|
|
28503
|
-
case 'participantIdentity':
|
|
28504
|
-
case 'participantMetadata':
|
|
28505
|
-
case 'participantAttributes':
|
|
28506
|
-
case 'agentName':
|
|
28507
|
-
case 'agentMetadata':
|
|
28508
|
-
if (this.cachedFetchOptions[key] !== options[key]) {
|
|
28509
|
-
return false;
|
|
28510
|
-
}
|
|
28511
|
-
break;
|
|
28512
|
-
default:
|
|
28513
|
-
// ref: https://stackoverflow.com/a/58009992
|
|
28514
|
-
const exhaustiveCheckedKey = key;
|
|
28515
|
-
throw new Error("Options key ".concat(exhaustiveCheckedKey, " not being checked for equality!"));
|
|
28471
|
+
checkConnectionProtocol(protocol) {
|
|
28472
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28473
|
+
yield this.connect();
|
|
28474
|
+
if (protocol === 'tcp') {
|
|
28475
|
+
yield this.switchProtocol('tcp');
|
|
28476
|
+
} else {
|
|
28477
|
+
yield this.switchProtocol('udp');
|
|
28516
28478
|
}
|
|
28517
|
-
|
|
28518
|
-
|
|
28479
|
+
// create a canvas with animated content
|
|
28480
|
+
const canvas = document.createElement('canvas');
|
|
28481
|
+
canvas.width = 1280;
|
|
28482
|
+
canvas.height = 720;
|
|
28483
|
+
const ctx = canvas.getContext('2d');
|
|
28484
|
+
if (!ctx) {
|
|
28485
|
+
throw new Error('Could not get canvas context');
|
|
28486
|
+
}
|
|
28487
|
+
let hue = 0;
|
|
28488
|
+
const animate = () => {
|
|
28489
|
+
hue = (hue + 1) % 360;
|
|
28490
|
+
ctx.fillStyle = "hsl(".concat(hue, ", 100%, 50%)");
|
|
28491
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
28492
|
+
requestAnimationFrame(animate);
|
|
28493
|
+
};
|
|
28494
|
+
animate();
|
|
28495
|
+
// create video track from canvas
|
|
28496
|
+
const stream = canvas.captureStream(30); // 30fps
|
|
28497
|
+
const videoTrack = stream.getVideoTracks()[0];
|
|
28498
|
+
// publish to room
|
|
28499
|
+
const pub = yield this.room.localParticipant.publishTrack(videoTrack, {
|
|
28500
|
+
simulcast: false,
|
|
28501
|
+
degradationPreference: 'maintain-resolution',
|
|
28502
|
+
videoEncoding: {
|
|
28503
|
+
maxBitrate: 2000000
|
|
28504
|
+
}
|
|
28505
|
+
});
|
|
28506
|
+
const track = pub.track;
|
|
28507
|
+
const protocolStats = {
|
|
28508
|
+
protocol,
|
|
28509
|
+
packetsLost: 0,
|
|
28510
|
+
packetsSent: 0,
|
|
28511
|
+
qualityLimitationDurations: {},
|
|
28512
|
+
rttTotal: 0,
|
|
28513
|
+
jitterTotal: 0,
|
|
28514
|
+
bitrateTotal: 0,
|
|
28515
|
+
count: 0
|
|
28516
|
+
};
|
|
28517
|
+
// gather stats once a second
|
|
28518
|
+
const interval = setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
28519
|
+
const stats = yield track.getRTCStatsReport();
|
|
28520
|
+
stats === null || stats === void 0 ? void 0 : stats.forEach(stat => {
|
|
28521
|
+
if (stat.type === 'outbound-rtp') {
|
|
28522
|
+
protocolStats.packetsSent = stat.packetsSent;
|
|
28523
|
+
protocolStats.qualityLimitationDurations = stat.qualityLimitationDurations;
|
|
28524
|
+
protocolStats.bitrateTotal += stat.targetBitrate;
|
|
28525
|
+
protocolStats.count++;
|
|
28526
|
+
} else if (stat.type === 'remote-inbound-rtp') {
|
|
28527
|
+
protocolStats.packetsLost = stat.packetsLost;
|
|
28528
|
+
protocolStats.rttTotal += stat.roundTripTime;
|
|
28529
|
+
protocolStats.jitterTotal += stat.jitter;
|
|
28530
|
+
}
|
|
28531
|
+
});
|
|
28532
|
+
}), 1000);
|
|
28533
|
+
// wait a bit to gather stats
|
|
28534
|
+
yield new Promise(resolve => setTimeout(resolve, TEST_DURATION));
|
|
28535
|
+
clearInterval(interval);
|
|
28536
|
+
videoTrack.stop();
|
|
28537
|
+
canvas.remove();
|
|
28538
|
+
yield this.disconnect();
|
|
28539
|
+
return protocolStats;
|
|
28540
|
+
});
|
|
28519
28541
|
}
|
|
28520
|
-
|
|
28521
|
-
|
|
28522
|
-
|
|
28523
|
-
}
|
|
28524
|
-
if (!isResponseTokenValid(this.cachedResponse)) {
|
|
28525
|
-
return false;
|
|
28526
|
-
}
|
|
28527
|
-
if (this.isSameAsCachedFetchOptions(fetchOptions)) {
|
|
28528
|
-
return false;
|
|
28529
|
-
}
|
|
28530
|
-
return true;
|
|
28542
|
+
}class PublishAudioCheck extends Checker {
|
|
28543
|
+
get description() {
|
|
28544
|
+
return 'Can publish audio';
|
|
28531
28545
|
}
|
|
28532
|
-
|
|
28533
|
-
|
|
28534
|
-
|
|
28535
|
-
|
|
28536
|
-
|
|
28546
|
+
perform() {
|
|
28547
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28548
|
+
var _a;
|
|
28549
|
+
const room = yield this.connect();
|
|
28550
|
+
const track = yield createLocalAudioTrack();
|
|
28551
|
+
const trackIsSilent = yield detectSilence(track, 1000);
|
|
28552
|
+
if (trackIsSilent) {
|
|
28553
|
+
throw new Error('unable to detect audio from microphone');
|
|
28554
|
+
}
|
|
28555
|
+
this.appendMessage('detected audio from microphone');
|
|
28556
|
+
room.localParticipant.publishTrack(track);
|
|
28557
|
+
// wait for a few seconds to publish
|
|
28558
|
+
yield new Promise(resolve => setTimeout(resolve, 3000));
|
|
28559
|
+
// verify RTC stats that it's publishing
|
|
28560
|
+
const stats = yield (_a = track.sender) === null || _a === void 0 ? void 0 : _a.getStats();
|
|
28561
|
+
if (!stats) {
|
|
28562
|
+
throw new Error('Could not get RTCStats');
|
|
28563
|
+
}
|
|
28564
|
+
let numPackets = 0;
|
|
28565
|
+
stats.forEach(stat => {
|
|
28566
|
+
if (stat.type === 'outbound-rtp' && (stat.kind === 'audio' || !stat.kind && stat.mediaType === 'audio')) {
|
|
28567
|
+
numPackets = stat.packetsSent;
|
|
28568
|
+
}
|
|
28569
|
+
});
|
|
28570
|
+
if (numPackets === 0) {
|
|
28571
|
+
throw new Error('Could not determine packets are sent');
|
|
28572
|
+
}
|
|
28573
|
+
this.appendMessage("published ".concat(numPackets, " audio packets"));
|
|
28574
|
+
});
|
|
28537
28575
|
}
|
|
28538
|
-
|
|
28576
|
+
}class PublishVideoCheck extends Checker {
|
|
28577
|
+
get description() {
|
|
28578
|
+
return 'Can publish video';
|
|
28579
|
+
}
|
|
28580
|
+
perform() {
|
|
28539
28581
|
return __awaiter(this, void 0, void 0, function* () {
|
|
28540
|
-
|
|
28541
|
-
|
|
28542
|
-
|
|
28543
|
-
|
|
28582
|
+
var _a;
|
|
28583
|
+
const room = yield this.connect();
|
|
28584
|
+
const track = yield createLocalVideoTrack();
|
|
28585
|
+
// check if we have video from camera
|
|
28586
|
+
yield this.checkForVideo(track.mediaStreamTrack);
|
|
28587
|
+
room.localParticipant.publishTrack(track);
|
|
28588
|
+
// wait for a few seconds to publish
|
|
28589
|
+
yield new Promise(resolve => setTimeout(resolve, 5000));
|
|
28590
|
+
// verify RTC stats that it's publishing
|
|
28591
|
+
const stats = yield (_a = track.sender) === null || _a === void 0 ? void 0 : _a.getStats();
|
|
28592
|
+
if (!stats) {
|
|
28593
|
+
throw new Error('Could not get RTCStats');
|
|
28594
|
+
}
|
|
28595
|
+
let numPackets = 0;
|
|
28596
|
+
stats.forEach(stat => {
|
|
28597
|
+
if (stat.type === 'outbound-rtp' && (stat.kind === 'video' || !stat.kind && stat.mediaType === 'video')) {
|
|
28598
|
+
numPackets += stat.packetsSent;
|
|
28544
28599
|
}
|
|
28545
|
-
|
|
28546
|
-
|
|
28547
|
-
|
|
28548
|
-
return tokenResponse.toJson();
|
|
28549
|
-
} finally {
|
|
28550
|
-
unlock();
|
|
28600
|
+
});
|
|
28601
|
+
if (numPackets === 0) {
|
|
28602
|
+
throw new Error('Could not determine packets are sent');
|
|
28551
28603
|
}
|
|
28604
|
+
this.appendMessage("published ".concat(numPackets, " video packets"));
|
|
28605
|
+
});
|
|
28606
|
+
}
|
|
28607
|
+
checkForVideo(track) {
|
|
28608
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28609
|
+
const stream = new MediaStream();
|
|
28610
|
+
stream.addTrack(track.clone());
|
|
28611
|
+
// Create video element to check frames
|
|
28612
|
+
const video = document.createElement('video');
|
|
28613
|
+
video.srcObject = stream;
|
|
28614
|
+
video.muted = true;
|
|
28615
|
+
video.autoplay = true;
|
|
28616
|
+
video.playsInline = true;
|
|
28617
|
+
// For iOS Safari
|
|
28618
|
+
video.setAttribute('playsinline', 'true');
|
|
28619
|
+
document.body.appendChild(video);
|
|
28620
|
+
yield new Promise(resolve => {
|
|
28621
|
+
video.onplay = () => {
|
|
28622
|
+
setTimeout(() => {
|
|
28623
|
+
var _a, _b, _c, _d;
|
|
28624
|
+
const canvas = document.createElement('canvas');
|
|
28625
|
+
const settings = track.getSettings();
|
|
28626
|
+
const width = (_b = (_a = settings.width) !== null && _a !== void 0 ? _a : video.videoWidth) !== null && _b !== void 0 ? _b : 1280;
|
|
28627
|
+
const height = (_d = (_c = settings.height) !== null && _c !== void 0 ? _c : video.videoHeight) !== null && _d !== void 0 ? _d : 720;
|
|
28628
|
+
canvas.width = width;
|
|
28629
|
+
canvas.height = height;
|
|
28630
|
+
const ctx = canvas.getContext('2d');
|
|
28631
|
+
// Draw video frame to canvas
|
|
28632
|
+
ctx.drawImage(video, 0, 0);
|
|
28633
|
+
// Get image data and check if all pixels are black
|
|
28634
|
+
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
28635
|
+
const data = imageData.data;
|
|
28636
|
+
let isAllBlack = true;
|
|
28637
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
28638
|
+
if (data[i] !== 0 || data[i + 1] !== 0 || data[i + 2] !== 0) {
|
|
28639
|
+
isAllBlack = false;
|
|
28640
|
+
break;
|
|
28641
|
+
}
|
|
28642
|
+
}
|
|
28643
|
+
if (isAllBlack) {
|
|
28644
|
+
this.appendError('camera appears to be producing only black frames');
|
|
28645
|
+
} else {
|
|
28646
|
+
this.appendMessage('received video frames');
|
|
28647
|
+
}
|
|
28648
|
+
resolve();
|
|
28649
|
+
}, 1000);
|
|
28650
|
+
};
|
|
28651
|
+
video.play();
|
|
28652
|
+
});
|
|
28653
|
+
stream.getTracks().forEach(t => t.stop());
|
|
28654
|
+
video.remove();
|
|
28552
28655
|
});
|
|
28553
28656
|
}
|
|
28554
|
-
}
|
|
28555
|
-
|
|
28556
|
-
|
|
28557
|
-
super();
|
|
28558
|
-
this.literalOrFn = literalOrFn;
|
|
28657
|
+
}class ReconnectCheck extends Checker {
|
|
28658
|
+
get description() {
|
|
28659
|
+
return 'Resuming connection after interruption';
|
|
28559
28660
|
}
|
|
28560
|
-
|
|
28661
|
+
perform() {
|
|
28561
28662
|
return __awaiter(this, void 0, void 0, function* () {
|
|
28562
|
-
|
|
28563
|
-
|
|
28564
|
-
|
|
28565
|
-
|
|
28663
|
+
var _a;
|
|
28664
|
+
const room = yield this.connect();
|
|
28665
|
+
let reconnectingTriggered = false;
|
|
28666
|
+
let reconnected = false;
|
|
28667
|
+
let reconnectResolver;
|
|
28668
|
+
const reconnectTimeout = new Promise(resolve => {
|
|
28669
|
+
setTimeout(resolve, 5000);
|
|
28670
|
+
reconnectResolver = resolve;
|
|
28671
|
+
});
|
|
28672
|
+
const handleReconnecting = () => {
|
|
28673
|
+
reconnectingTriggered = true;
|
|
28674
|
+
};
|
|
28675
|
+
room.on(RoomEvent.SignalReconnecting, handleReconnecting).on(RoomEvent.Reconnecting, handleReconnecting).on(RoomEvent.Reconnected, () => {
|
|
28676
|
+
reconnected = true;
|
|
28677
|
+
reconnectResolver(true);
|
|
28678
|
+
});
|
|
28679
|
+
(_a = room.engine.client.ws) === null || _a === void 0 ? void 0 : _a.close();
|
|
28680
|
+
const onClose = room.engine.client.onClose;
|
|
28681
|
+
if (onClose) {
|
|
28682
|
+
onClose('');
|
|
28683
|
+
}
|
|
28684
|
+
yield reconnectTimeout;
|
|
28685
|
+
if (!reconnectingTriggered) {
|
|
28686
|
+
throw new Error('Did not attempt to reconnect');
|
|
28687
|
+
} else if (!reconnected || room.state !== ConnectionState.Connected) {
|
|
28688
|
+
this.appendWarning('reconnection is only possible in Redis-based configurations');
|
|
28689
|
+
throw new Error('Not able to reconnect');
|
|
28566
28690
|
}
|
|
28567
28691
|
});
|
|
28568
28692
|
}
|
|
28569
|
-
}
|
|
28570
|
-
|
|
28571
|
-
|
|
28572
|
-
super();
|
|
28573
|
-
this.customFn = customFn;
|
|
28693
|
+
}class TURNCheck extends Checker {
|
|
28694
|
+
get description() {
|
|
28695
|
+
return 'Can connect via TURN';
|
|
28574
28696
|
}
|
|
28575
|
-
|
|
28697
|
+
perform() {
|
|
28576
28698
|
return __awaiter(this, void 0, void 0, function* () {
|
|
28577
|
-
|
|
28578
|
-
|
|
28579
|
-
|
|
28580
|
-
|
|
28581
|
-
} else {
|
|
28582
|
-
result = resultMaybePromise;
|
|
28699
|
+
var _a, _b, _c;
|
|
28700
|
+
if (isCloud(new URL(this.url))) {
|
|
28701
|
+
this.appendMessage('Using region specific url');
|
|
28702
|
+
this.url = (_a = yield new RegionUrlProvider(this.url, this.token).getNextBestRegionUrl()) !== null && _a !== void 0 ? _a : this.url;
|
|
28583
28703
|
}
|
|
28584
|
-
|
|
28585
|
-
|
|
28586
|
-
|
|
28587
|
-
|
|
28588
|
-
|
|
28589
|
-
|
|
28590
|
-
|
|
28591
|
-
|
|
28592
|
-
|
|
28593
|
-
|
|
28594
|
-
|
|
28595
|
-
|
|
28596
|
-
|
|
28597
|
-
|
|
28598
|
-
|
|
28599
|
-
|
|
28600
|
-
|
|
28601
|
-
|
|
28602
|
-
|
|
28603
|
-
switch (key) {
|
|
28604
|
-
case 'roomName':
|
|
28605
|
-
case 'participantName':
|
|
28606
|
-
case 'participantIdentity':
|
|
28607
|
-
case 'participantMetadata':
|
|
28608
|
-
request[key] = options[key];
|
|
28609
|
-
break;
|
|
28610
|
-
case 'participantAttributes':
|
|
28611
|
-
request.participantAttributes = (_a = options.participantAttributes) !== null && _a !== void 0 ? _a : {};
|
|
28612
|
-
break;
|
|
28613
|
-
case 'agentName':
|
|
28614
|
-
request.roomConfig = (_b = request.roomConfig) !== null && _b !== void 0 ? _b : new RoomConfiguration();
|
|
28615
|
-
if (request.roomConfig.agents.length === 0) {
|
|
28616
|
-
request.roomConfig.agents.push(new RoomAgentDispatch());
|
|
28704
|
+
const signalClient = new SignalClient();
|
|
28705
|
+
const joinRes = yield signalClient.join(this.url, this.token, {
|
|
28706
|
+
autoSubscribe: true,
|
|
28707
|
+
maxRetries: 0,
|
|
28708
|
+
e2eeEnabled: false,
|
|
28709
|
+
websocketTimeout: 15000
|
|
28710
|
+
}, undefined, true);
|
|
28711
|
+
let hasTLS = false;
|
|
28712
|
+
let hasTURN = false;
|
|
28713
|
+
let hasSTUN = false;
|
|
28714
|
+
for (let iceServer of joinRes.iceServers) {
|
|
28715
|
+
for (let url of iceServer.urls) {
|
|
28716
|
+
if (url.startsWith('turn:')) {
|
|
28717
|
+
hasTURN = true;
|
|
28718
|
+
hasSTUN = true;
|
|
28719
|
+
} else if (url.startsWith('turns:')) {
|
|
28720
|
+
hasTURN = true;
|
|
28721
|
+
hasSTUN = true;
|
|
28722
|
+
hasTLS = true;
|
|
28617
28723
|
}
|
|
28618
|
-
|
|
28619
|
-
|
|
28620
|
-
case 'agentMetadata':
|
|
28621
|
-
request.roomConfig = (_c = request.roomConfig) !== null && _c !== void 0 ? _c : new RoomConfiguration();
|
|
28622
|
-
if (request.roomConfig.agents.length === 0) {
|
|
28623
|
-
request.roomConfig.agents.push(new RoomAgentDispatch());
|
|
28724
|
+
if (url.startsWith('stun:')) {
|
|
28725
|
+
hasSTUN = true;
|
|
28624
28726
|
}
|
|
28625
|
-
|
|
28626
|
-
break;
|
|
28627
|
-
default:
|
|
28628
|
-
// ref: https://stackoverflow.com/a/58009992
|
|
28629
|
-
const exhaustiveCheckedKey = key;
|
|
28630
|
-
throw new Error("Options key ".concat(exhaustiveCheckedKey, " not being included in forming request!"));
|
|
28727
|
+
}
|
|
28631
28728
|
}
|
|
28632
|
-
|
|
28633
|
-
|
|
28634
|
-
|
|
28635
|
-
|
|
28636
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
28637
|
-
var _a;
|
|
28638
|
-
const request = this.createRequestFromOptions(options);
|
|
28639
|
-
const response = yield fetch(this.url, Object.assign(Object.assign({}, this.endpointOptions), {
|
|
28640
|
-
method: (_a = this.endpointOptions.method) !== null && _a !== void 0 ? _a : 'POST',
|
|
28641
|
-
headers: Object.assign({
|
|
28642
|
-
'Content-Type': 'application/json'
|
|
28643
|
-
}, this.endpointOptions.headers),
|
|
28644
|
-
body: request.toJsonString({
|
|
28645
|
-
useProtoFieldName: true
|
|
28646
|
-
})
|
|
28647
|
-
}));
|
|
28648
|
-
if (!response.ok) {
|
|
28649
|
-
throw new Error("Error generating token from endpoint ".concat(this.url, ": received ").concat(response.status, " / ").concat(yield response.text()));
|
|
28729
|
+
if (!hasSTUN) {
|
|
28730
|
+
this.appendWarning('No STUN servers configured on server side.');
|
|
28731
|
+
} else if (hasTURN && !hasTLS) {
|
|
28732
|
+
this.appendWarning('TURN is configured server side, but TURN/TLS is unavailable.');
|
|
28650
28733
|
}
|
|
28651
|
-
|
|
28652
|
-
|
|
28653
|
-
|
|
28654
|
-
|
|
28655
|
-
|
|
28656
|
-
|
|
28657
|
-
|
|
28658
|
-
|
|
28659
|
-
|
|
28660
|
-
|
|
28661
|
-
|
|
28662
|
-
const {
|
|
28663
|
-
baseUrl = 'https://cloud-api.livekit.io'
|
|
28664
|
-
} = options,
|
|
28665
|
-
rest = __rest(options, ["baseUrl"]);
|
|
28666
|
-
super("".concat(baseUrl, "/api/v2/sandbox/connection-details"), Object.assign(Object.assign({}, rest), {
|
|
28667
|
-
headers: {
|
|
28668
|
-
'X-Sandbox-ID': sandboxId
|
|
28734
|
+
yield signalClient.close();
|
|
28735
|
+
if (((_c = (_b = this.connectOptions) === null || _b === void 0 ? void 0 : _b.rtcConfig) === null || _c === void 0 ? void 0 : _c.iceServers) || hasTURN) {
|
|
28736
|
+
yield this.room.connect(this.url, this.token, {
|
|
28737
|
+
rtcConfig: {
|
|
28738
|
+
iceTransportPolicy: 'relay'
|
|
28739
|
+
}
|
|
28740
|
+
});
|
|
28741
|
+
} else {
|
|
28742
|
+
this.appendWarning('No TURN servers configured.');
|
|
28743
|
+
this.skip();
|
|
28744
|
+
yield new Promise(resolve => setTimeout(resolve, 0));
|
|
28669
28745
|
}
|
|
28670
|
-
})
|
|
28746
|
+
});
|
|
28671
28747
|
}
|
|
28672
|
-
}
|
|
28673
|
-
|
|
28674
|
-
|
|
28675
|
-
* credentials, either provided directly or returned from a provided function. */
|
|
28676
|
-
literal(literalOrFn) {
|
|
28677
|
-
return new TokenSourceLiteral(literalOrFn);
|
|
28678
|
-
},
|
|
28679
|
-
/**
|
|
28680
|
-
* TokenSource.custom allows a user to define a manual function which generates new
|
|
28681
|
-
* {@link TokenSourceResponseObject} values on demand.
|
|
28682
|
-
*
|
|
28683
|
-
* Use this to get credentials from custom backends / etc.
|
|
28684
|
-
*/
|
|
28685
|
-
custom(customFn) {
|
|
28686
|
-
return new TokenSourceCustom(customFn);
|
|
28687
|
-
},
|
|
28688
|
-
/**
|
|
28689
|
-
* TokenSource.endpoint creates a token source that fetches credentials from a given URL using
|
|
28690
|
-
* the standard endpoint format:
|
|
28691
|
-
* @see https://cloud.livekit.io/projects/p_/sandbox/templates/token-server
|
|
28692
|
-
*/
|
|
28693
|
-
endpoint(url) {
|
|
28694
|
-
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
28695
|
-
return new TokenSourceEndpoint(url, options);
|
|
28696
|
-
},
|
|
28697
|
-
/**
|
|
28698
|
-
* TokenSource.sandboxTokenServer queries a sandbox token server for credentials,
|
|
28699
|
-
* which supports quick prototyping / getting started types of use cases.
|
|
28700
|
-
*
|
|
28701
|
-
* This token provider is INSECURE and should NOT be used in production.
|
|
28702
|
-
*
|
|
28703
|
-
* For more info:
|
|
28704
|
-
* @see https://cloud.livekit.io/projects/p_/sandbox/templates/token-server
|
|
28705
|
-
*/
|
|
28706
|
-
sandboxTokenServer(sandboxId) {
|
|
28707
|
-
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
28708
|
-
return new TokenSourceSandboxTokenServer(sandboxId, options);
|
|
28748
|
+
}class WebRTCCheck extends Checker {
|
|
28749
|
+
get description() {
|
|
28750
|
+
return 'Establishing WebRTC connection';
|
|
28709
28751
|
}
|
|
28710
|
-
|
|
28711
|
-
|
|
28712
|
-
|
|
28713
|
-
|
|
28714
|
-
|
|
28715
|
-
|
|
28716
|
-
|
|
28717
|
-
|
|
28718
|
-
|
|
28719
|
-
|
|
28720
|
-
|
|
28721
|
-
|
|
28722
|
-
|
|
28723
|
-
|
|
28724
|
-
|
|
28725
|
-
|
|
28726
|
-
|
|
28727
|
-
|
|
28728
|
-
|
|
28729
|
-
|
|
28730
|
-
|
|
28731
|
-
|
|
28732
|
-
|
|
28733
|
-
|
|
28734
|
-
|
|
28752
|
+
perform() {
|
|
28753
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28754
|
+
let hasTcp = false;
|
|
28755
|
+
let hasIpv4Udp = false;
|
|
28756
|
+
this.room.on(RoomEvent.SignalConnected, () => {
|
|
28757
|
+
var _a;
|
|
28758
|
+
const prevTrickle = this.room.engine.client.onTrickle;
|
|
28759
|
+
this.room.engine.client.onTrickle = (sd, target) => {
|
|
28760
|
+
if (sd.candidate) {
|
|
28761
|
+
const candidate = new RTCIceCandidate(sd);
|
|
28762
|
+
let str = "".concat(candidate.protocol, " ").concat(candidate.address, ":").concat(candidate.port, " ").concat(candidate.type);
|
|
28763
|
+
if (candidate.address) {
|
|
28764
|
+
if (isIPPrivate(candidate.address)) {
|
|
28765
|
+
str += ' (private)';
|
|
28766
|
+
} else {
|
|
28767
|
+
if (candidate.protocol === 'tcp' && candidate.tcpType === 'passive') {
|
|
28768
|
+
hasTcp = true;
|
|
28769
|
+
str += ' (passive)';
|
|
28770
|
+
} else if (candidate.protocol === 'udp') {
|
|
28771
|
+
hasIpv4Udp = true;
|
|
28772
|
+
}
|
|
28773
|
+
}
|
|
28774
|
+
}
|
|
28775
|
+
this.appendMessage(str);
|
|
28776
|
+
}
|
|
28777
|
+
if (prevTrickle) {
|
|
28778
|
+
prevTrickle(sd, target);
|
|
28779
|
+
}
|
|
28780
|
+
};
|
|
28781
|
+
if ((_a = this.room.engine.pcManager) === null || _a === void 0 ? void 0 : _a.subscriber) {
|
|
28782
|
+
this.room.engine.pcManager.subscriber.onIceCandidateError = ev => {
|
|
28783
|
+
if (ev instanceof RTCPeerConnectionIceErrorEvent) {
|
|
28784
|
+
this.appendWarning("error with ICE candidate: ".concat(ev.errorCode, " ").concat(ev.errorText, " ").concat(ev.url));
|
|
28785
|
+
}
|
|
28786
|
+
};
|
|
28787
|
+
}
|
|
28788
|
+
});
|
|
28789
|
+
try {
|
|
28790
|
+
yield this.connect();
|
|
28791
|
+
livekitLogger.info('now the room is connected');
|
|
28792
|
+
} catch (err) {
|
|
28793
|
+
this.appendWarning('ports need to be open on firewall in order to connect.');
|
|
28794
|
+
throw err;
|
|
28795
|
+
}
|
|
28796
|
+
if (!hasTcp) {
|
|
28797
|
+
this.appendWarning('Server is not configured for ICE/TCP');
|
|
28798
|
+
}
|
|
28799
|
+
if (!hasIpv4Udp) {
|
|
28800
|
+
this.appendWarning('No public IPv4 UDP candidates were found. Your server is likely not configured correctly');
|
|
28801
|
+
}
|
|
28735
28802
|
});
|
|
28736
|
-
if (rawFacingMode && typeof rawFacingMode === 'string' && isFacingModeValue(rawFacingMode)) {
|
|
28737
|
-
result = {
|
|
28738
|
-
facingMode: rawFacingMode,
|
|
28739
|
-
confidence: 'high'
|
|
28740
|
-
};
|
|
28741
|
-
}
|
|
28742
28803
|
}
|
|
28743
|
-
|
|
28744
|
-
|
|
28745
|
-
|
|
28746
|
-
|
|
28747
|
-
if (
|
|
28748
|
-
|
|
28804
|
+
}
|
|
28805
|
+
function isIPPrivate(address) {
|
|
28806
|
+
const parts = address.split('.');
|
|
28807
|
+
if (parts.length === 4) {
|
|
28808
|
+
if (parts[0] === '10') {
|
|
28809
|
+
return true;
|
|
28810
|
+
} else if (parts[0] === '192' && parts[1] === '168') {
|
|
28811
|
+
return true;
|
|
28812
|
+
} else if (parts[0] === '172') {
|
|
28813
|
+
const second = parseInt(parts[1], 10);
|
|
28814
|
+
if (second >= 16 && second <= 31) {
|
|
28815
|
+
return true;
|
|
28816
|
+
}
|
|
28749
28817
|
}
|
|
28750
28818
|
}
|
|
28751
|
-
return
|
|
28752
|
-
}
|
|
28753
|
-
|
|
28754
|
-
|
|
28755
|
-
confidence: 'medium'
|
|
28756
|
-
}]]);
|
|
28757
|
-
const knownDeviceLabelSections = new Map([['iphone', {
|
|
28758
|
-
facingMode: 'environment',
|
|
28759
|
-
confidence: 'medium'
|
|
28760
|
-
}], ['ipad', {
|
|
28761
|
-
facingMode: 'environment',
|
|
28762
|
-
confidence: 'medium'
|
|
28763
|
-
}]]);
|
|
28764
|
-
/**
|
|
28765
|
-
* Attempt to analyze the device label to determine the facing mode.
|
|
28766
|
-
*
|
|
28767
|
-
* @experimental
|
|
28768
|
-
*/
|
|
28769
|
-
function facingModeFromDeviceLabel(deviceLabel) {
|
|
28770
|
-
var _a;
|
|
28771
|
-
const label = deviceLabel.trim().toLowerCase();
|
|
28772
|
-
// Empty string is a valid device label but we can't infer anything from it.
|
|
28773
|
-
if (label === '') {
|
|
28774
|
-
return undefined;
|
|
28819
|
+
return false;
|
|
28820
|
+
}class WebSocketCheck extends Checker {
|
|
28821
|
+
get description() {
|
|
28822
|
+
return 'Connecting to signal connection via WebSocket';
|
|
28775
28823
|
}
|
|
28776
|
-
|
|
28777
|
-
|
|
28778
|
-
|
|
28824
|
+
perform() {
|
|
28825
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28826
|
+
var _a, _b, _c;
|
|
28827
|
+
if (this.url.startsWith('ws:') || this.url.startsWith('http:')) {
|
|
28828
|
+
this.appendWarning('Server is insecure, clients may block connections to it');
|
|
28829
|
+
}
|
|
28830
|
+
let signalClient = new SignalClient();
|
|
28831
|
+
let joinRes;
|
|
28832
|
+
try {
|
|
28833
|
+
joinRes = yield signalClient.join(this.url, this.token, {
|
|
28834
|
+
autoSubscribe: true,
|
|
28835
|
+
maxRetries: 0,
|
|
28836
|
+
e2eeEnabled: false,
|
|
28837
|
+
websocketTimeout: 15000
|
|
28838
|
+
}, undefined, true);
|
|
28839
|
+
} catch (e) {
|
|
28840
|
+
if (isCloud(new URL(this.url))) {
|
|
28841
|
+
this.appendMessage("Initial connection failed with error ".concat(e.message, ". Retrying with region fallback"));
|
|
28842
|
+
const regionProvider = new RegionUrlProvider(this.url, this.token);
|
|
28843
|
+
const regionUrl = yield regionProvider.getNextBestRegionUrl();
|
|
28844
|
+
if (regionUrl) {
|
|
28845
|
+
joinRes = yield signalClient.join(regionUrl, this.token, {
|
|
28846
|
+
autoSubscribe: true,
|
|
28847
|
+
maxRetries: 0,
|
|
28848
|
+
e2eeEnabled: false,
|
|
28849
|
+
websocketTimeout: 15000
|
|
28850
|
+
}, undefined, true);
|
|
28851
|
+
this.appendMessage("Fallback to region worked. To avoid initial connections failing, ensure you're calling room.prepareConnection() ahead of time");
|
|
28852
|
+
}
|
|
28853
|
+
}
|
|
28854
|
+
}
|
|
28855
|
+
if (joinRes) {
|
|
28856
|
+
this.appendMessage("Connected to server, version ".concat(joinRes.serverVersion, "."));
|
|
28857
|
+
if (((_a = joinRes.serverInfo) === null || _a === void 0 ? void 0 : _a.edition) === ServerInfo_Edition.Cloud && ((_b = joinRes.serverInfo) === null || _b === void 0 ? void 0 : _b.region)) {
|
|
28858
|
+
this.appendMessage("LiveKit Cloud: ".concat((_c = joinRes.serverInfo) === null || _c === void 0 ? void 0 : _c.region));
|
|
28859
|
+
}
|
|
28860
|
+
} else {
|
|
28861
|
+
this.appendError("Websocket connection could not be established");
|
|
28862
|
+
}
|
|
28863
|
+
yield signalClient.close();
|
|
28864
|
+
});
|
|
28779
28865
|
}
|
|
28780
|
-
|
|
28781
|
-
|
|
28782
|
-
let [
|
|
28783
|
-
|
|
28784
|
-
|
|
28785
|
-
|
|
28786
|
-
|
|
28787
|
-
|
|
28788
|
-
|
|
28789
|
-
}const U16_MAX_SIZE = 0xffff;
|
|
28790
|
-
/**
|
|
28791
|
-
* A number of fields withing the data tracks packet specification assume wrap around behavior when
|
|
28792
|
-
* an unsigned type is incremented beyond its max size (ie, the packet `sequence` field). This
|
|
28793
|
-
* wrapper type manually reimplements this wrap around behavior given javascript's lack of fixed
|
|
28794
|
-
* size integer types.
|
|
28795
|
-
*/
|
|
28796
|
-
class WrapAroundUnsignedInt {
|
|
28797
|
-
static u16(raw) {
|
|
28798
|
-
return new WrapAroundUnsignedInt(raw, U16_MAX_SIZE);
|
|
28866
|
+
}class ConnectionCheck extends eventsExports.EventEmitter {
|
|
28867
|
+
constructor(url, token) {
|
|
28868
|
+
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
28869
|
+
super();
|
|
28870
|
+
this.options = {};
|
|
28871
|
+
this.checkResults = new Map();
|
|
28872
|
+
this.url = url;
|
|
28873
|
+
this.token = token;
|
|
28874
|
+
this.options = options;
|
|
28799
28875
|
}
|
|
28800
|
-
|
|
28801
|
-
|
|
28802
|
-
|
|
28803
|
-
|
|
28804
|
-
|
|
28805
|
-
|
|
28806
|
-
|
|
28807
|
-
}
|
|
28808
|
-
|
|
28809
|
-
this.clamp();
|
|
28876
|
+
getNextCheckId() {
|
|
28877
|
+
const nextId = this.checkResults.size;
|
|
28878
|
+
this.checkResults.set(nextId, {
|
|
28879
|
+
logs: [],
|
|
28880
|
+
status: CheckStatus.IDLE,
|
|
28881
|
+
name: '',
|
|
28882
|
+
description: ''
|
|
28883
|
+
});
|
|
28884
|
+
return nextId;
|
|
28810
28885
|
}
|
|
28811
|
-
|
|
28812
|
-
|
|
28813
|
-
|
|
28814
|
-
while (this.value > this.maxSize) {
|
|
28815
|
-
this.value -= this.maxSize + 1;
|
|
28816
|
-
}
|
|
28817
|
-
while (this.value < 0) {
|
|
28818
|
-
this.value += this.maxSize + 1;
|
|
28819
|
-
}
|
|
28886
|
+
updateCheck(checkId, info) {
|
|
28887
|
+
this.checkResults.set(checkId, info);
|
|
28888
|
+
this.emit('checkUpdate', checkId, info);
|
|
28820
28889
|
}
|
|
28821
|
-
|
|
28822
|
-
|
|
28823
|
-
update(updateFn) {
|
|
28824
|
-
this.value = updateFn(this.value);
|
|
28825
|
-
this.clamp();
|
|
28890
|
+
isSuccess() {
|
|
28891
|
+
return Array.from(this.checkResults.values()).every(r => r.status !== CheckStatus.FAILED);
|
|
28826
28892
|
}
|
|
28827
|
-
|
|
28828
|
-
|
|
28829
|
-
static fromRtpTicks(rtpTicks) {
|
|
28830
|
-
return new DataTrackTimestamp(rtpTicks, 90000);
|
|
28893
|
+
getResults() {
|
|
28894
|
+
return Array.from(this.checkResults.values());
|
|
28831
28895
|
}
|
|
28832
|
-
|
|
28833
|
-
return this
|
|
28896
|
+
createAndRunCheck(check) {
|
|
28897
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28898
|
+
const checkId = this.getNextCheckId();
|
|
28899
|
+
const test = new check(this.url, this.token, this.options);
|
|
28900
|
+
const handleUpdate = info => {
|
|
28901
|
+
this.updateCheck(checkId, info);
|
|
28902
|
+
};
|
|
28903
|
+
test.on('update', handleUpdate);
|
|
28904
|
+
const result = yield test.run();
|
|
28905
|
+
test.off('update', handleUpdate);
|
|
28906
|
+
return result;
|
|
28907
|
+
});
|
|
28834
28908
|
}
|
|
28835
|
-
|
|
28836
|
-
this
|
|
28837
|
-
|
|
28909
|
+
checkWebsocket() {
|
|
28910
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28911
|
+
return this.createAndRunCheck(WebSocketCheck);
|
|
28912
|
+
});
|
|
28838
28913
|
}
|
|
28839
|
-
|
|
28840
|
-
function
|
|
28841
|
-
|
|
28842
|
-
|
|
28843
|
-
} else if (input instanceof ArrayBuffer) {
|
|
28844
|
-
return new DataView(input);
|
|
28845
|
-
} else if (input instanceof Uint8Array) {
|
|
28846
|
-
return new DataView(input.buffer, input.byteOffset, input.byteLength);
|
|
28847
|
-
} else {
|
|
28848
|
-
throw new Error("Error coercing ".concat(input, " to DataView - input was not DataView, ArrayBuffer, or Uint8Array."));
|
|
28914
|
+
checkWebRTC() {
|
|
28915
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28916
|
+
return this.createAndRunCheck(WebRTCCheck);
|
|
28917
|
+
});
|
|
28849
28918
|
}
|
|
28850
|
-
|
|
28851
|
-
(function (
|
|
28852
|
-
|
|
28853
|
-
|
|
28854
|
-
})(DataTrackHandleErrorReason || (DataTrackHandleErrorReason = {}));
|
|
28855
|
-
class DataTrackHandleError extends LivekitReasonedError {
|
|
28856
|
-
constructor(message, reason) {
|
|
28857
|
-
super(19, message);
|
|
28858
|
-
this.name = 'DataTrackHandleError';
|
|
28859
|
-
this.reason = reason;
|
|
28860
|
-
this.reasonName = DataTrackHandleErrorReason[reason];
|
|
28919
|
+
checkTURN() {
|
|
28920
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28921
|
+
return this.createAndRunCheck(TURNCheck);
|
|
28922
|
+
});
|
|
28861
28923
|
}
|
|
28862
|
-
|
|
28863
|
-
return this
|
|
28924
|
+
checkReconnect() {
|
|
28925
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28926
|
+
return this.createAndRunCheck(ReconnectCheck);
|
|
28927
|
+
});
|
|
28864
28928
|
}
|
|
28865
|
-
|
|
28866
|
-
return
|
|
28929
|
+
checkPublishAudio() {
|
|
28930
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28931
|
+
return this.createAndRunCheck(PublishAudioCheck);
|
|
28932
|
+
});
|
|
28867
28933
|
}
|
|
28868
|
-
|
|
28869
|
-
return
|
|
28934
|
+
checkPublishVideo() {
|
|
28935
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28936
|
+
return this.createAndRunCheck(PublishVideoCheck);
|
|
28937
|
+
});
|
|
28870
28938
|
}
|
|
28871
|
-
|
|
28872
|
-
|
|
28873
|
-
|
|
28874
|
-
|
|
28875
|
-
|
|
28876
|
-
|
|
28877
|
-
|
|
28878
|
-
|
|
28879
|
-
}
|
|
28880
|
-
return new DataTrackHandle(raw);
|
|
28939
|
+
checkConnectionProtocol() {
|
|
28940
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28941
|
+
const info = yield this.createAndRunCheck(ConnectionProtocolCheck);
|
|
28942
|
+
if (info.data && 'protocol' in info.data) {
|
|
28943
|
+
const stats = info.data;
|
|
28944
|
+
this.options.protocol = stats.protocol;
|
|
28945
|
+
}
|
|
28946
|
+
return info;
|
|
28947
|
+
});
|
|
28881
28948
|
}
|
|
28882
|
-
|
|
28883
|
-
this
|
|
28949
|
+
checkCloudRegion() {
|
|
28950
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28951
|
+
return this.createAndRunCheck(CloudRegionCheck);
|
|
28952
|
+
});
|
|
28884
28953
|
}
|
|
28885
|
-
}
|
|
28886
|
-
|
|
28887
|
-
|
|
28888
|
-
|
|
28889
|
-
|
|
28890
|
-
|
|
28891
|
-
|
|
28892
|
-
|
|
28893
|
-
|
|
28894
|
-
|
|
28895
|
-
|
|
28896
|
-
|
|
28897
|
-
|
|
28898
|
-
|
|
28899
|
-
|
|
28900
|
-
|
|
28901
|
-
|
|
28902
|
-
|
|
28903
|
-
|
|
28904
|
-
|
|
28905
|
-
|
|
28906
|
-
|
|
28907
|
-
|
|
28908
|
-
|
|
28909
|
-
|
|
28910
|
-
|
|
28911
|
-
|
|
28912
|
-
|
|
28913
|
-
|
|
28914
|
-
|
|
28915
|
-
|
|
28916
|
-
|
|
28917
|
-
this.name = 'DataTrackDeserializeError';
|
|
28918
|
-
this.reason = reason;
|
|
28919
|
-
this.reasonName = DataTrackDeserializeErrorReason[reason];
|
|
28954
|
+
}/** A Fixed TokenSource is a token source that takes no parameters and returns a completely
|
|
28955
|
+
* independently derived value on each fetch() call.
|
|
28956
|
+
*
|
|
28957
|
+
* The most common downstream implementer is {@link TokenSourceLiteral}.
|
|
28958
|
+
*/
|
|
28959
|
+
class TokenSourceFixed {}
|
|
28960
|
+
/** A Configurable TokenSource is a token source that takes a
|
|
28961
|
+
* {@link TokenSourceFetchOptions} object as input and returns a deterministic
|
|
28962
|
+
* {@link TokenSourceResponseObject} output based on the options specified.
|
|
28963
|
+
*
|
|
28964
|
+
* For example, if options.participantName is set, it should be expected that
|
|
28965
|
+
* all tokens that are generated will have participant name field set to the
|
|
28966
|
+
* provided value.
|
|
28967
|
+
*
|
|
28968
|
+
* A few common downstream implementers are {@link TokenSourceEndpoint}
|
|
28969
|
+
* and {@link TokenSourceCustom}.
|
|
28970
|
+
*/
|
|
28971
|
+
class TokenSourceConfigurable {}function _defineProperty(e, r, t) {
|
|
28972
|
+
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
28973
|
+
value: t,
|
|
28974
|
+
enumerable: true,
|
|
28975
|
+
configurable: true,
|
|
28976
|
+
writable: true
|
|
28977
|
+
}) : e[r] = t, e;
|
|
28978
|
+
}
|
|
28979
|
+
function _toPrimitive(t, r) {
|
|
28980
|
+
if ("object" != typeof t || !t) return t;
|
|
28981
|
+
var e = t[Symbol.toPrimitive];
|
|
28982
|
+
if (void 0 !== e) {
|
|
28983
|
+
var i = e.call(t, r);
|
|
28984
|
+
if ("object" != typeof i) return i;
|
|
28985
|
+
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
28920
28986
|
}
|
|
28921
|
-
|
|
28922
|
-
|
|
28987
|
+
return ("string" === r ? String : Number)(t);
|
|
28988
|
+
}
|
|
28989
|
+
function _toPropertyKey(t) {
|
|
28990
|
+
var i = _toPrimitive(t, "string");
|
|
28991
|
+
return "symbol" == typeof i ? i : i + "";
|
|
28992
|
+
}new TextEncoder();
|
|
28993
|
+
const decoder = new TextDecoder();function decodeBase64(encoded) {
|
|
28994
|
+
if (Uint8Array.fromBase64) {
|
|
28995
|
+
return Uint8Array.fromBase64(encoded);
|
|
28923
28996
|
}
|
|
28924
|
-
|
|
28925
|
-
|
|
28997
|
+
const binary = atob(encoded);
|
|
28998
|
+
const bytes = new Uint8Array(binary.length);
|
|
28999
|
+
for (let i = 0; i < binary.length; i++) {
|
|
29000
|
+
bytes[i] = binary.charCodeAt(i);
|
|
28926
29001
|
}
|
|
28927
|
-
|
|
28928
|
-
|
|
29002
|
+
return bytes;
|
|
29003
|
+
}function decode(input) {
|
|
29004
|
+
if (Uint8Array.fromBase64) {
|
|
29005
|
+
return Uint8Array.fromBase64(typeof input === 'string' ? input : decoder.decode(input), {
|
|
29006
|
+
alphabet: 'base64url'
|
|
29007
|
+
});
|
|
28929
29008
|
}
|
|
28930
|
-
|
|
28931
|
-
|
|
29009
|
+
let encoded = input;
|
|
29010
|
+
if (encoded instanceof Uint8Array) {
|
|
29011
|
+
encoded = decoder.decode(encoded);
|
|
28932
29012
|
}
|
|
28933
|
-
|
|
28934
|
-
|
|
28935
|
-
|
|
28936
|
-
|
|
29013
|
+
encoded = encoded.replace(/-/g, '+').replace(/_/g, '/');
|
|
29014
|
+
try {
|
|
29015
|
+
return decodeBase64(encoded);
|
|
29016
|
+
} catch (_unused) {
|
|
29017
|
+
throw new TypeError('The input to be decoded is not correctly encoded.');
|
|
28937
29018
|
}
|
|
28938
|
-
|
|
28939
|
-
|
|
29019
|
+
}class JOSEError extends Error {
|
|
29020
|
+
constructor(message, options) {
|
|
29021
|
+
var _Error$captureStackTr;
|
|
29022
|
+
super(message, options);
|
|
29023
|
+
_defineProperty(this, "code", 'ERR_JOSE_GENERIC');
|
|
29024
|
+
this.name = this.constructor.name;
|
|
29025
|
+
(_Error$captureStackTr = Error.captureStackTrace) === null || _Error$captureStackTr === void 0 || _Error$captureStackTr.call(Error, this, this.constructor);
|
|
28940
29026
|
}
|
|
28941
29027
|
}
|
|
28942
|
-
|
|
28943
|
-
|
|
28944
|
-
|
|
28945
|
-
|
|
28946
|
-
|
|
28947
|
-
|
|
28948
|
-
|
|
28949
|
-
|
|
28950
|
-
|
|
29028
|
+
_defineProperty(JOSEError, "code", 'ERR_JOSE_GENERIC');
|
|
29029
|
+
class JWTClaimValidationFailed extends JOSEError {
|
|
29030
|
+
constructor(message, payload) {
|
|
29031
|
+
let claim = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'unspecified';
|
|
29032
|
+
let reason = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'unspecified';
|
|
29033
|
+
super(message, {
|
|
29034
|
+
cause: {
|
|
29035
|
+
claim,
|
|
29036
|
+
reason,
|
|
29037
|
+
payload
|
|
29038
|
+
}
|
|
29039
|
+
});
|
|
29040
|
+
_defineProperty(this, "code", 'ERR_JWT_CLAIM_VALIDATION_FAILED');
|
|
29041
|
+
_defineProperty(this, "claim", void 0);
|
|
29042
|
+
_defineProperty(this, "reason", void 0);
|
|
29043
|
+
_defineProperty(this, "payload", void 0);
|
|
29044
|
+
this.claim = claim;
|
|
28951
29045
|
this.reason = reason;
|
|
28952
|
-
this.
|
|
29046
|
+
this.payload = payload;
|
|
28953
29047
|
}
|
|
28954
|
-
|
|
28955
|
-
|
|
29048
|
+
}
|
|
29049
|
+
_defineProperty(JWTClaimValidationFailed, "code", 'ERR_JWT_CLAIM_VALIDATION_FAILED');
|
|
29050
|
+
class JWTExpired extends JOSEError {
|
|
29051
|
+
constructor(message, payload) {
|
|
29052
|
+
let claim = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'unspecified';
|
|
29053
|
+
let reason = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'unspecified';
|
|
29054
|
+
super(message, {
|
|
29055
|
+
cause: {
|
|
29056
|
+
claim,
|
|
29057
|
+
reason,
|
|
29058
|
+
payload
|
|
29059
|
+
}
|
|
29060
|
+
});
|
|
29061
|
+
_defineProperty(this, "code", 'ERR_JWT_EXPIRED');
|
|
29062
|
+
_defineProperty(this, "claim", void 0);
|
|
29063
|
+
_defineProperty(this, "reason", void 0);
|
|
29064
|
+
_defineProperty(this, "payload", void 0);
|
|
29065
|
+
this.claim = claim;
|
|
29066
|
+
this.reason = reason;
|
|
29067
|
+
this.payload = payload;
|
|
28956
29068
|
}
|
|
28957
|
-
|
|
28958
|
-
|
|
29069
|
+
}
|
|
29070
|
+
_defineProperty(JWTExpired, "code", 'ERR_JWT_EXPIRED');
|
|
29071
|
+
class JOSEAlgNotAllowed extends JOSEError {
|
|
29072
|
+
constructor() {
|
|
29073
|
+
super(...arguments);
|
|
29074
|
+
_defineProperty(this, "code", 'ERR_JOSE_ALG_NOT_ALLOWED');
|
|
28959
29075
|
}
|
|
28960
|
-
}
|
|
28961
|
-
|
|
28962
|
-
|
|
28963
|
-
|
|
28964
|
-
|
|
28965
|
-
|
|
28966
|
-
const view = new DataView(output);
|
|
28967
|
-
const writtenBytes = this.toBinaryInto(view);
|
|
28968
|
-
if (lengthBytes !== writtenBytes) {
|
|
28969
|
-
// @throws-transformer ignore - this should be treated as a "panic" and not be caught
|
|
28970
|
-
throw new Error("".concat(this.constructor.name, ".toBinary: written bytes (").concat(writtenBytes, " bytes) not equal to allocated array buffer length (").concat(lengthBytes, " bytes)."));
|
|
28971
|
-
}
|
|
28972
|
-
return new Uint8Array(output); // FIXME: return uint8array here? Or the arraybuffer?
|
|
29076
|
+
}
|
|
29077
|
+
_defineProperty(JOSEAlgNotAllowed, "code", 'ERR_JOSE_ALG_NOT_ALLOWED');
|
|
29078
|
+
class JOSENotSupported extends JOSEError {
|
|
29079
|
+
constructor() {
|
|
29080
|
+
super(...arguments);
|
|
29081
|
+
_defineProperty(this, "code", 'ERR_JOSE_NOT_SUPPORTED');
|
|
28973
29082
|
}
|
|
28974
|
-
}
|
|
28975
|
-
(
|
|
28976
|
-
|
|
28977
|
-
|
|
28978
|
-
|
|
28979
|
-
|
|
28980
|
-
|
|
28981
|
-
|
|
28982
|
-
super();
|
|
28983
|
-
this.timestamp = timestamp;
|
|
29083
|
+
}
|
|
29084
|
+
_defineProperty(JOSENotSupported, "code", 'ERR_JOSE_NOT_SUPPORTED');
|
|
29085
|
+
class JWEDecryptionFailed extends JOSEError {
|
|
29086
|
+
constructor() {
|
|
29087
|
+
let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'decryption operation failed';
|
|
29088
|
+
let options = arguments.length > 1 ? arguments[1] : undefined;
|
|
29089
|
+
super(message, options);
|
|
29090
|
+
_defineProperty(this, "code", 'ERR_JWE_DECRYPTION_FAILED');
|
|
28984
29091
|
}
|
|
28985
|
-
|
|
28986
|
-
|
|
29092
|
+
}
|
|
29093
|
+
_defineProperty(JWEDecryptionFailed, "code", 'ERR_JWE_DECRYPTION_FAILED');
|
|
29094
|
+
class JWEInvalid extends JOSEError {
|
|
29095
|
+
constructor() {
|
|
29096
|
+
super(...arguments);
|
|
29097
|
+
_defineProperty(this, "code", 'ERR_JWE_INVALID');
|
|
28987
29098
|
}
|
|
28988
|
-
|
|
28989
|
-
|
|
28990
|
-
|
|
28991
|
-
|
|
28992
|
-
|
|
28993
|
-
|
|
28994
|
-
byteIndex += U16_LENGTH_BYTES;
|
|
28995
|
-
dataView.setBigUint64(byteIndex, this.timestamp);
|
|
28996
|
-
byteIndex += U64_LENGTH_BYTES;
|
|
28997
|
-
const totalLengthBytes = this.toBinaryLengthBytes();
|
|
28998
|
-
if (byteIndex !== totalLengthBytes) {
|
|
28999
|
-
// @throws-transformer ignore - this should be treated as a "panic" and not be caught
|
|
29000
|
-
throw new Error("DataTrackUserTimestampExtension.toBinaryInto: Wrote ".concat(byteIndex, " bytes but expected length was ").concat(totalLengthBytes, " bytes"));
|
|
29001
|
-
}
|
|
29002
|
-
return byteIndex;
|
|
29099
|
+
}
|
|
29100
|
+
_defineProperty(JWEInvalid, "code", 'ERR_JWE_INVALID');
|
|
29101
|
+
class JWSInvalid extends JOSEError {
|
|
29102
|
+
constructor() {
|
|
29103
|
+
super(...arguments);
|
|
29104
|
+
_defineProperty(this, "code", 'ERR_JWS_INVALID');
|
|
29003
29105
|
}
|
|
29004
|
-
|
|
29005
|
-
|
|
29006
|
-
|
|
29007
|
-
|
|
29008
|
-
|
|
29009
|
-
|
|
29106
|
+
}
|
|
29107
|
+
_defineProperty(JWSInvalid, "code", 'ERR_JWS_INVALID');
|
|
29108
|
+
class JWTInvalid extends JOSEError {
|
|
29109
|
+
constructor() {
|
|
29110
|
+
super(...arguments);
|
|
29111
|
+
_defineProperty(this, "code", 'ERR_JWT_INVALID');
|
|
29010
29112
|
}
|
|
29011
29113
|
}
|
|
29012
|
-
|
|
29013
|
-
|
|
29014
|
-
|
|
29015
|
-
|
|
29016
|
-
|
|
29017
|
-
this.keyIndex = keyIndex;
|
|
29018
|
-
this.iv = iv;
|
|
29114
|
+
_defineProperty(JWTInvalid, "code", 'ERR_JWT_INVALID');
|
|
29115
|
+
class JWKInvalid extends JOSEError {
|
|
29116
|
+
constructor() {
|
|
29117
|
+
super(...arguments);
|
|
29118
|
+
_defineProperty(this, "code", 'ERR_JWK_INVALID');
|
|
29019
29119
|
}
|
|
29020
|
-
|
|
29021
|
-
|
|
29120
|
+
}
|
|
29121
|
+
_defineProperty(JWKInvalid, "code", 'ERR_JWK_INVALID');
|
|
29122
|
+
class JWKSInvalid extends JOSEError {
|
|
29123
|
+
constructor() {
|
|
29124
|
+
super(...arguments);
|
|
29125
|
+
_defineProperty(this, "code", 'ERR_JWKS_INVALID');
|
|
29022
29126
|
}
|
|
29023
|
-
|
|
29024
|
-
|
|
29025
|
-
|
|
29026
|
-
|
|
29027
|
-
|
|
29028
|
-
|
|
29029
|
-
|
|
29030
|
-
|
|
29031
|
-
byteIndex += U8_LENGTH_BYTES;
|
|
29032
|
-
for (let i = 0; i < this.iv.length; i += 1) {
|
|
29033
|
-
dataView.setUint8(byteIndex, this.iv[i]);
|
|
29034
|
-
byteIndex += U8_LENGTH_BYTES;
|
|
29035
|
-
}
|
|
29036
|
-
const totalLengthBytes = this.toBinaryLengthBytes();
|
|
29037
|
-
if (byteIndex !== totalLengthBytes) {
|
|
29038
|
-
// @throws-transformer ignore - this should be treated as a "panic" and not be caught
|
|
29039
|
-
throw new Error("DataTrackE2eeExtension.toBinaryInto: Wrote ".concat(byteIndex, " bytes but expected length was ").concat(totalLengthBytes, " bytes"));
|
|
29040
|
-
}
|
|
29041
|
-
return byteIndex;
|
|
29127
|
+
}
|
|
29128
|
+
_defineProperty(JWKSInvalid, "code", 'ERR_JWKS_INVALID');
|
|
29129
|
+
class JWKSNoMatchingKey extends JOSEError {
|
|
29130
|
+
constructor() {
|
|
29131
|
+
let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'no applicable key found in the JSON Web Key Set';
|
|
29132
|
+
let options = arguments.length > 1 ? arguments[1] : undefined;
|
|
29133
|
+
super(message, options);
|
|
29134
|
+
_defineProperty(this, "code", 'ERR_JWKS_NO_MATCHING_KEY');
|
|
29042
29135
|
}
|
|
29043
|
-
|
|
29044
|
-
|
|
29045
|
-
|
|
29046
|
-
|
|
29047
|
-
|
|
29048
|
-
|
|
29049
|
-
|
|
29136
|
+
}
|
|
29137
|
+
_defineProperty(JWKSNoMatchingKey, "code", 'ERR_JWKS_NO_MATCHING_KEY');
|
|
29138
|
+
class JWKSMultipleMatchingKeys extends JOSEError {
|
|
29139
|
+
constructor() {
|
|
29140
|
+
let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'multiple matching keys found in the JSON Web Key Set';
|
|
29141
|
+
let options = arguments.length > 1 ? arguments[1] : undefined;
|
|
29142
|
+
super(message, options);
|
|
29143
|
+
_defineProperty(this, Symbol.asyncIterator, void 0);
|
|
29144
|
+
_defineProperty(this, "code", 'ERR_JWKS_MULTIPLE_MATCHING_KEYS');
|
|
29050
29145
|
}
|
|
29051
29146
|
}
|
|
29052
|
-
|
|
29053
|
-
|
|
29054
|
-
class DataTrackExtensions extends Serializable {
|
|
29147
|
+
_defineProperty(JWKSMultipleMatchingKeys, "code", 'ERR_JWKS_MULTIPLE_MATCHING_KEYS');
|
|
29148
|
+
class JWKSTimeout extends JOSEError {
|
|
29055
29149
|
constructor() {
|
|
29056
|
-
let
|
|
29057
|
-
|
|
29058
|
-
|
|
29059
|
-
this
|
|
29150
|
+
let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'request timed out';
|
|
29151
|
+
let options = arguments.length > 1 ? arguments[1] : undefined;
|
|
29152
|
+
super(message, options);
|
|
29153
|
+
_defineProperty(this, "code", 'ERR_JWKS_TIMEOUT');
|
|
29060
29154
|
}
|
|
29061
|
-
|
|
29062
|
-
|
|
29063
|
-
|
|
29064
|
-
|
|
29065
|
-
|
|
29066
|
-
|
|
29067
|
-
|
|
29068
|
-
|
|
29069
|
-
return lengthBytes;
|
|
29155
|
+
}
|
|
29156
|
+
_defineProperty(JWKSTimeout, "code", 'ERR_JWKS_TIMEOUT');
|
|
29157
|
+
class JWSSignatureVerificationFailed extends JOSEError {
|
|
29158
|
+
constructor() {
|
|
29159
|
+
let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'signature verification failed';
|
|
29160
|
+
let options = arguments.length > 1 ? arguments[1] : undefined;
|
|
29161
|
+
super(message, options);
|
|
29162
|
+
_defineProperty(this, "code", 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED');
|
|
29070
29163
|
}
|
|
29071
|
-
|
|
29072
|
-
|
|
29073
|
-
|
|
29074
|
-
|
|
29075
|
-
|
|
29076
|
-
}
|
|
29077
|
-
if (this.userTimestamp) {
|
|
29078
|
-
const userTimestampBytes = this.userTimestamp.toBinaryInto(new DataView(dataView.buffer, dataView.byteOffset + byteIndex));
|
|
29079
|
-
byteIndex += userTimestampBytes;
|
|
29080
|
-
}
|
|
29081
|
-
const totalLengthBytes = this.toBinaryLengthBytes();
|
|
29082
|
-
if (byteIndex !== totalLengthBytes) {
|
|
29083
|
-
// @throws-transformer ignore - this should be treated as a "panic" and not be caught
|
|
29084
|
-
throw new Error("DataTrackExtensions.toBinaryInto: Wrote ".concat(byteIndex, " bytes but expected length was ").concat(totalLengthBytes, " bytes"));
|
|
29085
|
-
}
|
|
29086
|
-
return byteIndex;
|
|
29164
|
+
}
|
|
29165
|
+
_defineProperty(JWSSignatureVerificationFailed, "code", 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED');const isObjectLike = value => typeof value === 'object' && value !== null;
|
|
29166
|
+
function isObject(input) {
|
|
29167
|
+
if (!isObjectLike(input) || Object.prototype.toString.call(input) !== '[object Object]') {
|
|
29168
|
+
return false;
|
|
29087
29169
|
}
|
|
29088
|
-
|
|
29089
|
-
|
|
29090
|
-
|
|
29091
|
-
|
|
29092
|
-
|
|
29093
|
-
|
|
29094
|
-
|
|
29095
|
-
|
|
29096
|
-
|
|
29097
|
-
|
|
29098
|
-
|
|
29099
|
-
|
|
29100
|
-
|
|
29101
|
-
|
|
29102
|
-
|
|
29103
|
-
|
|
29104
|
-
|
|
29105
|
-
|
|
29106
|
-
|
|
29107
|
-
|
|
29108
|
-
|
|
29109
|
-
|
|
29110
|
-
|
|
29111
|
-
|
|
29112
|
-
|
|
29113
|
-
|
|
29114
|
-
|
|
29115
|
-
|
|
29116
|
-
|
|
29117
|
-
|
|
29118
|
-
|
|
29119
|
-
|
|
29120
|
-
|
|
29121
|
-
|
|
29170
|
+
if (Object.getPrototypeOf(input) === null) {
|
|
29171
|
+
return true;
|
|
29172
|
+
}
|
|
29173
|
+
let proto = input;
|
|
29174
|
+
while (Object.getPrototypeOf(proto) !== null) {
|
|
29175
|
+
proto = Object.getPrototypeOf(proto);
|
|
29176
|
+
}
|
|
29177
|
+
return Object.getPrototypeOf(input) === proto;
|
|
29178
|
+
}function decodeJwt(jwt) {
|
|
29179
|
+
if (typeof jwt !== 'string') throw new JWTInvalid('JWTs must use Compact JWS serialization, JWT must be a string');
|
|
29180
|
+
const {
|
|
29181
|
+
1: payload,
|
|
29182
|
+
length
|
|
29183
|
+
} = jwt.split('.');
|
|
29184
|
+
if (length === 5) throw new JWTInvalid('Only JWTs using Compact JWS serialization can be decoded');
|
|
29185
|
+
if (length !== 3) throw new JWTInvalid('Invalid JWT');
|
|
29186
|
+
if (!payload) throw new JWTInvalid('JWTs must contain a payload');
|
|
29187
|
+
let decoded;
|
|
29188
|
+
try {
|
|
29189
|
+
decoded = decode(payload);
|
|
29190
|
+
} catch (_unused) {
|
|
29191
|
+
throw new JWTInvalid('Failed to base64url decode the payload');
|
|
29192
|
+
}
|
|
29193
|
+
let result;
|
|
29194
|
+
try {
|
|
29195
|
+
result = JSON.parse(decoder.decode(decoded));
|
|
29196
|
+
} catch (_unused2) {
|
|
29197
|
+
throw new JWTInvalid('Failed to parse the decoded payload as JSON');
|
|
29198
|
+
}
|
|
29199
|
+
if (!isObject(result)) throw new JWTInvalid('Invalid JWT Claims Set');
|
|
29200
|
+
return result;
|
|
29201
|
+
}const ONE_SECOND_IN_MILLISECONDS = 1000;
|
|
29202
|
+
const ONE_MINUTE_IN_MILLISECONDS = 60 * ONE_SECOND_IN_MILLISECONDS;
|
|
29203
|
+
function isResponseTokenValid(response) {
|
|
29204
|
+
const jwtPayload = decodeTokenPayload(response.participantToken);
|
|
29205
|
+
if (!(jwtPayload === null || jwtPayload === void 0 ? void 0 : jwtPayload.nbf) || !(jwtPayload === null || jwtPayload === void 0 ? void 0 : jwtPayload.exp)) {
|
|
29206
|
+
return true;
|
|
29207
|
+
}
|
|
29208
|
+
const now = new Date();
|
|
29209
|
+
const nbfInMilliseconds = jwtPayload.nbf * ONE_SECOND_IN_MILLISECONDS;
|
|
29210
|
+
const nbfDate = new Date(nbfInMilliseconds);
|
|
29211
|
+
const expInMilliseconds = jwtPayload.exp * ONE_SECOND_IN_MILLISECONDS;
|
|
29212
|
+
const expDate = new Date(expInMilliseconds - ONE_MINUTE_IN_MILLISECONDS);
|
|
29213
|
+
return nbfDate <= now && expDate > now;
|
|
29214
|
+
}
|
|
29215
|
+
/** Given a LiveKit generated participant token, decodes and returns the associated {@link TokenPayload} data. */
|
|
29216
|
+
function decodeTokenPayload(token) {
|
|
29217
|
+
const payload = decodeJwt(token);
|
|
29218
|
+
const {
|
|
29219
|
+
roomConfig
|
|
29220
|
+
} = payload,
|
|
29221
|
+
rest = __rest(payload, ["roomConfig"]);
|
|
29222
|
+
const mappedPayload = Object.assign(Object.assign({}, rest), {
|
|
29223
|
+
roomConfig: payload.roomConfig ? RoomConfiguration.fromJson(payload.roomConfig) : undefined
|
|
29224
|
+
});
|
|
29225
|
+
return mappedPayload;
|
|
29226
|
+
}
|
|
29227
|
+
/** Given two TokenSourceFetchOptions values, check to see if they are deep equal. */
|
|
29228
|
+
function areTokenSourceFetchOptionsEqual(a, b) {
|
|
29229
|
+
const allKeysSet = new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
29230
|
+
for (const key of allKeysSet) {
|
|
29231
|
+
switch (key) {
|
|
29232
|
+
case 'roomName':
|
|
29233
|
+
case 'participantName':
|
|
29234
|
+
case 'participantIdentity':
|
|
29235
|
+
case 'participantMetadata':
|
|
29236
|
+
case 'participantAttributes':
|
|
29237
|
+
case 'agentName':
|
|
29238
|
+
case 'agentMetadata':
|
|
29239
|
+
if (a[key] !== b[key]) {
|
|
29240
|
+
return false;
|
|
29241
|
+
}
|
|
29242
|
+
break;
|
|
29243
|
+
default:
|
|
29244
|
+
// ref: https://stackoverflow.com/a/58009992
|
|
29245
|
+
const exhaustiveCheckedKey = key;
|
|
29246
|
+
throw new Error("Options key ".concat(exhaustiveCheckedKey, " not being checked for equality!"));
|
|
29247
|
+
}
|
|
29248
|
+
}
|
|
29249
|
+
return true;
|
|
29250
|
+
}/** A TokenSourceCached is a TokenSource which caches the last {@link TokenSourceResponseObject} value and returns it
|
|
29251
|
+
* until a) it expires or b) the {@link TokenSourceFetchOptions} provided to .fetch(...) change. */
|
|
29252
|
+
class TokenSourceCached extends TokenSourceConfigurable {
|
|
29253
|
+
constructor() {
|
|
29254
|
+
super(...arguments);
|
|
29255
|
+
this.cachedFetchOptions = null;
|
|
29256
|
+
this.cachedResponse = null;
|
|
29257
|
+
this.fetchMutex = new _();
|
|
29258
|
+
}
|
|
29259
|
+
isSameAsCachedFetchOptions(options) {
|
|
29260
|
+
if (!this.cachedFetchOptions) {
|
|
29261
|
+
return false;
|
|
29262
|
+
}
|
|
29263
|
+
for (const key of Object.keys(this.cachedFetchOptions)) {
|
|
29264
|
+
switch (key) {
|
|
29265
|
+
case 'roomName':
|
|
29266
|
+
case 'participantName':
|
|
29267
|
+
case 'participantIdentity':
|
|
29268
|
+
case 'participantMetadata':
|
|
29269
|
+
case 'participantAttributes':
|
|
29270
|
+
case 'agentName':
|
|
29271
|
+
case 'agentMetadata':
|
|
29272
|
+
if (this.cachedFetchOptions[key] !== options[key]) {
|
|
29273
|
+
return false;
|
|
29122
29274
|
}
|
|
29123
|
-
e2ee = new DataTrackE2eeExtension(keyIndex, iv);
|
|
29124
|
-
byteIndex += lengthBytes;
|
|
29125
29275
|
break;
|
|
29126
29276
|
default:
|
|
29127
|
-
//
|
|
29128
|
-
|
|
29129
|
-
|
|
29130
|
-
}
|
|
29131
|
-
byteIndex += lengthBytes;
|
|
29132
|
-
break;
|
|
29277
|
+
// ref: https://stackoverflow.com/a/58009992
|
|
29278
|
+
const exhaustiveCheckedKey = key;
|
|
29279
|
+
throw new Error("Options key ".concat(exhaustiveCheckedKey, " not being checked for equality!"));
|
|
29133
29280
|
}
|
|
29134
29281
|
}
|
|
29135
|
-
|
|
29136
|
-
return [new DataTrackExtensions({
|
|
29137
|
-
userTimestamp,
|
|
29138
|
-
e2ee
|
|
29139
|
-
}), dataView.byteLength];
|
|
29140
|
-
}
|
|
29141
|
-
toJSON() {
|
|
29142
|
-
var _a, _b, _c, _d;
|
|
29143
|
-
return {
|
|
29144
|
-
userTimestamp: (_b = (_a = this.userTimestamp) === null || _a === void 0 ? void 0 : _a.toJSON()) !== null && _b !== void 0 ? _b : null,
|
|
29145
|
-
e2ee: (_d = (_c = this.e2ee) === null || _c === void 0 ? void 0 : _c.toJSON()) !== null && _d !== void 0 ? _d : null
|
|
29146
|
-
};
|
|
29147
|
-
}
|
|
29148
|
-
}/** A class for serializing / deserializing data track packet header sections. */
|
|
29149
|
-
class DataTrackPacketHeader extends Serializable {
|
|
29150
|
-
constructor(opts) {
|
|
29151
|
-
var _a;
|
|
29152
|
-
super();
|
|
29153
|
-
this.marker = opts.marker;
|
|
29154
|
-
this.trackHandle = opts.trackHandle;
|
|
29155
|
-
this.sequence = opts.sequence;
|
|
29156
|
-
this.frameNumber = opts.frameNumber;
|
|
29157
|
-
this.timestamp = opts.timestamp;
|
|
29158
|
-
this.extensions = (_a = opts.extensions) !== null && _a !== void 0 ? _a : new DataTrackExtensions();
|
|
29159
|
-
}
|
|
29160
|
-
extensionsMetrics() {
|
|
29161
|
-
const lengthBytes = this.extensions.toBinaryLengthBytes();
|
|
29162
|
-
const lengthWords = Math.ceil(lengthBytes / 4);
|
|
29163
|
-
const paddingLengthBytes = lengthWords * 4 - lengthBytes;
|
|
29164
|
-
return {
|
|
29165
|
-
lengthBytes,
|
|
29166
|
-
lengthWords,
|
|
29167
|
-
paddingLengthBytes
|
|
29168
|
-
};
|
|
29282
|
+
return true;
|
|
29169
29283
|
}
|
|
29170
|
-
|
|
29171
|
-
|
|
29172
|
-
|
|
29173
|
-
paddingLengthBytes: extPaddingLengthBytes
|
|
29174
|
-
} = this.extensionsMetrics();
|
|
29175
|
-
let totalLengthBytes = BASE_HEADER_LEN;
|
|
29176
|
-
if (extLengthBytes > 0) {
|
|
29177
|
-
totalLengthBytes += EXT_WORDS_INDICATOR_SIZE + extLengthBytes + extPaddingLengthBytes;
|
|
29284
|
+
shouldReturnCachedValueFromFetch(fetchOptions) {
|
|
29285
|
+
if (!this.cachedResponse) {
|
|
29286
|
+
return false;
|
|
29178
29287
|
}
|
|
29179
|
-
|
|
29180
|
-
|
|
29181
|
-
toBinaryInto(dataView) {
|
|
29182
|
-
if (dataView.byteLength < this.toBinaryLengthBytes()) {
|
|
29183
|
-
throw DataTrackSerializeError.tooSmallForHeader();
|
|
29288
|
+
if (!isResponseTokenValid(this.cachedResponse)) {
|
|
29289
|
+
return false;
|
|
29184
29290
|
}
|
|
29185
|
-
|
|
29186
|
-
|
|
29187
|
-
switch (this.marker) {
|
|
29188
|
-
case FrameMarker.Inter:
|
|
29189
|
-
marker = FRAME_MARKER_INTER;
|
|
29190
|
-
break;
|
|
29191
|
-
case FrameMarker.Final:
|
|
29192
|
-
marker = FRAME_MARKER_FINAL;
|
|
29193
|
-
break;
|
|
29194
|
-
case FrameMarker.Start:
|
|
29195
|
-
marker = FRAME_MARKER_START;
|
|
29196
|
-
break;
|
|
29197
|
-
case FrameMarker.Single:
|
|
29198
|
-
marker = FRAME_MARKER_SINGLE;
|
|
29199
|
-
break;
|
|
29291
|
+
if (this.isSameAsCachedFetchOptions(fetchOptions)) {
|
|
29292
|
+
return false;
|
|
29200
29293
|
}
|
|
29201
|
-
|
|
29202
|
-
|
|
29203
|
-
|
|
29204
|
-
|
|
29205
|
-
|
|
29206
|
-
} = this.extensionsMetrics();
|
|
29207
|
-
if (extensionsLengthBytes > 0) {
|
|
29208
|
-
initial |= 1 << EXT_FLAG_SHIFT;
|
|
29294
|
+
return true;
|
|
29295
|
+
}
|
|
29296
|
+
getCachedResponseJwtPayload() {
|
|
29297
|
+
if (!this.cachedResponse) {
|
|
29298
|
+
return null;
|
|
29209
29299
|
}
|
|
29210
|
-
|
|
29211
|
-
|
|
29212
|
-
|
|
29213
|
-
|
|
29214
|
-
|
|
29215
|
-
|
|
29216
|
-
|
|
29217
|
-
|
|
29218
|
-
|
|
29219
|
-
|
|
29220
|
-
|
|
29221
|
-
|
|
29222
|
-
|
|
29223
|
-
|
|
29224
|
-
|
|
29225
|
-
// deserializer assumes the extensions section is at least one byte long, and the "length"
|
|
29226
|
-
// field represents the "number of additional bytes" long the extensions section is. This is
|
|
29227
|
-
// potentially unintuitive so I wanted to call it out.
|
|
29228
|
-
const rtpOrientedExtensionLengthWords = extensionsLengthWords - 1;
|
|
29229
|
-
dataView.setUint16(byteIndex, rtpOrientedExtensionLengthWords);
|
|
29230
|
-
byteIndex += U16_LENGTH_BYTES;
|
|
29231
|
-
const extensionBytes = this.extensions.toBinaryInto(new DataView(dataView.buffer, dataView.byteOffset + byteIndex));
|
|
29232
|
-
byteIndex += extensionBytes;
|
|
29233
|
-
for (let i = 0; i < extensionsPaddingLengthBytes; i += 1) {
|
|
29234
|
-
dataView.setUint8(byteIndex, 0);
|
|
29235
|
-
byteIndex += U8_LENGTH_BYTES;
|
|
29300
|
+
return decodeTokenPayload(this.cachedResponse.participantToken);
|
|
29301
|
+
}
|
|
29302
|
+
fetch(options) {
|
|
29303
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
29304
|
+
const unlock = yield this.fetchMutex.lock();
|
|
29305
|
+
try {
|
|
29306
|
+
if (this.shouldReturnCachedValueFromFetch(options)) {
|
|
29307
|
+
return this.cachedResponse.toJson();
|
|
29308
|
+
}
|
|
29309
|
+
this.cachedFetchOptions = options;
|
|
29310
|
+
const tokenResponse = yield this.update(options);
|
|
29311
|
+
this.cachedResponse = tokenResponse;
|
|
29312
|
+
return tokenResponse.toJson();
|
|
29313
|
+
} finally {
|
|
29314
|
+
unlock();
|
|
29236
29315
|
}
|
|
29237
|
-
}
|
|
29238
|
-
const totalLengthBytes = this.toBinaryLengthBytes();
|
|
29239
|
-
if (byteIndex !== totalLengthBytes) {
|
|
29240
|
-
// @throws-transformer ignore - this should be treated as a "panic" and not be caught
|
|
29241
|
-
throw new Error("DataTrackPacketHeader.toBinaryInto: Wrote ".concat(byteIndex, " bytes but expected length was ").concat(totalLengthBytes, " bytes"));
|
|
29242
|
-
}
|
|
29243
|
-
return totalLengthBytes;
|
|
29316
|
+
});
|
|
29244
29317
|
}
|
|
29245
|
-
|
|
29246
|
-
|
|
29247
|
-
|
|
29248
|
-
|
|
29249
|
-
|
|
29250
|
-
|
|
29251
|
-
|
|
29252
|
-
|
|
29253
|
-
|
|
29254
|
-
|
|
29255
|
-
throw DataTrackDeserializeError.unsupportedVersion(version);
|
|
29256
|
-
}
|
|
29257
|
-
let marker;
|
|
29258
|
-
switch (initial >> FRAME_MARKER_SHIFT & FRAME_MARKER_MASK) {
|
|
29259
|
-
case FRAME_MARKER_START:
|
|
29260
|
-
marker = FrameMarker.Start;
|
|
29261
|
-
break;
|
|
29262
|
-
case FRAME_MARKER_FINAL:
|
|
29263
|
-
marker = FrameMarker.Final;
|
|
29264
|
-
break;
|
|
29265
|
-
case FRAME_MARKER_SINGLE:
|
|
29266
|
-
marker = FrameMarker.Single;
|
|
29267
|
-
break;
|
|
29268
|
-
case FRAME_MARKER_INTER:
|
|
29269
|
-
default:
|
|
29270
|
-
marker = FrameMarker.Inter;
|
|
29271
|
-
break;
|
|
29272
|
-
}
|
|
29273
|
-
const extensionsFlag = (initial >> EXT_FLAG_SHIFT & EXT_FLAG_MASK) > 0;
|
|
29274
|
-
byteIndex += U8_LENGTH_BYTES; // Reserved
|
|
29275
|
-
let trackHandle;
|
|
29276
|
-
try {
|
|
29277
|
-
trackHandle = DataTrackHandle.fromNumber(dataView.getUint16(byteIndex));
|
|
29278
|
-
} catch (e) {
|
|
29279
|
-
if (e instanceof DataTrackHandleError && (e.isReason(DataTrackHandleErrorReason.Reserved) || e.isReason(DataTrackHandleErrorReason.TooLarge))) {
|
|
29280
|
-
throw DataTrackDeserializeError.invalidHandle(e);
|
|
29318
|
+
}
|
|
29319
|
+
class TokenSourceLiteral extends TokenSourceFixed {
|
|
29320
|
+
constructor(literalOrFn) {
|
|
29321
|
+
super();
|
|
29322
|
+
this.literalOrFn = literalOrFn;
|
|
29323
|
+
}
|
|
29324
|
+
fetch() {
|
|
29325
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
29326
|
+
if (typeof this.literalOrFn === 'function') {
|
|
29327
|
+
return this.literalOrFn();
|
|
29281
29328
|
} else {
|
|
29282
|
-
|
|
29283
|
-
}
|
|
29284
|
-
}
|
|
29285
|
-
byteIndex += U16_LENGTH_BYTES;
|
|
29286
|
-
const sequence = WrapAroundUnsignedInt.u16(dataView.getUint16(byteIndex));
|
|
29287
|
-
byteIndex += U16_LENGTH_BYTES;
|
|
29288
|
-
const frameNumber = WrapAroundUnsignedInt.u16(dataView.getUint16(byteIndex));
|
|
29289
|
-
byteIndex += U16_LENGTH_BYTES;
|
|
29290
|
-
const timestamp = DataTrackTimestamp.fromRtpTicks(dataView.getUint32(byteIndex));
|
|
29291
|
-
byteIndex += U32_LENGTH_BYTES;
|
|
29292
|
-
let extensions = new DataTrackExtensions();
|
|
29293
|
-
if (extensionsFlag) {
|
|
29294
|
-
if (dataView.byteLength - byteIndex < U16_LENGTH_BYTES) {
|
|
29295
|
-
throw DataTrackDeserializeError.missingExtWords();
|
|
29329
|
+
return this.literalOrFn;
|
|
29296
29330
|
}
|
|
29297
|
-
|
|
29298
|
-
|
|
29299
|
-
|
|
29300
|
-
|
|
29301
|
-
|
|
29302
|
-
|
|
29303
|
-
|
|
29304
|
-
|
|
29305
|
-
|
|
29306
|
-
|
|
29331
|
+
});
|
|
29332
|
+
}
|
|
29333
|
+
}
|
|
29334
|
+
class TokenSourceCustom extends TokenSourceCached {
|
|
29335
|
+
constructor(customFn) {
|
|
29336
|
+
super();
|
|
29337
|
+
this.customFn = customFn;
|
|
29338
|
+
}
|
|
29339
|
+
update(options) {
|
|
29340
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
29341
|
+
const resultMaybePromise = this.customFn(options);
|
|
29342
|
+
let result;
|
|
29343
|
+
if (resultMaybePromise instanceof Promise) {
|
|
29344
|
+
result = yield resultMaybePromise;
|
|
29345
|
+
} else {
|
|
29346
|
+
result = resultMaybePromise;
|
|
29347
|
+
}
|
|
29348
|
+
return TokenSourceResponse.fromJson(result, {
|
|
29349
|
+
// NOTE: it could be possible that the response body could contain more fields than just
|
|
29350
|
+
// what's in TokenSourceResponse depending on the implementation
|
|
29351
|
+
ignoreUnknownFields: true
|
|
29352
|
+
});
|
|
29353
|
+
});
|
|
29354
|
+
}
|
|
29355
|
+
}
|
|
29356
|
+
class TokenSourceEndpoint extends TokenSourceCached {
|
|
29357
|
+
constructor(url) {
|
|
29358
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
29359
|
+
super();
|
|
29360
|
+
this.url = url;
|
|
29361
|
+
this.endpointOptions = options;
|
|
29362
|
+
}
|
|
29363
|
+
createRequestFromOptions(options) {
|
|
29364
|
+
var _a, _b, _c;
|
|
29365
|
+
const request = new TokenSourceRequest();
|
|
29366
|
+
for (const key of Object.keys(options)) {
|
|
29367
|
+
switch (key) {
|
|
29368
|
+
case 'roomName':
|
|
29369
|
+
case 'participantName':
|
|
29370
|
+
case 'participantIdentity':
|
|
29371
|
+
case 'participantMetadata':
|
|
29372
|
+
request[key] = options[key];
|
|
29373
|
+
break;
|
|
29374
|
+
case 'participantAttributes':
|
|
29375
|
+
request.participantAttributes = (_a = options.participantAttributes) !== null && _a !== void 0 ? _a : {};
|
|
29376
|
+
break;
|
|
29377
|
+
case 'agentName':
|
|
29378
|
+
request.roomConfig = (_b = request.roomConfig) !== null && _b !== void 0 ? _b : new RoomConfiguration();
|
|
29379
|
+
if (request.roomConfig.agents.length === 0) {
|
|
29380
|
+
request.roomConfig.agents.push(new RoomAgentDispatch());
|
|
29381
|
+
}
|
|
29382
|
+
request.roomConfig.agents[0].agentName = options.agentName;
|
|
29383
|
+
break;
|
|
29384
|
+
case 'agentMetadata':
|
|
29385
|
+
request.roomConfig = (_c = request.roomConfig) !== null && _c !== void 0 ? _c : new RoomConfiguration();
|
|
29386
|
+
if (request.roomConfig.agents.length === 0) {
|
|
29387
|
+
request.roomConfig.agents.push(new RoomAgentDispatch());
|
|
29388
|
+
}
|
|
29389
|
+
request.roomConfig.agents[0].metadata = options.agentMetadata;
|
|
29390
|
+
break;
|
|
29391
|
+
default:
|
|
29392
|
+
// ref: https://stackoverflow.com/a/58009992
|
|
29393
|
+
const exhaustiveCheckedKey = key;
|
|
29394
|
+
throw new Error("Options key ".concat(exhaustiveCheckedKey, " not being included in forming request!"));
|
|
29307
29395
|
}
|
|
29308
|
-
let extensionDataView = new DataView(dataView.buffer, dataView.byteOffset + byteIndex, extensionLengthBytes);
|
|
29309
|
-
const [result, readBytes] = DataTrackExtensions.fromBinary(extensionDataView);
|
|
29310
|
-
extensions = result;
|
|
29311
|
-
byteIndex += readBytes;
|
|
29312
29396
|
}
|
|
29313
|
-
return
|
|
29314
|
-
marker,
|
|
29315
|
-
trackHandle: trackHandle,
|
|
29316
|
-
sequence,
|
|
29317
|
-
frameNumber,
|
|
29318
|
-
timestamp,
|
|
29319
|
-
extensions
|
|
29320
|
-
}), byteIndex];
|
|
29397
|
+
return request;
|
|
29321
29398
|
}
|
|
29322
|
-
|
|
29323
|
-
return {
|
|
29324
|
-
|
|
29325
|
-
|
|
29326
|
-
|
|
29327
|
-
|
|
29328
|
-
|
|
29329
|
-
|
|
29330
|
-
|
|
29399
|
+
update(options) {
|
|
29400
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
29401
|
+
var _a;
|
|
29402
|
+
const request = this.createRequestFromOptions(options);
|
|
29403
|
+
const response = yield fetch(this.url, Object.assign(Object.assign({}, this.endpointOptions), {
|
|
29404
|
+
method: (_a = this.endpointOptions.method) !== null && _a !== void 0 ? _a : 'POST',
|
|
29405
|
+
headers: Object.assign({
|
|
29406
|
+
'Content-Type': 'application/json'
|
|
29407
|
+
}, this.endpointOptions.headers),
|
|
29408
|
+
body: request.toJsonString({
|
|
29409
|
+
useProtoFieldName: true
|
|
29410
|
+
})
|
|
29411
|
+
}));
|
|
29412
|
+
if (!response.ok) {
|
|
29413
|
+
throw new Error("Error generating token from endpoint ".concat(this.url, ": received ").concat(response.status, " / ").concat(yield response.text()));
|
|
29414
|
+
}
|
|
29415
|
+
const body = yield response.json();
|
|
29416
|
+
return TokenSourceResponse.fromJson(body, {
|
|
29417
|
+
// NOTE: it could be possible that the response body could contain more fields than just
|
|
29418
|
+
// what's in TokenSourceResponse depending on the implementation (ie, SandboxTokenServer)
|
|
29419
|
+
ignoreUnknownFields: true
|
|
29420
|
+
});
|
|
29421
|
+
});
|
|
29331
29422
|
}
|
|
29332
29423
|
}
|
|
29333
|
-
|
|
29334
|
-
|
|
29335
|
-
|
|
29336
|
-
|
|
29337
|
-
|
|
29338
|
-
|
|
29339
|
-
|
|
29340
|
-
|
|
29341
|
-
|
|
29342
|
-
|
|
29343
|
-
|
|
29344
|
-
})(FrameMarker || (FrameMarker = {}));
|
|
29345
|
-
/** A class for serializing / deserializing data track packets. */
|
|
29346
|
-
class DataTrackPacket extends Serializable {
|
|
29347
|
-
constructor(header, payload) {
|
|
29348
|
-
super();
|
|
29349
|
-
this.header = header;
|
|
29350
|
-
this.payload = payload;
|
|
29424
|
+
class TokenSourceSandboxTokenServer extends TokenSourceEndpoint {
|
|
29425
|
+
constructor(sandboxId, options) {
|
|
29426
|
+
const {
|
|
29427
|
+
baseUrl = 'https://cloud-api.livekit.io'
|
|
29428
|
+
} = options,
|
|
29429
|
+
rest = __rest(options, ["baseUrl"]);
|
|
29430
|
+
super("".concat(baseUrl, "/api/v2/sandbox/connection-details"), Object.assign(Object.assign({}, rest), {
|
|
29431
|
+
headers: {
|
|
29432
|
+
'X-Sandbox-ID': sandboxId
|
|
29433
|
+
}
|
|
29434
|
+
}));
|
|
29351
29435
|
}
|
|
29352
|
-
|
|
29353
|
-
|
|
29436
|
+
}
|
|
29437
|
+
const TokenSource = {
|
|
29438
|
+
/** TokenSource.literal contains a single, literal set of {@link TokenSourceResponseObject}
|
|
29439
|
+
* credentials, either provided directly or returned from a provided function. */
|
|
29440
|
+
literal(literalOrFn) {
|
|
29441
|
+
return new TokenSourceLiteral(literalOrFn);
|
|
29442
|
+
},
|
|
29443
|
+
/**
|
|
29444
|
+
* TokenSource.custom allows a user to define a manual function which generates new
|
|
29445
|
+
* {@link TokenSourceResponseObject} values on demand.
|
|
29446
|
+
*
|
|
29447
|
+
* Use this to get credentials from custom backends / etc.
|
|
29448
|
+
*/
|
|
29449
|
+
custom(customFn) {
|
|
29450
|
+
return new TokenSourceCustom(customFn);
|
|
29451
|
+
},
|
|
29452
|
+
/**
|
|
29453
|
+
* TokenSource.endpoint creates a token source that fetches credentials from a given URL using
|
|
29454
|
+
* the standard endpoint format:
|
|
29455
|
+
* @see https://cloud.livekit.io/projects/p_/sandbox/templates/token-server
|
|
29456
|
+
*/
|
|
29457
|
+
endpoint(url) {
|
|
29458
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
29459
|
+
return new TokenSourceEndpoint(url, options);
|
|
29460
|
+
},
|
|
29461
|
+
/**
|
|
29462
|
+
* TokenSource.sandboxTokenServer queries a sandbox token server for credentials,
|
|
29463
|
+
* which supports quick prototyping / getting started types of use cases.
|
|
29464
|
+
*
|
|
29465
|
+
* This token provider is INSECURE and should NOT be used in production.
|
|
29466
|
+
*
|
|
29467
|
+
* For more info:
|
|
29468
|
+
* @see https://cloud.livekit.io/projects/p_/sandbox/templates/token-server
|
|
29469
|
+
*/
|
|
29470
|
+
sandboxTokenServer(sandboxId) {
|
|
29471
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
29472
|
+
return new TokenSourceSandboxTokenServer(sandboxId, options);
|
|
29354
29473
|
}
|
|
29355
|
-
|
|
29356
|
-
|
|
29357
|
-
|
|
29358
|
-
|
|
29359
|
-
|
|
29360
|
-
|
|
29361
|
-
|
|
29362
|
-
|
|
29363
|
-
|
|
29364
|
-
|
|
29365
|
-
|
|
29474
|
+
};/**
|
|
29475
|
+
* Try to analyze the local track to determine the facing mode of a track.
|
|
29476
|
+
*
|
|
29477
|
+
* @remarks
|
|
29478
|
+
* There is no property supported by all browsers to detect whether a video track originated from a user- or environment-facing camera device.
|
|
29479
|
+
* For this reason, we use the `facingMode` property when available, but will fall back on a string-based analysis of the device label to determine the facing mode.
|
|
29480
|
+
* If both methods fail, the default facing mode will be used.
|
|
29481
|
+
*
|
|
29482
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints/facingMode | MDN docs on facingMode}
|
|
29483
|
+
* @experimental
|
|
29484
|
+
*/
|
|
29485
|
+
function facingModeFromLocalTrack(localTrack) {
|
|
29486
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
29487
|
+
var _a;
|
|
29488
|
+
const track = isLocalTrack(localTrack) ? localTrack.mediaStreamTrack : localTrack;
|
|
29489
|
+
const trackSettings = track.getSettings();
|
|
29490
|
+
let result = {
|
|
29491
|
+
facingMode: (_a = options.defaultFacingMode) !== null && _a !== void 0 ? _a : 'user',
|
|
29492
|
+
confidence: 'low'
|
|
29493
|
+
};
|
|
29494
|
+
// 1. Try to get facingMode from track settings.
|
|
29495
|
+
if ('facingMode' in trackSettings) {
|
|
29496
|
+
const rawFacingMode = trackSettings.facingMode;
|
|
29497
|
+
livekitLogger.trace('rawFacingMode', {
|
|
29498
|
+
rawFacingMode
|
|
29499
|
+
});
|
|
29500
|
+
if (rawFacingMode && typeof rawFacingMode === 'string' && isFacingModeValue(rawFacingMode)) {
|
|
29501
|
+
result = {
|
|
29502
|
+
facingMode: rawFacingMode,
|
|
29503
|
+
confidence: 'high'
|
|
29504
|
+
};
|
|
29366
29505
|
}
|
|
29367
|
-
|
|
29368
|
-
|
|
29369
|
-
|
|
29370
|
-
|
|
29506
|
+
}
|
|
29507
|
+
// 2. If we don't have a high confidence we try to get the facing mode from the device label.
|
|
29508
|
+
if (['low', 'medium'].includes(result.confidence)) {
|
|
29509
|
+
livekitLogger.trace("Try to get facing mode from device label: (".concat(track.label, ")"));
|
|
29510
|
+
const labelAnalysisResult = facingModeFromDeviceLabel(track.label);
|
|
29511
|
+
if (labelAnalysisResult !== undefined) {
|
|
29512
|
+
result = labelAnalysisResult;
|
|
29371
29513
|
}
|
|
29372
|
-
return totalLengthBytes;
|
|
29373
29514
|
}
|
|
29374
|
-
|
|
29375
|
-
|
|
29376
|
-
|
|
29377
|
-
|
|
29378
|
-
|
|
29515
|
+
return result;
|
|
29516
|
+
}
|
|
29517
|
+
const knownDeviceLabels = new Map([['obs virtual camera', {
|
|
29518
|
+
facingMode: 'environment',
|
|
29519
|
+
confidence: 'medium'
|
|
29520
|
+
}]]);
|
|
29521
|
+
const knownDeviceLabelSections = new Map([['iphone', {
|
|
29522
|
+
facingMode: 'environment',
|
|
29523
|
+
confidence: 'medium'
|
|
29524
|
+
}], ['ipad', {
|
|
29525
|
+
facingMode: 'environment',
|
|
29526
|
+
confidence: 'medium'
|
|
29527
|
+
}]]);
|
|
29528
|
+
/**
|
|
29529
|
+
* Attempt to analyze the device label to determine the facing mode.
|
|
29530
|
+
*
|
|
29531
|
+
* @experimental
|
|
29532
|
+
*/
|
|
29533
|
+
function facingModeFromDeviceLabel(deviceLabel) {
|
|
29534
|
+
var _a;
|
|
29535
|
+
const label = deviceLabel.trim().toLowerCase();
|
|
29536
|
+
// Empty string is a valid device label but we can't infer anything from it.
|
|
29537
|
+
if (label === '') {
|
|
29538
|
+
return undefined;
|
|
29379
29539
|
}
|
|
29380
|
-
|
|
29381
|
-
|
|
29382
|
-
|
|
29383
|
-
payload: this.payload
|
|
29384
|
-
};
|
|
29540
|
+
// Can we match against widely known device labels.
|
|
29541
|
+
if (knownDeviceLabels.has(label)) {
|
|
29542
|
+
return knownDeviceLabels.get(label);
|
|
29385
29543
|
}
|
|
29544
|
+
// Can we match against sections of the device label.
|
|
29545
|
+
return (_a = Array.from(knownDeviceLabelSections.entries()).find(_ref => {
|
|
29546
|
+
let [section] = _ref;
|
|
29547
|
+
return label.includes(section);
|
|
29548
|
+
})) === null || _a === void 0 ? void 0 : _a[1];
|
|
29549
|
+
}
|
|
29550
|
+
function isFacingModeValue(item) {
|
|
29551
|
+
const allowedValues = ['user', 'environment', 'left', 'right'];
|
|
29552
|
+
return item === undefined || allowedValues.includes(item);
|
|
29386
29553
|
}export{AudioPresets,BackupCodecPolicy,BaseKeyProvider,CheckStatus,Checker,ConnectionCheck,ConnectionError,ConnectionErrorReason,ConnectionQuality,ConnectionState,CriticalTimers,CryptorError,CryptorErrorReason,CryptorEvent,DataPacket_Kind,DataStreamError,DataStreamErrorReason,DataTrackPacket,DefaultReconnectPolicy,DeviceUnsupportedError,DisconnectReason,EncryptionEvent,Encryption_Type,EngineEvent,ExternalE2EEKeyProvider,KeyHandlerEvent,KeyProviderEvent,LivekitError,LivekitReasonedError,LocalAudioTrack,LocalParticipant,LocalTrack,LocalTrackPublication,LocalTrackRecorder,LocalVideoTrack,LogLevel,LoggerNames,MediaDeviceFailure,_ as Mutex,NegotiationError,Participant,ParticipantEvent,ParticipantInfo_Kind as ParticipantKind,PublishDataError,PublishTrackError,RemoteAudioTrack,RemoteParticipant,RemoteTrack,RemoteTrackPublication,RemoteVideoTrack,Room,RoomEvent,RpcError,ScreenSharePresets,SignalReconnectError,SignalRequestError,SimulatedError,SubscriptionError,TokenSource,TokenSourceConfigurable,TokenSourceFixed,Track,TrackEvent,TrackInvalidError,TrackPublication,TrackType,UnexpectedConnectionState,UnsupportedServer,VideoPreset,VideoPresets,VideoPresets43,VideoQuality,areTokenSourceFetchOptionsEqual,asEncryptablePacket,attachToElement,attributeTypings as attributes,audioCodecs,compareVersions,createAudioAnalyser,createE2EEKey,createKeyMaterialFromBuffer,createKeyMaterialFromString,createLocalAudioTrack,createLocalScreenTracks,createLocalTracks,createLocalVideoTrack,decodeTokenPayload,deriveKeys,detachTrack,facingModeFromDeviceLabel,facingModeFromLocalTrack,getBrowser,getEmptyAudioStreamTrack,getEmptyVideoStreamTrack,getLogger,importKey,isAudioCodec,isAudioTrack,isBackupCodec,isBackupVideoCodec,isBrowserSupported,isE2EESupported,isInsertableStreamSupported,isLocalParticipant,isLocalTrack,isRemoteParticipant,isRemoteTrack,isScriptTransformSupported,isVideoCodec,isVideoFrame,isVideoTrack,needsRbspUnescaping,parseRbsp,protocolVersion,ratchet,setLogExtension,setLogLevel,supportsAV1,supportsAdaptiveStream,supportsAudioOutputSelection,supportsDynacast,supportsVP9,version,videoCodecs,writeRbsp};//# sourceMappingURL=livekit-client.esm.mjs.map
|