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.
Files changed (67) hide show
  1. package/README.md +2 -2
  2. package/dist/livekit-client.e2ee.worker.js +1 -1
  3. package/dist/livekit-client.e2ee.worker.js.map +1 -1
  4. package/dist/livekit-client.e2ee.worker.mjs +329 -124
  5. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  6. package/dist/livekit-client.esm.mjs +868 -548
  7. package/dist/livekit-client.esm.mjs.map +1 -1
  8. package/dist/livekit-client.umd.js +1 -1
  9. package/dist/livekit-client.umd.js.map +1 -1
  10. package/dist/src/api/SignalClient.d.ts.map +1 -1
  11. package/dist/src/e2ee/worker/FrameCryptor.d.ts +0 -46
  12. package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
  13. package/dist/src/e2ee/worker/naluUtils.d.ts +27 -0
  14. package/dist/src/e2ee/worker/naluUtils.d.ts.map +1 -0
  15. package/dist/src/index.d.ts +2 -2
  16. package/dist/src/index.d.ts.map +1 -1
  17. package/dist/src/room/Room.d.ts +6 -10
  18. package/dist/src/room/Room.d.ts.map +1 -1
  19. package/dist/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts +20 -0
  20. package/dist/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts.map +1 -0
  21. package/dist/src/room/{StreamReader.d.ts → data-stream/incoming/StreamReader.d.ts} +32 -6
  22. package/dist/src/room/data-stream/incoming/StreamReader.d.ts.map +1 -0
  23. package/dist/src/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts +27 -0
  24. package/dist/src/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts.map +1 -0
  25. package/dist/src/room/{StreamWriter.d.ts → data-stream/outgoing/StreamWriter.d.ts} +1 -1
  26. package/dist/src/room/data-stream/outgoing/StreamWriter.d.ts.map +1 -0
  27. package/dist/src/room/errors.d.ts +13 -0
  28. package/dist/src/room/errors.d.ts.map +1 -1
  29. package/dist/src/room/participant/LocalParticipant.d.ts +33 -20
  30. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  31. package/dist/src/room/track/LocalTrack.d.ts +8 -2
  32. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  33. package/dist/src/room/track/record.d.ts.map +1 -1
  34. package/dist/src/room/types.d.ts +17 -1
  35. package/dist/src/room/types.d.ts.map +1 -1
  36. package/dist/ts4.2/src/e2ee/worker/FrameCryptor.d.ts +0 -46
  37. package/dist/ts4.2/src/e2ee/worker/naluUtils.d.ts +27 -0
  38. package/dist/ts4.2/src/index.d.ts +2 -2
  39. package/dist/ts4.2/src/room/Room.d.ts +6 -10
  40. package/dist/ts4.2/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts +20 -0
  41. package/dist/ts4.2/src/room/{StreamReader.d.ts → data-stream/incoming/StreamReader.d.ts} +32 -6
  42. package/dist/ts4.2/src/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts +27 -0
  43. package/dist/ts4.2/src/room/{StreamWriter.d.ts → data-stream/outgoing/StreamWriter.d.ts} +1 -1
  44. package/dist/ts4.2/src/room/errors.d.ts +13 -0
  45. package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +33 -20
  46. package/dist/ts4.2/src/room/track/LocalTrack.d.ts +8 -2
  47. package/dist/ts4.2/src/room/types.d.ts +17 -1
  48. package/package.json +1 -1
  49. package/src/api/SignalClient.ts +6 -0
  50. package/src/e2ee/worker/FrameCryptor.ts +48 -139
  51. package/src/e2ee/worker/naluUtils.ts +328 -0
  52. package/src/index.ts +2 -2
  53. package/src/room/Room.ts +94 -207
  54. package/src/room/data-stream/incoming/IncomingDataStreamManager.ts +247 -0
  55. package/src/room/data-stream/incoming/StreamReader.ts +317 -0
  56. package/src/room/data-stream/outgoing/OutgoingDataStreamManager.ts +316 -0
  57. package/src/room/{StreamWriter.ts → data-stream/outgoing/StreamWriter.ts} +1 -1
  58. package/src/room/errors.ts +34 -0
  59. package/src/room/participant/LocalParticipant.ts +48 -299
  60. package/src/room/track/LocalAudioTrack.ts +2 -2
  61. package/src/room/track/LocalTrack.ts +75 -49
  62. package/src/room/track/record.ts +15 -2
  63. package/src/room/types.ts +22 -1
  64. package/src/room/utils.ts +3 -3
  65. package/dist/src/room/StreamReader.d.ts.map +0 -1
  66. package/dist/src/room/StreamWriter.d.ts.map +0 -1
  67. 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.3";
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
- const arrayBuffer = yield event.data.arrayBuffer();
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(new Uint8Array(arrayBuffer));
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.processorLock = new _();
15919
- this.restartLock = new _();
15920
- this.setMediaStreamTrack(mediaTrack, true);
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
- const unlock = yield this.processorLock.lock();
15997
- try {
15998
- this.log.debug('restarting processor', this.logContext);
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
- if (!this.sender) {
16114
- throw new TrackInvalidError('unable to replace an unpublished track');
16115
- }
16116
- let userProvidedTrack;
16117
- let stopProcessor;
16118
- if (typeof userProvidedOrOptions === 'boolean') {
16119
- userProvidedTrack = userProvidedOrOptions;
16120
- } else if (userProvidedOrOptions !== undefined) {
16121
- userProvidedTrack = userProvidedOrOptions.userProvidedTrack;
16122
- stopProcessor = userProvidedOrOptions.stopProcessor;
16123
- }
16124
- this.providedByUser = userProvidedTrack !== null && userProvidedTrack !== void 0 ? userProvidedTrack : true;
16125
- this.log.debug('replace MediaStreamTrack', this.logContext);
16126
- yield this.setMediaStreamTrack(track);
16127
- // this must be synced *after* setting mediaStreamTrack above, since it relies
16128
- // on the previous state in order to cleanup
16129
- if (stopProcessor && this.processor) {
16130
- yield this.stopProcessor();
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.restartLock.lock();
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.processorLock.lock();
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.stopProcessor();
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 (!_this4.processor) return;
16395
- _this4.log.debug('stopping processor', _this4.logContext);
16396
- (_a = _this4.processor.processedTrack) === null || _a === void 0 ? void 0 : _a.stop();
16397
- yield _this4.processor.destroy();
16398
- _this4.processor = undefined;
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 = _this4.processorElement) === null || _b === void 0 ? void 0 : _b.remove();
16401
- _this4.processorElement = undefined;
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 _this4._mediaStreamTrack.applyConstraints(_this4._constraints);
16468
+ yield _this5._mediaStreamTrack.applyConstraints(_this5._constraints);
16405
16469
  // force re-setting of the mediaStreamTrack on the sender
16406
- yield _this4.setMediaStreamTrack(_this4._mediaStreamTrack, true);
16407
- _this4.emit(TrackEvent.TrackProcessorUpdate);
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: 'audio/webm;codecs=opus'
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.processorLock.lock();
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.stopProcessor();
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
- constructor(info, stream, totalByteSize) {
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 (error) {
19018
- // TODO handle errors
19019
- return {
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
- reader.releaseLock();
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, void 0, void 0, function* () {
19038
- var _a, e_1, _b, _c;
19039
- let chunks = new Set();
19040
- try {
19041
- for (var _d = true, _e = __asyncValues(this), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
19042
- _c = _f.value;
19043
- _d = false;
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
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
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
- if (e_1) throw e_1.error;
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
- return Array.from(chunks);
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: decoder.decode(value.content)
19276
+ value: decodedResult
19112
19277
  };
19113
19278
  }
19114
- } catch (error) {
19115
- // TODO handle errors
19116
- return {
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
- reader.releaseLock();
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
- var _a, e_2, _b, _c;
19136
- let finalString = '';
19137
- try {
19138
- for (var _d = true, _e = __asyncValues(this), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
19139
- _c = _f.value;
19140
- _d = false;
19141
- const chunk = _c;
19142
- finalString += chunk;
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
- } catch (e_2_1) {
19145
- e_2 = {
19146
- error: e_2_1
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
- } finally {
19149
- try {
19150
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
19151
- } finally {
19152
- if (e_2) throw e_2.error;
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
- class RemoteTrack extends Track {
19183
- constructor(mediaTrack, sid, kind, receiver, loggerOptions) {
19184
- super(mediaTrack, kind, loggerOptions);
19185
- this.sid = sid;
19186
- this.receiver = receiver;
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.handleDisconnected = () => {
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.Disconnected, this.handleDisconnected).on(EngineEvent.SignalRequestResponse, this.handleSignalRequestResponse).on(EngineEvent.DataPacketReceived, this.handleDataPacket);
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
- if (source === Track.Source.Microphone && isAudioTrack(localTrack) && (publishOptions === null || publishOptions === void 0 ? void 0 : publishOptions.preConnectBuffer)) {
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: 'audio/opus',
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
- let chunkId = 0;
22143
- const writeMutex = new _();
22144
- const engine = this.engine;
22145
- const log = this.log;
22146
- const writableStream = new WritableStream({
22147
- write(chunk) {
22148
- return __awaiter(this, void 0, void 0, function* () {
22149
- const unlock = yield writeMutex.lock();
22150
- let byteOffset = 0;
22151
- try {
22152
- while (byteOffset < chunk.byteLength) {
22153
- const subChunk = chunk.slice(byteOffset, byteOffset + STREAM_CHUNK_SIZE);
22154
- yield engine.waitForBufferStatusLow(DataPacket_Kind.RELIABLE);
22155
- const chunkPacket = new DataPacket({
22156
- destinationIdentities,
22157
- value: {
22158
- case: 'streamChunk',
22159
- value: new DataStream_Chunk({
22160
- content: subChunk,
22161
- streamId,
22162
- chunkIndex: numberToBigInt(chunkId)
22163
- })
22164
- }
22165
- });
22166
- yield engine.sendDataPacket(chunkPacket, DataPacket_Kind.RELIABLE);
22167
- chunkId += 1;
22168
- byteOffset += subChunk.byteLength;
22169
- }
22170
- } finally {
22171
- unlock();
22172
- }
22173
- });
22174
- },
22175
- close() {
22176
- return __awaiter(this, void 0, void 0, function* () {
22177
- const trailer = new DataStream_Trailer({
22178
- streamId
22179
- });
22180
- const trailerPacket = new DataPacket({
22181
- destinationIdentities,
22182
- value: {
22183
- case: 'streamTrailer',
22184
- value: trailer
22185
- }
22186
- });
22187
- yield engine.sendDataPacket(trailerPacket, DataPacket_Kind.RELIABLE);
22188
- });
22189
- },
22190
- abort(err) {
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.handleStreamHeader(packet.value.value, packet.participantIdentity);
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
- if (this.textStreamHandlers.has(topic)) {
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.textStreamHandlers.delete(topic);
24187
+ return this.incomingDataStreamManager.unregisterTextStreamHandler(topic);
23777
24188
  }
23778
24189
  registerByteStreamHandler(topic, callback) {
23779
- if (this.byteStreamHandlers.has(topic)) {
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.byteStreamHandlers.delete(topic);
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, setSinkId not supported');
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
- handleStreamHeader(streamHeader, participantIdentity) {
24838
+ handleIncomingRpcRequest(callerIdentity, requestId, method, payload, responseTimeout, version) {
24464
24839
  return __awaiter(this, void 0, void 0, function* () {
24465
- var _a;
24466
- if (streamHeader.contentHeader.case === 'byteHeader') {
24467
- const streamHandlerCallback = this.byteStreamHandlers.get(streamHeader.topic);
24468
- if (!streamHandlerCallback) {
24469
- this.log.debug('ignoring incoming byte stream due to no handler for topic', streamHeader.topic);
24470
- return;
24471
- }
24472
- let streamController;
24473
- const info = {
24474
- id: streamHeader.streamId,
24475
- name: (_a = streamHeader.contentHeader.value.name) !== null && _a !== void 0 ? _a : 'unknown',
24476
- mimeType: streamHeader.mimeType,
24477
- size: streamHeader.totalLength ? Number(streamHeader.totalLength) : undefined,
24478
- topic: streamHeader.topic,
24479
- timestamp: bigIntToNumber(streamHeader.timestamp),
24480
- attributes: streamHeader.attributes
24481
- };
24482
- const stream = new ReadableStream({
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
- } else if (streamHeader.contentHeader.case === 'textHeader') {
24496
- const streamHandlerCallback = this.textStreamHandlers.get(streamHeader.topic);
24497
- if (!streamHandlerCallback) {
24498
- this.log.debug('ignoring incoming text stream due to no handler for topic', streamHeader.topic);
24499
- return;
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