livekit-client 2.15.3 → 2.15.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- 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 +329 -124
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +868 -548
- 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/api/SignalClient.d.ts.map +1 -1
- package/dist/src/e2ee/worker/FrameCryptor.d.ts +0 -46
- 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/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/src/room/{StreamReader.d.ts → data-stream/incoming/StreamReader.d.ts} +32 -6
- 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 +33 -20
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +8 -2
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/record.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/ts4.2/src/e2ee/worker/FrameCryptor.d.ts +0 -46
- package/dist/ts4.2/src/e2ee/worker/naluUtils.d.ts +27 -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/ts4.2/src/room/{StreamReader.d.ts → data-stream/incoming/StreamReader.d.ts} +32 -6
- 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 +33 -20
- package/dist/ts4.2/src/room/track/LocalTrack.d.ts +8 -2
- package/dist/ts4.2/src/room/types.d.ts +17 -1
- package/package.json +1 -1
- package/src/api/SignalClient.ts +6 -0
- package/src/e2ee/worker/FrameCryptor.ts +48 -139
- package/src/e2ee/worker/naluUtils.ts +328 -0
- package/src/index.ts +2 -2
- package/src/room/Room.ts +94 -207
- 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 +48 -299
- package/src/room/track/LocalAudioTrack.ts +2 -2
- package/src/room/track/LocalTrack.ts +75 -49
- package/src/room/track/record.ts +15 -2
- package/src/room/types.ts +22 -1
- package/src/room/utils.ts +3 -3
- package/dist/src/room/StreamReader.d.ts.map +0 -1
- package/dist/src/room/StreamWriter.d.ts.map +0 -1
- 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.5";
|
11368
11392
|
|
11369
11393
|
const version = version$1;
|
11370
11394
|
const protocolVersion = 16;
|
@@ -11956,7 +11980,7 @@ function isSVCCodec(codec) {
|
|
11956
11980
|
return codec === 'av1' || codec === 'vp9';
|
11957
11981
|
}
|
11958
11982
|
function supportsSetSinkId(elm) {
|
11959
|
-
if (!document) {
|
11983
|
+
if (!document || isSafariBased()) {
|
11960
11984
|
return false;
|
11961
11985
|
}
|
11962
11986
|
if (!elm) {
|
@@ -12246,13 +12270,13 @@ function unwrapConstraint(constraint) {
|
|
12246
12270
|
if (Array.isArray(constraint)) {
|
12247
12271
|
return constraint[0];
|
12248
12272
|
}
|
12249
|
-
if (constraint.exact) {
|
12273
|
+
if (constraint.exact !== undefined) {
|
12250
12274
|
if (Array.isArray(constraint.exact)) {
|
12251
12275
|
return constraint.exact[0];
|
12252
12276
|
}
|
12253
12277
|
return constraint.exact;
|
12254
12278
|
}
|
12255
|
-
if (constraint.ideal) {
|
12279
|
+
if (constraint.ideal !== undefined) {
|
12256
12280
|
if (Array.isArray(constraint.ideal)) {
|
12257
12281
|
return constraint.ideal[0];
|
12258
12282
|
}
|
@@ -13639,6 +13663,12 @@ class SignalClient {
|
|
13639
13663
|
if (_this3.signalLatency) {
|
13640
13664
|
yield sleep(_this3.signalLatency);
|
13641
13665
|
}
|
13666
|
+
if (_this3.isDisconnected) {
|
13667
|
+
// Skip requests if the signal layer is disconnected
|
13668
|
+
// This can happen if an event is sent in the mist of room.connect() initializing
|
13669
|
+
_this3.log.debug("skipping signal request (type: ".concat(message.case, ") - SignalClient disconnected"));
|
13670
|
+
return;
|
13671
|
+
}
|
13642
13672
|
if (!_this3.ws || _this3.ws.readyState !== _this3.ws.OPEN) {
|
13643
13673
|
_this3.log.error("cannot send signal request before connected, type: ".concat(message === null || message === void 0 ? void 0 : message.case), _this3.logContext);
|
13644
13674
|
return;
|
@@ -15844,11 +15874,21 @@ class LocalTrackRecorder extends RecorderBase {
|
|
15844
15874
|
start: controller => {
|
15845
15875
|
streamController = controller;
|
15846
15876
|
dataListener = event => __awaiter(this, void 0, void 0, function* () {
|
15847
|
-
|
15877
|
+
let data;
|
15878
|
+
if (event.data.arrayBuffer) {
|
15879
|
+
const arrayBuffer = yield event.data.arrayBuffer();
|
15880
|
+
data = new Uint8Array(arrayBuffer);
|
15881
|
+
// @ts-expect-error react-native passes over Uint8Arrays directly
|
15882
|
+
} else if (event.data.byteArray) {
|
15883
|
+
// @ts-expect-error
|
15884
|
+
data = event.data.byteArray;
|
15885
|
+
} else {
|
15886
|
+
throw new Error('no data available!');
|
15887
|
+
}
|
15848
15888
|
if (isClosed()) {
|
15849
15889
|
return;
|
15850
15890
|
}
|
15851
|
-
controller.enqueue(
|
15891
|
+
controller.enqueue(data);
|
15852
15892
|
});
|
15853
15893
|
this.addEventListener('dataavailable', dataListener);
|
15854
15894
|
},
|
@@ -15915,9 +15955,14 @@ class LocalTrack extends Track {
|
|
15915
15955
|
this.providedByUser = userProvidedTrack;
|
15916
15956
|
this.muteLock = new _();
|
15917
15957
|
this.pauseUpstreamLock = new _();
|
15918
|
-
this.
|
15919
|
-
this.
|
15920
|
-
|
15958
|
+
this.trackChangeLock = new _();
|
15959
|
+
this.trackChangeLock.lock().then(unlock => __awaiter(this, void 0, void 0, function* () {
|
15960
|
+
try {
|
15961
|
+
yield this.setMediaStreamTrack(mediaTrack, true);
|
15962
|
+
} finally {
|
15963
|
+
unlock();
|
15964
|
+
}
|
15965
|
+
}));
|
15921
15966
|
// added to satisfy TS compiler, constraints are synced with MediaStreamTrack
|
15922
15967
|
this._constraints = mediaTrack.getConstraints();
|
15923
15968
|
if (constraints) {
|
@@ -15993,26 +16038,21 @@ class LocalTrack extends Track {
|
|
15993
16038
|
}
|
15994
16039
|
let processedTrack;
|
15995
16040
|
if (this.processor && newTrack) {
|
15996
|
-
|
15997
|
-
|
15998
|
-
|
15999
|
-
if (this.kind === 'unknown') {
|
16000
|
-
throw TypeError('cannot set processor on track of unknown kind');
|
16001
|
-
}
|
16002
|
-
if (this.processorElement) {
|
16003
|
-
attachToElement(newTrack, this.processorElement);
|
16004
|
-
// ensure the processorElement itself stays muted
|
16005
|
-
this.processorElement.muted = true;
|
16006
|
-
}
|
16007
|
-
yield this.processor.restart({
|
16008
|
-
track: newTrack,
|
16009
|
-
kind: this.kind,
|
16010
|
-
element: this.processorElement
|
16011
|
-
});
|
16012
|
-
processedTrack = this.processor.processedTrack;
|
16013
|
-
} finally {
|
16014
|
-
unlock();
|
16041
|
+
this.log.debug('restarting processor', this.logContext);
|
16042
|
+
if (this.kind === 'unknown') {
|
16043
|
+
throw TypeError('cannot set processor on track of unknown kind');
|
16015
16044
|
}
|
16045
|
+
if (this.processorElement) {
|
16046
|
+
attachToElement(newTrack, this.processorElement);
|
16047
|
+
// ensure the processorElement itself stays muted
|
16048
|
+
this.processorElement.muted = true;
|
16049
|
+
}
|
16050
|
+
yield this.processor.restart({
|
16051
|
+
track: newTrack,
|
16052
|
+
kind: this.kind,
|
16053
|
+
element: this.processorElement
|
16054
|
+
});
|
16055
|
+
processedTrack = this.processor.processedTrack;
|
16016
16056
|
}
|
16017
16057
|
if (this.sender && ((_a = this.sender.transport) === null || _a === void 0 ? void 0 : _a.state) !== 'closed') {
|
16018
16058
|
yield this.sender.replaceTrack(processedTrack !== null && processedTrack !== void 0 ? processedTrack : newTrack);
|
@@ -16110,32 +16150,37 @@ class LocalTrack extends Track {
|
|
16110
16150
|
}
|
16111
16151
|
replaceTrack(track, userProvidedOrOptions) {
|
16112
16152
|
return __awaiter(this, void 0, void 0, function* () {
|
16113
|
-
|
16114
|
-
|
16115
|
-
|
16116
|
-
|
16117
|
-
|
16118
|
-
|
16119
|
-
|
16120
|
-
|
16121
|
-
|
16122
|
-
|
16123
|
-
|
16124
|
-
|
16125
|
-
|
16126
|
-
|
16127
|
-
|
16128
|
-
|
16129
|
-
|
16130
|
-
|
16153
|
+
const unlock = yield this.trackChangeLock.lock();
|
16154
|
+
try {
|
16155
|
+
if (!this.sender) {
|
16156
|
+
throw new TrackInvalidError('unable to replace an unpublished track');
|
16157
|
+
}
|
16158
|
+
let userProvidedTrack;
|
16159
|
+
let stopProcessor;
|
16160
|
+
if (typeof userProvidedOrOptions === 'boolean') {
|
16161
|
+
userProvidedTrack = userProvidedOrOptions;
|
16162
|
+
} else if (userProvidedOrOptions !== undefined) {
|
16163
|
+
userProvidedTrack = userProvidedOrOptions.userProvidedTrack;
|
16164
|
+
stopProcessor = userProvidedOrOptions.stopProcessor;
|
16165
|
+
}
|
16166
|
+
this.providedByUser = userProvidedTrack !== null && userProvidedTrack !== void 0 ? userProvidedTrack : true;
|
16167
|
+
this.log.debug('replace MediaStreamTrack', this.logContext);
|
16168
|
+
yield this.setMediaStreamTrack(track);
|
16169
|
+
// this must be synced *after* setting mediaStreamTrack above, since it relies
|
16170
|
+
// on the previous state in order to cleanup
|
16171
|
+
if (stopProcessor && this.processor) {
|
16172
|
+
yield this.internalStopProcessor();
|
16173
|
+
}
|
16174
|
+
return this;
|
16175
|
+
} finally {
|
16176
|
+
unlock();
|
16131
16177
|
}
|
16132
|
-
return this;
|
16133
16178
|
});
|
16134
16179
|
}
|
16135
16180
|
restart(constraints) {
|
16136
16181
|
return __awaiter(this, void 0, void 0, function* () {
|
16137
16182
|
this.manuallyStopped = false;
|
16138
|
-
const unlock = yield this.
|
16183
|
+
const unlock = yield this.trackChangeLock.lock();
|
16139
16184
|
try {
|
16140
16185
|
if (!constraints) {
|
16141
16186
|
constraints = this._constraints;
|
@@ -16318,7 +16363,7 @@ class LocalTrack extends Track {
|
|
16318
16363
|
let showProcessedStreamLocally = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
16319
16364
|
return function* () {
|
16320
16365
|
var _a;
|
16321
|
-
const unlock = yield _this3.
|
16366
|
+
const unlock = yield _this3.trackChangeLock.lock();
|
16322
16367
|
try {
|
16323
16368
|
_this3.log.debug('setting up processor', _this3.logContext);
|
16324
16369
|
const processorElement = document.createElement(_this3.kind);
|
@@ -16331,7 +16376,7 @@ class LocalTrack extends Track {
|
|
16331
16376
|
yield processor.init(processorOptions);
|
16332
16377
|
_this3.log.debug('processor initialized', _this3.logContext);
|
16333
16378
|
if (_this3.processor) {
|
16334
|
-
yield _this3.
|
16379
|
+
yield _this3.internalStopProcessor();
|
16335
16380
|
}
|
16336
16381
|
if (_this3.kind === 'unknown') {
|
16337
16382
|
throw TypeError('cannot set processor on track of unknown kind');
|
@@ -16389,22 +16434,41 @@ class LocalTrack extends Track {
|
|
16389
16434
|
return __awaiter(this, arguments, void 0, function () {
|
16390
16435
|
var _this4 = this;
|
16391
16436
|
let keepElement = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
16437
|
+
return function* () {
|
16438
|
+
const unlock = yield _this4.trackChangeLock.lock();
|
16439
|
+
try {
|
16440
|
+
yield _this4.internalStopProcessor(keepElement);
|
16441
|
+
} finally {
|
16442
|
+
unlock();
|
16443
|
+
}
|
16444
|
+
}();
|
16445
|
+
});
|
16446
|
+
}
|
16447
|
+
/**
|
16448
|
+
* @internal
|
16449
|
+
* This method assumes the caller has acquired a trackChangeLock already.
|
16450
|
+
* The public facing method for stopping the processor is `stopProcessor` and it wraps this method in the trackChangeLock.
|
16451
|
+
*/
|
16452
|
+
internalStopProcessor() {
|
16453
|
+
return __awaiter(this, arguments, void 0, function () {
|
16454
|
+
var _this5 = this;
|
16455
|
+
let keepElement = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
16392
16456
|
return function* () {
|
16393
16457
|
var _a, _b;
|
16394
|
-
if (!
|
16395
|
-
|
16396
|
-
(_a =
|
16397
|
-
yield
|
16398
|
-
|
16458
|
+
if (!_this5.processor) return;
|
16459
|
+
_this5.log.debug('stopping processor', _this5.logContext);
|
16460
|
+
(_a = _this5.processor.processedTrack) === null || _a === void 0 ? void 0 : _a.stop();
|
16461
|
+
yield _this5.processor.destroy();
|
16462
|
+
_this5.processor = undefined;
|
16399
16463
|
if (!keepElement) {
|
16400
|
-
(_b =
|
16401
|
-
|
16464
|
+
(_b = _this5.processorElement) === null || _b === void 0 ? void 0 : _b.remove();
|
16465
|
+
_this5.processorElement = undefined;
|
16402
16466
|
}
|
16403
16467
|
// apply original track constraints in case the processor changed them
|
16404
|
-
yield
|
16468
|
+
yield _this5._mediaStreamTrack.applyConstraints(_this5._constraints);
|
16405
16469
|
// force re-setting of the mediaStreamTrack on the sender
|
16406
|
-
yield
|
16407
|
-
|
16470
|
+
yield _this5.setMediaStreamTrack(_this5._mediaStreamTrack, true);
|
16471
|
+
_this5.emit(TrackEvent.TrackProcessorUpdate);
|
16408
16472
|
}();
|
16409
16473
|
});
|
16410
16474
|
}
|
@@ -16416,8 +16480,13 @@ class LocalTrack extends Track {
|
|
16416
16480
|
return;
|
16417
16481
|
}
|
16418
16482
|
if (!this.localTrackRecorder) {
|
16483
|
+
let mimeType = 'audio/webm;codecs=opus';
|
16484
|
+
if (!MediaRecorder.isTypeSupported(mimeType)) {
|
16485
|
+
// iOS currently only supports video/mp4 as a mime type - even for audio.
|
16486
|
+
mimeType = 'video/mp4';
|
16487
|
+
}
|
16419
16488
|
this.localTrackRecorder = new LocalTrackRecorder(this, {
|
16420
|
-
mimeType
|
16489
|
+
mimeType
|
16421
16490
|
});
|
16422
16491
|
} else {
|
16423
16492
|
this.log.warn('preconnect buffer already started');
|
@@ -16442,6 +16511,10 @@ class LocalTrack extends Track {
|
|
16442
16511
|
var _a;
|
16443
16512
|
return (_a = this.localTrackRecorder) === null || _a === void 0 ? void 0 : _a.byteStream;
|
16444
16513
|
}
|
16514
|
+
getPreConnectBufferMimeType() {
|
16515
|
+
var _a;
|
16516
|
+
return (_a = this.localTrackRecorder) === null || _a === void 0 ? void 0 : _a.mimeType;
|
16517
|
+
}
|
16445
16518
|
}
|
16446
16519
|
|
16447
16520
|
class LocalAudioTrack extends LocalTrack {
|
@@ -16589,13 +16662,13 @@ class LocalAudioTrack extends LocalTrack {
|
|
16589
16662
|
setProcessor(processor) {
|
16590
16663
|
return __awaiter(this, void 0, void 0, function* () {
|
16591
16664
|
var _a;
|
16592
|
-
const unlock = yield this.
|
16665
|
+
const unlock = yield this.trackChangeLock.lock();
|
16593
16666
|
try {
|
16594
16667
|
if (!isReactNative() && !this.audioContext) {
|
16595
16668
|
throw Error('Audio context needs to be set on LocalAudioTrack in order to enable processors');
|
16596
16669
|
}
|
16597
16670
|
if (this.processor) {
|
16598
|
-
yield this.
|
16671
|
+
yield this.internalStopProcessor();
|
16599
16672
|
}
|
16600
16673
|
const processorOptions = {
|
16601
16674
|
kind: this.kind,
|
@@ -18979,30 +19052,71 @@ class BaseStreamReader {
|
|
18979
19052
|
get info() {
|
18980
19053
|
return this._info;
|
18981
19054
|
}
|
18982
|
-
|
19055
|
+
/** @internal */
|
19056
|
+
validateBytesReceived() {
|
19057
|
+
let doneReceiving = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
19058
|
+
if (typeof this.totalByteSize !== 'number' || this.totalByteSize === 0) {
|
19059
|
+
return;
|
19060
|
+
}
|
19061
|
+
if (doneReceiving && this.bytesReceived < this.totalByteSize) {
|
19062
|
+
throw new DataStreamError("Not enough chunk(s) received - expected ".concat(this.totalByteSize, " bytes of data total, only received ").concat(this.bytesReceived, " bytes"), DataStreamErrorReason.Incomplete);
|
19063
|
+
} else if (this.bytesReceived > this.totalByteSize) {
|
19064
|
+
throw new DataStreamError("Extra chunk(s) received - expected ".concat(this.totalByteSize, " bytes of data total, received ").concat(this.bytesReceived, " bytes"), DataStreamErrorReason.LengthExceeded);
|
19065
|
+
}
|
19066
|
+
}
|
19067
|
+
constructor(info, stream, totalByteSize, outOfBandFailureRejectingFuture) {
|
18983
19068
|
this.reader = stream;
|
18984
19069
|
this.totalByteSize = totalByteSize;
|
18985
19070
|
this._info = info;
|
18986
19071
|
this.bytesReceived = 0;
|
19072
|
+
this.outOfBandFailureRejectingFuture = outOfBandFailureRejectingFuture;
|
18987
19073
|
}
|
18988
19074
|
}
|
18989
19075
|
class ByteStreamReader extends BaseStreamReader {
|
18990
19076
|
handleChunkReceived(chunk) {
|
18991
19077
|
var _a;
|
18992
19078
|
this.bytesReceived += chunk.content.byteLength;
|
19079
|
+
this.validateBytesReceived();
|
18993
19080
|
const currentProgress = this.totalByteSize ? this.bytesReceived / this.totalByteSize : undefined;
|
18994
19081
|
(_a = this.onProgress) === null || _a === void 0 ? void 0 : _a.call(this, currentProgress);
|
18995
19082
|
}
|
18996
19083
|
[Symbol.asyncIterator]() {
|
18997
19084
|
const reader = this.reader.getReader();
|
19085
|
+
let rejectingSignalFuture = new Future();
|
19086
|
+
let activeSignal = null;
|
19087
|
+
let onAbort = null;
|
19088
|
+
if (this.signal) {
|
19089
|
+
const signal = this.signal;
|
19090
|
+
onAbort = () => {
|
19091
|
+
var _a;
|
19092
|
+
(_a = rejectingSignalFuture.reject) === null || _a === void 0 ? void 0 : _a.call(rejectingSignalFuture, signal.reason);
|
19093
|
+
};
|
19094
|
+
signal.addEventListener('abort', onAbort);
|
19095
|
+
activeSignal = signal;
|
19096
|
+
}
|
19097
|
+
const cleanup = () => {
|
19098
|
+
reader.releaseLock();
|
19099
|
+
if (activeSignal && onAbort) {
|
19100
|
+
activeSignal.removeEventListener('abort', onAbort);
|
19101
|
+
}
|
19102
|
+
this.signal = undefined;
|
19103
|
+
};
|
18998
19104
|
return {
|
18999
19105
|
next: () => __awaiter(this, void 0, void 0, function* () {
|
19106
|
+
var _a, _b;
|
19000
19107
|
try {
|
19001
19108
|
const {
|
19002
19109
|
done,
|
19003
19110
|
value
|
19004
|
-
} = yield reader.read()
|
19111
|
+
} = yield Promise.race([reader.read(),
|
19112
|
+
// Rejects if this.signal is aborted
|
19113
|
+
rejectingSignalFuture.promise,
|
19114
|
+
// Rejects if something external says it should, like a participant disconnecting, etc
|
19115
|
+
(_b = (_a = this.outOfBandFailureRejectingFuture) === null || _a === void 0 ? void 0 : _a.promise) !== null && _b !== void 0 ? _b : new Promise(() => {
|
19116
|
+
/* never resolves */
|
19117
|
+
})]);
|
19005
19118
|
if (done) {
|
19119
|
+
this.validateBytesReceived(true);
|
19006
19120
|
return {
|
19007
19121
|
done: true,
|
19008
19122
|
value: undefined
|
@@ -19014,17 +19128,16 @@ class ByteStreamReader extends BaseStreamReader {
|
|
19014
19128
|
value: value.content
|
19015
19129
|
};
|
19016
19130
|
}
|
19017
|
-
} catch (
|
19018
|
-
|
19019
|
-
|
19020
|
-
done: true,
|
19021
|
-
value: undefined
|
19022
|
-
};
|
19131
|
+
} catch (err) {
|
19132
|
+
cleanup();
|
19133
|
+
throw err;
|
19023
19134
|
}
|
19024
19135
|
}),
|
19136
|
+
// note: `return` runs only for premature exits, see:
|
19137
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#errors_during_iteration
|
19025
19138
|
return() {
|
19026
19139
|
return __awaiter(this, void 0, void 0, function* () {
|
19027
|
-
|
19140
|
+
cleanup();
|
19028
19141
|
return {
|
19029
19142
|
done: true,
|
19030
19143
|
value: undefined
|
@@ -19033,29 +19146,45 @@ class ByteStreamReader extends BaseStreamReader {
|
|
19033
19146
|
}
|
19034
19147
|
};
|
19035
19148
|
}
|
19149
|
+
/**
|
19150
|
+
* Injects an AbortSignal, which if aborted, will terminate the currently active
|
19151
|
+
* stream iteration operation.
|
19152
|
+
*
|
19153
|
+
* Note that when using AbortSignal.timeout(...), the timeout applies across
|
19154
|
+
* the whole iteration operation, not just one individual chunk read.
|
19155
|
+
*/
|
19156
|
+
withAbortSignal(signal) {
|
19157
|
+
this.signal = signal;
|
19158
|
+
return this;
|
19159
|
+
}
|
19036
19160
|
readAll() {
|
19037
|
-
return __awaiter(this,
|
19038
|
-
var
|
19039
|
-
let
|
19040
|
-
|
19041
|
-
|
19042
|
-
|
19043
|
-
|
19044
|
-
const chunk = _c;
|
19045
|
-
chunks.add(chunk);
|
19046
|
-
}
|
19047
|
-
} catch (e_1_1) {
|
19048
|
-
e_1 = {
|
19049
|
-
error: e_1_1
|
19050
|
-
};
|
19051
|
-
} finally {
|
19161
|
+
return __awaiter(this, arguments, void 0, function () {
|
19162
|
+
var _this = this;
|
19163
|
+
let opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
19164
|
+
return function* () {
|
19165
|
+
var _a, e_1, _b, _c;
|
19166
|
+
let chunks = new Set();
|
19167
|
+
const iterator = opts.signal ? _this.withAbortSignal(opts.signal) : _this;
|
19052
19168
|
try {
|
19053
|
-
|
19169
|
+
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) {
|
19170
|
+
_c = iterator_1_1.value;
|
19171
|
+
_d = false;
|
19172
|
+
const chunk = _c;
|
19173
|
+
chunks.add(chunk);
|
19174
|
+
}
|
19175
|
+
} catch (e_1_1) {
|
19176
|
+
e_1 = {
|
19177
|
+
error: e_1_1
|
19178
|
+
};
|
19054
19179
|
} finally {
|
19055
|
-
|
19180
|
+
try {
|
19181
|
+
if (!_d && !_a && (_b = iterator_1.return)) yield _b.call(iterator_1);
|
19182
|
+
} finally {
|
19183
|
+
if (e_1) throw e_1.error;
|
19184
|
+
}
|
19056
19185
|
}
|
19057
|
-
|
19058
|
-
|
19186
|
+
return Array.from(chunks);
|
19187
|
+
}();
|
19059
19188
|
});
|
19060
19189
|
}
|
19061
19190
|
}
|
@@ -19067,8 +19196,8 @@ class TextStreamReader extends BaseStreamReader {
|
|
19067
19196
|
* A TextStreamReader instance can be used as an AsyncIterator that returns the entire string
|
19068
19197
|
* that has been received up to the current point in time.
|
19069
19198
|
*/
|
19070
|
-
constructor(info, stream, totalChunkCount) {
|
19071
|
-
super(info, stream, totalChunkCount);
|
19199
|
+
constructor(info, stream, totalChunkCount, outOfBandFailureRejectingFuture) {
|
19200
|
+
super(info, stream, totalChunkCount, outOfBandFailureRejectingFuture);
|
19072
19201
|
this.receivedChunks = new Map();
|
19073
19202
|
}
|
19074
19203
|
handleChunkReceived(chunk) {
|
@@ -19081,6 +19210,7 @@ class TextStreamReader extends BaseStreamReader {
|
|
19081
19210
|
}
|
19082
19211
|
this.receivedChunks.set(index, chunk);
|
19083
19212
|
this.bytesReceived += chunk.content.byteLength;
|
19213
|
+
this.validateBytesReceived();
|
19084
19214
|
const currentProgress = this.totalByteSize ? this.bytesReceived / this.totalByteSize : undefined;
|
19085
19215
|
(_a = this.onProgress) === null || _a === void 0 ? void 0 : _a.call(this, currentProgress);
|
19086
19216
|
}
|
@@ -19091,37 +19221,71 @@ class TextStreamReader extends BaseStreamReader {
|
|
19091
19221
|
*/
|
19092
19222
|
[Symbol.asyncIterator]() {
|
19093
19223
|
const reader = this.reader.getReader();
|
19094
|
-
const decoder = new TextDecoder(
|
19224
|
+
const decoder = new TextDecoder('utf-8', {
|
19225
|
+
fatal: true
|
19226
|
+
});
|
19227
|
+
let rejectingSignalFuture = new Future();
|
19228
|
+
let activeSignal = null;
|
19229
|
+
let onAbort = null;
|
19230
|
+
if (this.signal) {
|
19231
|
+
const signal = this.signal;
|
19232
|
+
onAbort = () => {
|
19233
|
+
var _a;
|
19234
|
+
(_a = rejectingSignalFuture.reject) === null || _a === void 0 ? void 0 : _a.call(rejectingSignalFuture, signal.reason);
|
19235
|
+
};
|
19236
|
+
signal.addEventListener('abort', onAbort);
|
19237
|
+
activeSignal = signal;
|
19238
|
+
}
|
19239
|
+
const cleanup = () => {
|
19240
|
+
reader.releaseLock();
|
19241
|
+
if (activeSignal && onAbort) {
|
19242
|
+
activeSignal.removeEventListener('abort', onAbort);
|
19243
|
+
}
|
19244
|
+
this.signal = undefined;
|
19245
|
+
};
|
19095
19246
|
return {
|
19096
19247
|
next: () => __awaiter(this, void 0, void 0, function* () {
|
19248
|
+
var _a, _b;
|
19097
19249
|
try {
|
19098
19250
|
const {
|
19099
19251
|
done,
|
19100
19252
|
value
|
19101
|
-
} = yield reader.read()
|
19253
|
+
} = yield Promise.race([reader.read(),
|
19254
|
+
// Rejects if this.signal is aborted
|
19255
|
+
rejectingSignalFuture.promise,
|
19256
|
+
// Rejects if something external says it should, like a participant disconnecting, etc
|
19257
|
+
(_b = (_a = this.outOfBandFailureRejectingFuture) === null || _a === void 0 ? void 0 : _a.promise) !== null && _b !== void 0 ? _b : new Promise(() => {
|
19258
|
+
/* never resolves */
|
19259
|
+
})]);
|
19102
19260
|
if (done) {
|
19261
|
+
this.validateBytesReceived(true);
|
19103
19262
|
return {
|
19104
19263
|
done: true,
|
19105
19264
|
value: undefined
|
19106
19265
|
};
|
19107
19266
|
} else {
|
19108
19267
|
this.handleChunkReceived(value);
|
19268
|
+
let decodedResult;
|
19269
|
+
try {
|
19270
|
+
decodedResult = decoder.decode(value.content);
|
19271
|
+
} catch (err) {
|
19272
|
+
throw new DataStreamError("Cannot decode datastream chunk ".concat(value.chunkIndex, " as text: ").concat(err), DataStreamErrorReason.DecodeFailed);
|
19273
|
+
}
|
19109
19274
|
return {
|
19110
19275
|
done: false,
|
19111
|
-
value:
|
19276
|
+
value: decodedResult
|
19112
19277
|
};
|
19113
19278
|
}
|
19114
|
-
} catch (
|
19115
|
-
|
19116
|
-
|
19117
|
-
done: true,
|
19118
|
-
value: undefined
|
19119
|
-
};
|
19279
|
+
} catch (err) {
|
19280
|
+
cleanup();
|
19281
|
+
throw err;
|
19120
19282
|
}
|
19121
19283
|
}),
|
19284
|
+
// note: `return` runs only for premature exits, see:
|
19285
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#errors_during_iteration
|
19122
19286
|
return() {
|
19123
19287
|
return __awaiter(this, void 0, void 0, function* () {
|
19124
|
-
|
19288
|
+
cleanup();
|
19125
19289
|
return {
|
19126
19290
|
done: true,
|
19127
19291
|
value: undefined
|
@@ -19130,31 +19294,217 @@ class TextStreamReader extends BaseStreamReader {
|
|
19130
19294
|
}
|
19131
19295
|
};
|
19132
19296
|
}
|
19297
|
+
/**
|
19298
|
+
* Injects an AbortSignal, which if aborted, will terminate the currently active
|
19299
|
+
* stream iteration operation.
|
19300
|
+
*
|
19301
|
+
* Note that when using AbortSignal.timeout(...), the timeout applies across
|
19302
|
+
* the whole iteration operation, not just one individual chunk read.
|
19303
|
+
*/
|
19304
|
+
withAbortSignal(signal) {
|
19305
|
+
this.signal = signal;
|
19306
|
+
return this;
|
19307
|
+
}
|
19133
19308
|
readAll() {
|
19309
|
+
return __awaiter(this, arguments, void 0, function () {
|
19310
|
+
var _this2 = this;
|
19311
|
+
let opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
19312
|
+
return function* () {
|
19313
|
+
var _a, e_2, _b, _c;
|
19314
|
+
let finalString = '';
|
19315
|
+
const iterator = opts.signal ? _this2.withAbortSignal(opts.signal) : _this2;
|
19316
|
+
try {
|
19317
|
+
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) {
|
19318
|
+
_c = iterator_2_1.value;
|
19319
|
+
_d = false;
|
19320
|
+
const chunk = _c;
|
19321
|
+
finalString += chunk;
|
19322
|
+
}
|
19323
|
+
} catch (e_2_1) {
|
19324
|
+
e_2 = {
|
19325
|
+
error: e_2_1
|
19326
|
+
};
|
19327
|
+
} finally {
|
19328
|
+
try {
|
19329
|
+
if (!_d && !_a && (_b = iterator_2.return)) yield _b.call(iterator_2);
|
19330
|
+
} finally {
|
19331
|
+
if (e_2) throw e_2.error;
|
19332
|
+
}
|
19333
|
+
}
|
19334
|
+
return finalString;
|
19335
|
+
}();
|
19336
|
+
});
|
19337
|
+
}
|
19338
|
+
}
|
19339
|
+
|
19340
|
+
class IncomingDataStreamManager {
|
19341
|
+
constructor() {
|
19342
|
+
this.log = livekitLogger;
|
19343
|
+
this.byteStreamControllers = new Map();
|
19344
|
+
this.textStreamControllers = new Map();
|
19345
|
+
this.byteStreamHandlers = new Map();
|
19346
|
+
this.textStreamHandlers = new Map();
|
19347
|
+
}
|
19348
|
+
registerTextStreamHandler(topic, callback) {
|
19349
|
+
if (this.textStreamHandlers.has(topic)) {
|
19350
|
+
throw new DataStreamError("A text stream handler for topic \"".concat(topic, "\" has already been set."), DataStreamErrorReason.HandlerAlreadyRegistered);
|
19351
|
+
}
|
19352
|
+
this.textStreamHandlers.set(topic, callback);
|
19353
|
+
}
|
19354
|
+
unregisterTextStreamHandler(topic) {
|
19355
|
+
this.textStreamHandlers.delete(topic);
|
19356
|
+
}
|
19357
|
+
registerByteStreamHandler(topic, callback) {
|
19358
|
+
if (this.byteStreamHandlers.has(topic)) {
|
19359
|
+
throw new DataStreamError("A byte stream handler for topic \"".concat(topic, "\" has already been set."), DataStreamErrorReason.HandlerAlreadyRegistered);
|
19360
|
+
}
|
19361
|
+
this.byteStreamHandlers.set(topic, callback);
|
19362
|
+
}
|
19363
|
+
unregisterByteStreamHandler(topic) {
|
19364
|
+
this.byteStreamHandlers.delete(topic);
|
19365
|
+
}
|
19366
|
+
clearHandlersAndControllers() {
|
19367
|
+
this.byteStreamControllers.clear();
|
19368
|
+
this.textStreamControllers.clear();
|
19369
|
+
this.byteStreamHandlers.clear();
|
19370
|
+
this.textStreamHandlers.clear();
|
19371
|
+
}
|
19372
|
+
validateParticipantHasNoActiveDataStreams(participantIdentity) {
|
19373
|
+
var _a, _b, _c, _d;
|
19374
|
+
// Terminate any in flight data stream receives from the given participant
|
19375
|
+
const textStreamsBeingSentByDisconnectingParticipant = Array.from(this.textStreamControllers.entries()).filter(entry => entry[1].sendingParticipantIdentity === participantIdentity);
|
19376
|
+
const byteStreamsBeingSentByDisconnectingParticipant = Array.from(this.byteStreamControllers.entries()).filter(entry => entry[1].sendingParticipantIdentity === participantIdentity);
|
19377
|
+
if (textStreamsBeingSentByDisconnectingParticipant.length > 0 || byteStreamsBeingSentByDisconnectingParticipant.length > 0) {
|
19378
|
+
const abnormalEndError = new DataStreamError("Participant ".concat(participantIdentity, " unexpectedly disconnected in the middle of sending data"), DataStreamErrorReason.AbnormalEnd);
|
19379
|
+
for (const [id, controller] of byteStreamsBeingSentByDisconnectingParticipant) {
|
19380
|
+
(_b = (_a = controller.outOfBandFailureRejectingFuture).reject) === null || _b === void 0 ? void 0 : _b.call(_a, abnormalEndError);
|
19381
|
+
this.byteStreamControllers.delete(id);
|
19382
|
+
}
|
19383
|
+
for (const [id, controller] of textStreamsBeingSentByDisconnectingParticipant) {
|
19384
|
+
(_d = (_c = controller.outOfBandFailureRejectingFuture).reject) === null || _d === void 0 ? void 0 : _d.call(_c, abnormalEndError);
|
19385
|
+
this.textStreamControllers.delete(id);
|
19386
|
+
}
|
19387
|
+
}
|
19388
|
+
}
|
19389
|
+
handleDataStreamPacket(packet) {
|
19134
19390
|
return __awaiter(this, void 0, void 0, function* () {
|
19135
|
-
|
19136
|
-
|
19137
|
-
|
19138
|
-
|
19139
|
-
|
19140
|
-
|
19141
|
-
|
19142
|
-
|
19391
|
+
switch (packet.value.case) {
|
19392
|
+
case 'streamHeader':
|
19393
|
+
return this.handleStreamHeader(packet.value.value, packet.participantIdentity);
|
19394
|
+
case 'streamChunk':
|
19395
|
+
return this.handleStreamChunk(packet.value.value);
|
19396
|
+
case 'streamTrailer':
|
19397
|
+
return this.handleStreamTrailer(packet.value.value);
|
19398
|
+
default:
|
19399
|
+
throw new Error("DataPacket of value \"".concat(packet.value.case, "\" is not data stream related!"));
|
19400
|
+
}
|
19401
|
+
});
|
19402
|
+
}
|
19403
|
+
handleStreamHeader(streamHeader, participantIdentity) {
|
19404
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19405
|
+
var _a;
|
19406
|
+
if (streamHeader.contentHeader.case === 'byteHeader') {
|
19407
|
+
const streamHandlerCallback = this.byteStreamHandlers.get(streamHeader.topic);
|
19408
|
+
if (!streamHandlerCallback) {
|
19409
|
+
this.log.debug('ignoring incoming byte stream due to no handler for topic', streamHeader.topic);
|
19410
|
+
return;
|
19143
19411
|
}
|
19144
|
-
|
19145
|
-
|
19146
|
-
|
19412
|
+
let streamController;
|
19413
|
+
const outOfBandFailureRejectingFuture = new Future();
|
19414
|
+
const info = {
|
19415
|
+
id: streamHeader.streamId,
|
19416
|
+
name: (_a = streamHeader.contentHeader.value.name) !== null && _a !== void 0 ? _a : 'unknown',
|
19417
|
+
mimeType: streamHeader.mimeType,
|
19418
|
+
size: streamHeader.totalLength ? Number(streamHeader.totalLength) : undefined,
|
19419
|
+
topic: streamHeader.topic,
|
19420
|
+
timestamp: bigIntToNumber(streamHeader.timestamp),
|
19421
|
+
attributes: streamHeader.attributes
|
19147
19422
|
};
|
19148
|
-
|
19149
|
-
|
19150
|
-
|
19151
|
-
|
19152
|
-
|
19423
|
+
const stream = new ReadableStream({
|
19424
|
+
start: controller => {
|
19425
|
+
streamController = controller;
|
19426
|
+
if (this.textStreamControllers.has(streamHeader.streamId)) {
|
19427
|
+
throw new DataStreamError("A data stream read is already in progress for a stream with id ".concat(streamHeader.streamId, "."), DataStreamErrorReason.AlreadyOpened);
|
19428
|
+
}
|
19429
|
+
this.byteStreamControllers.set(streamHeader.streamId, {
|
19430
|
+
info,
|
19431
|
+
controller: streamController,
|
19432
|
+
startTime: Date.now(),
|
19433
|
+
sendingParticipantIdentity: participantIdentity,
|
19434
|
+
outOfBandFailureRejectingFuture
|
19435
|
+
});
|
19436
|
+
}
|
19437
|
+
});
|
19438
|
+
streamHandlerCallback(new ByteStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength), outOfBandFailureRejectingFuture), {
|
19439
|
+
identity: participantIdentity
|
19440
|
+
});
|
19441
|
+
} else if (streamHeader.contentHeader.case === 'textHeader') {
|
19442
|
+
const streamHandlerCallback = this.textStreamHandlers.get(streamHeader.topic);
|
19443
|
+
if (!streamHandlerCallback) {
|
19444
|
+
this.log.debug('ignoring incoming text stream due to no handler for topic', streamHeader.topic);
|
19445
|
+
return;
|
19153
19446
|
}
|
19447
|
+
let streamController;
|
19448
|
+
const outOfBandFailureRejectingFuture = new Future();
|
19449
|
+
const info = {
|
19450
|
+
id: streamHeader.streamId,
|
19451
|
+
mimeType: streamHeader.mimeType,
|
19452
|
+
size: streamHeader.totalLength ? Number(streamHeader.totalLength) : undefined,
|
19453
|
+
topic: streamHeader.topic,
|
19454
|
+
timestamp: Number(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.textStreamControllers.set(streamHeader.streamId, {
|
19464
|
+
info,
|
19465
|
+
controller: streamController,
|
19466
|
+
startTime: Date.now(),
|
19467
|
+
sendingParticipantIdentity: participantIdentity,
|
19468
|
+
outOfBandFailureRejectingFuture
|
19469
|
+
});
|
19470
|
+
}
|
19471
|
+
});
|
19472
|
+
streamHandlerCallback(new TextStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength), outOfBandFailureRejectingFuture), {
|
19473
|
+
identity: participantIdentity
|
19474
|
+
});
|
19154
19475
|
}
|
19155
|
-
return finalString;
|
19156
19476
|
});
|
19157
19477
|
}
|
19478
|
+
handleStreamChunk(chunk) {
|
19479
|
+
const fileBuffer = this.byteStreamControllers.get(chunk.streamId);
|
19480
|
+
if (fileBuffer) {
|
19481
|
+
if (chunk.content.length > 0) {
|
19482
|
+
fileBuffer.controller.enqueue(chunk);
|
19483
|
+
}
|
19484
|
+
}
|
19485
|
+
const textBuffer = this.textStreamControllers.get(chunk.streamId);
|
19486
|
+
if (textBuffer) {
|
19487
|
+
if (chunk.content.length > 0) {
|
19488
|
+
textBuffer.controller.enqueue(chunk);
|
19489
|
+
}
|
19490
|
+
}
|
19491
|
+
}
|
19492
|
+
handleStreamTrailer(trailer) {
|
19493
|
+
const textBuffer = this.textStreamControllers.get(trailer.streamId);
|
19494
|
+
if (textBuffer) {
|
19495
|
+
textBuffer.info.attributes = Object.assign(Object.assign({}, textBuffer.info.attributes), trailer.attributes);
|
19496
|
+
textBuffer.controller.close();
|
19497
|
+
this.textStreamControllers.delete(trailer.streamId);
|
19498
|
+
}
|
19499
|
+
const fileBuffer = this.byteStreamControllers.get(trailer.streamId);
|
19500
|
+
if (fileBuffer) {
|
19501
|
+
{
|
19502
|
+
fileBuffer.info.attributes = Object.assign(Object.assign({}, fileBuffer.info.attributes), trailer.attributes);
|
19503
|
+
fileBuffer.controller.close();
|
19504
|
+
this.byteStreamControllers.delete(trailer.streamId);
|
19505
|
+
}
|
19506
|
+
}
|
19507
|
+
}
|
19158
19508
|
}
|
19159
19509
|
|
19160
19510
|
class BaseStreamWriter {
|
@@ -19179,11 +19529,289 @@ class BaseStreamWriter {
|
|
19179
19529
|
class TextStreamWriter extends BaseStreamWriter {}
|
19180
19530
|
class ByteStreamWriter extends BaseStreamWriter {}
|
19181
19531
|
|
19182
|
-
|
19183
|
-
|
19184
|
-
|
19185
|
-
|
19186
|
-
|
19532
|
+
const STREAM_CHUNK_SIZE = 15000;
|
19533
|
+
/**
|
19534
|
+
* Manages sending custom user data via data channels.
|
19535
|
+
* @internal
|
19536
|
+
*/
|
19537
|
+
class OutgoingDataStreamManager {
|
19538
|
+
constructor(engine, log) {
|
19539
|
+
this.engine = engine;
|
19540
|
+
this.log = log;
|
19541
|
+
}
|
19542
|
+
setupEngine(engine) {
|
19543
|
+
this.engine = engine;
|
19544
|
+
}
|
19545
|
+
/** {@inheritDoc LocalParticipant.sendText} */
|
19546
|
+
sendText(text, options) {
|
19547
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19548
|
+
var _a;
|
19549
|
+
const streamId = crypto.randomUUID();
|
19550
|
+
const textInBytes = new TextEncoder().encode(text);
|
19551
|
+
const totalTextLength = textInBytes.byteLength;
|
19552
|
+
const fileIds = (_a = options === null || options === void 0 ? void 0 : options.attachments) === null || _a === void 0 ? void 0 : _a.map(() => crypto.randomUUID());
|
19553
|
+
const progresses = new Array(fileIds ? fileIds.length + 1 : 1).fill(0);
|
19554
|
+
const handleProgress = (progress, idx) => {
|
19555
|
+
var _a;
|
19556
|
+
progresses[idx] = progress;
|
19557
|
+
const totalProgress = progresses.reduce((acc, val) => acc + val, 0);
|
19558
|
+
(_a = options === null || options === void 0 ? void 0 : options.onProgress) === null || _a === void 0 ? void 0 : _a.call(options, totalProgress);
|
19559
|
+
};
|
19560
|
+
const writer = yield this.streamText({
|
19561
|
+
streamId,
|
19562
|
+
totalSize: totalTextLength,
|
19563
|
+
destinationIdentities: options === null || options === void 0 ? void 0 : options.destinationIdentities,
|
19564
|
+
topic: options === null || options === void 0 ? void 0 : options.topic,
|
19565
|
+
attachedStreamIds: fileIds,
|
19566
|
+
attributes: options === null || options === void 0 ? void 0 : options.attributes
|
19567
|
+
});
|
19568
|
+
yield writer.write(text);
|
19569
|
+
// set text part of progress to 1
|
19570
|
+
handleProgress(1, 0);
|
19571
|
+
yield writer.close();
|
19572
|
+
if ((options === null || options === void 0 ? void 0 : options.attachments) && fileIds) {
|
19573
|
+
yield Promise.all(options.attachments.map((file, idx) => __awaiter(this, void 0, void 0, function* () {
|
19574
|
+
return this._sendFile(fileIds[idx], file, {
|
19575
|
+
topic: options.topic,
|
19576
|
+
mimeType: file.type,
|
19577
|
+
onProgress: progress => {
|
19578
|
+
handleProgress(progress, idx + 1);
|
19579
|
+
}
|
19580
|
+
});
|
19581
|
+
})));
|
19582
|
+
}
|
19583
|
+
return writer.info;
|
19584
|
+
});
|
19585
|
+
}
|
19586
|
+
/**
|
19587
|
+
* @internal
|
19588
|
+
* @experimental CAUTION, might get removed in a minor release
|
19589
|
+
*/
|
19590
|
+
streamText(options) {
|
19591
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19592
|
+
var _a, _b;
|
19593
|
+
const streamId = (_a = options === null || options === void 0 ? void 0 : options.streamId) !== null && _a !== void 0 ? _a : crypto.randomUUID();
|
19594
|
+
const info = {
|
19595
|
+
id: streamId,
|
19596
|
+
mimeType: 'text/plain',
|
19597
|
+
timestamp: Date.now(),
|
19598
|
+
topic: (_b = options === null || options === void 0 ? void 0 : options.topic) !== null && _b !== void 0 ? _b : '',
|
19599
|
+
size: options === null || options === void 0 ? void 0 : options.totalSize,
|
19600
|
+
attributes: options === null || options === void 0 ? void 0 : options.attributes
|
19601
|
+
};
|
19602
|
+
const header = new DataStream_Header({
|
19603
|
+
streamId,
|
19604
|
+
mimeType: info.mimeType,
|
19605
|
+
topic: info.topic,
|
19606
|
+
timestamp: numberToBigInt(info.timestamp),
|
19607
|
+
totalLength: numberToBigInt(options === null || options === void 0 ? void 0 : options.totalSize),
|
19608
|
+
attributes: info.attributes,
|
19609
|
+
contentHeader: {
|
19610
|
+
case: 'textHeader',
|
19611
|
+
value: new DataStream_TextHeader({
|
19612
|
+
version: options === null || options === void 0 ? void 0 : options.version,
|
19613
|
+
attachedStreamIds: options === null || options === void 0 ? void 0 : options.attachedStreamIds,
|
19614
|
+
replyToStreamId: options === null || options === void 0 ? void 0 : options.replyToStreamId,
|
19615
|
+
operationType: (options === null || options === void 0 ? void 0 : options.type) === 'update' ? DataStream_OperationType.UPDATE : DataStream_OperationType.CREATE
|
19616
|
+
})
|
19617
|
+
}
|
19618
|
+
});
|
19619
|
+
const destinationIdentities = options === null || options === void 0 ? void 0 : options.destinationIdentities;
|
19620
|
+
const packet = new DataPacket({
|
19621
|
+
destinationIdentities,
|
19622
|
+
value: {
|
19623
|
+
case: 'streamHeader',
|
19624
|
+
value: header
|
19625
|
+
}
|
19626
|
+
});
|
19627
|
+
yield this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
|
19628
|
+
let chunkId = 0;
|
19629
|
+
const engine = this.engine;
|
19630
|
+
const writableStream = new WritableStream({
|
19631
|
+
// Implement the sink
|
19632
|
+
write(text) {
|
19633
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19634
|
+
for (const textByteChunk of splitUtf8(text, STREAM_CHUNK_SIZE)) {
|
19635
|
+
yield engine.waitForBufferStatusLow(DataPacket_Kind.RELIABLE);
|
19636
|
+
const chunk = new DataStream_Chunk({
|
19637
|
+
content: textByteChunk,
|
19638
|
+
streamId,
|
19639
|
+
chunkIndex: numberToBigInt(chunkId)
|
19640
|
+
});
|
19641
|
+
const chunkPacket = new DataPacket({
|
19642
|
+
destinationIdentities,
|
19643
|
+
value: {
|
19644
|
+
case: 'streamChunk',
|
19645
|
+
value: chunk
|
19646
|
+
}
|
19647
|
+
});
|
19648
|
+
yield engine.sendDataPacket(chunkPacket, DataPacket_Kind.RELIABLE);
|
19649
|
+
chunkId += 1;
|
19650
|
+
}
|
19651
|
+
});
|
19652
|
+
},
|
19653
|
+
close() {
|
19654
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19655
|
+
const trailer = new DataStream_Trailer({
|
19656
|
+
streamId
|
19657
|
+
});
|
19658
|
+
const trailerPacket = new DataPacket({
|
19659
|
+
destinationIdentities,
|
19660
|
+
value: {
|
19661
|
+
case: 'streamTrailer',
|
19662
|
+
value: trailer
|
19663
|
+
}
|
19664
|
+
});
|
19665
|
+
yield engine.sendDataPacket(trailerPacket, DataPacket_Kind.RELIABLE);
|
19666
|
+
});
|
19667
|
+
},
|
19668
|
+
abort(err) {
|
19669
|
+
console.log('Sink error:', err);
|
19670
|
+
// TODO handle aborts to signal something to receiver side
|
19671
|
+
}
|
19672
|
+
});
|
19673
|
+
let onEngineClose = () => __awaiter(this, void 0, void 0, function* () {
|
19674
|
+
yield writer.close();
|
19675
|
+
});
|
19676
|
+
engine.once(EngineEvent.Closing, onEngineClose);
|
19677
|
+
const writer = new TextStreamWriter(writableStream, info, () => this.engine.off(EngineEvent.Closing, onEngineClose));
|
19678
|
+
return writer;
|
19679
|
+
});
|
19680
|
+
}
|
19681
|
+
sendFile(file, options) {
|
19682
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19683
|
+
const streamId = crypto.randomUUID();
|
19684
|
+
yield this._sendFile(streamId, file, options);
|
19685
|
+
return {
|
19686
|
+
id: streamId
|
19687
|
+
};
|
19688
|
+
});
|
19689
|
+
}
|
19690
|
+
_sendFile(streamId, file, options) {
|
19691
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19692
|
+
var _a;
|
19693
|
+
const writer = yield this.streamBytes({
|
19694
|
+
streamId,
|
19695
|
+
totalSize: file.size,
|
19696
|
+
name: file.name,
|
19697
|
+
mimeType: (_a = options === null || options === void 0 ? void 0 : options.mimeType) !== null && _a !== void 0 ? _a : file.type,
|
19698
|
+
topic: options === null || options === void 0 ? void 0 : options.topic,
|
19699
|
+
destinationIdentities: options === null || options === void 0 ? void 0 : options.destinationIdentities
|
19700
|
+
});
|
19701
|
+
const reader = file.stream().getReader();
|
19702
|
+
while (true) {
|
19703
|
+
const {
|
19704
|
+
done,
|
19705
|
+
value
|
19706
|
+
} = yield reader.read();
|
19707
|
+
if (done) {
|
19708
|
+
break;
|
19709
|
+
}
|
19710
|
+
yield writer.write(value);
|
19711
|
+
}
|
19712
|
+
yield writer.close();
|
19713
|
+
return writer.info;
|
19714
|
+
});
|
19715
|
+
}
|
19716
|
+
streamBytes(options) {
|
19717
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19718
|
+
var _a, _b, _c, _d, _e;
|
19719
|
+
const streamId = (_a = options === null || options === void 0 ? void 0 : options.streamId) !== null && _a !== void 0 ? _a : crypto.randomUUID();
|
19720
|
+
const destinationIdentities = options === null || options === void 0 ? void 0 : options.destinationIdentities;
|
19721
|
+
const info = {
|
19722
|
+
id: streamId,
|
19723
|
+
mimeType: (_b = options === null || options === void 0 ? void 0 : options.mimeType) !== null && _b !== void 0 ? _b : 'application/octet-stream',
|
19724
|
+
topic: (_c = options === null || options === void 0 ? void 0 : options.topic) !== null && _c !== void 0 ? _c : '',
|
19725
|
+
timestamp: Date.now(),
|
19726
|
+
attributes: options === null || options === void 0 ? void 0 : options.attributes,
|
19727
|
+
size: options === null || options === void 0 ? void 0 : options.totalSize,
|
19728
|
+
name: (_d = options === null || options === void 0 ? void 0 : options.name) !== null && _d !== void 0 ? _d : 'unknown'
|
19729
|
+
};
|
19730
|
+
const header = new DataStream_Header({
|
19731
|
+
totalLength: numberToBigInt((_e = info.size) !== null && _e !== void 0 ? _e : 0),
|
19732
|
+
mimeType: info.mimeType,
|
19733
|
+
streamId,
|
19734
|
+
topic: info.topic,
|
19735
|
+
timestamp: numberToBigInt(Date.now()),
|
19736
|
+
attributes: info.attributes,
|
19737
|
+
contentHeader: {
|
19738
|
+
case: 'byteHeader',
|
19739
|
+
value: new DataStream_ByteHeader({
|
19740
|
+
name: info.name
|
19741
|
+
})
|
19742
|
+
}
|
19743
|
+
});
|
19744
|
+
const packet = new DataPacket({
|
19745
|
+
destinationIdentities,
|
19746
|
+
value: {
|
19747
|
+
case: 'streamHeader',
|
19748
|
+
value: header
|
19749
|
+
}
|
19750
|
+
});
|
19751
|
+
yield this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
|
19752
|
+
let chunkId = 0;
|
19753
|
+
const writeMutex = new _();
|
19754
|
+
const engine = this.engine;
|
19755
|
+
const logLocal = this.log;
|
19756
|
+
const writableStream = new WritableStream({
|
19757
|
+
write(chunk) {
|
19758
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19759
|
+
const unlock = yield writeMutex.lock();
|
19760
|
+
let byteOffset = 0;
|
19761
|
+
try {
|
19762
|
+
while (byteOffset < chunk.byteLength) {
|
19763
|
+
const subChunk = chunk.slice(byteOffset, byteOffset + STREAM_CHUNK_SIZE);
|
19764
|
+
yield engine.waitForBufferStatusLow(DataPacket_Kind.RELIABLE);
|
19765
|
+
const chunkPacket = new DataPacket({
|
19766
|
+
destinationIdentities,
|
19767
|
+
value: {
|
19768
|
+
case: 'streamChunk',
|
19769
|
+
value: new DataStream_Chunk({
|
19770
|
+
content: subChunk,
|
19771
|
+
streamId,
|
19772
|
+
chunkIndex: numberToBigInt(chunkId)
|
19773
|
+
})
|
19774
|
+
}
|
19775
|
+
});
|
19776
|
+
yield engine.sendDataPacket(chunkPacket, DataPacket_Kind.RELIABLE);
|
19777
|
+
chunkId += 1;
|
19778
|
+
byteOffset += subChunk.byteLength;
|
19779
|
+
}
|
19780
|
+
} finally {
|
19781
|
+
unlock();
|
19782
|
+
}
|
19783
|
+
});
|
19784
|
+
},
|
19785
|
+
close() {
|
19786
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19787
|
+
const trailer = new DataStream_Trailer({
|
19788
|
+
streamId
|
19789
|
+
});
|
19790
|
+
const trailerPacket = new DataPacket({
|
19791
|
+
destinationIdentities,
|
19792
|
+
value: {
|
19793
|
+
case: 'streamTrailer',
|
19794
|
+
value: trailer
|
19795
|
+
}
|
19796
|
+
});
|
19797
|
+
yield engine.sendDataPacket(trailerPacket, DataPacket_Kind.RELIABLE);
|
19798
|
+
});
|
19799
|
+
},
|
19800
|
+
abort(err) {
|
19801
|
+
logLocal.error('Sink error:', err);
|
19802
|
+
}
|
19803
|
+
});
|
19804
|
+
const byteWriter = new ByteStreamWriter(writableStream, info);
|
19805
|
+
return byteWriter;
|
19806
|
+
});
|
19807
|
+
}
|
19808
|
+
}
|
19809
|
+
|
19810
|
+
class RemoteTrack extends Track {
|
19811
|
+
constructor(mediaTrack, sid, kind, receiver, loggerOptions) {
|
19812
|
+
super(mediaTrack, kind, loggerOptions);
|
19813
|
+
this.sid = sid;
|
19814
|
+
this.receiver = receiver;
|
19187
19815
|
}
|
19188
19816
|
get isLocal() {
|
19189
19817
|
return false;
|
@@ -20508,10 +21136,9 @@ function trackPermissionToProto(perms) {
|
|
20508
21136
|
});
|
20509
21137
|
}
|
20510
21138
|
|
20511
|
-
const STREAM_CHUNK_SIZE = 15000;
|
20512
21139
|
class LocalParticipant extends Participant {
|
20513
21140
|
/** @internal */
|
20514
|
-
constructor(sid, identity, engine, options, roomRpcHandlers) {
|
21141
|
+
constructor(sid, identity, engine, options, roomRpcHandlers, roomOutgoingDataStreamManager) {
|
20515
21142
|
super(sid, identity, undefined, undefined, undefined, {
|
20516
21143
|
loggerName: options.loggerName,
|
20517
21144
|
loggerContextCb: () => this.engine.logContext
|
@@ -20535,7 +21162,7 @@ class LocalParticipant extends Participant {
|
|
20535
21162
|
this.reconnectFuture = undefined;
|
20536
21163
|
this.updateTrackSubscriptionPermissions();
|
20537
21164
|
};
|
20538
|
-
this.
|
21165
|
+
this.handleClosing = () => {
|
20539
21166
|
var _a, _b, _c, _d, _e, _f;
|
20540
21167
|
if (this.reconnectFuture) {
|
20541
21168
|
this.reconnectFuture.promise.catch(e => this.log.warn(e.message, this.logContext));
|
@@ -20743,6 +21370,7 @@ class LocalParticipant extends Participant {
|
|
20743
21370
|
this.activeDeviceMap = new Map([['audioinput', 'default'], ['videoinput', 'default'], ['audiooutput', 'default']]);
|
20744
21371
|
this.pendingSignalRequests = new Map();
|
20745
21372
|
this.rpcHandlers = roomRpcHandlers;
|
21373
|
+
this.roomOutgoingDataStreamManager = roomOutgoingDataStreamManager;
|
20746
21374
|
}
|
20747
21375
|
get lastCameraError() {
|
20748
21376
|
return this.cameraError;
|
@@ -20785,7 +21413,7 @@ class LocalParticipant extends Participant {
|
|
20785
21413
|
if ((_a = this.signalConnectedFuture) === null || _a === void 0 ? void 0 : _a.isResolved) {
|
20786
21414
|
this.signalConnectedFuture = undefined;
|
20787
21415
|
}
|
20788
|
-
this.engine.on(EngineEvent.Connected, this.handleReconnected).on(EngineEvent.SignalConnected, this.handleSignalConnected).on(EngineEvent.SignalRestarted, this.handleReconnected).on(EngineEvent.SignalResumed, this.handleReconnected).on(EngineEvent.Restarting, this.handleReconnecting).on(EngineEvent.Resuming, this.handleReconnecting).on(EngineEvent.LocalTrackUnpublished, this.handleLocalTrackUnpublished).on(EngineEvent.SubscribedQualityUpdate, this.handleSubscribedQualityUpdate).on(EngineEvent.
|
21416
|
+
this.engine.on(EngineEvent.Connected, this.handleReconnected).on(EngineEvent.SignalConnected, this.handleSignalConnected).on(EngineEvent.SignalRestarted, this.handleReconnected).on(EngineEvent.SignalResumed, this.handleReconnected).on(EngineEvent.Restarting, this.handleReconnecting).on(EngineEvent.Resuming, this.handleReconnecting).on(EngineEvent.LocalTrackUnpublished, this.handleLocalTrackUnpublished).on(EngineEvent.SubscribedQualityUpdate, this.handleSubscribedQualityUpdate).on(EngineEvent.Closing, this.handleClosing).on(EngineEvent.SignalRequestResponse, this.handleSignalRequestResponse).on(EngineEvent.DataPacketReceived, this.handleDataPacket);
|
20789
21417
|
}
|
20790
21418
|
/**
|
20791
21419
|
* Sets and updates the metadata of the local participant.
|
@@ -20969,7 +21597,8 @@ class LocalParticipant extends Participant {
|
|
20969
21597
|
throw e;
|
20970
21598
|
}
|
20971
21599
|
for (const localTrack of localTracks) {
|
20972
|
-
|
21600
|
+
const opts = Object.assign(Object.assign({}, this.roomOptions.publishDefaults), options);
|
21601
|
+
if (source === Track.Source.Microphone && isAudioTrack(localTrack) && opts.preConnectBuffer) {
|
20973
21602
|
this.log.info('starting preconnect buffer for microphone', Object.assign({}, this.logContext));
|
20974
21603
|
localTrack.startPreConnectBuffer();
|
20975
21604
|
}
|
@@ -21569,6 +22198,7 @@ class LocalParticipant extends Participant {
|
|
21569
22198
|
this.emit(ParticipantEvent.LocalTrackPublished, publication);
|
21570
22199
|
if (isLocalAudioTrack(track) && ti.audioFeatures.includes(AudioTrackFeature.TF_PRECONNECT_BUFFER)) {
|
21571
22200
|
const stream = track.getPreConnectBuffer();
|
22201
|
+
const mimeType = track.getPreConnectBufferMimeType();
|
21572
22202
|
// TODO: we're registering the listener after negotiation, so there might be a race
|
21573
22203
|
this.on(ParticipantEvent.LocalTrackSubscribed, pub => {
|
21574
22204
|
if (pub.trackSid === ti.sid) {
|
@@ -21594,7 +22224,7 @@ class LocalParticipant extends Participant {
|
|
21594
22224
|
this.log.debug('sending preconnect buffer', Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)));
|
21595
22225
|
const writer = yield this.streamBytes({
|
21596
22226
|
name: 'preconnect-buffer',
|
21597
|
-
mimeType
|
22227
|
+
mimeType,
|
21598
22228
|
topic: 'lk.agent.pre-connect-audio-buffer',
|
21599
22229
|
destinationIdentities: [agent.identity],
|
21600
22230
|
attributes: {
|
@@ -21892,6 +22522,7 @@ class LocalParticipant extends Participant {
|
|
21892
22522
|
yield this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
|
21893
22523
|
});
|
21894
22524
|
}
|
22525
|
+
/** @deprecated Consider migrating to {@link sendText} */
|
21895
22526
|
sendChatMessage(text, options) {
|
21896
22527
|
return __awaiter(this, void 0, void 0, function* () {
|
21897
22528
|
const msg = {
|
@@ -21913,6 +22544,7 @@ class LocalParticipant extends Participant {
|
|
21913
22544
|
return msg;
|
21914
22545
|
});
|
21915
22546
|
}
|
22547
|
+
/** @deprecated Consider migrating to {@link sendText} */
|
21916
22548
|
editChatMessage(editText, originalMessage) {
|
21917
22549
|
return __awaiter(this, void 0, void 0, function* () {
|
21918
22550
|
const msg = Object.assign(Object.assign({}, originalMessage), {
|
@@ -21922,277 +22554,62 @@ class LocalParticipant extends Participant {
|
|
21922
22554
|
const packet = new DataPacket({
|
21923
22555
|
value: {
|
21924
22556
|
case: 'chatMessage',
|
21925
|
-
value: new ChatMessage(Object.assign(Object.assign({}, msg), {
|
21926
|
-
timestamp: protoInt64.parse(msg.timestamp),
|
21927
|
-
editTimestamp: protoInt64.parse(msg.editTimestamp)
|
21928
|
-
}))
|
21929
|
-
}
|
21930
|
-
});
|
21931
|
-
yield this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
|
21932
|
-
this.emit(ParticipantEvent.ChatMessage, msg);
|
21933
|
-
return msg;
|
21934
|
-
});
|
21935
|
-
}
|
21936
|
-
sendText(text, options) {
|
21937
|
-
return __awaiter(this, void 0, void 0, function* () {
|
21938
|
-
var _a;
|
21939
|
-
const streamId = crypto.randomUUID();
|
21940
|
-
const textInBytes = new TextEncoder().encode(text);
|
21941
|
-
const totalTextLength = textInBytes.byteLength;
|
21942
|
-
const fileIds = (_a = options === null || options === void 0 ? void 0 : options.attachments) === null || _a === void 0 ? void 0 : _a.map(() => crypto.randomUUID());
|
21943
|
-
const progresses = new Array(fileIds ? fileIds.length + 1 : 1).fill(0);
|
21944
|
-
const handleProgress = (progress, idx) => {
|
21945
|
-
var _a;
|
21946
|
-
progresses[idx] = progress;
|
21947
|
-
const totalProgress = progresses.reduce((acc, val) => acc + val, 0);
|
21948
|
-
(_a = options === null || options === void 0 ? void 0 : options.onProgress) === null || _a === void 0 ? void 0 : _a.call(options, totalProgress);
|
21949
|
-
};
|
21950
|
-
const writer = yield this.streamText({
|
21951
|
-
streamId,
|
21952
|
-
totalSize: totalTextLength,
|
21953
|
-
destinationIdentities: options === null || options === void 0 ? void 0 : options.destinationIdentities,
|
21954
|
-
topic: options === null || options === void 0 ? void 0 : options.topic,
|
21955
|
-
attachedStreamIds: fileIds,
|
21956
|
-
attributes: options === null || options === void 0 ? void 0 : options.attributes
|
21957
|
-
});
|
21958
|
-
yield writer.write(text);
|
21959
|
-
// set text part of progress to 1
|
21960
|
-
handleProgress(1, 0);
|
21961
|
-
yield writer.close();
|
21962
|
-
if ((options === null || options === void 0 ? void 0 : options.attachments) && fileIds) {
|
21963
|
-
yield Promise.all(options.attachments.map((file, idx) => __awaiter(this, void 0, void 0, function* () {
|
21964
|
-
return this._sendFile(fileIds[idx], file, {
|
21965
|
-
topic: options.topic,
|
21966
|
-
mimeType: file.type,
|
21967
|
-
onProgress: progress => {
|
21968
|
-
handleProgress(progress, idx + 1);
|
21969
|
-
}
|
21970
|
-
});
|
21971
|
-
})));
|
21972
|
-
}
|
21973
|
-
return writer.info;
|
21974
|
-
});
|
21975
|
-
}
|
21976
|
-
/**
|
21977
|
-
* @internal
|
21978
|
-
* @experimental CAUTION, might get removed in a minor release
|
21979
|
-
*/
|
21980
|
-
streamText(options) {
|
21981
|
-
return __awaiter(this, void 0, void 0, function* () {
|
21982
|
-
var _a, _b;
|
21983
|
-
const streamId = (_a = options === null || options === void 0 ? void 0 : options.streamId) !== null && _a !== void 0 ? _a : crypto.randomUUID();
|
21984
|
-
const info = {
|
21985
|
-
id: streamId,
|
21986
|
-
mimeType: 'text/plain',
|
21987
|
-
timestamp: Date.now(),
|
21988
|
-
topic: (_b = options === null || options === void 0 ? void 0 : options.topic) !== null && _b !== void 0 ? _b : '',
|
21989
|
-
size: options === null || options === void 0 ? void 0 : options.totalSize,
|
21990
|
-
attributes: options === null || options === void 0 ? void 0 : options.attributes
|
21991
|
-
};
|
21992
|
-
const header = new DataStream_Header({
|
21993
|
-
streamId,
|
21994
|
-
mimeType: info.mimeType,
|
21995
|
-
topic: info.topic,
|
21996
|
-
timestamp: numberToBigInt(info.timestamp),
|
21997
|
-
totalLength: numberToBigInt(options === null || options === void 0 ? void 0 : options.totalSize),
|
21998
|
-
attributes: info.attributes,
|
21999
|
-
contentHeader: {
|
22000
|
-
case: 'textHeader',
|
22001
|
-
value: new DataStream_TextHeader({
|
22002
|
-
version: options === null || options === void 0 ? void 0 : options.version,
|
22003
|
-
attachedStreamIds: options === null || options === void 0 ? void 0 : options.attachedStreamIds,
|
22004
|
-
replyToStreamId: options === null || options === void 0 ? void 0 : options.replyToStreamId,
|
22005
|
-
operationType: (options === null || options === void 0 ? void 0 : options.type) === 'update' ? DataStream_OperationType.UPDATE : DataStream_OperationType.CREATE
|
22006
|
-
})
|
22007
|
-
}
|
22008
|
-
});
|
22009
|
-
const destinationIdentities = options === null || options === void 0 ? void 0 : options.destinationIdentities;
|
22010
|
-
const packet = new DataPacket({
|
22011
|
-
destinationIdentities,
|
22012
|
-
value: {
|
22013
|
-
case: 'streamHeader',
|
22014
|
-
value: header
|
22015
|
-
}
|
22016
|
-
});
|
22017
|
-
yield this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
|
22018
|
-
let chunkId = 0;
|
22019
|
-
const localP = this;
|
22020
|
-
const writableStream = new WritableStream({
|
22021
|
-
// Implement the sink
|
22022
|
-
write(text) {
|
22023
|
-
return __awaiter(this, void 0, void 0, function* () {
|
22024
|
-
for (const textByteChunk of splitUtf8(text, STREAM_CHUNK_SIZE)) {
|
22025
|
-
yield localP.engine.waitForBufferStatusLow(DataPacket_Kind.RELIABLE);
|
22026
|
-
const chunk = new DataStream_Chunk({
|
22027
|
-
content: textByteChunk,
|
22028
|
-
streamId,
|
22029
|
-
chunkIndex: numberToBigInt(chunkId)
|
22030
|
-
});
|
22031
|
-
const chunkPacket = new DataPacket({
|
22032
|
-
destinationIdentities,
|
22033
|
-
value: {
|
22034
|
-
case: 'streamChunk',
|
22035
|
-
value: chunk
|
22036
|
-
}
|
22037
|
-
});
|
22038
|
-
yield localP.engine.sendDataPacket(chunkPacket, DataPacket_Kind.RELIABLE);
|
22039
|
-
chunkId += 1;
|
22040
|
-
}
|
22041
|
-
});
|
22042
|
-
},
|
22043
|
-
close() {
|
22044
|
-
return __awaiter(this, void 0, void 0, function* () {
|
22045
|
-
const trailer = new DataStream_Trailer({
|
22046
|
-
streamId
|
22047
|
-
});
|
22048
|
-
const trailerPacket = new DataPacket({
|
22049
|
-
destinationIdentities,
|
22050
|
-
value: {
|
22051
|
-
case: 'streamTrailer',
|
22052
|
-
value: trailer
|
22053
|
-
}
|
22054
|
-
});
|
22055
|
-
yield localP.engine.sendDataPacket(trailerPacket, DataPacket_Kind.RELIABLE);
|
22056
|
-
});
|
22057
|
-
},
|
22058
|
-
abort(err) {
|
22059
|
-
console.log('Sink error:', err);
|
22060
|
-
// TODO handle aborts to signal something to receiver side
|
22061
|
-
}
|
22062
|
-
});
|
22063
|
-
let onEngineClose = () => __awaiter(this, void 0, void 0, function* () {
|
22064
|
-
yield writer.close();
|
22065
|
-
});
|
22066
|
-
localP.engine.once(EngineEvent.Closing, onEngineClose);
|
22067
|
-
const writer = new TextStreamWriter(writableStream, info, () => this.engine.off(EngineEvent.Closing, onEngineClose));
|
22068
|
-
return writer;
|
22069
|
-
});
|
22070
|
-
}
|
22071
|
-
sendFile(file, options) {
|
22072
|
-
return __awaiter(this, void 0, void 0, function* () {
|
22073
|
-
const streamId = crypto.randomUUID();
|
22074
|
-
yield this._sendFile(streamId, file, options);
|
22075
|
-
return {
|
22076
|
-
id: streamId
|
22077
|
-
};
|
22078
|
-
});
|
22079
|
-
}
|
22080
|
-
_sendFile(streamId, file, options) {
|
22081
|
-
return __awaiter(this, void 0, void 0, function* () {
|
22082
|
-
var _a;
|
22083
|
-
const writer = yield this.streamBytes({
|
22084
|
-
streamId,
|
22085
|
-
totalSize: file.size,
|
22086
|
-
name: file.name,
|
22087
|
-
mimeType: (_a = options === null || options === void 0 ? void 0 : options.mimeType) !== null && _a !== void 0 ? _a : file.type,
|
22088
|
-
topic: options === null || options === void 0 ? void 0 : options.topic,
|
22089
|
-
destinationIdentities: options === null || options === void 0 ? void 0 : options.destinationIdentities
|
22090
|
-
});
|
22091
|
-
const reader = file.stream().getReader();
|
22092
|
-
while (true) {
|
22093
|
-
const {
|
22094
|
-
done,
|
22095
|
-
value
|
22096
|
-
} = yield reader.read();
|
22097
|
-
if (done) {
|
22098
|
-
break;
|
22099
|
-
}
|
22100
|
-
yield writer.write(value);
|
22101
|
-
}
|
22102
|
-
yield writer.close();
|
22103
|
-
return writer.info;
|
22104
|
-
});
|
22105
|
-
}
|
22106
|
-
streamBytes(options) {
|
22107
|
-
return __awaiter(this, void 0, void 0, function* () {
|
22108
|
-
var _a, _b, _c, _d, _e;
|
22109
|
-
const streamId = (_a = options === null || options === void 0 ? void 0 : options.streamId) !== null && _a !== void 0 ? _a : crypto.randomUUID();
|
22110
|
-
const destinationIdentities = options === null || options === void 0 ? void 0 : options.destinationIdentities;
|
22111
|
-
const info = {
|
22112
|
-
id: streamId,
|
22113
|
-
mimeType: (_b = options === null || options === void 0 ? void 0 : options.mimeType) !== null && _b !== void 0 ? _b : 'application/octet-stream',
|
22114
|
-
topic: (_c = options === null || options === void 0 ? void 0 : options.topic) !== null && _c !== void 0 ? _c : '',
|
22115
|
-
timestamp: Date.now(),
|
22116
|
-
attributes: options === null || options === void 0 ? void 0 : options.attributes,
|
22117
|
-
size: options === null || options === void 0 ? void 0 : options.totalSize,
|
22118
|
-
name: (_d = options === null || options === void 0 ? void 0 : options.name) !== null && _d !== void 0 ? _d : 'unknown'
|
22119
|
-
};
|
22120
|
-
const header = new DataStream_Header({
|
22121
|
-
totalLength: numberToBigInt((_e = info.size) !== null && _e !== void 0 ? _e : 0),
|
22122
|
-
mimeType: info.mimeType,
|
22123
|
-
streamId,
|
22124
|
-
topic: info.topic,
|
22125
|
-
timestamp: numberToBigInt(Date.now()),
|
22126
|
-
attributes: info.attributes,
|
22127
|
-
contentHeader: {
|
22128
|
-
case: 'byteHeader',
|
22129
|
-
value: new DataStream_ByteHeader({
|
22130
|
-
name: info.name
|
22131
|
-
})
|
22132
|
-
}
|
22133
|
-
});
|
22134
|
-
const packet = new DataPacket({
|
22135
|
-
destinationIdentities,
|
22136
|
-
value: {
|
22137
|
-
case: 'streamHeader',
|
22138
|
-
value: header
|
22557
|
+
value: new ChatMessage(Object.assign(Object.assign({}, msg), {
|
22558
|
+
timestamp: protoInt64.parse(msg.timestamp),
|
22559
|
+
editTimestamp: protoInt64.parse(msg.editTimestamp)
|
22560
|
+
}))
|
22139
22561
|
}
|
22140
22562
|
});
|
22141
22563
|
yield this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
|
22142
|
-
|
22143
|
-
|
22144
|
-
|
22145
|
-
|
22146
|
-
|
22147
|
-
|
22148
|
-
|
22149
|
-
|
22150
|
-
|
22151
|
-
|
22152
|
-
|
22153
|
-
|
22154
|
-
|
22155
|
-
|
22156
|
-
|
22157
|
-
|
22158
|
-
|
22159
|
-
|
22160
|
-
|
22161
|
-
|
22162
|
-
|
22163
|
-
|
22164
|
-
|
22165
|
-
|
22166
|
-
|
22167
|
-
|
22168
|
-
|
22169
|
-
|
22170
|
-
|
22171
|
-
|
22172
|
-
|
22173
|
-
|
22174
|
-
|
22175
|
-
|
22176
|
-
|
22177
|
-
|
22178
|
-
|
22179
|
-
|
22180
|
-
|
22181
|
-
|
22182
|
-
|
22183
|
-
|
22184
|
-
|
22185
|
-
|
22186
|
-
|
22187
|
-
|
22188
|
-
|
22189
|
-
|
22190
|
-
|
22191
|
-
log.error('Sink error:', err);
|
22192
|
-
}
|
22193
|
-
});
|
22194
|
-
const byteWriter = new ByteStreamWriter(writableStream, info);
|
22195
|
-
return byteWriter;
|
22564
|
+
this.emit(ParticipantEvent.ChatMessage, msg);
|
22565
|
+
return msg;
|
22566
|
+
});
|
22567
|
+
}
|
22568
|
+
/**
|
22569
|
+
* Sends the given string to participants in the room via the data channel.
|
22570
|
+
* For longer messages, consider using {@link streamText} instead.
|
22571
|
+
*
|
22572
|
+
* @param text The text payload
|
22573
|
+
* @param options.topic Topic identifier used to route the stream to appropriate handlers.
|
22574
|
+
*/
|
22575
|
+
sendText(text, options) {
|
22576
|
+
return __awaiter(this, void 0, void 0, function* () {
|
22577
|
+
return this.roomOutgoingDataStreamManager.sendText(text, options);
|
22578
|
+
});
|
22579
|
+
}
|
22580
|
+
/**
|
22581
|
+
* Creates a new TextStreamWriter which can be used to stream text incrementally
|
22582
|
+
* to participants in the room via the data channel.
|
22583
|
+
*
|
22584
|
+
* @param options.topic Topic identifier used to route the stream to appropriate handlers.
|
22585
|
+
*
|
22586
|
+
* @internal
|
22587
|
+
* @experimental CAUTION, might get removed in a minor release
|
22588
|
+
*/
|
22589
|
+
streamText(options) {
|
22590
|
+
return __awaiter(this, void 0, void 0, function* () {
|
22591
|
+
return this.roomOutgoingDataStreamManager.streamText(options);
|
22592
|
+
});
|
22593
|
+
}
|
22594
|
+
/** Send a File to all participants in the room via the data channel.
|
22595
|
+
* @param file The File object payload
|
22596
|
+
* @param options.topic Topic identifier used to route the stream to appropriate handlers.
|
22597
|
+
* @param options.onProgress A callback function used to monitor the upload progress percentage.
|
22598
|
+
*/
|
22599
|
+
sendFile(file, options) {
|
22600
|
+
return __awaiter(this, void 0, void 0, function* () {
|
22601
|
+
return this.roomOutgoingDataStreamManager.sendFile(file, options);
|
22602
|
+
});
|
22603
|
+
}
|
22604
|
+
/**
|
22605
|
+
* Stream bytes incrementally to participants in the room via the data channel.
|
22606
|
+
* For sending files, consider using {@link sendFile} instead.
|
22607
|
+
*
|
22608
|
+
* @param options.topic Topic identifier used to route the stream to appropriate handlers.
|
22609
|
+
*/
|
22610
|
+
streamBytes(options) {
|
22611
|
+
return __awaiter(this, void 0, void 0, function* () {
|
22612
|
+
return this.roomOutgoingDataStreamManager.streamBytes(options);
|
22196
22613
|
});
|
22197
22614
|
}
|
22198
22615
|
/**
|
@@ -23024,10 +23441,6 @@ class Room extends eventsExports.EventEmitter {
|
|
23024
23441
|
this.log = livekitLogger;
|
23025
23442
|
this.bufferedEvents = [];
|
23026
23443
|
this.isResuming = false;
|
23027
|
-
this.byteStreamControllers = new Map();
|
23028
|
-
this.textStreamControllers = new Map();
|
23029
|
-
this.byteStreamHandlers = new Map();
|
23030
|
-
this.textStreamHandlers = new Map();
|
23031
23444
|
this.rpcHandlers = new Map();
|
23032
23445
|
this.connect = (url, token, opts) => __awaiter(this, void 0, void 0, function* () {
|
23033
23446
|
var _a;
|
@@ -23567,12 +23980,8 @@ class Room extends eventsExports.EventEmitter {
|
|
23567
23980
|
this.handleChatMessage(participant, packet.value.value);
|
23568
23981
|
} else if (packet.value.case === 'metrics') {
|
23569
23982
|
this.handleMetrics(packet.value.value, participant);
|
23570
|
-
} else if (packet.value.case === 'streamHeader') {
|
23571
|
-
this.
|
23572
|
-
} else if (packet.value.case === 'streamChunk') {
|
23573
|
-
this.handleStreamChunk(packet.value.value);
|
23574
|
-
} else if (packet.value.case === 'streamTrailer') {
|
23575
|
-
this.handleStreamTrailer(packet.value.value);
|
23983
|
+
} else if (packet.value.case === 'streamHeader' || packet.value.case === 'streamChunk' || packet.value.case === 'streamTrailer') {
|
23984
|
+
this.handleDataStream(packet);
|
23576
23985
|
} else if (packet.value.case === 'rpcRequest') {
|
23577
23986
|
const rpc = packet.value.value;
|
23578
23987
|
this.handleIncomingRpcRequest(packet.participantIdentity, rpc.id, rpc.method, rpc.payload, rpc.responseTimeoutMs, rpc.version);
|
@@ -23588,7 +23997,6 @@ class Room extends eventsExports.EventEmitter {
|
|
23588
23997
|
// also emit on the participant
|
23589
23998
|
participant === null || participant === void 0 ? void 0 : participant.emit(ParticipantEvent.SipDTMFReceived, dtmf);
|
23590
23999
|
};
|
23591
|
-
this.bufferedSegments = new Map();
|
23592
24000
|
this.handleTranscription = (_remoteParticipant, transcription) => {
|
23593
24001
|
// find the participant
|
23594
24002
|
const participant = transcription.transcribedParticipantIdentity === this.localParticipant.identity ? this.localParticipant : this.getParticipantByIdentity(transcription.transcribedParticipantIdentity);
|
@@ -23605,6 +24013,10 @@ class Room extends eventsExports.EventEmitter {
|
|
23605
24013
|
this.handleMetrics = (metrics, participant) => {
|
23606
24014
|
this.emit(RoomEvent.MetricsReceived, metrics, participant);
|
23607
24015
|
};
|
24016
|
+
this.handleDataStream = packet => {
|
24017
|
+
this.incomingDataStreamManager.handleDataStreamPacket(packet);
|
24018
|
+
};
|
24019
|
+
this.bufferedSegments = new Map();
|
23608
24020
|
this.handleAudioPlaybackStarted = () => {
|
23609
24021
|
if (this.canPlaybackAudio) {
|
23610
24022
|
return;
|
@@ -23739,8 +24151,10 @@ class Room extends eventsExports.EventEmitter {
|
|
23739
24151
|
this.options.videoCaptureDefaults = Object.assign(Object.assign({}, videoDefaults), options === null || options === void 0 ? void 0 : options.videoCaptureDefaults);
|
23740
24152
|
this.options.publishDefaults = Object.assign(Object.assign({}, publishDefaults), options === null || options === void 0 ? void 0 : options.publishDefaults);
|
23741
24153
|
this.maybeCreateEngine();
|
24154
|
+
this.incomingDataStreamManager = new IncomingDataStreamManager();
|
24155
|
+
this.outgoingDataStreamManager = new OutgoingDataStreamManager(this.engine, this.log);
|
23742
24156
|
this.disconnectLock = new _();
|
23743
|
-
this.localParticipant = new LocalParticipant('', '', this.engine, this.options, this.rpcHandlers);
|
24157
|
+
this.localParticipant = new LocalParticipant('', '', this.engine, this.options, this.rpcHandlers, this.outgoingDataStreamManager);
|
23744
24158
|
if (this.options.videoCaptureDefaults.deviceId) {
|
23745
24159
|
this.localParticipant.activeDeviceMap.set('videoinput', unwrapConstraint(this.options.videoCaptureDefaults.deviceId));
|
23746
24160
|
}
|
@@ -23767,22 +24181,16 @@ class Room extends eventsExports.EventEmitter {
|
|
23767
24181
|
}
|
23768
24182
|
}
|
23769
24183
|
registerTextStreamHandler(topic, callback) {
|
23770
|
-
|
23771
|
-
throw new TypeError("A text stream handler for topic \"".concat(topic, "\" has already been set."));
|
23772
|
-
}
|
23773
|
-
this.textStreamHandlers.set(topic, callback);
|
24184
|
+
return this.incomingDataStreamManager.registerTextStreamHandler(topic, callback);
|
23774
24185
|
}
|
23775
24186
|
unregisterTextStreamHandler(topic) {
|
23776
|
-
this.
|
24187
|
+
return this.incomingDataStreamManager.unregisterTextStreamHandler(topic);
|
23777
24188
|
}
|
23778
24189
|
registerByteStreamHandler(topic, callback) {
|
23779
|
-
|
23780
|
-
throw new TypeError("A byte stream handler for topic \"".concat(topic, "\" has already been set."));
|
23781
|
-
}
|
23782
|
-
this.byteStreamHandlers.set(topic, callback);
|
24190
|
+
return this.incomingDataStreamManager.registerByteStreamHandler(topic, callback);
|
23783
24191
|
}
|
23784
24192
|
unregisterByteStreamHandler(topic) {
|
23785
|
-
this.
|
24193
|
+
return this.incomingDataStreamManager.unregisterByteStreamHandler(topic);
|
23786
24194
|
}
|
23787
24195
|
/**
|
23788
24196
|
* Establishes the participant as a receiver for calls of the specified RPC method.
|
@@ -23824,44 +24232,6 @@ class Room extends eventsExports.EventEmitter {
|
|
23824
24232
|
unregisterRpcMethod(method) {
|
23825
24233
|
this.rpcHandlers.delete(method);
|
23826
24234
|
}
|
23827
|
-
handleIncomingRpcRequest(callerIdentity, requestId, method, payload, responseTimeout, version) {
|
23828
|
-
return __awaiter(this, void 0, void 0, function* () {
|
23829
|
-
yield this.engine.publishRpcAck(callerIdentity, requestId);
|
23830
|
-
if (version !== 1) {
|
23831
|
-
yield this.engine.publishRpcResponse(callerIdentity, requestId, null, RpcError.builtIn('UNSUPPORTED_VERSION'));
|
23832
|
-
return;
|
23833
|
-
}
|
23834
|
-
const handler = this.rpcHandlers.get(method);
|
23835
|
-
if (!handler) {
|
23836
|
-
yield this.engine.publishRpcResponse(callerIdentity, requestId, null, RpcError.builtIn('UNSUPPORTED_METHOD'));
|
23837
|
-
return;
|
23838
|
-
}
|
23839
|
-
let responseError = null;
|
23840
|
-
let responsePayload = null;
|
23841
|
-
try {
|
23842
|
-
const response = yield handler({
|
23843
|
-
requestId,
|
23844
|
-
callerIdentity,
|
23845
|
-
payload,
|
23846
|
-
responseTimeout
|
23847
|
-
});
|
23848
|
-
if (byteLength(response) > MAX_PAYLOAD_BYTES) {
|
23849
|
-
responseError = RpcError.builtIn('RESPONSE_PAYLOAD_TOO_LARGE');
|
23850
|
-
console.warn("RPC Response payload too large for ".concat(method));
|
23851
|
-
} else {
|
23852
|
-
responsePayload = response;
|
23853
|
-
}
|
23854
|
-
} catch (error) {
|
23855
|
-
if (error instanceof RpcError) {
|
23856
|
-
responseError = error;
|
23857
|
-
} else {
|
23858
|
-
console.warn("Uncaught error returned by RPC handler for ".concat(method, ". Returning APPLICATION_ERROR instead."), error);
|
23859
|
-
responseError = RpcError.builtIn('APPLICATION_ERROR');
|
23860
|
-
}
|
23861
|
-
}
|
23862
|
-
yield this.engine.publishRpcResponse(callerIdentity, requestId, responsePayload, responseError);
|
23863
|
-
});
|
23864
|
-
}
|
23865
24235
|
/**
|
23866
24236
|
* @experimental
|
23867
24237
|
*/
|
@@ -24026,6 +24396,9 @@ class Room extends eventsExports.EventEmitter {
|
|
24026
24396
|
if (this.e2eeManager) {
|
24027
24397
|
this.e2eeManager.setupEngine(this.engine);
|
24028
24398
|
}
|
24399
|
+
if (this.outgoingDataStreamManager) {
|
24400
|
+
this.outgoingDataStreamManager.setupEngine(this.engine);
|
24401
|
+
}
|
24029
24402
|
}
|
24030
24403
|
/**
|
24031
24404
|
* getLocalDevices abstracts navigator.mediaDevices.enumerateDevices.
|
@@ -24291,7 +24664,7 @@ class Room extends eventsExports.EventEmitter {
|
|
24291
24664
|
} else if (kind === 'audiooutput') {
|
24292
24665
|
shouldTriggerImmediateDeviceChange = true;
|
24293
24666
|
if (!supportsSetSinkId() && !_this3.options.webAudioMix || _this3.options.webAudioMix && _this3.audioContext && !('setSinkId' in _this3.audioContext)) {
|
24294
|
-
throw new Error('cannot switch audio output,
|
24667
|
+
throw new Error('cannot switch audio output, the current browser does not support it');
|
24295
24668
|
}
|
24296
24669
|
if (_this3.options.webAudioMix) {
|
24297
24670
|
// setting `default` for web audio output doesn't work, so we need to normalize the id before
|
@@ -24402,6 +24775,7 @@ class Room extends eventsExports.EventEmitter {
|
|
24402
24775
|
this.isResuming = false;
|
24403
24776
|
this.bufferedEvents = [];
|
24404
24777
|
this.transcriptionReceivedTimes.clear();
|
24778
|
+
this.incomingDataStreamManager.clearHandlersAndControllers();
|
24405
24779
|
if (this.state === ConnectionState.Disconnected) {
|
24406
24780
|
return;
|
24407
24781
|
}
|
@@ -24453,6 +24827,7 @@ class Room extends eventsExports.EventEmitter {
|
|
24453
24827
|
if (!participant) {
|
24454
24828
|
return;
|
24455
24829
|
}
|
24830
|
+
this.incomingDataStreamManager.validateParticipantHasNoActiveDataStreams(identity);
|
24456
24831
|
participant.trackPublications.forEach(publication => {
|
24457
24832
|
participant.unpublishTrack(publication.trackSid, true);
|
24458
24833
|
});
|
@@ -24460,99 +24835,44 @@ class Room extends eventsExports.EventEmitter {
|
|
24460
24835
|
participant.setDisconnected();
|
24461
24836
|
(_a = this.localParticipant) === null || _a === void 0 ? void 0 : _a.handleParticipantDisconnected(participant.identity);
|
24462
24837
|
}
|
24463
|
-
|
24838
|
+
handleIncomingRpcRequest(callerIdentity, requestId, method, payload, responseTimeout, version) {
|
24464
24839
|
return __awaiter(this, void 0, void 0, function* () {
|
24465
|
-
|
24466
|
-
if (
|
24467
|
-
|
24468
|
-
|
24469
|
-
|
24470
|
-
|
24471
|
-
|
24472
|
-
|
24473
|
-
|
24474
|
-
|
24475
|
-
|
24476
|
-
|
24477
|
-
|
24478
|
-
|
24479
|
-
|
24480
|
-
|
24481
|
-
|
24482
|
-
|
24483
|
-
start: controller => {
|
24484
|
-
streamController = controller;
|
24485
|
-
this.byteStreamControllers.set(streamHeader.streamId, {
|
24486
|
-
info,
|
24487
|
-
controller: streamController,
|
24488
|
-
startTime: Date.now()
|
24489
|
-
});
|
24490
|
-
}
|
24491
|
-
});
|
24492
|
-
streamHandlerCallback(new ByteStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength)), {
|
24493
|
-
identity: participantIdentity
|
24840
|
+
yield this.engine.publishRpcAck(callerIdentity, requestId);
|
24841
|
+
if (version !== 1) {
|
24842
|
+
yield this.engine.publishRpcResponse(callerIdentity, requestId, null, RpcError.builtIn('UNSUPPORTED_VERSION'));
|
24843
|
+
return;
|
24844
|
+
}
|
24845
|
+
const handler = this.rpcHandlers.get(method);
|
24846
|
+
if (!handler) {
|
24847
|
+
yield this.engine.publishRpcResponse(callerIdentity, requestId, null, RpcError.builtIn('UNSUPPORTED_METHOD'));
|
24848
|
+
return;
|
24849
|
+
}
|
24850
|
+
let responseError = null;
|
24851
|
+
let responsePayload = null;
|
24852
|
+
try {
|
24853
|
+
const response = yield handler({
|
24854
|
+
requestId,
|
24855
|
+
callerIdentity,
|
24856
|
+
payload,
|
24857
|
+
responseTimeout
|
24494
24858
|
});
|
24495
|
-
|
24496
|
-
|
24497
|
-
|
24498
|
-
|
24499
|
-
|
24859
|
+
if (byteLength(response) > MAX_PAYLOAD_BYTES) {
|
24860
|
+
responseError = RpcError.builtIn('RESPONSE_PAYLOAD_TOO_LARGE');
|
24861
|
+
console.warn("RPC Response payload too large for ".concat(method));
|
24862
|
+
} else {
|
24863
|
+
responsePayload = response;
|
24864
|
+
}
|
24865
|
+
} catch (error) {
|
24866
|
+
if (error instanceof RpcError) {
|
24867
|
+
responseError = error;
|
24868
|
+
} else {
|
24869
|
+
console.warn("Uncaught error returned by RPC handler for ".concat(method, ". Returning APPLICATION_ERROR instead."), error);
|
24870
|
+
responseError = RpcError.builtIn('APPLICATION_ERROR');
|
24500
24871
|
}
|
24501
|
-
let streamController;
|
24502
|
-
const info = {
|
24503
|
-
id: streamHeader.streamId,
|
24504
|
-
mimeType: streamHeader.mimeType,
|
24505
|
-
size: streamHeader.totalLength ? Number(streamHeader.totalLength) : undefined,
|
24506
|
-
topic: streamHeader.topic,
|
24507
|
-
timestamp: Number(streamHeader.timestamp),
|
24508
|
-
attributes: streamHeader.attributes
|
24509
|
-
};
|
24510
|
-
const stream = new ReadableStream({
|
24511
|
-
start: controller => {
|
24512
|
-
streamController = controller;
|
24513
|
-
this.textStreamControllers.set(streamHeader.streamId, {
|
24514
|
-
info,
|
24515
|
-
controller: streamController,
|
24516
|
-
startTime: Date.now()
|
24517
|
-
});
|
24518
|
-
}
|
24519
|
-
});
|
24520
|
-
streamHandlerCallback(new TextStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength)), {
|
24521
|
-
identity: participantIdentity
|
24522
|
-
});
|
24523
24872
|
}
|
24873
|
+
yield this.engine.publishRpcResponse(callerIdentity, requestId, responsePayload, responseError);
|
24524
24874
|
});
|
24525
24875
|
}
|
24526
|
-
handleStreamChunk(chunk) {
|
24527
|
-
const fileBuffer = this.byteStreamControllers.get(chunk.streamId);
|
24528
|
-
if (fileBuffer) {
|
24529
|
-
if (chunk.content.length > 0) {
|
24530
|
-
fileBuffer.controller.enqueue(chunk);
|
24531
|
-
}
|
24532
|
-
}
|
24533
|
-
const textBuffer = this.textStreamControllers.get(chunk.streamId);
|
24534
|
-
if (textBuffer) {
|
24535
|
-
if (chunk.content.length > 0) {
|
24536
|
-
textBuffer.controller.enqueue(chunk);
|
24537
|
-
}
|
24538
|
-
}
|
24539
|
-
}
|
24540
|
-
handleStreamTrailer(trailer) {
|
24541
|
-
const textBuffer = this.textStreamControllers.get(trailer.streamId);
|
24542
|
-
if (textBuffer) {
|
24543
|
-
textBuffer.info.attributes = Object.assign(Object.assign({}, textBuffer.info.attributes), trailer.attributes);
|
24544
|
-
textBuffer.controller.close();
|
24545
|
-
this.textStreamControllers.delete(trailer.streamId);
|
24546
|
-
}
|
24547
|
-
const fileBuffer = this.byteStreamControllers.get(trailer.streamId);
|
24548
|
-
if (fileBuffer) {
|
24549
|
-
{
|
24550
|
-
fileBuffer.info.attributes = Object.assign(Object.assign({}, fileBuffer.info.attributes), trailer.attributes);
|
24551
|
-
fileBuffer.controller.close();
|
24552
|
-
this.byteStreamControllers.delete(trailer.streamId);
|
24553
|
-
}
|
24554
|
-
}
|
24555
|
-
}
|
24556
24876
|
/**
|
24557
24877
|
* attempt to select the default devices if the previously selected devices are no longer available after a device change event
|
24558
24878
|
*/
|
@@ -25808,5 +26128,5 @@ function isFacingModeValue(item) {
|
|
25808
26128
|
return item === undefined || allowedValues.includes(item);
|
25809
26129
|
}
|
25810
26130
|
|
25811
|
-
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 };
|
26131
|
+
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 };
|
25812
26132
|
//# sourceMappingURL=livekit-client.esm.mjs.map
|