livekit-client 2.15.4 → 2.15.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/livekit-client.e2ee.worker.js +1 -1
- package/dist/livekit-client.e2ee.worker.js.map +1 -1
- package/dist/livekit-client.e2ee.worker.mjs +373 -164
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +982 -643
- 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.map +1 -1
- package/dist/src/e2ee/worker/FrameCryptor.d.ts +0 -47
- package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/naluUtils.d.ts +27 -0
- package/dist/src/e2ee/worker/naluUtils.d.ts.map +1 -0
- package/dist/src/e2ee/worker/sifPayload.d.ts +22 -0
- package/dist/src/e2ee/worker/sifPayload.d.ts.map +1 -0
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +6 -10
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts +20 -0
- package/dist/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts.map +1 -0
- package/dist/{ts4.2/src/room → src/room/data-stream/incoming}/StreamReader.d.ts +82 -56
- package/dist/src/room/data-stream/incoming/StreamReader.d.ts.map +1 -0
- package/dist/src/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts +27 -0
- package/dist/src/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts.map +1 -0
- package/dist/src/room/{StreamWriter.d.ts → data-stream/outgoing/StreamWriter.d.ts} +1 -1
- package/dist/src/room/data-stream/outgoing/StreamWriter.d.ts.map +1 -0
- package/dist/src/room/errors.d.ts +13 -0
- package/dist/src/room/errors.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +32 -19
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +7 -2
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteVideoTrack.d.ts +1 -0
- package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts +4 -1
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/types.d.ts +17 -1
- package/dist/src/room/types.d.ts.map +1 -1
- package/dist/src/room/utils.d.ts +8 -0
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/ts4.2/src/e2ee/worker/FrameCryptor.d.ts +0 -47
- package/dist/ts4.2/src/e2ee/worker/naluUtils.d.ts +27 -0
- package/dist/ts4.2/src/e2ee/worker/sifPayload.d.ts +22 -0
- package/dist/ts4.2/src/index.d.ts +2 -2
- package/dist/ts4.2/src/room/Room.d.ts +6 -10
- package/dist/ts4.2/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts +20 -0
- package/dist/{src/room → ts4.2/src/room/data-stream/incoming}/StreamReader.d.ts +82 -56
- package/dist/ts4.2/src/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts +27 -0
- package/dist/ts4.2/src/room/{StreamWriter.d.ts → data-stream/outgoing/StreamWriter.d.ts} +1 -1
- package/dist/ts4.2/src/room/errors.d.ts +13 -0
- package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +32 -19
- package/dist/ts4.2/src/room/track/LocalTrack.d.ts +7 -2
- package/dist/ts4.2/src/room/track/RemoteVideoTrack.d.ts +1 -0
- package/dist/ts4.2/src/room/track/Track.d.ts +4 -1
- package/dist/ts4.2/src/room/types.d.ts +17 -1
- package/dist/ts4.2/src/room/utils.d.ts +8 -0
- package/package.json +7 -7
- package/src/e2ee/E2eeManager.ts +18 -1
- package/src/e2ee/worker/FrameCryptor.ts +56 -157
- package/src/e2ee/worker/e2ee.worker.ts +6 -1
- package/src/e2ee/worker/naluUtils.ts +328 -0
- package/src/e2ee/worker/sifPayload.ts +75 -0
- package/src/index.ts +2 -2
- package/src/room/Room.ts +104 -208
- package/src/room/data-stream/incoming/IncomingDataStreamManager.ts +247 -0
- package/src/room/data-stream/incoming/StreamReader.ts +317 -0
- package/src/room/data-stream/outgoing/OutgoingDataStreamManager.ts +316 -0
- package/src/room/{StreamWriter.ts → data-stream/outgoing/StreamWriter.ts} +1 -1
- package/src/room/errors.ts +34 -0
- package/src/room/participant/LocalParticipant.ts +39 -295
- package/src/room/track/LocalAudioTrack.ts +2 -2
- package/src/room/track/LocalTrack.ts +70 -50
- package/src/room/track/RemoteVideoTrack.ts +12 -2
- package/src/room/track/Track.ts +10 -1
- package/src/room/types.ts +22 -1
- package/src/room/utils.ts +14 -5
- package/dist/src/e2ee/worker/SifGuard.d.ts +0 -11
- package/dist/src/e2ee/worker/SifGuard.d.ts.map +0 -1
- package/dist/src/room/StreamReader.d.ts.map +0 -1
- package/dist/src/room/StreamWriter.d.ts.map +0 -1
- package/dist/ts4.2/src/e2ee/worker/SifGuard.d.ts +0 -11
- package/src/e2ee/worker/SifGuard.ts +0 -47
- package/src/room/StreamReader.ts +0 -170
@@ -10617,6 +10617,30 @@ class SignalRequestError extends LivekitError {
|
|
10617
10617
|
this.reasonName = typeof reason === 'string' ? reason : RequestResponse_Reason[reason];
|
10618
10618
|
}
|
10619
10619
|
}
|
10620
|
+
// NOTE: matches with https://github.com/livekit/client-sdk-swift/blob/f37bbd260d61e165084962db822c79f995f1a113/Sources/LiveKit/DataStream/StreamError.swift#L17
|
10621
|
+
var DataStreamErrorReason;
|
10622
|
+
(function (DataStreamErrorReason) {
|
10623
|
+
// Unable to open a stream with the same ID more than once.
|
10624
|
+
DataStreamErrorReason[DataStreamErrorReason["AlreadyOpened"] = 0] = "AlreadyOpened";
|
10625
|
+
// Stream closed abnormally by remote participant.
|
10626
|
+
DataStreamErrorReason[DataStreamErrorReason["AbnormalEnd"] = 1] = "AbnormalEnd";
|
10627
|
+
// Incoming chunk data could not be decoded.
|
10628
|
+
DataStreamErrorReason[DataStreamErrorReason["DecodeFailed"] = 2] = "DecodeFailed";
|
10629
|
+
// Read length exceeded total length specified in stream header.
|
10630
|
+
DataStreamErrorReason[DataStreamErrorReason["LengthExceeded"] = 3] = "LengthExceeded";
|
10631
|
+
// Read length less than total length specified in stream header.
|
10632
|
+
DataStreamErrorReason[DataStreamErrorReason["Incomplete"] = 4] = "Incomplete";
|
10633
|
+
// Unable to register a stream handler more than once.
|
10634
|
+
DataStreamErrorReason[DataStreamErrorReason["HandlerAlreadyRegistered"] = 7] = "HandlerAlreadyRegistered";
|
10635
|
+
})(DataStreamErrorReason || (DataStreamErrorReason = {}));
|
10636
|
+
class DataStreamError extends LivekitError {
|
10637
|
+
constructor(message, reason) {
|
10638
|
+
super(16, message);
|
10639
|
+
this.name = 'DataStreamError';
|
10640
|
+
this.reason = reason;
|
10641
|
+
this.reasonName = DataStreamErrorReason[reason];
|
10642
|
+
}
|
10643
|
+
}
|
10620
10644
|
var MediaDeviceFailure;
|
10621
10645
|
(function (MediaDeviceFailure) {
|
10622
10646
|
// user rejected permissions
|
@@ -11364,7 +11388,7 @@ function getOSVersion(ua) {
|
|
11364
11388
|
return ua.includes('mac os') ? getMatch(/\(.+?(\d+_\d+(:?_\d+)?)/, ua, 1).replace(/_/g, '.') : undefined;
|
11365
11389
|
}
|
11366
11390
|
|
11367
|
-
var version$1 = "2.15.
|
11391
|
+
var version$1 = "2.15.6";
|
11368
11392
|
|
11369
11393
|
const version = version$1;
|
11370
11394
|
const protocolVersion = 16;
|
@@ -11401,17 +11425,24 @@ var VideoQuality;
|
|
11401
11425
|
VideoQuality[VideoQuality["HIGH"] = 2] = "HIGH";
|
11402
11426
|
})(VideoQuality || (VideoQuality = {}));
|
11403
11427
|
class Track extends eventsExports.EventEmitter {
|
11428
|
+
/**
|
11429
|
+
* indicates current state of stream, it'll indicate `paused` if the track
|
11430
|
+
* has been paused by congestion controller
|
11431
|
+
*/
|
11432
|
+
get streamState() {
|
11433
|
+
return this._streamState;
|
11434
|
+
}
|
11435
|
+
/** @internal */
|
11436
|
+
setStreamState(value) {
|
11437
|
+
this._streamState = value;
|
11438
|
+
}
|
11404
11439
|
constructor(mediaTrack, kind) {
|
11405
11440
|
let loggerOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
11406
11441
|
var _a;
|
11407
11442
|
super();
|
11408
11443
|
this.attachedElements = [];
|
11409
11444
|
this.isMuted = false;
|
11410
|
-
|
11411
|
-
* indicates current state of stream, it'll indicate `paused` if the track
|
11412
|
-
* has been paused by congestion controller
|
11413
|
-
*/
|
11414
|
-
this.streamState = Track.StreamState.Active;
|
11445
|
+
this._streamState = Track.StreamState.Active;
|
11415
11446
|
this.isInBackground = false;
|
11416
11447
|
this._currentBitrate = 0;
|
11417
11448
|
this.log = livekitLogger;
|
@@ -11904,8 +11935,9 @@ function supportsAV1() {
|
|
11904
11935
|
if (!('getCapabilities' in RTCRtpSender)) {
|
11905
11936
|
return false;
|
11906
11937
|
}
|
11907
|
-
if (isSafari()) {
|
11938
|
+
if (isSafari() || isFireFox()) {
|
11908
11939
|
// Safari 17 on iPhone14 reports AV1 capability, but does not actually support it
|
11940
|
+
// Firefox does support AV1, but SVC publishing is not supported
|
11909
11941
|
return false;
|
11910
11942
|
}
|
11911
11943
|
const capabilities = RTCRtpSender.getCapabilities('video');
|
@@ -12007,9 +12039,9 @@ function isE2EESimulcastSupported() {
|
|
12007
12039
|
if (browser) {
|
12008
12040
|
if (browser.name !== 'Safari' && browser.os !== 'iOS') {
|
12009
12041
|
return true;
|
12010
|
-
} else if (browser.os === 'iOS' && browser.osVersion && compareVersions(
|
12042
|
+
} else if (browser.os === 'iOS' && browser.osVersion && compareVersions(browser.osVersion, supportedSafariVersion) >= 0) {
|
12011
12043
|
return true;
|
12012
|
-
} else if (browser.name === 'Safari' && compareVersions(
|
12044
|
+
} else if (browser.name === 'Safari' && compareVersions(browser.version, supportedSafariVersion) >= 0) {
|
12013
12045
|
return true;
|
12014
12046
|
} else {
|
12015
12047
|
return false;
|
@@ -12057,6 +12089,14 @@ function getDevicePixelRatio() {
|
|
12057
12089
|
}
|
12058
12090
|
return 1;
|
12059
12091
|
}
|
12092
|
+
/**
|
12093
|
+
* @param v1 - The first version string to compare.
|
12094
|
+
* @param v2 - The second version string to compare.
|
12095
|
+
* @returns A number indicating the order of the versions:
|
12096
|
+
* - 1 if v1 is greater than v2
|
12097
|
+
* - -1 if v1 is less than v2
|
12098
|
+
* - 0 if v1 and v2 are equal
|
12099
|
+
*/
|
12060
12100
|
function compareVersions(v1, v2) {
|
12061
12101
|
const parts1 = v1.split('.');
|
12062
12102
|
const parts2 = v2.split('.');
|
@@ -12246,13 +12286,13 @@ function unwrapConstraint(constraint) {
|
|
12246
12286
|
if (Array.isArray(constraint)) {
|
12247
12287
|
return constraint[0];
|
12248
12288
|
}
|
12249
|
-
if (constraint.exact) {
|
12289
|
+
if (constraint.exact !== undefined) {
|
12250
12290
|
if (Array.isArray(constraint.exact)) {
|
12251
12291
|
return constraint.exact[0];
|
12252
12292
|
}
|
12253
12293
|
return constraint.exact;
|
12254
12294
|
}
|
12255
|
-
if (constraint.ideal) {
|
12295
|
+
if (constraint.ideal !== undefined) {
|
12256
12296
|
if (Array.isArray(constraint.ideal)) {
|
12257
12297
|
return constraint.ideal[0];
|
12258
12298
|
}
|
@@ -12851,6 +12891,21 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
12851
12891
|
room.localParticipant.on(ParticipantEvent.LocalSenderCreated, (sender, track) => __awaiter(this, void 0, void 0, function* () {
|
12852
12892
|
this.setupE2EESender(track, sender);
|
12853
12893
|
}));
|
12894
|
+
room.localParticipant.on(ParticipantEvent.LocalTrackPublished, publication => {
|
12895
|
+
// Safari doesn't support retrieving payload information on RTCEncodedVideoFrame, so we need to update the codec manually once we have the trackInfo from the server
|
12896
|
+
if (!isVideoTrack(publication.track) || !isSafariBased()) {
|
12897
|
+
return;
|
12898
|
+
}
|
12899
|
+
const msg = {
|
12900
|
+
kind: 'updateCodec',
|
12901
|
+
data: {
|
12902
|
+
trackId: publication.track.mediaStreamID,
|
12903
|
+
codec: mimeTypeToVideoCodecString(publication.trackInfo.codecs[0].mimeType),
|
12904
|
+
participantIdentity: this.room.localParticipant.identity
|
12905
|
+
}
|
12906
|
+
};
|
12907
|
+
this.worker.postMessage(msg);
|
12908
|
+
});
|
12854
12909
|
keyProvider.on(KeyProviderEvent.SetKey, keyInfo => this.postKey(keyInfo)).on(KeyProviderEvent.RatchetRequest, (participantId, keyIndex) => this.postRatchetRequest(participantId, keyIndex));
|
12855
12910
|
}
|
12856
12911
|
postRatchetRequest(participantIdentity, keyIndex) {
|
@@ -15931,9 +15986,14 @@ class LocalTrack extends Track {
|
|
15931
15986
|
this.providedByUser = userProvidedTrack;
|
15932
15987
|
this.muteLock = new _();
|
15933
15988
|
this.pauseUpstreamLock = new _();
|
15934
|
-
this.
|
15935
|
-
this.
|
15936
|
-
|
15989
|
+
this.trackChangeLock = new _();
|
15990
|
+
this.trackChangeLock.lock().then(unlock => __awaiter(this, void 0, void 0, function* () {
|
15991
|
+
try {
|
15992
|
+
yield this.setMediaStreamTrack(mediaTrack, true);
|
15993
|
+
} finally {
|
15994
|
+
unlock();
|
15995
|
+
}
|
15996
|
+
}));
|
15937
15997
|
// added to satisfy TS compiler, constraints are synced with MediaStreamTrack
|
15938
15998
|
this._constraints = mediaTrack.getConstraints();
|
15939
15999
|
if (constraints) {
|
@@ -16009,26 +16069,21 @@ class LocalTrack extends Track {
|
|
16009
16069
|
}
|
16010
16070
|
let processedTrack;
|
16011
16071
|
if (this.processor && newTrack) {
|
16012
|
-
|
16013
|
-
|
16014
|
-
|
16015
|
-
|
16016
|
-
|
16017
|
-
|
16018
|
-
|
16019
|
-
|
16020
|
-
// ensure the processorElement itself stays muted
|
16021
|
-
this.processorElement.muted = true;
|
16022
|
-
}
|
16023
|
-
yield this.processor.restart({
|
16024
|
-
track: newTrack,
|
16025
|
-
kind: this.kind,
|
16026
|
-
element: this.processorElement
|
16027
|
-
});
|
16028
|
-
processedTrack = this.processor.processedTrack;
|
16029
|
-
} finally {
|
16030
|
-
unlock();
|
16072
|
+
this.log.debug('restarting processor', this.logContext);
|
16073
|
+
if (this.kind === 'unknown') {
|
16074
|
+
throw TypeError('cannot set processor on track of unknown kind');
|
16075
|
+
}
|
16076
|
+
if (this.processorElement) {
|
16077
|
+
attachToElement(newTrack, this.processorElement);
|
16078
|
+
// ensure the processorElement itself stays muted
|
16079
|
+
this.processorElement.muted = true;
|
16031
16080
|
}
|
16081
|
+
yield this.processor.restart({
|
16082
|
+
track: newTrack,
|
16083
|
+
kind: this.kind,
|
16084
|
+
element: this.processorElement
|
16085
|
+
});
|
16086
|
+
processedTrack = this.processor.processedTrack;
|
16032
16087
|
}
|
16033
16088
|
if (this.sender && ((_a = this.sender.transport) === null || _a === void 0 ? void 0 : _a.state) !== 'closed') {
|
16034
16089
|
yield this.sender.replaceTrack(processedTrack !== null && processedTrack !== void 0 ? processedTrack : newTrack);
|
@@ -16126,32 +16181,37 @@ class LocalTrack extends Track {
|
|
16126
16181
|
}
|
16127
16182
|
replaceTrack(track, userProvidedOrOptions) {
|
16128
16183
|
return __awaiter(this, void 0, void 0, function* () {
|
16129
|
-
|
16130
|
-
|
16131
|
-
|
16132
|
-
|
16133
|
-
|
16134
|
-
|
16135
|
-
|
16136
|
-
|
16137
|
-
|
16138
|
-
|
16139
|
-
|
16140
|
-
|
16141
|
-
|
16142
|
-
|
16143
|
-
|
16144
|
-
|
16145
|
-
|
16146
|
-
|
16184
|
+
const unlock = yield this.trackChangeLock.lock();
|
16185
|
+
try {
|
16186
|
+
if (!this.sender) {
|
16187
|
+
throw new TrackInvalidError('unable to replace an unpublished track');
|
16188
|
+
}
|
16189
|
+
let userProvidedTrack;
|
16190
|
+
let stopProcessor;
|
16191
|
+
if (typeof userProvidedOrOptions === 'boolean') {
|
16192
|
+
userProvidedTrack = userProvidedOrOptions;
|
16193
|
+
} else if (userProvidedOrOptions !== undefined) {
|
16194
|
+
userProvidedTrack = userProvidedOrOptions.userProvidedTrack;
|
16195
|
+
stopProcessor = userProvidedOrOptions.stopProcessor;
|
16196
|
+
}
|
16197
|
+
this.providedByUser = userProvidedTrack !== null && userProvidedTrack !== void 0 ? userProvidedTrack : true;
|
16198
|
+
this.log.debug('replace MediaStreamTrack', this.logContext);
|
16199
|
+
yield this.setMediaStreamTrack(track);
|
16200
|
+
// this must be synced *after* setting mediaStreamTrack above, since it relies
|
16201
|
+
// on the previous state in order to cleanup
|
16202
|
+
if (stopProcessor && this.processor) {
|
16203
|
+
yield this.internalStopProcessor();
|
16204
|
+
}
|
16205
|
+
return this;
|
16206
|
+
} finally {
|
16207
|
+
unlock();
|
16147
16208
|
}
|
16148
|
-
return this;
|
16149
16209
|
});
|
16150
16210
|
}
|
16151
16211
|
restart(constraints) {
|
16152
16212
|
return __awaiter(this, void 0, void 0, function* () {
|
16153
16213
|
this.manuallyStopped = false;
|
16154
|
-
const unlock = yield this.
|
16214
|
+
const unlock = yield this.trackChangeLock.lock();
|
16155
16215
|
try {
|
16156
16216
|
if (!constraints) {
|
16157
16217
|
constraints = this._constraints;
|
@@ -16174,9 +16234,9 @@ class LocalTrack extends Track {
|
|
16174
16234
|
facingMode
|
16175
16235
|
} : true;
|
16176
16236
|
} else {
|
16177
|
-
streamConstraints.audio = deviceId ? {
|
16237
|
+
streamConstraints.audio = deviceId ? Object.assign({
|
16178
16238
|
deviceId
|
16179
|
-
} : true;
|
16239
|
+
}, otherConstraints) : true;
|
16180
16240
|
}
|
16181
16241
|
// these steps are duplicated from setMediaStreamTrack because we must stop
|
16182
16242
|
// the previous tracks before new tracks can be acquired
|
@@ -16191,7 +16251,10 @@ class LocalTrack extends Track {
|
|
16191
16251
|
// create new track and attach
|
16192
16252
|
const mediaStream = yield navigator.mediaDevices.getUserMedia(streamConstraints);
|
16193
16253
|
const newTrack = mediaStream.getTracks()[0];
|
16194
|
-
|
16254
|
+
if (this.kind === Track.Kind.Video) {
|
16255
|
+
// we already captured the audio track with the constraints, so we only need to apply the video constraints
|
16256
|
+
yield newTrack.applyConstraints(otherConstraints);
|
16257
|
+
}
|
16195
16258
|
newTrack.addEventListener('ended', this.handleEnded);
|
16196
16259
|
this.log.debug('re-acquired MediaStreamTrack', this.logContext);
|
16197
16260
|
yield this.setMediaStreamTrack(newTrack);
|
@@ -16334,7 +16397,7 @@ class LocalTrack extends Track {
|
|
16334
16397
|
let showProcessedStreamLocally = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
16335
16398
|
return function* () {
|
16336
16399
|
var _a;
|
16337
|
-
const unlock = yield _this3.
|
16400
|
+
const unlock = yield _this3.trackChangeLock.lock();
|
16338
16401
|
try {
|
16339
16402
|
_this3.log.debug('setting up processor', _this3.logContext);
|
16340
16403
|
const processorElement = document.createElement(_this3.kind);
|
@@ -16347,7 +16410,7 @@ class LocalTrack extends Track {
|
|
16347
16410
|
yield processor.init(processorOptions);
|
16348
16411
|
_this3.log.debug('processor initialized', _this3.logContext);
|
16349
16412
|
if (_this3.processor) {
|
16350
|
-
yield _this3.
|
16413
|
+
yield _this3.internalStopProcessor();
|
16351
16414
|
}
|
16352
16415
|
if (_this3.kind === 'unknown') {
|
16353
16416
|
throw TypeError('cannot set processor on track of unknown kind');
|
@@ -16405,22 +16468,41 @@ class LocalTrack extends Track {
|
|
16405
16468
|
return __awaiter(this, arguments, void 0, function () {
|
16406
16469
|
var _this4 = this;
|
16407
16470
|
let keepElement = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
16471
|
+
return function* () {
|
16472
|
+
const unlock = yield _this4.trackChangeLock.lock();
|
16473
|
+
try {
|
16474
|
+
yield _this4.internalStopProcessor(keepElement);
|
16475
|
+
} finally {
|
16476
|
+
unlock();
|
16477
|
+
}
|
16478
|
+
}();
|
16479
|
+
});
|
16480
|
+
}
|
16481
|
+
/**
|
16482
|
+
* @internal
|
16483
|
+
* This method assumes the caller has acquired a trackChangeLock already.
|
16484
|
+
* The public facing method for stopping the processor is `stopProcessor` and it wraps this method in the trackChangeLock.
|
16485
|
+
*/
|
16486
|
+
internalStopProcessor() {
|
16487
|
+
return __awaiter(this, arguments, void 0, function () {
|
16488
|
+
var _this5 = this;
|
16489
|
+
let keepElement = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
16408
16490
|
return function* () {
|
16409
16491
|
var _a, _b;
|
16410
|
-
if (!
|
16411
|
-
|
16412
|
-
(_a =
|
16413
|
-
yield
|
16414
|
-
|
16492
|
+
if (!_this5.processor) return;
|
16493
|
+
_this5.log.debug('stopping processor', _this5.logContext);
|
16494
|
+
(_a = _this5.processor.processedTrack) === null || _a === void 0 ? void 0 : _a.stop();
|
16495
|
+
yield _this5.processor.destroy();
|
16496
|
+
_this5.processor = undefined;
|
16415
16497
|
if (!keepElement) {
|
16416
|
-
(_b =
|
16417
|
-
|
16498
|
+
(_b = _this5.processorElement) === null || _b === void 0 ? void 0 : _b.remove();
|
16499
|
+
_this5.processorElement = undefined;
|
16418
16500
|
}
|
16419
16501
|
// apply original track constraints in case the processor changed them
|
16420
|
-
yield
|
16502
|
+
yield _this5._mediaStreamTrack.applyConstraints(_this5._constraints);
|
16421
16503
|
// force re-setting of the mediaStreamTrack on the sender
|
16422
|
-
yield
|
16423
|
-
|
16504
|
+
yield _this5.setMediaStreamTrack(_this5._mediaStreamTrack, true);
|
16505
|
+
_this5.emit(TrackEvent.TrackProcessorUpdate);
|
16424
16506
|
}();
|
16425
16507
|
});
|
16426
16508
|
}
|
@@ -16614,13 +16696,13 @@ class LocalAudioTrack extends LocalTrack {
|
|
16614
16696
|
setProcessor(processor) {
|
16615
16697
|
return __awaiter(this, void 0, void 0, function* () {
|
16616
16698
|
var _a;
|
16617
|
-
const unlock = yield this.
|
16699
|
+
const unlock = yield this.trackChangeLock.lock();
|
16618
16700
|
try {
|
16619
16701
|
if (!isReactNative() && !this.audioContext) {
|
16620
16702
|
throw Error('Audio context needs to be set on LocalAudioTrack in order to enable processors');
|
16621
16703
|
}
|
16622
16704
|
if (this.processor) {
|
16623
|
-
yield this.
|
16705
|
+
yield this.internalStopProcessor();
|
16624
16706
|
}
|
16625
16707
|
const processorOptions = {
|
16626
16708
|
kind: this.kind,
|
@@ -19004,30 +19086,71 @@ class BaseStreamReader {
|
|
19004
19086
|
get info() {
|
19005
19087
|
return this._info;
|
19006
19088
|
}
|
19007
|
-
|
19089
|
+
/** @internal */
|
19090
|
+
validateBytesReceived() {
|
19091
|
+
let doneReceiving = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
19092
|
+
if (typeof this.totalByteSize !== 'number' || this.totalByteSize === 0) {
|
19093
|
+
return;
|
19094
|
+
}
|
19095
|
+
if (doneReceiving && this.bytesReceived < this.totalByteSize) {
|
19096
|
+
throw new DataStreamError("Not enough chunk(s) received - expected ".concat(this.totalByteSize, " bytes of data total, only received ").concat(this.bytesReceived, " bytes"), DataStreamErrorReason.Incomplete);
|
19097
|
+
} else if (this.bytesReceived > this.totalByteSize) {
|
19098
|
+
throw new DataStreamError("Extra chunk(s) received - expected ".concat(this.totalByteSize, " bytes of data total, received ").concat(this.bytesReceived, " bytes"), DataStreamErrorReason.LengthExceeded);
|
19099
|
+
}
|
19100
|
+
}
|
19101
|
+
constructor(info, stream, totalByteSize, outOfBandFailureRejectingFuture) {
|
19008
19102
|
this.reader = stream;
|
19009
19103
|
this.totalByteSize = totalByteSize;
|
19010
19104
|
this._info = info;
|
19011
19105
|
this.bytesReceived = 0;
|
19106
|
+
this.outOfBandFailureRejectingFuture = outOfBandFailureRejectingFuture;
|
19012
19107
|
}
|
19013
19108
|
}
|
19014
19109
|
class ByteStreamReader extends BaseStreamReader {
|
19015
19110
|
handleChunkReceived(chunk) {
|
19016
19111
|
var _a;
|
19017
19112
|
this.bytesReceived += chunk.content.byteLength;
|
19113
|
+
this.validateBytesReceived();
|
19018
19114
|
const currentProgress = this.totalByteSize ? this.bytesReceived / this.totalByteSize : undefined;
|
19019
19115
|
(_a = this.onProgress) === null || _a === void 0 ? void 0 : _a.call(this, currentProgress);
|
19020
19116
|
}
|
19021
19117
|
[Symbol.asyncIterator]() {
|
19022
19118
|
const reader = this.reader.getReader();
|
19119
|
+
let rejectingSignalFuture = new Future();
|
19120
|
+
let activeSignal = null;
|
19121
|
+
let onAbort = null;
|
19122
|
+
if (this.signal) {
|
19123
|
+
const signal = this.signal;
|
19124
|
+
onAbort = () => {
|
19125
|
+
var _a;
|
19126
|
+
(_a = rejectingSignalFuture.reject) === null || _a === void 0 ? void 0 : _a.call(rejectingSignalFuture, signal.reason);
|
19127
|
+
};
|
19128
|
+
signal.addEventListener('abort', onAbort);
|
19129
|
+
activeSignal = signal;
|
19130
|
+
}
|
19131
|
+
const cleanup = () => {
|
19132
|
+
reader.releaseLock();
|
19133
|
+
if (activeSignal && onAbort) {
|
19134
|
+
activeSignal.removeEventListener('abort', onAbort);
|
19135
|
+
}
|
19136
|
+
this.signal = undefined;
|
19137
|
+
};
|
19023
19138
|
return {
|
19024
19139
|
next: () => __awaiter(this, void 0, void 0, function* () {
|
19140
|
+
var _a, _b;
|
19025
19141
|
try {
|
19026
19142
|
const {
|
19027
19143
|
done,
|
19028
19144
|
value
|
19029
|
-
} = yield reader.read()
|
19145
|
+
} = yield Promise.race([reader.read(),
|
19146
|
+
// Rejects if this.signal is aborted
|
19147
|
+
rejectingSignalFuture.promise,
|
19148
|
+
// Rejects if something external says it should, like a participant disconnecting, etc
|
19149
|
+
(_b = (_a = this.outOfBandFailureRejectingFuture) === null || _a === void 0 ? void 0 : _a.promise) !== null && _b !== void 0 ? _b : new Promise(() => {
|
19150
|
+
/* never resolves */
|
19151
|
+
})]);
|
19030
19152
|
if (done) {
|
19153
|
+
this.validateBytesReceived(true);
|
19031
19154
|
return {
|
19032
19155
|
done: true,
|
19033
19156
|
value: undefined
|
@@ -19039,17 +19162,16 @@ class ByteStreamReader extends BaseStreamReader {
|
|
19039
19162
|
value: value.content
|
19040
19163
|
};
|
19041
19164
|
}
|
19042
|
-
} catch (
|
19043
|
-
|
19044
|
-
|
19045
|
-
done: true,
|
19046
|
-
value: undefined
|
19047
|
-
};
|
19165
|
+
} catch (err) {
|
19166
|
+
cleanup();
|
19167
|
+
throw err;
|
19048
19168
|
}
|
19049
19169
|
}),
|
19170
|
+
// note: `return` runs only for premature exits, see:
|
19171
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#errors_during_iteration
|
19050
19172
|
return() {
|
19051
19173
|
return __awaiter(this, void 0, void 0, function* () {
|
19052
|
-
|
19174
|
+
cleanup();
|
19053
19175
|
return {
|
19054
19176
|
done: true,
|
19055
19177
|
value: undefined
|
@@ -19058,29 +19180,45 @@ class ByteStreamReader extends BaseStreamReader {
|
|
19058
19180
|
}
|
19059
19181
|
};
|
19060
19182
|
}
|
19183
|
+
/**
|
19184
|
+
* Injects an AbortSignal, which if aborted, will terminate the currently active
|
19185
|
+
* stream iteration operation.
|
19186
|
+
*
|
19187
|
+
* Note that when using AbortSignal.timeout(...), the timeout applies across
|
19188
|
+
* the whole iteration operation, not just one individual chunk read.
|
19189
|
+
*/
|
19190
|
+
withAbortSignal(signal) {
|
19191
|
+
this.signal = signal;
|
19192
|
+
return this;
|
19193
|
+
}
|
19061
19194
|
readAll() {
|
19062
|
-
return __awaiter(this,
|
19063
|
-
var
|
19064
|
-
let
|
19065
|
-
|
19066
|
-
|
19067
|
-
|
19068
|
-
|
19069
|
-
const chunk = _c;
|
19070
|
-
chunks.add(chunk);
|
19071
|
-
}
|
19072
|
-
} catch (e_1_1) {
|
19073
|
-
e_1 = {
|
19074
|
-
error: e_1_1
|
19075
|
-
};
|
19076
|
-
} finally {
|
19195
|
+
return __awaiter(this, arguments, void 0, function () {
|
19196
|
+
var _this = this;
|
19197
|
+
let opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
19198
|
+
return function* () {
|
19199
|
+
var _a, e_1, _b, _c;
|
19200
|
+
let chunks = new Set();
|
19201
|
+
const iterator = opts.signal ? _this.withAbortSignal(opts.signal) : _this;
|
19077
19202
|
try {
|
19078
|
-
|
19203
|
+
for (var _d = true, iterator_1 = __asyncValues(iterator), iterator_1_1; iterator_1_1 = yield iterator_1.next(), _a = iterator_1_1.done, !_a; _d = true) {
|
19204
|
+
_c = iterator_1_1.value;
|
19205
|
+
_d = false;
|
19206
|
+
const chunk = _c;
|
19207
|
+
chunks.add(chunk);
|
19208
|
+
}
|
19209
|
+
} catch (e_1_1) {
|
19210
|
+
e_1 = {
|
19211
|
+
error: e_1_1
|
19212
|
+
};
|
19079
19213
|
} finally {
|
19080
|
-
|
19214
|
+
try {
|
19215
|
+
if (!_d && !_a && (_b = iterator_1.return)) yield _b.call(iterator_1);
|
19216
|
+
} finally {
|
19217
|
+
if (e_1) throw e_1.error;
|
19218
|
+
}
|
19081
19219
|
}
|
19082
|
-
|
19083
|
-
|
19220
|
+
return Array.from(chunks);
|
19221
|
+
}();
|
19084
19222
|
});
|
19085
19223
|
}
|
19086
19224
|
}
|
@@ -19092,8 +19230,8 @@ class TextStreamReader extends BaseStreamReader {
|
|
19092
19230
|
* A TextStreamReader instance can be used as an AsyncIterator that returns the entire string
|
19093
19231
|
* that has been received up to the current point in time.
|
19094
19232
|
*/
|
19095
|
-
constructor(info, stream, totalChunkCount) {
|
19096
|
-
super(info, stream, totalChunkCount);
|
19233
|
+
constructor(info, stream, totalChunkCount, outOfBandFailureRejectingFuture) {
|
19234
|
+
super(info, stream, totalChunkCount, outOfBandFailureRejectingFuture);
|
19097
19235
|
this.receivedChunks = new Map();
|
19098
19236
|
}
|
19099
19237
|
handleChunkReceived(chunk) {
|
@@ -19106,6 +19244,7 @@ class TextStreamReader extends BaseStreamReader {
|
|
19106
19244
|
}
|
19107
19245
|
this.receivedChunks.set(index, chunk);
|
19108
19246
|
this.bytesReceived += chunk.content.byteLength;
|
19247
|
+
this.validateBytesReceived();
|
19109
19248
|
const currentProgress = this.totalByteSize ? this.bytesReceived / this.totalByteSize : undefined;
|
19110
19249
|
(_a = this.onProgress) === null || _a === void 0 ? void 0 : _a.call(this, currentProgress);
|
19111
19250
|
}
|
@@ -19116,37 +19255,71 @@ class TextStreamReader extends BaseStreamReader {
|
|
19116
19255
|
*/
|
19117
19256
|
[Symbol.asyncIterator]() {
|
19118
19257
|
const reader = this.reader.getReader();
|
19119
|
-
const decoder = new TextDecoder(
|
19258
|
+
const decoder = new TextDecoder('utf-8', {
|
19259
|
+
fatal: true
|
19260
|
+
});
|
19261
|
+
let rejectingSignalFuture = new Future();
|
19262
|
+
let activeSignal = null;
|
19263
|
+
let onAbort = null;
|
19264
|
+
if (this.signal) {
|
19265
|
+
const signal = this.signal;
|
19266
|
+
onAbort = () => {
|
19267
|
+
var _a;
|
19268
|
+
(_a = rejectingSignalFuture.reject) === null || _a === void 0 ? void 0 : _a.call(rejectingSignalFuture, signal.reason);
|
19269
|
+
};
|
19270
|
+
signal.addEventListener('abort', onAbort);
|
19271
|
+
activeSignal = signal;
|
19272
|
+
}
|
19273
|
+
const cleanup = () => {
|
19274
|
+
reader.releaseLock();
|
19275
|
+
if (activeSignal && onAbort) {
|
19276
|
+
activeSignal.removeEventListener('abort', onAbort);
|
19277
|
+
}
|
19278
|
+
this.signal = undefined;
|
19279
|
+
};
|
19120
19280
|
return {
|
19121
19281
|
next: () => __awaiter(this, void 0, void 0, function* () {
|
19282
|
+
var _a, _b;
|
19122
19283
|
try {
|
19123
19284
|
const {
|
19124
19285
|
done,
|
19125
19286
|
value
|
19126
|
-
} = yield reader.read()
|
19287
|
+
} = yield Promise.race([reader.read(),
|
19288
|
+
// Rejects if this.signal is aborted
|
19289
|
+
rejectingSignalFuture.promise,
|
19290
|
+
// Rejects if something external says it should, like a participant disconnecting, etc
|
19291
|
+
(_b = (_a = this.outOfBandFailureRejectingFuture) === null || _a === void 0 ? void 0 : _a.promise) !== null && _b !== void 0 ? _b : new Promise(() => {
|
19292
|
+
/* never resolves */
|
19293
|
+
})]);
|
19127
19294
|
if (done) {
|
19295
|
+
this.validateBytesReceived(true);
|
19128
19296
|
return {
|
19129
19297
|
done: true,
|
19130
19298
|
value: undefined
|
19131
19299
|
};
|
19132
19300
|
} else {
|
19133
19301
|
this.handleChunkReceived(value);
|
19302
|
+
let decodedResult;
|
19303
|
+
try {
|
19304
|
+
decodedResult = decoder.decode(value.content);
|
19305
|
+
} catch (err) {
|
19306
|
+
throw new DataStreamError("Cannot decode datastream chunk ".concat(value.chunkIndex, " as text: ").concat(err), DataStreamErrorReason.DecodeFailed);
|
19307
|
+
}
|
19134
19308
|
return {
|
19135
19309
|
done: false,
|
19136
|
-
value:
|
19310
|
+
value: decodedResult
|
19137
19311
|
};
|
19138
19312
|
}
|
19139
|
-
} catch (
|
19140
|
-
|
19141
|
-
|
19142
|
-
done: true,
|
19143
|
-
value: undefined
|
19144
|
-
};
|
19313
|
+
} catch (err) {
|
19314
|
+
cleanup();
|
19315
|
+
throw err;
|
19145
19316
|
}
|
19146
19317
|
}),
|
19318
|
+
// note: `return` runs only for premature exits, see:
|
19319
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#errors_during_iteration
|
19147
19320
|
return() {
|
19148
19321
|
return __awaiter(this, void 0, void 0, function* () {
|
19149
|
-
|
19322
|
+
cleanup();
|
19150
19323
|
return {
|
19151
19324
|
done: true,
|
19152
19325
|
value: undefined
|
@@ -19155,138 +19328,602 @@ class TextStreamReader extends BaseStreamReader {
|
|
19155
19328
|
}
|
19156
19329
|
};
|
19157
19330
|
}
|
19331
|
+
/**
|
19332
|
+
* Injects an AbortSignal, which if aborted, will terminate the currently active
|
19333
|
+
* stream iteration operation.
|
19334
|
+
*
|
19335
|
+
* Note that when using AbortSignal.timeout(...), the timeout applies across
|
19336
|
+
* the whole iteration operation, not just one individual chunk read.
|
19337
|
+
*/
|
19338
|
+
withAbortSignal(signal) {
|
19339
|
+
this.signal = signal;
|
19340
|
+
return this;
|
19341
|
+
}
|
19158
19342
|
readAll() {
|
19159
|
-
return __awaiter(this,
|
19160
|
-
var
|
19161
|
-
let
|
19162
|
-
|
19163
|
-
|
19164
|
-
|
19165
|
-
|
19166
|
-
const chunk = _c;
|
19167
|
-
finalString += chunk;
|
19168
|
-
}
|
19169
|
-
} catch (e_2_1) {
|
19170
|
-
e_2 = {
|
19171
|
-
error: e_2_1
|
19172
|
-
};
|
19173
|
-
} finally {
|
19343
|
+
return __awaiter(this, arguments, void 0, function () {
|
19344
|
+
var _this2 = this;
|
19345
|
+
let opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
19346
|
+
return function* () {
|
19347
|
+
var _a, e_2, _b, _c;
|
19348
|
+
let finalString = '';
|
19349
|
+
const iterator = opts.signal ? _this2.withAbortSignal(opts.signal) : _this2;
|
19174
19350
|
try {
|
19175
|
-
|
19351
|
+
for (var _d = true, iterator_2 = __asyncValues(iterator), iterator_2_1; iterator_2_1 = yield iterator_2.next(), _a = iterator_2_1.done, !_a; _d = true) {
|
19352
|
+
_c = iterator_2_1.value;
|
19353
|
+
_d = false;
|
19354
|
+
const chunk = _c;
|
19355
|
+
finalString += chunk;
|
19356
|
+
}
|
19357
|
+
} catch (e_2_1) {
|
19358
|
+
e_2 = {
|
19359
|
+
error: e_2_1
|
19360
|
+
};
|
19176
19361
|
} finally {
|
19177
|
-
|
19362
|
+
try {
|
19363
|
+
if (!_d && !_a && (_b = iterator_2.return)) yield _b.call(iterator_2);
|
19364
|
+
} finally {
|
19365
|
+
if (e_2) throw e_2.error;
|
19366
|
+
}
|
19178
19367
|
}
|
19179
|
-
|
19180
|
-
|
19368
|
+
return finalString;
|
19369
|
+
}();
|
19181
19370
|
});
|
19182
19371
|
}
|
19183
19372
|
}
|
19184
19373
|
|
19185
|
-
class
|
19186
|
-
constructor(
|
19187
|
-
this.
|
19188
|
-
this.
|
19189
|
-
this.
|
19190
|
-
this.
|
19191
|
-
|
19192
|
-
write(chunk) {
|
19193
|
-
return this.defaultWriter.write(chunk);
|
19194
|
-
}
|
19195
|
-
close() {
|
19196
|
-
return __awaiter(this, void 0, void 0, function* () {
|
19197
|
-
var _a;
|
19198
|
-
yield this.defaultWriter.close();
|
19199
|
-
this.defaultWriter.releaseLock();
|
19200
|
-
(_a = this.onClose) === null || _a === void 0 ? void 0 : _a.call(this);
|
19201
|
-
});
|
19374
|
+
class IncomingDataStreamManager {
|
19375
|
+
constructor() {
|
19376
|
+
this.log = livekitLogger;
|
19377
|
+
this.byteStreamControllers = new Map();
|
19378
|
+
this.textStreamControllers = new Map();
|
19379
|
+
this.byteStreamHandlers = new Map();
|
19380
|
+
this.textStreamHandlers = new Map();
|
19202
19381
|
}
|
19203
|
-
|
19204
|
-
|
19205
|
-
|
19206
|
-
|
19207
|
-
|
19208
|
-
constructor(mediaTrack, sid, kind, receiver, loggerOptions) {
|
19209
|
-
super(mediaTrack, kind, loggerOptions);
|
19210
|
-
this.sid = sid;
|
19211
|
-
this.receiver = receiver;
|
19382
|
+
registerTextStreamHandler(topic, callback) {
|
19383
|
+
if (this.textStreamHandlers.has(topic)) {
|
19384
|
+
throw new DataStreamError("A text stream handler for topic \"".concat(topic, "\" has already been set."), DataStreamErrorReason.HandlerAlreadyRegistered);
|
19385
|
+
}
|
19386
|
+
this.textStreamHandlers.set(topic, callback);
|
19212
19387
|
}
|
19213
|
-
|
19214
|
-
|
19388
|
+
unregisterTextStreamHandler(topic) {
|
19389
|
+
this.textStreamHandlers.delete(topic);
|
19215
19390
|
}
|
19216
|
-
|
19217
|
-
|
19218
|
-
|
19219
|
-
this.isMuted = muted;
|
19220
|
-
this._mediaStreamTrack.enabled = !muted;
|
19221
|
-
this.emit(muted ? TrackEvent.Muted : TrackEvent.Unmuted, this);
|
19391
|
+
registerByteStreamHandler(topic, callback) {
|
19392
|
+
if (this.byteStreamHandlers.has(topic)) {
|
19393
|
+
throw new DataStreamError("A byte stream handler for topic \"".concat(topic, "\" has already been set."), DataStreamErrorReason.HandlerAlreadyRegistered);
|
19222
19394
|
}
|
19395
|
+
this.byteStreamHandlers.set(topic, callback);
|
19223
19396
|
}
|
19224
|
-
|
19225
|
-
|
19226
|
-
// this is needed to determine when the track is finished
|
19227
|
-
this.mediaStream = stream;
|
19228
|
-
const onRemoveTrack = event => {
|
19229
|
-
if (event.track === this._mediaStreamTrack) {
|
19230
|
-
stream.removeEventListener('removetrack', onRemoveTrack);
|
19231
|
-
if (this.receiver && 'playoutDelayHint' in this.receiver) {
|
19232
|
-
this.receiver.playoutDelayHint = undefined;
|
19233
|
-
}
|
19234
|
-
this.receiver = undefined;
|
19235
|
-
this._currentBitrate = 0;
|
19236
|
-
this.emit(TrackEvent.Ended, this);
|
19237
|
-
}
|
19238
|
-
};
|
19239
|
-
stream.addEventListener('removetrack', onRemoveTrack);
|
19397
|
+
unregisterByteStreamHandler(topic) {
|
19398
|
+
this.byteStreamHandlers.delete(topic);
|
19240
19399
|
}
|
19241
|
-
|
19242
|
-
this.
|
19243
|
-
|
19244
|
-
|
19400
|
+
clearHandlersAndControllers() {
|
19401
|
+
this.byteStreamControllers.clear();
|
19402
|
+
this.textStreamControllers.clear();
|
19403
|
+
this.byteStreamHandlers.clear();
|
19404
|
+
this.textStreamHandlers.clear();
|
19245
19405
|
}
|
19246
|
-
|
19247
|
-
|
19248
|
-
//
|
19249
|
-
|
19406
|
+
validateParticipantHasNoActiveDataStreams(participantIdentity) {
|
19407
|
+
var _a, _b, _c, _d;
|
19408
|
+
// Terminate any in flight data stream receives from the given participant
|
19409
|
+
const textStreamsBeingSentByDisconnectingParticipant = Array.from(this.textStreamControllers.entries()).filter(entry => entry[1].sendingParticipantIdentity === participantIdentity);
|
19410
|
+
const byteStreamsBeingSentByDisconnectingParticipant = Array.from(this.byteStreamControllers.entries()).filter(entry => entry[1].sendingParticipantIdentity === participantIdentity);
|
19411
|
+
if (textStreamsBeingSentByDisconnectingParticipant.length > 0 || byteStreamsBeingSentByDisconnectingParticipant.length > 0) {
|
19412
|
+
const abnormalEndError = new DataStreamError("Participant ".concat(participantIdentity, " unexpectedly disconnected in the middle of sending data"), DataStreamErrorReason.AbnormalEnd);
|
19413
|
+
for (const [id, controller] of byteStreamsBeingSentByDisconnectingParticipant) {
|
19414
|
+
(_b = (_a = controller.outOfBandFailureRejectingFuture).reject) === null || _b === void 0 ? void 0 : _b.call(_a, abnormalEndError);
|
19415
|
+
this.byteStreamControllers.delete(id);
|
19416
|
+
}
|
19417
|
+
for (const [id, controller] of textStreamsBeingSentByDisconnectingParticipant) {
|
19418
|
+
(_d = (_c = controller.outOfBandFailureRejectingFuture).reject) === null || _d === void 0 ? void 0 : _d.call(_c, abnormalEndError);
|
19419
|
+
this.textStreamControllers.delete(id);
|
19420
|
+
}
|
19421
|
+
}
|
19250
19422
|
}
|
19251
|
-
|
19252
|
-
* Gets the RTCStatsReport for the RemoteTrack's underlying RTCRtpReceiver
|
19253
|
-
* See https://developer.mozilla.org/en-US/docs/Web/API/RTCStatsReport
|
19254
|
-
*
|
19255
|
-
* @returns Promise<RTCStatsReport> | undefined
|
19256
|
-
*/
|
19257
|
-
getRTCStatsReport() {
|
19423
|
+
handleDataStreamPacket(packet) {
|
19258
19424
|
return __awaiter(this, void 0, void 0, function* () {
|
19259
|
-
|
19260
|
-
|
19261
|
-
|
19425
|
+
switch (packet.value.case) {
|
19426
|
+
case 'streamHeader':
|
19427
|
+
return this.handleStreamHeader(packet.value.value, packet.participantIdentity);
|
19428
|
+
case 'streamChunk':
|
19429
|
+
return this.handleStreamChunk(packet.value.value);
|
19430
|
+
case 'streamTrailer':
|
19431
|
+
return this.handleStreamTrailer(packet.value.value);
|
19432
|
+
default:
|
19433
|
+
throw new Error("DataPacket of value \"".concat(packet.value.case, "\" is not data stream related!"));
|
19262
19434
|
}
|
19263
|
-
const statsReport = yield this.receiver.getStats();
|
19264
|
-
return statsReport;
|
19265
19435
|
});
|
19266
19436
|
}
|
19267
|
-
|
19268
|
-
|
19269
|
-
|
19270
|
-
|
19271
|
-
|
19272
|
-
|
19273
|
-
|
19274
|
-
|
19275
|
-
|
19276
|
-
|
19277
|
-
|
19278
|
-
|
19279
|
-
|
19280
|
-
|
19281
|
-
|
19282
|
-
|
19283
|
-
|
19284
|
-
|
19285
|
-
|
19286
|
-
|
19287
|
-
|
19288
|
-
|
19289
|
-
|
19437
|
+
handleStreamHeader(streamHeader, participantIdentity) {
|
19438
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19439
|
+
var _a;
|
19440
|
+
if (streamHeader.contentHeader.case === 'byteHeader') {
|
19441
|
+
const streamHandlerCallback = this.byteStreamHandlers.get(streamHeader.topic);
|
19442
|
+
if (!streamHandlerCallback) {
|
19443
|
+
this.log.debug('ignoring incoming byte stream due to no handler for topic', streamHeader.topic);
|
19444
|
+
return;
|
19445
|
+
}
|
19446
|
+
let streamController;
|
19447
|
+
const outOfBandFailureRejectingFuture = new Future();
|
19448
|
+
const info = {
|
19449
|
+
id: streamHeader.streamId,
|
19450
|
+
name: (_a = streamHeader.contentHeader.value.name) !== null && _a !== void 0 ? _a : 'unknown',
|
19451
|
+
mimeType: streamHeader.mimeType,
|
19452
|
+
size: streamHeader.totalLength ? Number(streamHeader.totalLength) : undefined,
|
19453
|
+
topic: streamHeader.topic,
|
19454
|
+
timestamp: bigIntToNumber(streamHeader.timestamp),
|
19455
|
+
attributes: streamHeader.attributes
|
19456
|
+
};
|
19457
|
+
const stream = new ReadableStream({
|
19458
|
+
start: controller => {
|
19459
|
+
streamController = controller;
|
19460
|
+
if (this.textStreamControllers.has(streamHeader.streamId)) {
|
19461
|
+
throw new DataStreamError("A data stream read is already in progress for a stream with id ".concat(streamHeader.streamId, "."), DataStreamErrorReason.AlreadyOpened);
|
19462
|
+
}
|
19463
|
+
this.byteStreamControllers.set(streamHeader.streamId, {
|
19464
|
+
info,
|
19465
|
+
controller: streamController,
|
19466
|
+
startTime: Date.now(),
|
19467
|
+
sendingParticipantIdentity: participantIdentity,
|
19468
|
+
outOfBandFailureRejectingFuture
|
19469
|
+
});
|
19470
|
+
}
|
19471
|
+
});
|
19472
|
+
streamHandlerCallback(new ByteStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength), outOfBandFailureRejectingFuture), {
|
19473
|
+
identity: participantIdentity
|
19474
|
+
});
|
19475
|
+
} else if (streamHeader.contentHeader.case === 'textHeader') {
|
19476
|
+
const streamHandlerCallback = this.textStreamHandlers.get(streamHeader.topic);
|
19477
|
+
if (!streamHandlerCallback) {
|
19478
|
+
this.log.debug('ignoring incoming text stream due to no handler for topic', streamHeader.topic);
|
19479
|
+
return;
|
19480
|
+
}
|
19481
|
+
let streamController;
|
19482
|
+
const outOfBandFailureRejectingFuture = new Future();
|
19483
|
+
const info = {
|
19484
|
+
id: streamHeader.streamId,
|
19485
|
+
mimeType: streamHeader.mimeType,
|
19486
|
+
size: streamHeader.totalLength ? Number(streamHeader.totalLength) : undefined,
|
19487
|
+
topic: streamHeader.topic,
|
19488
|
+
timestamp: Number(streamHeader.timestamp),
|
19489
|
+
attributes: streamHeader.attributes
|
19490
|
+
};
|
19491
|
+
const stream = new ReadableStream({
|
19492
|
+
start: controller => {
|
19493
|
+
streamController = controller;
|
19494
|
+
if (this.textStreamControllers.has(streamHeader.streamId)) {
|
19495
|
+
throw new DataStreamError("A data stream read is already in progress for a stream with id ".concat(streamHeader.streamId, "."), DataStreamErrorReason.AlreadyOpened);
|
19496
|
+
}
|
19497
|
+
this.textStreamControllers.set(streamHeader.streamId, {
|
19498
|
+
info,
|
19499
|
+
controller: streamController,
|
19500
|
+
startTime: Date.now(),
|
19501
|
+
sendingParticipantIdentity: participantIdentity,
|
19502
|
+
outOfBandFailureRejectingFuture
|
19503
|
+
});
|
19504
|
+
}
|
19505
|
+
});
|
19506
|
+
streamHandlerCallback(new TextStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength), outOfBandFailureRejectingFuture), {
|
19507
|
+
identity: participantIdentity
|
19508
|
+
});
|
19509
|
+
}
|
19510
|
+
});
|
19511
|
+
}
|
19512
|
+
handleStreamChunk(chunk) {
|
19513
|
+
const fileBuffer = this.byteStreamControllers.get(chunk.streamId);
|
19514
|
+
if (fileBuffer) {
|
19515
|
+
if (chunk.content.length > 0) {
|
19516
|
+
fileBuffer.controller.enqueue(chunk);
|
19517
|
+
}
|
19518
|
+
}
|
19519
|
+
const textBuffer = this.textStreamControllers.get(chunk.streamId);
|
19520
|
+
if (textBuffer) {
|
19521
|
+
if (chunk.content.length > 0) {
|
19522
|
+
textBuffer.controller.enqueue(chunk);
|
19523
|
+
}
|
19524
|
+
}
|
19525
|
+
}
|
19526
|
+
handleStreamTrailer(trailer) {
|
19527
|
+
const textBuffer = this.textStreamControllers.get(trailer.streamId);
|
19528
|
+
if (textBuffer) {
|
19529
|
+
textBuffer.info.attributes = Object.assign(Object.assign({}, textBuffer.info.attributes), trailer.attributes);
|
19530
|
+
textBuffer.controller.close();
|
19531
|
+
this.textStreamControllers.delete(trailer.streamId);
|
19532
|
+
}
|
19533
|
+
const fileBuffer = this.byteStreamControllers.get(trailer.streamId);
|
19534
|
+
if (fileBuffer) {
|
19535
|
+
{
|
19536
|
+
fileBuffer.info.attributes = Object.assign(Object.assign({}, fileBuffer.info.attributes), trailer.attributes);
|
19537
|
+
fileBuffer.controller.close();
|
19538
|
+
this.byteStreamControllers.delete(trailer.streamId);
|
19539
|
+
}
|
19540
|
+
}
|
19541
|
+
}
|
19542
|
+
}
|
19543
|
+
|
19544
|
+
class BaseStreamWriter {
|
19545
|
+
constructor(writableStream, info, onClose) {
|
19546
|
+
this.writableStream = writableStream;
|
19547
|
+
this.defaultWriter = writableStream.getWriter();
|
19548
|
+
this.onClose = onClose;
|
19549
|
+
this.info = info;
|
19550
|
+
}
|
19551
|
+
write(chunk) {
|
19552
|
+
return this.defaultWriter.write(chunk);
|
19553
|
+
}
|
19554
|
+
close() {
|
19555
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19556
|
+
var _a;
|
19557
|
+
yield this.defaultWriter.close();
|
19558
|
+
this.defaultWriter.releaseLock();
|
19559
|
+
(_a = this.onClose) === null || _a === void 0 ? void 0 : _a.call(this);
|
19560
|
+
});
|
19561
|
+
}
|
19562
|
+
}
|
19563
|
+
class TextStreamWriter extends BaseStreamWriter {}
|
19564
|
+
class ByteStreamWriter extends BaseStreamWriter {}
|
19565
|
+
|
19566
|
+
const STREAM_CHUNK_SIZE = 15000;
|
19567
|
+
/**
|
19568
|
+
* Manages sending custom user data via data channels.
|
19569
|
+
* @internal
|
19570
|
+
*/
|
19571
|
+
class OutgoingDataStreamManager {
|
19572
|
+
constructor(engine, log) {
|
19573
|
+
this.engine = engine;
|
19574
|
+
this.log = log;
|
19575
|
+
}
|
19576
|
+
setupEngine(engine) {
|
19577
|
+
this.engine = engine;
|
19578
|
+
}
|
19579
|
+
/** {@inheritDoc LocalParticipant.sendText} */
|
19580
|
+
sendText(text, options) {
|
19581
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19582
|
+
var _a;
|
19583
|
+
const streamId = crypto.randomUUID();
|
19584
|
+
const textInBytes = new TextEncoder().encode(text);
|
19585
|
+
const totalTextLength = textInBytes.byteLength;
|
19586
|
+
const fileIds = (_a = options === null || options === void 0 ? void 0 : options.attachments) === null || _a === void 0 ? void 0 : _a.map(() => crypto.randomUUID());
|
19587
|
+
const progresses = new Array(fileIds ? fileIds.length + 1 : 1).fill(0);
|
19588
|
+
const handleProgress = (progress, idx) => {
|
19589
|
+
var _a;
|
19590
|
+
progresses[idx] = progress;
|
19591
|
+
const totalProgress = progresses.reduce((acc, val) => acc + val, 0);
|
19592
|
+
(_a = options === null || options === void 0 ? void 0 : options.onProgress) === null || _a === void 0 ? void 0 : _a.call(options, totalProgress);
|
19593
|
+
};
|
19594
|
+
const writer = yield this.streamText({
|
19595
|
+
streamId,
|
19596
|
+
totalSize: totalTextLength,
|
19597
|
+
destinationIdentities: options === null || options === void 0 ? void 0 : options.destinationIdentities,
|
19598
|
+
topic: options === null || options === void 0 ? void 0 : options.topic,
|
19599
|
+
attachedStreamIds: fileIds,
|
19600
|
+
attributes: options === null || options === void 0 ? void 0 : options.attributes
|
19601
|
+
});
|
19602
|
+
yield writer.write(text);
|
19603
|
+
// set text part of progress to 1
|
19604
|
+
handleProgress(1, 0);
|
19605
|
+
yield writer.close();
|
19606
|
+
if ((options === null || options === void 0 ? void 0 : options.attachments) && fileIds) {
|
19607
|
+
yield Promise.all(options.attachments.map((file, idx) => __awaiter(this, void 0, void 0, function* () {
|
19608
|
+
return this._sendFile(fileIds[idx], file, {
|
19609
|
+
topic: options.topic,
|
19610
|
+
mimeType: file.type,
|
19611
|
+
onProgress: progress => {
|
19612
|
+
handleProgress(progress, idx + 1);
|
19613
|
+
}
|
19614
|
+
});
|
19615
|
+
})));
|
19616
|
+
}
|
19617
|
+
return writer.info;
|
19618
|
+
});
|
19619
|
+
}
|
19620
|
+
/**
|
19621
|
+
* @internal
|
19622
|
+
* @experimental CAUTION, might get removed in a minor release
|
19623
|
+
*/
|
19624
|
+
streamText(options) {
|
19625
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19626
|
+
var _a, _b;
|
19627
|
+
const streamId = (_a = options === null || options === void 0 ? void 0 : options.streamId) !== null && _a !== void 0 ? _a : crypto.randomUUID();
|
19628
|
+
const info = {
|
19629
|
+
id: streamId,
|
19630
|
+
mimeType: 'text/plain',
|
19631
|
+
timestamp: Date.now(),
|
19632
|
+
topic: (_b = options === null || options === void 0 ? void 0 : options.topic) !== null && _b !== void 0 ? _b : '',
|
19633
|
+
size: options === null || options === void 0 ? void 0 : options.totalSize,
|
19634
|
+
attributes: options === null || options === void 0 ? void 0 : options.attributes
|
19635
|
+
};
|
19636
|
+
const header = new DataStream_Header({
|
19637
|
+
streamId,
|
19638
|
+
mimeType: info.mimeType,
|
19639
|
+
topic: info.topic,
|
19640
|
+
timestamp: numberToBigInt(info.timestamp),
|
19641
|
+
totalLength: numberToBigInt(options === null || options === void 0 ? void 0 : options.totalSize),
|
19642
|
+
attributes: info.attributes,
|
19643
|
+
contentHeader: {
|
19644
|
+
case: 'textHeader',
|
19645
|
+
value: new DataStream_TextHeader({
|
19646
|
+
version: options === null || options === void 0 ? void 0 : options.version,
|
19647
|
+
attachedStreamIds: options === null || options === void 0 ? void 0 : options.attachedStreamIds,
|
19648
|
+
replyToStreamId: options === null || options === void 0 ? void 0 : options.replyToStreamId,
|
19649
|
+
operationType: (options === null || options === void 0 ? void 0 : options.type) === 'update' ? DataStream_OperationType.UPDATE : DataStream_OperationType.CREATE
|
19650
|
+
})
|
19651
|
+
}
|
19652
|
+
});
|
19653
|
+
const destinationIdentities = options === null || options === void 0 ? void 0 : options.destinationIdentities;
|
19654
|
+
const packet = new DataPacket({
|
19655
|
+
destinationIdentities,
|
19656
|
+
value: {
|
19657
|
+
case: 'streamHeader',
|
19658
|
+
value: header
|
19659
|
+
}
|
19660
|
+
});
|
19661
|
+
yield this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
|
19662
|
+
let chunkId = 0;
|
19663
|
+
const engine = this.engine;
|
19664
|
+
const writableStream = new WritableStream({
|
19665
|
+
// Implement the sink
|
19666
|
+
write(text) {
|
19667
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19668
|
+
for (const textByteChunk of splitUtf8(text, STREAM_CHUNK_SIZE)) {
|
19669
|
+
yield engine.waitForBufferStatusLow(DataPacket_Kind.RELIABLE);
|
19670
|
+
const chunk = new DataStream_Chunk({
|
19671
|
+
content: textByteChunk,
|
19672
|
+
streamId,
|
19673
|
+
chunkIndex: numberToBigInt(chunkId)
|
19674
|
+
});
|
19675
|
+
const chunkPacket = new DataPacket({
|
19676
|
+
destinationIdentities,
|
19677
|
+
value: {
|
19678
|
+
case: 'streamChunk',
|
19679
|
+
value: chunk
|
19680
|
+
}
|
19681
|
+
});
|
19682
|
+
yield engine.sendDataPacket(chunkPacket, DataPacket_Kind.RELIABLE);
|
19683
|
+
chunkId += 1;
|
19684
|
+
}
|
19685
|
+
});
|
19686
|
+
},
|
19687
|
+
close() {
|
19688
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19689
|
+
const trailer = new DataStream_Trailer({
|
19690
|
+
streamId
|
19691
|
+
});
|
19692
|
+
const trailerPacket = new DataPacket({
|
19693
|
+
destinationIdentities,
|
19694
|
+
value: {
|
19695
|
+
case: 'streamTrailer',
|
19696
|
+
value: trailer
|
19697
|
+
}
|
19698
|
+
});
|
19699
|
+
yield engine.sendDataPacket(trailerPacket, DataPacket_Kind.RELIABLE);
|
19700
|
+
});
|
19701
|
+
},
|
19702
|
+
abort(err) {
|
19703
|
+
console.log('Sink error:', err);
|
19704
|
+
// TODO handle aborts to signal something to receiver side
|
19705
|
+
}
|
19706
|
+
});
|
19707
|
+
let onEngineClose = () => __awaiter(this, void 0, void 0, function* () {
|
19708
|
+
yield writer.close();
|
19709
|
+
});
|
19710
|
+
engine.once(EngineEvent.Closing, onEngineClose);
|
19711
|
+
const writer = new TextStreamWriter(writableStream, info, () => this.engine.off(EngineEvent.Closing, onEngineClose));
|
19712
|
+
return writer;
|
19713
|
+
});
|
19714
|
+
}
|
19715
|
+
sendFile(file, options) {
|
19716
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19717
|
+
const streamId = crypto.randomUUID();
|
19718
|
+
yield this._sendFile(streamId, file, options);
|
19719
|
+
return {
|
19720
|
+
id: streamId
|
19721
|
+
};
|
19722
|
+
});
|
19723
|
+
}
|
19724
|
+
_sendFile(streamId, file, options) {
|
19725
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19726
|
+
var _a;
|
19727
|
+
const writer = yield this.streamBytes({
|
19728
|
+
streamId,
|
19729
|
+
totalSize: file.size,
|
19730
|
+
name: file.name,
|
19731
|
+
mimeType: (_a = options === null || options === void 0 ? void 0 : options.mimeType) !== null && _a !== void 0 ? _a : file.type,
|
19732
|
+
topic: options === null || options === void 0 ? void 0 : options.topic,
|
19733
|
+
destinationIdentities: options === null || options === void 0 ? void 0 : options.destinationIdentities
|
19734
|
+
});
|
19735
|
+
const reader = file.stream().getReader();
|
19736
|
+
while (true) {
|
19737
|
+
const {
|
19738
|
+
done,
|
19739
|
+
value
|
19740
|
+
} = yield reader.read();
|
19741
|
+
if (done) {
|
19742
|
+
break;
|
19743
|
+
}
|
19744
|
+
yield writer.write(value);
|
19745
|
+
}
|
19746
|
+
yield writer.close();
|
19747
|
+
return writer.info;
|
19748
|
+
});
|
19749
|
+
}
|
19750
|
+
streamBytes(options) {
|
19751
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19752
|
+
var _a, _b, _c, _d, _e;
|
19753
|
+
const streamId = (_a = options === null || options === void 0 ? void 0 : options.streamId) !== null && _a !== void 0 ? _a : crypto.randomUUID();
|
19754
|
+
const destinationIdentities = options === null || options === void 0 ? void 0 : options.destinationIdentities;
|
19755
|
+
const info = {
|
19756
|
+
id: streamId,
|
19757
|
+
mimeType: (_b = options === null || options === void 0 ? void 0 : options.mimeType) !== null && _b !== void 0 ? _b : 'application/octet-stream',
|
19758
|
+
topic: (_c = options === null || options === void 0 ? void 0 : options.topic) !== null && _c !== void 0 ? _c : '',
|
19759
|
+
timestamp: Date.now(),
|
19760
|
+
attributes: options === null || options === void 0 ? void 0 : options.attributes,
|
19761
|
+
size: options === null || options === void 0 ? void 0 : options.totalSize,
|
19762
|
+
name: (_d = options === null || options === void 0 ? void 0 : options.name) !== null && _d !== void 0 ? _d : 'unknown'
|
19763
|
+
};
|
19764
|
+
const header = new DataStream_Header({
|
19765
|
+
totalLength: numberToBigInt((_e = info.size) !== null && _e !== void 0 ? _e : 0),
|
19766
|
+
mimeType: info.mimeType,
|
19767
|
+
streamId,
|
19768
|
+
topic: info.topic,
|
19769
|
+
timestamp: numberToBigInt(Date.now()),
|
19770
|
+
attributes: info.attributes,
|
19771
|
+
contentHeader: {
|
19772
|
+
case: 'byteHeader',
|
19773
|
+
value: new DataStream_ByteHeader({
|
19774
|
+
name: info.name
|
19775
|
+
})
|
19776
|
+
}
|
19777
|
+
});
|
19778
|
+
const packet = new DataPacket({
|
19779
|
+
destinationIdentities,
|
19780
|
+
value: {
|
19781
|
+
case: 'streamHeader',
|
19782
|
+
value: header
|
19783
|
+
}
|
19784
|
+
});
|
19785
|
+
yield this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
|
19786
|
+
let chunkId = 0;
|
19787
|
+
const writeMutex = new _();
|
19788
|
+
const engine = this.engine;
|
19789
|
+
const logLocal = this.log;
|
19790
|
+
const writableStream = new WritableStream({
|
19791
|
+
write(chunk) {
|
19792
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19793
|
+
const unlock = yield writeMutex.lock();
|
19794
|
+
let byteOffset = 0;
|
19795
|
+
try {
|
19796
|
+
while (byteOffset < chunk.byteLength) {
|
19797
|
+
const subChunk = chunk.slice(byteOffset, byteOffset + STREAM_CHUNK_SIZE);
|
19798
|
+
yield engine.waitForBufferStatusLow(DataPacket_Kind.RELIABLE);
|
19799
|
+
const chunkPacket = new DataPacket({
|
19800
|
+
destinationIdentities,
|
19801
|
+
value: {
|
19802
|
+
case: 'streamChunk',
|
19803
|
+
value: new DataStream_Chunk({
|
19804
|
+
content: subChunk,
|
19805
|
+
streamId,
|
19806
|
+
chunkIndex: numberToBigInt(chunkId)
|
19807
|
+
})
|
19808
|
+
}
|
19809
|
+
});
|
19810
|
+
yield engine.sendDataPacket(chunkPacket, DataPacket_Kind.RELIABLE);
|
19811
|
+
chunkId += 1;
|
19812
|
+
byteOffset += subChunk.byteLength;
|
19813
|
+
}
|
19814
|
+
} finally {
|
19815
|
+
unlock();
|
19816
|
+
}
|
19817
|
+
});
|
19818
|
+
},
|
19819
|
+
close() {
|
19820
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19821
|
+
const trailer = new DataStream_Trailer({
|
19822
|
+
streamId
|
19823
|
+
});
|
19824
|
+
const trailerPacket = new DataPacket({
|
19825
|
+
destinationIdentities,
|
19826
|
+
value: {
|
19827
|
+
case: 'streamTrailer',
|
19828
|
+
value: trailer
|
19829
|
+
}
|
19830
|
+
});
|
19831
|
+
yield engine.sendDataPacket(trailerPacket, DataPacket_Kind.RELIABLE);
|
19832
|
+
});
|
19833
|
+
},
|
19834
|
+
abort(err) {
|
19835
|
+
logLocal.error('Sink error:', err);
|
19836
|
+
}
|
19837
|
+
});
|
19838
|
+
const byteWriter = new ByteStreamWriter(writableStream, info);
|
19839
|
+
return byteWriter;
|
19840
|
+
});
|
19841
|
+
}
|
19842
|
+
}
|
19843
|
+
|
19844
|
+
class RemoteTrack extends Track {
|
19845
|
+
constructor(mediaTrack, sid, kind, receiver, loggerOptions) {
|
19846
|
+
super(mediaTrack, kind, loggerOptions);
|
19847
|
+
this.sid = sid;
|
19848
|
+
this.receiver = receiver;
|
19849
|
+
}
|
19850
|
+
get isLocal() {
|
19851
|
+
return false;
|
19852
|
+
}
|
19853
|
+
/** @internal */
|
19854
|
+
setMuted(muted) {
|
19855
|
+
if (this.isMuted !== muted) {
|
19856
|
+
this.isMuted = muted;
|
19857
|
+
this._mediaStreamTrack.enabled = !muted;
|
19858
|
+
this.emit(muted ? TrackEvent.Muted : TrackEvent.Unmuted, this);
|
19859
|
+
}
|
19860
|
+
}
|
19861
|
+
/** @internal */
|
19862
|
+
setMediaStream(stream) {
|
19863
|
+
// this is needed to determine when the track is finished
|
19864
|
+
this.mediaStream = stream;
|
19865
|
+
const onRemoveTrack = event => {
|
19866
|
+
if (event.track === this._mediaStreamTrack) {
|
19867
|
+
stream.removeEventListener('removetrack', onRemoveTrack);
|
19868
|
+
if (this.receiver && 'playoutDelayHint' in this.receiver) {
|
19869
|
+
this.receiver.playoutDelayHint = undefined;
|
19870
|
+
}
|
19871
|
+
this.receiver = undefined;
|
19872
|
+
this._currentBitrate = 0;
|
19873
|
+
this.emit(TrackEvent.Ended, this);
|
19874
|
+
}
|
19875
|
+
};
|
19876
|
+
stream.addEventListener('removetrack', onRemoveTrack);
|
19877
|
+
}
|
19878
|
+
start() {
|
19879
|
+
this.startMonitor();
|
19880
|
+
// use `enabled` of track to enable re-use of transceiver
|
19881
|
+
super.enable();
|
19882
|
+
}
|
19883
|
+
stop() {
|
19884
|
+
this.stopMonitor();
|
19885
|
+
// use `enabled` of track to enable re-use of transceiver
|
19886
|
+
super.disable();
|
19887
|
+
}
|
19888
|
+
/**
|
19889
|
+
* Gets the RTCStatsReport for the RemoteTrack's underlying RTCRtpReceiver
|
19890
|
+
* See https://developer.mozilla.org/en-US/docs/Web/API/RTCStatsReport
|
19891
|
+
*
|
19892
|
+
* @returns Promise<RTCStatsReport> | undefined
|
19893
|
+
*/
|
19894
|
+
getRTCStatsReport() {
|
19895
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19896
|
+
var _a;
|
19897
|
+
if (!((_a = this.receiver) === null || _a === void 0 ? void 0 : _a.getStats)) {
|
19898
|
+
return;
|
19899
|
+
}
|
19900
|
+
const statsReport = yield this.receiver.getStats();
|
19901
|
+
return statsReport;
|
19902
|
+
});
|
19903
|
+
}
|
19904
|
+
/**
|
19905
|
+
* Allows to set a playout delay (in seconds) for this track.
|
19906
|
+
* A higher value allows for more buffering of the track in the browser
|
19907
|
+
* and will result in a delay of media being played back of `delayInSeconds`
|
19908
|
+
*/
|
19909
|
+
setPlayoutDelay(delayInSeconds) {
|
19910
|
+
if (this.receiver) {
|
19911
|
+
if ('playoutDelayHint' in this.receiver) {
|
19912
|
+
this.receiver.playoutDelayHint = delayInSeconds;
|
19913
|
+
} else {
|
19914
|
+
this.log.warn('Playout delay not supported in this browser');
|
19915
|
+
}
|
19916
|
+
} else {
|
19917
|
+
this.log.warn('Cannot set playout delay, track already ended');
|
19918
|
+
}
|
19919
|
+
}
|
19920
|
+
/**
|
19921
|
+
* Returns the current playout delay (in seconds) of this track.
|
19922
|
+
*/
|
19923
|
+
getPlayoutDelay() {
|
19924
|
+
if (this.receiver) {
|
19925
|
+
if ('playoutDelayHint' in this.receiver) {
|
19926
|
+
return this.receiver.playoutDelayHint;
|
19290
19927
|
} else {
|
19291
19928
|
this.log.warn('Playout delay not supported in this browser');
|
19292
19929
|
}
|
@@ -19552,6 +20189,15 @@ class RemoteVideoTrack extends RemoteTrack {
|
|
19552
20189
|
get isAdaptiveStream() {
|
19553
20190
|
return this.adaptiveStreamSettings !== undefined;
|
19554
20191
|
}
|
20192
|
+
setStreamState(value) {
|
20193
|
+
super.setStreamState(value);
|
20194
|
+
console.log('setStreamState', value);
|
20195
|
+
if (value === Track.StreamState.Active) {
|
20196
|
+
// update visibility for adaptive stream tracks when stream state received from server is active
|
20197
|
+
// this is needed to ensure the track is stopped when there's no element attached to it at all
|
20198
|
+
this.updateVisibility();
|
20199
|
+
}
|
20200
|
+
}
|
19555
20201
|
/**
|
19556
20202
|
* Note: When using adaptiveStream, you need to use remoteVideoTrack.attach() to add the track to a HTMLVideoElement, otherwise your video tracks might never start
|
19557
20203
|
*/
|
@@ -19701,14 +20347,14 @@ class RemoteVideoTrack extends RemoteTrack {
|
|
19701
20347
|
this.updateVisibility();
|
19702
20348
|
});
|
19703
20349
|
}
|
19704
|
-
updateVisibility() {
|
20350
|
+
updateVisibility(forceEmit) {
|
19705
20351
|
var _a, _b;
|
19706
20352
|
const lastVisibilityChange = this.elementInfos.reduce((prev, info) => Math.max(prev, info.visibilityChangedAt || 0), 0);
|
19707
20353
|
const backgroundPause = ((_b = (_a = this.adaptiveStreamSettings) === null || _a === void 0 ? void 0 : _a.pauseVideoInBackground) !== null && _b !== void 0 ? _b : true // default to true
|
19708
20354
|
) ? this.isInBackground : false;
|
19709
20355
|
const isPiPMode = this.elementInfos.some(info => info.pictureInPicture);
|
19710
20356
|
const isVisible = this.elementInfos.some(info => info.visible) && !backgroundPause || isPiPMode;
|
19711
|
-
if (this.lastVisible === isVisible) {
|
20357
|
+
if (this.lastVisible === isVisible && !forceEmit) {
|
19712
20358
|
return;
|
19713
20359
|
}
|
19714
20360
|
if (!isVisible && Date.now() - lastVisibilityChange < REACTION_DELAY) {
|
@@ -20533,10 +21179,9 @@ function trackPermissionToProto(perms) {
|
|
20533
21179
|
});
|
20534
21180
|
}
|
20535
21181
|
|
20536
|
-
const STREAM_CHUNK_SIZE = 15000;
|
20537
21182
|
class LocalParticipant extends Participant {
|
20538
21183
|
/** @internal */
|
20539
|
-
constructor(sid, identity, engine, options, roomRpcHandlers) {
|
21184
|
+
constructor(sid, identity, engine, options, roomRpcHandlers, roomOutgoingDataStreamManager) {
|
20540
21185
|
super(sid, identity, undefined, undefined, undefined, {
|
20541
21186
|
loggerName: options.loggerName,
|
20542
21187
|
loggerContextCb: () => this.engine.logContext
|
@@ -20768,6 +21413,7 @@ class LocalParticipant extends Participant {
|
|
20768
21413
|
this.activeDeviceMap = new Map([['audioinput', 'default'], ['videoinput', 'default'], ['audiooutput', 'default']]);
|
20769
21414
|
this.pendingSignalRequests = new Map();
|
20770
21415
|
this.rpcHandlers = roomRpcHandlers;
|
21416
|
+
this.roomOutgoingDataStreamManager = roomOutgoingDataStreamManager;
|
20771
21417
|
}
|
20772
21418
|
get lastCameraError() {
|
20773
21419
|
return this.cameraError;
|
@@ -21919,6 +22565,7 @@ class LocalParticipant extends Participant {
|
|
21919
22565
|
yield this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
|
21920
22566
|
});
|
21921
22567
|
}
|
22568
|
+
/** @deprecated Consider migrating to {@link sendText} */
|
21922
22569
|
sendChatMessage(text, options) {
|
21923
22570
|
return __awaiter(this, void 0, void 0, function* () {
|
21924
22571
|
const msg = {
|
@@ -21940,6 +22587,7 @@ class LocalParticipant extends Participant {
|
|
21940
22587
|
return msg;
|
21941
22588
|
});
|
21942
22589
|
}
|
22590
|
+
/** @deprecated Consider migrating to {@link sendText} */
|
21943
22591
|
editChatMessage(editText, originalMessage) {
|
21944
22592
|
return __awaiter(this, void 0, void 0, function* () {
|
21945
22593
|
const msg = Object.assign(Object.assign({}, originalMessage), {
|
@@ -21950,276 +22598,61 @@ class LocalParticipant extends Participant {
|
|
21950
22598
|
value: {
|
21951
22599
|
case: 'chatMessage',
|
21952
22600
|
value: new ChatMessage(Object.assign(Object.assign({}, msg), {
|
21953
|
-
timestamp: protoInt64.parse(msg.timestamp),
|
21954
|
-
editTimestamp: protoInt64.parse(msg.editTimestamp)
|
21955
|
-
}))
|
21956
|
-
}
|
21957
|
-
});
|
21958
|
-
yield this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
|
21959
|
-
this.emit(ParticipantEvent.ChatMessage, msg);
|
21960
|
-
return msg;
|
21961
|
-
});
|
21962
|
-
}
|
21963
|
-
sendText(text, options) {
|
21964
|
-
return __awaiter(this, void 0, void 0, function* () {
|
21965
|
-
var _a;
|
21966
|
-
const streamId = crypto.randomUUID();
|
21967
|
-
const textInBytes = new TextEncoder().encode(text);
|
21968
|
-
const totalTextLength = textInBytes.byteLength;
|
21969
|
-
const fileIds = (_a = options === null || options === void 0 ? void 0 : options.attachments) === null || _a === void 0 ? void 0 : _a.map(() => crypto.randomUUID());
|
21970
|
-
const progresses = new Array(fileIds ? fileIds.length + 1 : 1).fill(0);
|
21971
|
-
const handleProgress = (progress, idx) => {
|
21972
|
-
var _a;
|
21973
|
-
progresses[idx] = progress;
|
21974
|
-
const totalProgress = progresses.reduce((acc, val) => acc + val, 0);
|
21975
|
-
(_a = options === null || options === void 0 ? void 0 : options.onProgress) === null || _a === void 0 ? void 0 : _a.call(options, totalProgress);
|
21976
|
-
};
|
21977
|
-
const writer = yield this.streamText({
|
21978
|
-
streamId,
|
21979
|
-
totalSize: totalTextLength,
|
21980
|
-
destinationIdentities: options === null || options === void 0 ? void 0 : options.destinationIdentities,
|
21981
|
-
topic: options === null || options === void 0 ? void 0 : options.topic,
|
21982
|
-
attachedStreamIds: fileIds,
|
21983
|
-
attributes: options === null || options === void 0 ? void 0 : options.attributes
|
21984
|
-
});
|
21985
|
-
yield writer.write(text);
|
21986
|
-
// set text part of progress to 1
|
21987
|
-
handleProgress(1, 0);
|
21988
|
-
yield writer.close();
|
21989
|
-
if ((options === null || options === void 0 ? void 0 : options.attachments) && fileIds) {
|
21990
|
-
yield Promise.all(options.attachments.map((file, idx) => __awaiter(this, void 0, void 0, function* () {
|
21991
|
-
return this._sendFile(fileIds[idx], file, {
|
21992
|
-
topic: options.topic,
|
21993
|
-
mimeType: file.type,
|
21994
|
-
onProgress: progress => {
|
21995
|
-
handleProgress(progress, idx + 1);
|
21996
|
-
}
|
21997
|
-
});
|
21998
|
-
})));
|
21999
|
-
}
|
22000
|
-
return writer.info;
|
22001
|
-
});
|
22002
|
-
}
|
22003
|
-
/**
|
22004
|
-
* @internal
|
22005
|
-
* @experimental CAUTION, might get removed in a minor release
|
22006
|
-
*/
|
22007
|
-
streamText(options) {
|
22008
|
-
return __awaiter(this, void 0, void 0, function* () {
|
22009
|
-
var _a, _b;
|
22010
|
-
const streamId = (_a = options === null || options === void 0 ? void 0 : options.streamId) !== null && _a !== void 0 ? _a : crypto.randomUUID();
|
22011
|
-
const info = {
|
22012
|
-
id: streamId,
|
22013
|
-
mimeType: 'text/plain',
|
22014
|
-
timestamp: Date.now(),
|
22015
|
-
topic: (_b = options === null || options === void 0 ? void 0 : options.topic) !== null && _b !== void 0 ? _b : '',
|
22016
|
-
size: options === null || options === void 0 ? void 0 : options.totalSize,
|
22017
|
-
attributes: options === null || options === void 0 ? void 0 : options.attributes
|
22018
|
-
};
|
22019
|
-
const header = new DataStream_Header({
|
22020
|
-
streamId,
|
22021
|
-
mimeType: info.mimeType,
|
22022
|
-
topic: info.topic,
|
22023
|
-
timestamp: numberToBigInt(info.timestamp),
|
22024
|
-
totalLength: numberToBigInt(options === null || options === void 0 ? void 0 : options.totalSize),
|
22025
|
-
attributes: info.attributes,
|
22026
|
-
contentHeader: {
|
22027
|
-
case: 'textHeader',
|
22028
|
-
value: new DataStream_TextHeader({
|
22029
|
-
version: options === null || options === void 0 ? void 0 : options.version,
|
22030
|
-
attachedStreamIds: options === null || options === void 0 ? void 0 : options.attachedStreamIds,
|
22031
|
-
replyToStreamId: options === null || options === void 0 ? void 0 : options.replyToStreamId,
|
22032
|
-
operationType: (options === null || options === void 0 ? void 0 : options.type) === 'update' ? DataStream_OperationType.UPDATE : DataStream_OperationType.CREATE
|
22033
|
-
})
|
22034
|
-
}
|
22035
|
-
});
|
22036
|
-
const destinationIdentities = options === null || options === void 0 ? void 0 : options.destinationIdentities;
|
22037
|
-
const packet = new DataPacket({
|
22038
|
-
destinationIdentities,
|
22039
|
-
value: {
|
22040
|
-
case: 'streamHeader',
|
22041
|
-
value: header
|
22042
|
-
}
|
22043
|
-
});
|
22044
|
-
yield this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
|
22045
|
-
let chunkId = 0;
|
22046
|
-
const localP = this;
|
22047
|
-
const writableStream = new WritableStream({
|
22048
|
-
// Implement the sink
|
22049
|
-
write(text) {
|
22050
|
-
return __awaiter(this, void 0, void 0, function* () {
|
22051
|
-
for (const textByteChunk of splitUtf8(text, STREAM_CHUNK_SIZE)) {
|
22052
|
-
yield localP.engine.waitForBufferStatusLow(DataPacket_Kind.RELIABLE);
|
22053
|
-
const chunk = new DataStream_Chunk({
|
22054
|
-
content: textByteChunk,
|
22055
|
-
streamId,
|
22056
|
-
chunkIndex: numberToBigInt(chunkId)
|
22057
|
-
});
|
22058
|
-
const chunkPacket = new DataPacket({
|
22059
|
-
destinationIdentities,
|
22060
|
-
value: {
|
22061
|
-
case: 'streamChunk',
|
22062
|
-
value: chunk
|
22063
|
-
}
|
22064
|
-
});
|
22065
|
-
yield localP.engine.sendDataPacket(chunkPacket, DataPacket_Kind.RELIABLE);
|
22066
|
-
chunkId += 1;
|
22067
|
-
}
|
22068
|
-
});
|
22069
|
-
},
|
22070
|
-
close() {
|
22071
|
-
return __awaiter(this, void 0, void 0, function* () {
|
22072
|
-
const trailer = new DataStream_Trailer({
|
22073
|
-
streamId
|
22074
|
-
});
|
22075
|
-
const trailerPacket = new DataPacket({
|
22076
|
-
destinationIdentities,
|
22077
|
-
value: {
|
22078
|
-
case: 'streamTrailer',
|
22079
|
-
value: trailer
|
22080
|
-
}
|
22081
|
-
});
|
22082
|
-
yield localP.engine.sendDataPacket(trailerPacket, DataPacket_Kind.RELIABLE);
|
22083
|
-
});
|
22084
|
-
},
|
22085
|
-
abort(err) {
|
22086
|
-
console.log('Sink error:', err);
|
22087
|
-
// TODO handle aborts to signal something to receiver side
|
22088
|
-
}
|
22089
|
-
});
|
22090
|
-
let onEngineClose = () => __awaiter(this, void 0, void 0, function* () {
|
22091
|
-
yield writer.close();
|
22092
|
-
});
|
22093
|
-
localP.engine.once(EngineEvent.Closing, onEngineClose);
|
22094
|
-
const writer = new TextStreamWriter(writableStream, info, () => this.engine.off(EngineEvent.Closing, onEngineClose));
|
22095
|
-
return writer;
|
22096
|
-
});
|
22097
|
-
}
|
22098
|
-
sendFile(file, options) {
|
22099
|
-
return __awaiter(this, void 0, void 0, function* () {
|
22100
|
-
const streamId = crypto.randomUUID();
|
22101
|
-
yield this._sendFile(streamId, file, options);
|
22102
|
-
return {
|
22103
|
-
id: streamId
|
22104
|
-
};
|
22105
|
-
});
|
22106
|
-
}
|
22107
|
-
_sendFile(streamId, file, options) {
|
22108
|
-
return __awaiter(this, void 0, void 0, function* () {
|
22109
|
-
var _a;
|
22110
|
-
const writer = yield this.streamBytes({
|
22111
|
-
streamId,
|
22112
|
-
totalSize: file.size,
|
22113
|
-
name: file.name,
|
22114
|
-
mimeType: (_a = options === null || options === void 0 ? void 0 : options.mimeType) !== null && _a !== void 0 ? _a : file.type,
|
22115
|
-
topic: options === null || options === void 0 ? void 0 : options.topic,
|
22116
|
-
destinationIdentities: options === null || options === void 0 ? void 0 : options.destinationIdentities
|
22117
|
-
});
|
22118
|
-
const reader = file.stream().getReader();
|
22119
|
-
while (true) {
|
22120
|
-
const {
|
22121
|
-
done,
|
22122
|
-
value
|
22123
|
-
} = yield reader.read();
|
22124
|
-
if (done) {
|
22125
|
-
break;
|
22126
|
-
}
|
22127
|
-
yield writer.write(value);
|
22128
|
-
}
|
22129
|
-
yield writer.close();
|
22130
|
-
return writer.info;
|
22131
|
-
});
|
22132
|
-
}
|
22133
|
-
streamBytes(options) {
|
22134
|
-
return __awaiter(this, void 0, void 0, function* () {
|
22135
|
-
var _a, _b, _c, _d, _e;
|
22136
|
-
const streamId = (_a = options === null || options === void 0 ? void 0 : options.streamId) !== null && _a !== void 0 ? _a : crypto.randomUUID();
|
22137
|
-
const destinationIdentities = options === null || options === void 0 ? void 0 : options.destinationIdentities;
|
22138
|
-
const info = {
|
22139
|
-
id: streamId,
|
22140
|
-
mimeType: (_b = options === null || options === void 0 ? void 0 : options.mimeType) !== null && _b !== void 0 ? _b : 'application/octet-stream',
|
22141
|
-
topic: (_c = options === null || options === void 0 ? void 0 : options.topic) !== null && _c !== void 0 ? _c : '',
|
22142
|
-
timestamp: Date.now(),
|
22143
|
-
attributes: options === null || options === void 0 ? void 0 : options.attributes,
|
22144
|
-
size: options === null || options === void 0 ? void 0 : options.totalSize,
|
22145
|
-
name: (_d = options === null || options === void 0 ? void 0 : options.name) !== null && _d !== void 0 ? _d : 'unknown'
|
22146
|
-
};
|
22147
|
-
const header = new DataStream_Header({
|
22148
|
-
totalLength: numberToBigInt((_e = info.size) !== null && _e !== void 0 ? _e : 0),
|
22149
|
-
mimeType: info.mimeType,
|
22150
|
-
streamId,
|
22151
|
-
topic: info.topic,
|
22152
|
-
timestamp: numberToBigInt(Date.now()),
|
22153
|
-
attributes: info.attributes,
|
22154
|
-
contentHeader: {
|
22155
|
-
case: 'byteHeader',
|
22156
|
-
value: new DataStream_ByteHeader({
|
22157
|
-
name: info.name
|
22158
|
-
})
|
22159
|
-
}
|
22160
|
-
});
|
22161
|
-
const packet = new DataPacket({
|
22162
|
-
destinationIdentities,
|
22163
|
-
value: {
|
22164
|
-
case: 'streamHeader',
|
22165
|
-
value: header
|
22601
|
+
timestamp: protoInt64.parse(msg.timestamp),
|
22602
|
+
editTimestamp: protoInt64.parse(msg.editTimestamp)
|
22603
|
+
}))
|
22166
22604
|
}
|
22167
22605
|
});
|
22168
22606
|
yield this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
|
22169
|
-
|
22170
|
-
|
22171
|
-
|
22172
|
-
|
22173
|
-
|
22174
|
-
|
22175
|
-
|
22176
|
-
|
22177
|
-
|
22178
|
-
|
22179
|
-
|
22180
|
-
|
22181
|
-
|
22182
|
-
|
22183
|
-
|
22184
|
-
|
22185
|
-
|
22186
|
-
|
22187
|
-
|
22188
|
-
|
22189
|
-
|
22190
|
-
|
22191
|
-
|
22192
|
-
|
22193
|
-
|
22194
|
-
|
22195
|
-
|
22196
|
-
|
22197
|
-
|
22198
|
-
|
22199
|
-
|
22200
|
-
|
22201
|
-
|
22202
|
-
|
22203
|
-
|
22204
|
-
|
22205
|
-
|
22206
|
-
|
22207
|
-
|
22208
|
-
|
22209
|
-
|
22210
|
-
|
22211
|
-
|
22212
|
-
|
22213
|
-
|
22214
|
-
|
22215
|
-
|
22216
|
-
|
22217
|
-
|
22218
|
-
log.error('Sink error:', err);
|
22219
|
-
}
|
22220
|
-
});
|
22221
|
-
const byteWriter = new ByteStreamWriter(writableStream, info);
|
22222
|
-
return byteWriter;
|
22607
|
+
this.emit(ParticipantEvent.ChatMessage, msg);
|
22608
|
+
return msg;
|
22609
|
+
});
|
22610
|
+
}
|
22611
|
+
/**
|
22612
|
+
* Sends the given string to participants in the room via the data channel.
|
22613
|
+
* For longer messages, consider using {@link streamText} instead.
|
22614
|
+
*
|
22615
|
+
* @param text The text payload
|
22616
|
+
* @param options.topic Topic identifier used to route the stream to appropriate handlers.
|
22617
|
+
*/
|
22618
|
+
sendText(text, options) {
|
22619
|
+
return __awaiter(this, void 0, void 0, function* () {
|
22620
|
+
return this.roomOutgoingDataStreamManager.sendText(text, options);
|
22621
|
+
});
|
22622
|
+
}
|
22623
|
+
/**
|
22624
|
+
* Creates a new TextStreamWriter which can be used to stream text incrementally
|
22625
|
+
* to participants in the room via the data channel.
|
22626
|
+
*
|
22627
|
+
* @param options.topic Topic identifier used to route the stream to appropriate handlers.
|
22628
|
+
*
|
22629
|
+
* @internal
|
22630
|
+
* @experimental CAUTION, might get removed in a minor release
|
22631
|
+
*/
|
22632
|
+
streamText(options) {
|
22633
|
+
return __awaiter(this, void 0, void 0, function* () {
|
22634
|
+
return this.roomOutgoingDataStreamManager.streamText(options);
|
22635
|
+
});
|
22636
|
+
}
|
22637
|
+
/** Send a File to all participants in the room via the data channel.
|
22638
|
+
* @param file The File object payload
|
22639
|
+
* @param options.topic Topic identifier used to route the stream to appropriate handlers.
|
22640
|
+
* @param options.onProgress A callback function used to monitor the upload progress percentage.
|
22641
|
+
*/
|
22642
|
+
sendFile(file, options) {
|
22643
|
+
return __awaiter(this, void 0, void 0, function* () {
|
22644
|
+
return this.roomOutgoingDataStreamManager.sendFile(file, options);
|
22645
|
+
});
|
22646
|
+
}
|
22647
|
+
/**
|
22648
|
+
* Stream bytes incrementally to participants in the room via the data channel.
|
22649
|
+
* For sending files, consider using {@link sendFile} instead.
|
22650
|
+
*
|
22651
|
+
* @param options.topic Topic identifier used to route the stream to appropriate handlers.
|
22652
|
+
*/
|
22653
|
+
streamBytes(options) {
|
22654
|
+
return __awaiter(this, void 0, void 0, function* () {
|
22655
|
+
return this.roomOutgoingDataStreamManager.streamBytes(options);
|
22223
22656
|
});
|
22224
22657
|
}
|
22225
22658
|
/**
|
@@ -23051,10 +23484,6 @@ class Room extends eventsExports.EventEmitter {
|
|
23051
23484
|
this.log = livekitLogger;
|
23052
23485
|
this.bufferedEvents = [];
|
23053
23486
|
this.isResuming = false;
|
23054
|
-
this.byteStreamControllers = new Map();
|
23055
|
-
this.textStreamControllers = new Map();
|
23056
|
-
this.byteStreamHandlers = new Map();
|
23057
|
-
this.textStreamHandlers = new Map();
|
23058
23487
|
this.rpcHandlers = new Map();
|
23059
23488
|
this.connect = (url, token, opts) => __awaiter(this, void 0, void 0, function* () {
|
23060
23489
|
var _a;
|
@@ -23552,8 +23981,8 @@ class Room extends eventsExports.EventEmitter {
|
|
23552
23981
|
return;
|
23553
23982
|
}
|
23554
23983
|
const newStreamState = Track.streamStateFromProto(streamState.state);
|
23984
|
+
pub.track.setStreamState(newStreamState);
|
23555
23985
|
if (newStreamState !== pub.track.streamState) {
|
23556
|
-
pub.track.streamState = newStreamState;
|
23557
23986
|
participant.emit(ParticipantEvent.TrackStreamStateChanged, pub, pub.track.streamState);
|
23558
23987
|
this.emitWhenConnected(RoomEvent.TrackStreamStateChanged, pub, pub.track.streamState, participant);
|
23559
23988
|
}
|
@@ -23594,12 +24023,8 @@ class Room extends eventsExports.EventEmitter {
|
|
23594
24023
|
this.handleChatMessage(participant, packet.value.value);
|
23595
24024
|
} else if (packet.value.case === 'metrics') {
|
23596
24025
|
this.handleMetrics(packet.value.value, participant);
|
23597
|
-
} else if (packet.value.case === 'streamHeader') {
|
23598
|
-
this.
|
23599
|
-
} else if (packet.value.case === 'streamChunk') {
|
23600
|
-
this.handleStreamChunk(packet.value.value);
|
23601
|
-
} else if (packet.value.case === 'streamTrailer') {
|
23602
|
-
this.handleStreamTrailer(packet.value.value);
|
24026
|
+
} else if (packet.value.case === 'streamHeader' || packet.value.case === 'streamChunk' || packet.value.case === 'streamTrailer') {
|
24027
|
+
this.handleDataStream(packet);
|
23603
24028
|
} else if (packet.value.case === 'rpcRequest') {
|
23604
24029
|
const rpc = packet.value.value;
|
23605
24030
|
this.handleIncomingRpcRequest(packet.participantIdentity, rpc.id, rpc.method, rpc.payload, rpc.responseTimeoutMs, rpc.version);
|
@@ -23615,7 +24040,6 @@ class Room extends eventsExports.EventEmitter {
|
|
23615
24040
|
// also emit on the participant
|
23616
24041
|
participant === null || participant === void 0 ? void 0 : participant.emit(ParticipantEvent.SipDTMFReceived, dtmf);
|
23617
24042
|
};
|
23618
|
-
this.bufferedSegments = new Map();
|
23619
24043
|
this.handleTranscription = (_remoteParticipant, transcription) => {
|
23620
24044
|
// find the participant
|
23621
24045
|
const participant = transcription.transcribedParticipantIdentity === this.localParticipant.identity ? this.localParticipant : this.getParticipantByIdentity(transcription.transcribedParticipantIdentity);
|
@@ -23632,6 +24056,10 @@ class Room extends eventsExports.EventEmitter {
|
|
23632
24056
|
this.handleMetrics = (metrics, participant) => {
|
23633
24057
|
this.emit(RoomEvent.MetricsReceived, metrics, participant);
|
23634
24058
|
};
|
24059
|
+
this.handleDataStream = packet => {
|
24060
|
+
this.incomingDataStreamManager.handleDataStreamPacket(packet);
|
24061
|
+
};
|
24062
|
+
this.bufferedSegments = new Map();
|
23635
24063
|
this.handleAudioPlaybackStarted = () => {
|
23636
24064
|
if (this.canPlaybackAudio) {
|
23637
24065
|
return;
|
@@ -23766,8 +24194,10 @@ class Room extends eventsExports.EventEmitter {
|
|
23766
24194
|
this.options.videoCaptureDefaults = Object.assign(Object.assign({}, videoDefaults), options === null || options === void 0 ? void 0 : options.videoCaptureDefaults);
|
23767
24195
|
this.options.publishDefaults = Object.assign(Object.assign({}, publishDefaults), options === null || options === void 0 ? void 0 : options.publishDefaults);
|
23768
24196
|
this.maybeCreateEngine();
|
24197
|
+
this.incomingDataStreamManager = new IncomingDataStreamManager();
|
24198
|
+
this.outgoingDataStreamManager = new OutgoingDataStreamManager(this.engine, this.log);
|
23769
24199
|
this.disconnectLock = new _();
|
23770
|
-
this.localParticipant = new LocalParticipant('', '', this.engine, this.options, this.rpcHandlers);
|
24200
|
+
this.localParticipant = new LocalParticipant('', '', this.engine, this.options, this.rpcHandlers, this.outgoingDataStreamManager);
|
23771
24201
|
if (this.options.videoCaptureDefaults.deviceId) {
|
23772
24202
|
this.localParticipant.activeDeviceMap.set('videoinput', unwrapConstraint(this.options.videoCaptureDefaults.deviceId));
|
23773
24203
|
}
|
@@ -23794,22 +24224,16 @@ class Room extends eventsExports.EventEmitter {
|
|
23794
24224
|
}
|
23795
24225
|
}
|
23796
24226
|
registerTextStreamHandler(topic, callback) {
|
23797
|
-
|
23798
|
-
throw new TypeError("A text stream handler for topic \"".concat(topic, "\" has already been set."));
|
23799
|
-
}
|
23800
|
-
this.textStreamHandlers.set(topic, callback);
|
24227
|
+
return this.incomingDataStreamManager.registerTextStreamHandler(topic, callback);
|
23801
24228
|
}
|
23802
24229
|
unregisterTextStreamHandler(topic) {
|
23803
|
-
this.
|
24230
|
+
return this.incomingDataStreamManager.unregisterTextStreamHandler(topic);
|
23804
24231
|
}
|
23805
24232
|
registerByteStreamHandler(topic, callback) {
|
23806
|
-
|
23807
|
-
throw new TypeError("A byte stream handler for topic \"".concat(topic, "\" has already been set."));
|
23808
|
-
}
|
23809
|
-
this.byteStreamHandlers.set(topic, callback);
|
24233
|
+
return this.incomingDataStreamManager.registerByteStreamHandler(topic, callback);
|
23810
24234
|
}
|
23811
24235
|
unregisterByteStreamHandler(topic) {
|
23812
|
-
this.
|
24236
|
+
return this.incomingDataStreamManager.unregisterByteStreamHandler(topic);
|
23813
24237
|
}
|
23814
24238
|
/**
|
23815
24239
|
* Establishes the participant as a receiver for calls of the specified RPC method.
|
@@ -23851,44 +24275,6 @@ class Room extends eventsExports.EventEmitter {
|
|
23851
24275
|
unregisterRpcMethod(method) {
|
23852
24276
|
this.rpcHandlers.delete(method);
|
23853
24277
|
}
|
23854
|
-
handleIncomingRpcRequest(callerIdentity, requestId, method, payload, responseTimeout, version) {
|
23855
|
-
return __awaiter(this, void 0, void 0, function* () {
|
23856
|
-
yield this.engine.publishRpcAck(callerIdentity, requestId);
|
23857
|
-
if (version !== 1) {
|
23858
|
-
yield this.engine.publishRpcResponse(callerIdentity, requestId, null, RpcError.builtIn('UNSUPPORTED_VERSION'));
|
23859
|
-
return;
|
23860
|
-
}
|
23861
|
-
const handler = this.rpcHandlers.get(method);
|
23862
|
-
if (!handler) {
|
23863
|
-
yield this.engine.publishRpcResponse(callerIdentity, requestId, null, RpcError.builtIn('UNSUPPORTED_METHOD'));
|
23864
|
-
return;
|
23865
|
-
}
|
23866
|
-
let responseError = null;
|
23867
|
-
let responsePayload = null;
|
23868
|
-
try {
|
23869
|
-
const response = yield handler({
|
23870
|
-
requestId,
|
23871
|
-
callerIdentity,
|
23872
|
-
payload,
|
23873
|
-
responseTimeout
|
23874
|
-
});
|
23875
|
-
if (byteLength(response) > MAX_PAYLOAD_BYTES) {
|
23876
|
-
responseError = RpcError.builtIn('RESPONSE_PAYLOAD_TOO_LARGE');
|
23877
|
-
console.warn("RPC Response payload too large for ".concat(method));
|
23878
|
-
} else {
|
23879
|
-
responsePayload = response;
|
23880
|
-
}
|
23881
|
-
} catch (error) {
|
23882
|
-
if (error instanceof RpcError) {
|
23883
|
-
responseError = error;
|
23884
|
-
} else {
|
23885
|
-
console.warn("Uncaught error returned by RPC handler for ".concat(method, ". Returning APPLICATION_ERROR instead."), error);
|
23886
|
-
responseError = RpcError.builtIn('APPLICATION_ERROR');
|
23887
|
-
}
|
23888
|
-
}
|
23889
|
-
yield this.engine.publishRpcResponse(callerIdentity, requestId, responsePayload, responseError);
|
23890
|
-
});
|
23891
|
-
}
|
23892
24278
|
/**
|
23893
24279
|
* @experimental
|
23894
24280
|
*/
|
@@ -24053,6 +24439,9 @@ class Room extends eventsExports.EventEmitter {
|
|
24053
24439
|
if (this.e2eeManager) {
|
24054
24440
|
this.e2eeManager.setupEngine(this.engine);
|
24055
24441
|
}
|
24442
|
+
if (this.outgoingDataStreamManager) {
|
24443
|
+
this.outgoingDataStreamManager.setupEngine(this.engine);
|
24444
|
+
}
|
24056
24445
|
}
|
24057
24446
|
/**
|
24058
24447
|
* getLocalDevices abstracts navigator.mediaDevices.enumerateDevices.
|
@@ -24419,7 +24808,10 @@ class Room extends eventsExports.EventEmitter {
|
|
24419
24808
|
adaptiveStreamSettings = {};
|
24420
24809
|
}
|
24421
24810
|
}
|
24422
|
-
participant.addSubscribedMediaTrack(mediaTrack, trackId, stream, receiver, adaptiveStreamSettings);
|
24811
|
+
const publication = participant.addSubscribedMediaTrack(mediaTrack, trackId, stream, receiver, adaptiveStreamSettings);
|
24812
|
+
if ((publication === null || publication === void 0 ? void 0 : publication.isEncrypted) && !this.e2eeManager) {
|
24813
|
+
this.emit(RoomEvent.EncryptionError, new Error("Encrypted ".concat(publication.source, " track received from participant ").concat(participant.sid, ", but room does not have encryption enabled!")));
|
24814
|
+
}
|
24423
24815
|
}
|
24424
24816
|
handleDisconnect() {
|
24425
24817
|
let shouldStopTracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
@@ -24429,6 +24821,7 @@ class Room extends eventsExports.EventEmitter {
|
|
24429
24821
|
this.isResuming = false;
|
24430
24822
|
this.bufferedEvents = [];
|
24431
24823
|
this.transcriptionReceivedTimes.clear();
|
24824
|
+
this.incomingDataStreamManager.clearHandlersAndControllers();
|
24432
24825
|
if (this.state === ConnectionState.Disconnected) {
|
24433
24826
|
return;
|
24434
24827
|
}
|
@@ -24480,6 +24873,7 @@ class Room extends eventsExports.EventEmitter {
|
|
24480
24873
|
if (!participant) {
|
24481
24874
|
return;
|
24482
24875
|
}
|
24876
|
+
this.incomingDataStreamManager.validateParticipantHasNoActiveDataStreams(identity);
|
24483
24877
|
participant.trackPublications.forEach(publication => {
|
24484
24878
|
participant.unpublishTrack(publication.trackSid, true);
|
24485
24879
|
});
|
@@ -24487,99 +24881,44 @@ class Room extends eventsExports.EventEmitter {
|
|
24487
24881
|
participant.setDisconnected();
|
24488
24882
|
(_a = this.localParticipant) === null || _a === void 0 ? void 0 : _a.handleParticipantDisconnected(participant.identity);
|
24489
24883
|
}
|
24490
|
-
|
24884
|
+
handleIncomingRpcRequest(callerIdentity, requestId, method, payload, responseTimeout, version) {
|
24491
24885
|
return __awaiter(this, void 0, void 0, function* () {
|
24492
|
-
|
24493
|
-
if (
|
24494
|
-
|
24495
|
-
|
24496
|
-
|
24497
|
-
|
24498
|
-
|
24499
|
-
|
24500
|
-
|
24501
|
-
|
24502
|
-
|
24503
|
-
|
24504
|
-
|
24505
|
-
|
24506
|
-
|
24507
|
-
|
24508
|
-
|
24509
|
-
|
24510
|
-
start: controller => {
|
24511
|
-
streamController = controller;
|
24512
|
-
this.byteStreamControllers.set(streamHeader.streamId, {
|
24513
|
-
info,
|
24514
|
-
controller: streamController,
|
24515
|
-
startTime: Date.now()
|
24516
|
-
});
|
24517
|
-
}
|
24518
|
-
});
|
24519
|
-
streamHandlerCallback(new ByteStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength)), {
|
24520
|
-
identity: participantIdentity
|
24886
|
+
yield this.engine.publishRpcAck(callerIdentity, requestId);
|
24887
|
+
if (version !== 1) {
|
24888
|
+
yield this.engine.publishRpcResponse(callerIdentity, requestId, null, RpcError.builtIn('UNSUPPORTED_VERSION'));
|
24889
|
+
return;
|
24890
|
+
}
|
24891
|
+
const handler = this.rpcHandlers.get(method);
|
24892
|
+
if (!handler) {
|
24893
|
+
yield this.engine.publishRpcResponse(callerIdentity, requestId, null, RpcError.builtIn('UNSUPPORTED_METHOD'));
|
24894
|
+
return;
|
24895
|
+
}
|
24896
|
+
let responseError = null;
|
24897
|
+
let responsePayload = null;
|
24898
|
+
try {
|
24899
|
+
const response = yield handler({
|
24900
|
+
requestId,
|
24901
|
+
callerIdentity,
|
24902
|
+
payload,
|
24903
|
+
responseTimeout
|
24521
24904
|
});
|
24522
|
-
|
24523
|
-
|
24524
|
-
|
24525
|
-
|
24526
|
-
|
24905
|
+
if (byteLength(response) > MAX_PAYLOAD_BYTES) {
|
24906
|
+
responseError = RpcError.builtIn('RESPONSE_PAYLOAD_TOO_LARGE');
|
24907
|
+
console.warn("RPC Response payload too large for ".concat(method));
|
24908
|
+
} else {
|
24909
|
+
responsePayload = response;
|
24910
|
+
}
|
24911
|
+
} catch (error) {
|
24912
|
+
if (error instanceof RpcError) {
|
24913
|
+
responseError = error;
|
24914
|
+
} else {
|
24915
|
+
console.warn("Uncaught error returned by RPC handler for ".concat(method, ". Returning APPLICATION_ERROR instead."), error);
|
24916
|
+
responseError = RpcError.builtIn('APPLICATION_ERROR');
|
24527
24917
|
}
|
24528
|
-
let streamController;
|
24529
|
-
const info = {
|
24530
|
-
id: streamHeader.streamId,
|
24531
|
-
mimeType: streamHeader.mimeType,
|
24532
|
-
size: streamHeader.totalLength ? Number(streamHeader.totalLength) : undefined,
|
24533
|
-
topic: streamHeader.topic,
|
24534
|
-
timestamp: Number(streamHeader.timestamp),
|
24535
|
-
attributes: streamHeader.attributes
|
24536
|
-
};
|
24537
|
-
const stream = new ReadableStream({
|
24538
|
-
start: controller => {
|
24539
|
-
streamController = controller;
|
24540
|
-
this.textStreamControllers.set(streamHeader.streamId, {
|
24541
|
-
info,
|
24542
|
-
controller: streamController,
|
24543
|
-
startTime: Date.now()
|
24544
|
-
});
|
24545
|
-
}
|
24546
|
-
});
|
24547
|
-
streamHandlerCallback(new TextStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength)), {
|
24548
|
-
identity: participantIdentity
|
24549
|
-
});
|
24550
24918
|
}
|
24919
|
+
yield this.engine.publishRpcResponse(callerIdentity, requestId, responsePayload, responseError);
|
24551
24920
|
});
|
24552
24921
|
}
|
24553
|
-
handleStreamChunk(chunk) {
|
24554
|
-
const fileBuffer = this.byteStreamControllers.get(chunk.streamId);
|
24555
|
-
if (fileBuffer) {
|
24556
|
-
if (chunk.content.length > 0) {
|
24557
|
-
fileBuffer.controller.enqueue(chunk);
|
24558
|
-
}
|
24559
|
-
}
|
24560
|
-
const textBuffer = this.textStreamControllers.get(chunk.streamId);
|
24561
|
-
if (textBuffer) {
|
24562
|
-
if (chunk.content.length > 0) {
|
24563
|
-
textBuffer.controller.enqueue(chunk);
|
24564
|
-
}
|
24565
|
-
}
|
24566
|
-
}
|
24567
|
-
handleStreamTrailer(trailer) {
|
24568
|
-
const textBuffer = this.textStreamControllers.get(trailer.streamId);
|
24569
|
-
if (textBuffer) {
|
24570
|
-
textBuffer.info.attributes = Object.assign(Object.assign({}, textBuffer.info.attributes), trailer.attributes);
|
24571
|
-
textBuffer.controller.close();
|
24572
|
-
this.textStreamControllers.delete(trailer.streamId);
|
24573
|
-
}
|
24574
|
-
const fileBuffer = this.byteStreamControllers.get(trailer.streamId);
|
24575
|
-
if (fileBuffer) {
|
24576
|
-
{
|
24577
|
-
fileBuffer.info.attributes = Object.assign(Object.assign({}, fileBuffer.info.attributes), trailer.attributes);
|
24578
|
-
fileBuffer.controller.close();
|
24579
|
-
this.byteStreamControllers.delete(trailer.streamId);
|
24580
|
-
}
|
24581
|
-
}
|
24582
|
-
}
|
24583
24922
|
/**
|
24584
24923
|
* attempt to select the default devices if the previously selected devices are no longer available after a device change event
|
24585
24924
|
*/
|
@@ -25835,5 +26174,5 @@ function isFacingModeValue(item) {
|
|
25835
26174
|
return item === undefined || allowedValues.includes(item);
|
25836
26175
|
}
|
25837
26176
|
|
25838
|
-
export { AudioPresets, BackupCodecPolicy, BaseKeyProvider, CheckStatus, Checker, ConnectionCheck, ConnectionError, ConnectionErrorReason, ConnectionQuality, ConnectionState, CriticalTimers, CryptorError, CryptorErrorReason, CryptorEvent, DataPacket_Kind, DefaultReconnectPolicy, DeviceUnsupportedError, DisconnectReason, EncryptionEvent, EngineEvent, ExternalE2EEKeyProvider, KeyHandlerEvent, KeyProviderEvent, LivekitError, 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, SignalRequestError, SubscriptionError, Track, TrackEvent, TrackInvalidError, TrackPublication, TrackType, UnexpectedConnectionState, UnsupportedServer, VideoPreset, VideoPresets, VideoPresets43, VideoQuality, attachToElement, attributeTypings as attributes, compareVersions, createAudioAnalyser, createE2EEKey, createKeyMaterialFromBuffer, createKeyMaterialFromString, createLocalAudioTrack, createLocalScreenTracks, createLocalTracks, createLocalVideoTrack, deriveKeys, detachTrack, facingModeFromDeviceLabel, facingModeFromLocalTrack, getBrowser, getEmptyAudioStreamTrack, getEmptyVideoStreamTrack, getLogger, importKey, isAudioTrack, isBackupCodec, isBrowserSupported, isE2EESupported, isInsertableStreamSupported, isLocalParticipant, isLocalTrack, isRemoteParticipant, isRemoteTrack, isScriptTransformSupported, isVideoFrame, isVideoTrack, needsRbspUnescaping, parseRbsp, protocolVersion, ratchet, setLogExtension, setLogLevel, supportsAV1, supportsAdaptiveStream, supportsDynacast, supportsVP9, version, videoCodecs, writeRbsp };
|
26177
|
+
export { AudioPresets, BackupCodecPolicy, BaseKeyProvider, CheckStatus, Checker, ConnectionCheck, ConnectionError, ConnectionErrorReason, ConnectionQuality, ConnectionState, CriticalTimers, CryptorError, CryptorErrorReason, CryptorEvent, DataPacket_Kind, DataStreamError, DataStreamErrorReason, DefaultReconnectPolicy, DeviceUnsupportedError, DisconnectReason, EncryptionEvent, EngineEvent, ExternalE2EEKeyProvider, KeyHandlerEvent, KeyProviderEvent, LivekitError, 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, SignalRequestError, SubscriptionError, Track, TrackEvent, TrackInvalidError, TrackPublication, TrackType, UnexpectedConnectionState, UnsupportedServer, VideoPreset, VideoPresets, VideoPresets43, VideoQuality, attachToElement, attributeTypings as attributes, compareVersions, createAudioAnalyser, createE2EEKey, createKeyMaterialFromBuffer, createKeyMaterialFromString, createLocalAudioTrack, createLocalScreenTracks, createLocalTracks, createLocalVideoTrack, deriveKeys, detachTrack, facingModeFromDeviceLabel, facingModeFromLocalTrack, getBrowser, getEmptyAudioStreamTrack, getEmptyVideoStreamTrack, getLogger, importKey, isAudioTrack, isBackupCodec, isBrowserSupported, isE2EESupported, isInsertableStreamSupported, isLocalParticipant, isLocalTrack, isRemoteParticipant, isRemoteTrack, isScriptTransformSupported, isVideoFrame, isVideoTrack, needsRbspUnescaping, parseRbsp, protocolVersion, ratchet, setLogExtension, setLogLevel, supportsAV1, supportsAdaptiveStream, supportsDynacast, supportsVP9, version, videoCodecs, writeRbsp };
|
25839
26178
|
//# sourceMappingURL=livekit-client.esm.mjs.map
|