livekit-client 2.0.2 → 2.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. package/dist/livekit-client.e2ee.worker.js +1 -1
  2. package/dist/livekit-client.e2ee.worker.js.map +1 -1
  3. package/dist/livekit-client.e2ee.worker.mjs +53 -17
  4. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  5. package/dist/livekit-client.esm.mjs +158 -65
  6. package/dist/livekit-client.esm.mjs.map +1 -1
  7. package/dist/livekit-client.umd.js +1 -1
  8. package/dist/livekit-client.umd.js.map +1 -1
  9. package/dist/src/api/SignalClient.d.ts.map +1 -1
  10. package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
  11. package/dist/src/e2ee/KeyProvider.d.ts +1 -1
  12. package/dist/src/e2ee/KeyProvider.d.ts.map +1 -1
  13. package/dist/src/e2ee/types.d.ts +2 -0
  14. package/dist/src/e2ee/types.d.ts.map +1 -1
  15. package/dist/src/e2ee/worker/FrameCryptor.d.ts +1 -0
  16. package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
  17. package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts +2 -2
  18. package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts.map +1 -1
  19. package/dist/src/index.d.ts +2 -2
  20. package/dist/src/index.d.ts.map +1 -1
  21. package/dist/src/logger.d.ts +2 -0
  22. package/dist/src/logger.d.ts.map +1 -1
  23. package/dist/src/room/DeviceManager.d.ts.map +1 -1
  24. package/dist/src/room/RTCEngine.d.ts +1 -0
  25. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  26. package/dist/src/room/Room.d.ts +1 -0
  27. package/dist/src/room/Room.d.ts.map +1 -1
  28. package/dist/src/room/events.d.ts +7 -2
  29. package/dist/src/room/events.d.ts.map +1 -1
  30. package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
  31. package/dist/src/room/track/LocalTrack.d.ts +4 -1
  32. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  33. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
  34. package/dist/src/room/track/Track.d.ts +2 -0
  35. package/dist/src/room/track/Track.d.ts.map +1 -1
  36. package/dist/src/room/track/options.d.ts +10 -0
  37. package/dist/src/room/track/options.d.ts.map +1 -1
  38. package/dist/src/room/track/types.d.ts +4 -0
  39. package/dist/src/room/track/types.d.ts.map +1 -1
  40. package/dist/ts4.2/src/e2ee/KeyProvider.d.ts +1 -1
  41. package/dist/ts4.2/src/e2ee/types.d.ts +2 -0
  42. package/dist/ts4.2/src/e2ee/worker/FrameCryptor.d.ts +1 -0
  43. package/dist/ts4.2/src/e2ee/worker/ParticipantKeyHandler.d.ts +2 -2
  44. package/dist/ts4.2/src/index.d.ts +2 -2
  45. package/dist/ts4.2/src/logger.d.ts +2 -0
  46. package/dist/ts4.2/src/room/RTCEngine.d.ts +1 -0
  47. package/dist/ts4.2/src/room/Room.d.ts +1 -0
  48. package/dist/ts4.2/src/room/events.d.ts +7 -2
  49. package/dist/ts4.2/src/room/track/LocalTrack.d.ts +4 -1
  50. package/dist/ts4.2/src/room/track/Track.d.ts +2 -0
  51. package/dist/ts4.2/src/room/track/options.d.ts +10 -0
  52. package/dist/ts4.2/src/room/track/types.d.ts +4 -0
  53. package/package.json +1 -1
  54. package/src/api/SignalClient.ts +1 -0
  55. package/src/e2ee/E2eeManager.ts +2 -1
  56. package/src/e2ee/KeyProvider.ts +6 -1
  57. package/src/e2ee/types.ts +2 -0
  58. package/src/e2ee/worker/FrameCryptor.ts +26 -0
  59. package/src/e2ee/worker/ParticipantKeyHandler.ts +9 -5
  60. package/src/e2ee/worker/e2ee.worker.ts +17 -17
  61. package/src/index.ts +2 -1
  62. package/src/logger.ts +2 -0
  63. package/src/room/DeviceManager.ts +10 -1
  64. package/src/room/RTCEngine.ts +14 -0
  65. package/src/room/Room.ts +29 -4
  66. package/src/room/events.ts +5 -0
  67. package/src/room/participant/LocalParticipant.ts +4 -4
  68. package/src/room/track/LocalAudioTrack.ts +11 -0
  69. package/src/room/track/LocalTrack.ts +62 -36
  70. package/src/room/track/LocalVideoTrack.ts +10 -0
  71. package/src/room/track/Track.ts +2 -0
  72. package/src/room/track/options.ts +41 -8
  73. package/src/room/track/types.ts +5 -0
@@ -352,7 +352,7 @@ function setLogExtension(extension) {
352
352
  };
353
353
  logger.setLevel(logger.getLevel()); // Be sure to call setLevel method in order to apply plugin
354
354
  }
355
- loglevelExports.getLogger('lk-e2ee');
355
+ const workerLogger = loglevelExports.getLogger('lk-e2ee');
356
356
 
357
357
  // Copyright 2021-2023 Buf Technologies, Inc.
358
358
  //
@@ -9980,6 +9980,9 @@ class BaseKeyProvider extends eventsExports.EventEmitter {
9980
9980
  participantIdentity,
9981
9981
  keyIndex
9982
9982
  };
9983
+ if (!this.options.sharedKey && !participantIdentity) {
9984
+ throw new Error('participant identity needs to be passed for encryption key if sharedKey option is false');
9985
+ }
9983
9986
  this.keyInfoMap.set("".concat(participantIdentity !== null && participantIdentity !== void 0 ? participantIdentity : 'shared', "-").concat(keyIndex !== null && keyIndex !== void 0 ? keyIndex : 0), keyInfo);
9984
9987
  this.emit(KeyProviderEvent.SetKey, keyInfo);
9985
9988
  }
@@ -10534,6 +10537,7 @@ var EngineEvent;
10534
10537
  EngineEvent["RemoteMute"] = "remoteMute";
10535
10538
  EngineEvent["SubscribedQualityUpdate"] = "subscribedQualityUpdate";
10536
10539
  EngineEvent["LocalTrackUnpublished"] = "localTrackUnpublished";
10540
+ EngineEvent["Offline"] = "offline";
10537
10541
  })(EngineEvent || (EngineEvent = {}));
10538
10542
  var TrackEvent;
10539
10543
  (function (TrackEvent) {
@@ -10595,6 +10599,10 @@ var TrackEvent;
10595
10599
  * Fires on RemoteTrackPublication
10596
10600
  */
10597
10601
  TrackEvent["SubscriptionFailed"] = "subscriptionFailed";
10602
+ /**
10603
+ * @internal
10604
+ */
10605
+ TrackEvent["TrackProcessorUpdate"] = "trackProcessorUpdate";
10598
10606
  })(TrackEvent || (TrackEvent = {}));
10599
10607
 
10600
10608
  function r(r, e, n) {
@@ -10703,7 +10711,7 @@ function getMatch(exp, ua) {
10703
10711
  return match && match.length >= id && match[id] || '';
10704
10712
  }
10705
10713
 
10706
- var version$1 = "2.0.2";
10714
+ var version$1 = "2.0.4";
10707
10715
 
10708
10716
  const version = version$1;
10709
10717
  const protocolVersion = 12;
@@ -10730,21 +10738,35 @@ CriticalTimers.clearInterval = function () {
10730
10738
  };
10731
10739
 
10732
10740
  class VideoPreset {
10733
- constructor(width, height, maxBitrate, maxFramerate, priority) {
10734
- this.width = width;
10735
- this.height = height;
10736
- this.encoding = {
10737
- maxBitrate,
10738
- maxFramerate,
10739
- priority
10740
- };
10741
+ constructor(widthOrOptions, height, maxBitrate, maxFramerate, priority) {
10742
+ if (typeof widthOrOptions === 'object') {
10743
+ this.width = widthOrOptions.width;
10744
+ this.height = widthOrOptions.height;
10745
+ this.aspectRatio = widthOrOptions.aspectRatio;
10746
+ this.encoding = {
10747
+ maxBitrate: widthOrOptions.maxBitrate,
10748
+ maxFramerate: widthOrOptions.maxFramerate,
10749
+ priority: widthOrOptions.priority
10750
+ };
10751
+ } else if (height !== undefined && maxBitrate !== undefined) {
10752
+ this.width = widthOrOptions;
10753
+ this.height = height;
10754
+ this.aspectRatio = widthOrOptions / height;
10755
+ this.encoding = {
10756
+ maxBitrate,
10757
+ maxFramerate,
10758
+ priority
10759
+ };
10760
+ } else {
10761
+ throw new TypeError('Unsupported options: provide at least width, height and maxBitrate');
10762
+ }
10741
10763
  }
10742
10764
  get resolution() {
10743
10765
  return {
10744
10766
  width: this.width,
10745
10767
  height: this.height,
10746
10768
  frameRate: this.encoding.maxFramerate,
10747
- aspectRatio: this.width / this.height
10769
+ aspectRatio: this.aspectRatio
10748
10770
  };
10749
10771
  }
10750
10772
  }
@@ -14157,7 +14179,16 @@ class DeviceManager {
14157
14179
  // resolve actual device id if it's 'default': Chrome returns it when no
14158
14180
  // device has been chosen
14159
14181
  const devices = yield this.getDevices(kind);
14160
- const device = devices.find(d => d.groupId === groupId && d.deviceId !== defaultId);
14182
+ // `default` devices will have the same groupId as the entry with the actual device id so we store the counts for each group id
14183
+ const groupIdCounts = new Map(devices.map(d => [d.groupId, 0]));
14184
+ devices.forEach(d => {
14185
+ var _a;
14186
+ return groupIdCounts.set(d.groupId, ((_a = groupIdCounts.get(d.groupId)) !== null && _a !== void 0 ? _a : 0) + 1);
14187
+ });
14188
+ const device = devices.find(d => {
14189
+ var _a;
14190
+ return (groupId === d.groupId || ((_a = groupIdCounts.get(d.groupId)) !== null && _a !== void 0 ? _a : 0) > 1) && d.deviceId !== defaultId;
14191
+ });
14161
14192
  return device === null || device === void 0 ? void 0 : device.deviceId;
14162
14193
  });
14163
14194
  }
@@ -14206,6 +14237,7 @@ class LocalTrack extends Track {
14206
14237
  this.muteLock = new Mutex();
14207
14238
  this.pauseUpstreamLock = new Mutex();
14208
14239
  this.processorLock = new Mutex();
14240
+ this.restartLock = new Mutex();
14209
14241
  this.setMediaStreamTrack(mediaTrack, true);
14210
14242
  // added to satisfy TS compiler, constraints are synced with MediaStreamTrack
14211
14243
  this._constraints = mediaTrack.getConstraints();
@@ -14364,18 +14396,25 @@ class LocalTrack extends Track {
14364
14396
  return this;
14365
14397
  });
14366
14398
  }
14367
- replaceTrack(track) {
14368
- let userProvidedTrack = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
14399
+ replaceTrack(track, userProvidedOrOptions) {
14369
14400
  return __awaiter(this, void 0, void 0, function* () {
14370
14401
  if (!this.sender) {
14371
14402
  throw new TrackInvalidError('unable to replace an unpublished track');
14372
14403
  }
14404
+ let userProvidedTrack;
14405
+ let stopProcessor;
14406
+ if (typeof userProvidedOrOptions === 'boolean') {
14407
+ userProvidedTrack = userProvidedOrOptions;
14408
+ } else if (userProvidedOrOptions !== undefined) {
14409
+ userProvidedTrack = userProvidedOrOptions.userProvidedTrack;
14410
+ stopProcessor = userProvidedOrOptions.stopProcessor;
14411
+ }
14412
+ this.providedByUser = userProvidedTrack !== null && userProvidedTrack !== void 0 ? userProvidedTrack : true;
14373
14413
  this.log.debug('replace MediaStreamTrack', this.logContext);
14374
14414
  yield this.setMediaStreamTrack(track);
14375
14415
  // this must be synced *after* setting mediaStreamTrack above, since it relies
14376
14416
  // on the previous state in order to cleanup
14377
- this.providedByUser = userProvidedTrack;
14378
- if (this.processor) {
14417
+ if (stopProcessor && this.processor) {
14379
14418
  yield this.stopProcessor();
14380
14419
  }
14381
14420
  return this;
@@ -14383,40 +14422,45 @@ class LocalTrack extends Track {
14383
14422
  }
14384
14423
  restart(constraints) {
14385
14424
  return __awaiter(this, void 0, void 0, function* () {
14386
- if (!constraints) {
14387
- constraints = this._constraints;
14388
- }
14389
- this.log.debug('restarting track with constraints', Object.assign(Object.assign({}, this.logContext), {
14390
- constraints
14391
- }));
14392
- const streamConstraints = {
14393
- audio: false,
14394
- video: false
14395
- };
14396
- if (this.kind === Track.Kind.Video) {
14397
- streamConstraints.video = constraints;
14398
- } else {
14399
- streamConstraints.audio = constraints;
14425
+ const unlock = yield this.restartLock.lock();
14426
+ try {
14427
+ if (!constraints) {
14428
+ constraints = this._constraints;
14429
+ }
14430
+ this.log.debug('restarting track with constraints', Object.assign(Object.assign({}, this.logContext), {
14431
+ constraints
14432
+ }));
14433
+ const streamConstraints = {
14434
+ audio: false,
14435
+ video: false
14436
+ };
14437
+ if (this.kind === Track.Kind.Video) {
14438
+ streamConstraints.video = constraints;
14439
+ } else {
14440
+ streamConstraints.audio = constraints;
14441
+ }
14442
+ // these steps are duplicated from setMediaStreamTrack because we must stop
14443
+ // the previous tracks before new tracks can be acquired
14444
+ this.attachedElements.forEach(el => {
14445
+ detachTrack(this.mediaStreamTrack, el);
14446
+ });
14447
+ this._mediaStreamTrack.removeEventListener('ended', this.handleEnded);
14448
+ // on Safari, the old audio track must be stopped before attempting to acquire
14449
+ // the new track, otherwise the new track will stop with
14450
+ // 'A MediaStreamTrack ended due to a capture failure`
14451
+ this._mediaStreamTrack.stop();
14452
+ // create new track and attach
14453
+ const mediaStream = yield navigator.mediaDevices.getUserMedia(streamConstraints);
14454
+ const newTrack = mediaStream.getTracks()[0];
14455
+ newTrack.addEventListener('ended', this.handleEnded);
14456
+ this.log.debug('re-acquired MediaStreamTrack', this.logContext);
14457
+ yield this.setMediaStreamTrack(newTrack);
14458
+ this._constraints = constraints;
14459
+ this.emit(TrackEvent.Restarted, this);
14460
+ return this;
14461
+ } finally {
14462
+ unlock();
14400
14463
  }
14401
- // these steps are duplicated from setMediaStreamTrack because we must stop
14402
- // the previous tracks before new tracks can be acquired
14403
- this.attachedElements.forEach(el => {
14404
- detachTrack(this.mediaStreamTrack, el);
14405
- });
14406
- this._mediaStreamTrack.removeEventListener('ended', this.handleEnded);
14407
- // on Safari, the old audio track must be stopped before attempting to acquire
14408
- // the new track, otherwise the new track will stop with
14409
- // 'A MediaStreamTrack ended due to a capture failure`
14410
- this._mediaStreamTrack.stop();
14411
- // create new track and attach
14412
- const mediaStream = yield navigator.mediaDevices.getUserMedia(streamConstraints);
14413
- const newTrack = mediaStream.getTracks()[0];
14414
- newTrack.addEventListener('ended', this.handleEnded);
14415
- this.log.debug('re-acquired MediaStreamTrack', this.logContext);
14416
- yield this.setMediaStreamTrack(newTrack);
14417
- this._constraints = constraints;
14418
- this.emit(TrackEvent.Restarted, this);
14419
- return this;
14420
14464
  });
14421
14465
  }
14422
14466
  setTrackMuted(muted) {
@@ -14569,6 +14613,7 @@ class LocalTrack extends Track {
14569
14613
  }
14570
14614
  yield (_b = this.sender) === null || _b === void 0 ? void 0 : _b.replaceTrack(this.processor.processedTrack);
14571
14615
  }
14616
+ this.emit(TrackEvent.TrackProcessorUpdate, this.processor);
14572
14617
  } finally {
14573
14618
  unlock();
14574
14619
  }
@@ -14595,6 +14640,7 @@ class LocalTrack extends Track {
14595
14640
  (_b = this.processorElement) === null || _b === void 0 ? void 0 : _b.remove();
14596
14641
  this.processorElement = undefined;
14597
14642
  yield this.restart();
14643
+ this.emit(TrackEvent.TrackProcessorUpdate);
14598
14644
  });
14599
14645
  }
14600
14646
  }
@@ -14670,7 +14716,8 @@ class E2EEManager extends eventsExports.EventEmitter {
14670
14716
  const msg = {
14671
14717
  kind: 'init',
14672
14718
  data: {
14673
- keyProviderOptions: this.keyProvider.getOptions()
14719
+ keyProviderOptions: this.keyProvider.getOptions(),
14720
+ loglevel: workerLogger.getLevel()
14674
14721
  }
14675
14722
  };
14676
14723
  if (this.worker) {
@@ -15108,6 +15155,7 @@ class SignalClient {
15108
15155
  };
15109
15156
  this.ws.onerror = ev => __awaiter(this, void 0, void 0, function* () {
15110
15157
  if (this.state !== SignalConnectionState.CONNECTED) {
15158
+ this.state = SignalConnectionState.DISCONNECTED;
15111
15159
  clearTimeout(wsTimeout);
15112
15160
  try {
15113
15161
  const resp = yield fetch("http".concat(url.substring(2), "/validate").concat(params));
@@ -17517,6 +17565,12 @@ class RTCEngine extends eventsExports.EventEmitter {
17517
17565
  this.handleDisconnect('peerconnection failed', subscriberState === 'failed' ? ReconnectReason.RR_SUBSCRIBER_FAILED : ReconnectReason.RR_PUBLISHER_FAILED);
17518
17566
  }
17519
17567
  }
17568
+ // detect cases where both signal client and peer connection are severed and assume that user has lost network connection
17569
+ const isSignalSevered = this.client.isDisconnected || this.client.currentState === SignalConnectionState.RECONNECTING;
17570
+ const isPCSevered = [PCTransportState.FAILED, PCTransportState.CLOSING, PCTransportState.CLOSED].includes(connectionState);
17571
+ if (isSignalSevered && isPCSevered && !this._isClosed) {
17572
+ this.emit(EngineEvent.Offline);
17573
+ }
17520
17574
  });
17521
17575
  this.pcManager.onTrack = ev => {
17522
17576
  this.emit(EngineEvent.MediaTrackAdded, ev.track, ev.streams[0], ev.receiver);
@@ -18347,6 +18401,10 @@ class LocalAudioTrack extends LocalTrack {
18347
18401
  return __awaiter(this, void 0, void 0, function* () {
18348
18402
  const unlock = yield this.muteLock.lock();
18349
18403
  try {
18404
+ if (this.isMuted) {
18405
+ this.log.debug('Track already muted', this.logContext);
18406
+ return this;
18407
+ }
18350
18408
  // disabled special handling as it will cause BT headsets to switch communication modes
18351
18409
  if (this.source === Track.Source.Microphone && this.stopOnMute && !this.isUserProvided) {
18352
18410
  this.log.debug('stopping mic track', this.logContext);
@@ -18369,6 +18427,10 @@ class LocalAudioTrack extends LocalTrack {
18369
18427
  return __awaiter(this, void 0, void 0, function* () {
18370
18428
  const unlock = yield this.muteLock.lock();
18371
18429
  try {
18430
+ if (!this.isMuted) {
18431
+ this.log.debug('Track already unmuted', this.logContext);
18432
+ return this;
18433
+ }
18372
18434
  const deviceHasChanged = this._constraints.deviceId && this._mediaStreamTrack.getSettings().deviceId !== unwrapConstraint(this._constraints.deviceId);
18373
18435
  if (this.source === Track.Source.Microphone && (this.stopOnMute || this._mediaStreamTrack.readyState === 'ended' || deviceHasChanged) && !this.isUserProvided) {
18374
18436
  this.log.debug('reacquiring mic track', this.logContext);
@@ -18441,6 +18503,7 @@ class LocalAudioTrack extends LocalTrack {
18441
18503
  if (this.processor.processedTrack) {
18442
18504
  yield (_a = this.sender) === null || _a === void 0 ? void 0 : _a.replaceTrack(this.processor.processedTrack);
18443
18505
  }
18506
+ this.emit(TrackEvent.TrackProcessorUpdate, this.processor);
18444
18507
  } finally {
18445
18508
  unlock();
18446
18509
  }
@@ -18937,6 +19000,10 @@ class LocalVideoTrack extends LocalTrack {
18937
19000
  return __awaiter(this, void 0, void 0, function* () {
18938
19001
  const unlock = yield this.muteLock.lock();
18939
19002
  try {
19003
+ if (this.isMuted) {
19004
+ this.log.debug('Track already muted', this.logContext);
19005
+ return this;
19006
+ }
18940
19007
  if (this.source === Track.Source.Camera && !this.isUserProvided) {
18941
19008
  this.log.debug('stopping camera track', this.logContext);
18942
19009
  // also stop the track, so that camera indicator is turned off
@@ -18958,6 +19025,10 @@ class LocalVideoTrack extends LocalTrack {
18958
19025
  return __awaiter(this, void 0, void 0, function* () {
18959
19026
  const unlock = yield this.muteLock.lock();
18960
19027
  try {
19028
+ if (!this.isMuted) {
19029
+ this.log.debug('Track already unmuted', this.logContext);
19030
+ return this;
19031
+ }
18961
19032
  if (this.source === Track.Source.Camera && !this.isUserProvided) {
18962
19033
  this.log.debug('reacquiring camera track', this.logContext);
18963
19034
  yield this.restartTrack();
@@ -20813,6 +20884,9 @@ class LocalParticipant extends Participant {
20813
20884
  publishTrack(track, options) {
20814
20885
  var _a, _b, _c, _d;
20815
20886
  return __awaiter(this, void 0, void 0, function* () {
20887
+ if (track instanceof LocalAudioTrack) {
20888
+ track.setAudioContext(this.audioContext);
20889
+ }
20816
20890
  yield (_a = this.reconnectFuture) === null || _a === void 0 ? void 0 : _a.promise;
20817
20891
  if (track instanceof LocalTrack && this.pendingPublishPromises.has(track)) {
20818
20892
  yield this.pendingPublishPromises.get(track);
@@ -20862,9 +20936,6 @@ class LocalParticipant extends Participant {
20862
20936
  loggerContextCb: () => this.logContext
20863
20937
  });
20864
20938
  }
20865
- if (track instanceof LocalAudioTrack) {
20866
- track.setAudioContext(this.audioContext);
20867
- }
20868
20939
  // is it already published? if so skip
20869
20940
  let existingPublication;
20870
20941
  this.trackPublications.forEach(publication => {
@@ -22041,14 +22112,20 @@ class Room extends eventsExports.EventEmitter {
22041
22112
  const pi = joinResponse.participant;
22042
22113
  this.localParticipant.sid = pi.sid;
22043
22114
  this.localParticipant.identity = pi.identity;
22115
+ if (this.options.e2ee && this.e2eeManager) {
22116
+ try {
22117
+ this.e2eeManager.setSifTrailer(joinResponse.sifTrailer);
22118
+ } catch (e) {
22119
+ this.log.error(e instanceof Error ? e.message : 'Could not set SifTrailer', Object.assign(Object.assign({}, this.logContext), {
22120
+ error: e
22121
+ }));
22122
+ }
22123
+ }
22044
22124
  // populate remote participants, these should not trigger new events
22045
22125
  this.handleParticipantUpdates([pi, ...joinResponse.otherParticipants]);
22046
22126
  if (joinResponse.room) {
22047
22127
  this.handleRoomUpdate(joinResponse.room);
22048
22128
  }
22049
- if (this.options.e2ee && this.e2eeManager) {
22050
- this.e2eeManager.setSifTrailer(joinResponse.sifTrailer);
22051
- }
22052
22129
  };
22053
22130
  this.attemptConnection = (url, token, opts, abortController) => __awaiter(this, void 0, void 0, function* () {
22054
22131
  var _h, _j, _k;
@@ -22158,6 +22235,7 @@ class Room extends eventsExports.EventEmitter {
22158
22235
  });
22159
22236
  };
22160
22237
  this.onPageLeave = () => __awaiter(this, void 0, void 0, function* () {
22238
+ this.log.info('Page leave detected, disconnecting', this.logContext);
22161
22239
  yield this.disconnect();
22162
22240
  });
22163
22241
  /**
@@ -22483,9 +22561,14 @@ class Room extends eventsExports.EventEmitter {
22483
22561
  this.onLocalTrackUnmuted = pub => {
22484
22562
  this.emit(RoomEvent.TrackUnmuted, pub, this.localParticipant);
22485
22563
  };
22564
+ this.onTrackProcessorUpdate = processor => {
22565
+ var _a;
22566
+ (_a = processor === null || processor === void 0 ? void 0 : processor.onPublish) === null || _a === void 0 ? void 0 : _a.call(processor, this);
22567
+ };
22486
22568
  this.onLocalTrackPublished = pub => __awaiter(this, void 0, void 0, function* () {
22487
- var _r, _s, _t, _u;
22488
- (_t = (_s = (_r = pub.track) === null || _r === void 0 ? void 0 : _r.getProcessor()) === null || _s === void 0 ? void 0 : _s.onPublish) === null || _t === void 0 ? void 0 : _t.call(_s, this);
22569
+ var _r, _s, _t, _u, _v;
22570
+ (_r = pub.track) === null || _r === void 0 ? void 0 : _r.on(TrackEvent.TrackProcessorUpdate, this.onTrackProcessorUpdate);
22571
+ (_u = (_t = (_s = pub.track) === null || _s === void 0 ? void 0 : _s.getProcessor()) === null || _t === void 0 ? void 0 : _t.onPublish) === null || _u === void 0 ? void 0 : _u.call(_t, this);
22489
22572
  this.emit(RoomEvent.LocalTrackPublished, pub, this.localParticipant);
22490
22573
  if (pub.track instanceof LocalAudioTrack) {
22491
22574
  const trackIsSilent = yield pub.track.checkForSilence();
@@ -22493,7 +22576,7 @@ class Room extends eventsExports.EventEmitter {
22493
22576
  this.emit(RoomEvent.LocalAudioSilenceDetected, pub);
22494
22577
  }
22495
22578
  }
22496
- const deviceId = yield (_u = pub.track) === null || _u === void 0 ? void 0 : _u.getDeviceId();
22579
+ const deviceId = yield (_v = pub.track) === null || _v === void 0 ? void 0 : _v.getDeviceId();
22497
22580
  const deviceKind = sourceToKind(pub.source);
22498
22581
  if (deviceKind && deviceId && deviceId !== this.localParticipant.activeDeviceMap.get(deviceKind)) {
22499
22582
  this.localParticipant.activeDeviceMap.set(deviceKind, deviceId);
@@ -22501,6 +22584,8 @@ class Room extends eventsExports.EventEmitter {
22501
22584
  }
22502
22585
  });
22503
22586
  this.onLocalTrackUnpublished = pub => {
22587
+ var _a;
22588
+ (_a = pub.track) === null || _a === void 0 ? void 0 : _a.off(TrackEvent.TrackProcessorUpdate, this.onTrackProcessorUpdate);
22504
22589
  this.emit(RoomEvent.LocalTrackUnpublished, pub, this.localParticipant);
22505
22590
  };
22506
22591
  this.onLocalConnectionQualityChanged = quality => {
@@ -22649,7 +22734,11 @@ class Room extends eventsExports.EventEmitter {
22649
22734
  if (this.state === ConnectionState.Reconnecting || this.isResuming) {
22650
22735
  this.sendSyncState();
22651
22736
  }
22652
- }).on(EngineEvent.Restarting, this.handleRestarting).on(EngineEvent.SignalRestarted, this.handleSignalRestarted).on(EngineEvent.DCBufferStatusChanged, (status, kind) => {
22737
+ }).on(EngineEvent.Restarting, this.handleRestarting).on(EngineEvent.SignalRestarted, this.handleSignalRestarted).on(EngineEvent.Offline, () => {
22738
+ if (this.setAndEmitConnectionState(ConnectionState.Reconnecting)) {
22739
+ this.emit(RoomEvent.Reconnecting);
22740
+ }
22741
+ }).on(EngineEvent.DCBufferStatusChanged, (status, kind) => {
22653
22742
  this.emit(RoomEvent.DCBufferStatusChanged, status, kind);
22654
22743
  });
22655
22744
  if (this.localParticipant) {
@@ -22866,8 +22955,8 @@ class Room extends eventsExports.EventEmitter {
22866
22955
  */
22867
22956
  switchActiveDevice(kind, deviceId) {
22868
22957
  let exact = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
22869
- var _a, _b;
22870
- var _c;
22958
+ var _a, _b, _c;
22959
+ var _d;
22871
22960
  return __awaiter(this, void 0, void 0, function* () {
22872
22961
  let deviceHasChanged = false;
22873
22962
  let success = true;
@@ -22906,14 +22995,18 @@ class Room extends eventsExports.EventEmitter {
22906
22995
  if (!supportsSetSinkId() && !this.options.webAudioMix || this.options.webAudioMix && this.audioContext && !('setSinkId' in this.audioContext)) {
22907
22996
  throw new Error('cannot switch audio output, setSinkId not supported');
22908
22997
  }
22909
- (_a = (_c = this.options).audioOutput) !== null && _a !== void 0 ? _a : _c.audioOutput = {};
22998
+ if (this.options.webAudioMix) {
22999
+ // setting `default` for web audio output doesn't work, so we need to normalize the id before
23000
+ deviceId = (_a = yield DeviceManager.getInstance().normalizeDeviceId('audiooutput', deviceId)) !== null && _a !== void 0 ? _a : '';
23001
+ }
23002
+ (_b = (_d = this.options).audioOutput) !== null && _b !== void 0 ? _b : _d.audioOutput = {};
22910
23003
  const prevDeviceId = this.options.audioOutput.deviceId;
22911
23004
  this.options.audioOutput.deviceId = deviceId;
22912
23005
  deviceHasChanged = prevDeviceId !== deviceConstraint;
22913
23006
  try {
22914
23007
  if (this.options.webAudioMix) {
22915
23008
  // @ts-expect-error setSinkId is not yet in the typescript type of AudioContext
22916
- (_b = this.audioContext) === null || _b === void 0 ? void 0 : _b.setSinkId(deviceId);
23009
+ (_c = this.audioContext) === null || _c === void 0 ? void 0 : _c.setSinkId(deviceId);
22917
23010
  } else {
22918
23011
  yield Promise.all(Array.from(this.remoteParticipants.values()).map(p => p.setAudioOutput({
22919
23012
  deviceId
@@ -24036,5 +24129,5 @@ function isFacingModeValue(item) {
24036
24129
  return item === undefined || allowedValues.includes(item);
24037
24130
  }
24038
24131
 
24039
- export { AudioPresets, BaseKeyProvider, ConnectionCheck, ConnectionError, ConnectionQuality, ConnectionState, CriticalTimers, CryptorEvent, DataPacket_Kind, DefaultReconnectPolicy, DeviceUnsupportedError, DisconnectReason, EncryptionEvent, EngineEvent, ExternalE2EEKeyProvider, KeyHandlerEvent, KeyProviderEvent, LivekitError, LocalAudioTrack, LocalParticipant, LocalTrack, LocalTrackPublication, LocalVideoTrack, LogLevel, MediaDeviceFailure, NegotiationError, Participant, ParticipantEvent, PublishDataError, RemoteAudioTrack, RemoteParticipant, RemoteTrack, RemoteTrackPublication, RemoteVideoTrack, Room, RoomEvent, ScreenSharePresets, Track, TrackEvent, TrackInvalidError, TrackPublication, UnexpectedConnectionState, UnsupportedServer, VideoPreset, VideoPresets, VideoPresets43, VideoQuality, attachToElement, createAudioAnalyser, createE2EEKey, createKeyMaterialFromBuffer, createKeyMaterialFromString, createLocalAudioTrack, createLocalScreenTracks, createLocalTracks, createLocalVideoTrack, deriveKeys, detachTrack, facingModeFromDeviceLabel, facingModeFromLocalTrack, getEmptyAudioStreamTrack, getEmptyVideoStreamTrack, getLogger, importKey, isBackupCodec, isBrowserSupported, isE2EESupported, isInsertableStreamSupported, isScriptTransformSupported, isVideoFrame, needsRbspUnescaping, parseRbsp, protocolVersion, ratchet, setLogExtension, setLogLevel, supportsAV1, supportsAdaptiveStream, supportsDynacast, supportsVP9, version, videoCodecs, writeRbsp };
24132
+ export { AudioPresets, BaseKeyProvider, ConnectionCheck, ConnectionError, ConnectionQuality, ConnectionState, CriticalTimers, CryptorEvent, DataPacket_Kind, DefaultReconnectPolicy, DeviceUnsupportedError, DisconnectReason, EncryptionEvent, EngineEvent, ExternalE2EEKeyProvider, KeyHandlerEvent, KeyProviderEvent, LivekitError, LocalAudioTrack, LocalParticipant, LocalTrack, LocalTrackPublication, LocalVideoTrack, LogLevel, LoggerNames, MediaDeviceFailure, NegotiationError, Participant, ParticipantEvent, PublishDataError, RemoteAudioTrack, RemoteParticipant, RemoteTrack, RemoteTrackPublication, RemoteVideoTrack, Room, RoomEvent, ScreenSharePresets, Track, TrackEvent, TrackInvalidError, TrackPublication, UnexpectedConnectionState, UnsupportedServer, VideoPreset, VideoPresets, VideoPresets43, VideoQuality, attachToElement, createAudioAnalyser, createE2EEKey, createKeyMaterialFromBuffer, createKeyMaterialFromString, createLocalAudioTrack, createLocalScreenTracks, createLocalTracks, createLocalVideoTrack, deriveKeys, detachTrack, facingModeFromDeviceLabel, facingModeFromLocalTrack, getEmptyAudioStreamTrack, getEmptyVideoStreamTrack, getLogger, importKey, isBackupCodec, isBrowserSupported, isE2EESupported, isInsertableStreamSupported, isScriptTransformSupported, isVideoFrame, needsRbspUnescaping, parseRbsp, protocolVersion, ratchet, setLogExtension, setLogLevel, supportsAV1, supportsAdaptiveStream, supportsDynacast, supportsVP9, version, videoCodecs, writeRbsp };
24040
24133
  //# sourceMappingURL=livekit-client.esm.mjs.map