livekit-client 2.0.3 → 2.0.5

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 +11 -8
  4. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  5. package/dist/livekit-client.esm.mjs +166 -77
  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 +1 -1
  10. package/dist/src/api/SignalClient.d.ts.map +1 -1
  11. package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
  12. package/dist/src/e2ee/types.d.ts +2 -0
  13. package/dist/src/e2ee/types.d.ts.map +1 -1
  14. package/dist/src/e2ee/worker/FrameCryptor.d.ts +1 -0
  15. package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
  16. package/dist/src/index.d.ts +2 -2
  17. package/dist/src/index.d.ts.map +1 -1
  18. package/dist/src/logger.d.ts +4 -2
  19. package/dist/src/logger.d.ts.map +1 -1
  20. package/dist/src/room/DeviceManager.d.ts.map +1 -1
  21. package/dist/src/room/RTCEngine.d.ts +4 -2
  22. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  23. package/dist/src/room/Room.d.ts.map +1 -1
  24. package/dist/src/room/events.d.ts +2 -1
  25. package/dist/src/room/events.d.ts.map +1 -1
  26. package/dist/src/room/participant/Participant.d.ts +1 -2
  27. package/dist/src/room/participant/Participant.d.ts.map +1 -1
  28. package/dist/src/room/participant/RemoteParticipant.d.ts +4 -0
  29. package/dist/src/room/participant/RemoteParticipant.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 +3 -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/options.d.ts +10 -0
  35. package/dist/src/room/track/options.d.ts.map +1 -1
  36. package/dist/src/room/track/types.d.ts +4 -0
  37. package/dist/src/room/track/types.d.ts.map +1 -1
  38. package/dist/src/room/track/utils.d.ts.map +1 -1
  39. package/dist/src/room/utils.d.ts.map +1 -1
  40. package/dist/ts4.2/src/api/SignalClient.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/index.d.ts +2 -2
  44. package/dist/ts4.2/src/logger.d.ts +4 -2
  45. package/dist/ts4.2/src/room/RTCEngine.d.ts +4 -2
  46. package/dist/ts4.2/src/room/events.d.ts +2 -1
  47. package/dist/ts4.2/src/room/participant/Participant.d.ts +1 -2
  48. package/dist/ts4.2/src/room/participant/RemoteParticipant.d.ts +4 -0
  49. package/dist/ts4.2/src/room/track/LocalTrack.d.ts +3 -1
  50. package/dist/ts4.2/src/room/track/options.d.ts +10 -0
  51. package/dist/ts4.2/src/room/track/types.d.ts +4 -0
  52. package/package.json +1 -1
  53. package/src/api/SignalClient.ts +10 -5
  54. package/src/e2ee/E2eeManager.ts +2 -1
  55. package/src/e2ee/types.ts +2 -0
  56. package/src/e2ee/worker/FrameCryptor.ts +12 -6
  57. package/src/e2ee/worker/e2ee.worker.ts +1 -0
  58. package/src/index.ts +2 -1
  59. package/src/logger.ts +23 -18
  60. package/src/room/DeviceManager.ts +10 -1
  61. package/src/room/RTCEngine.ts +26 -8
  62. package/src/room/Room.ts +26 -2
  63. package/src/room/events.ts +1 -0
  64. package/src/room/participant/LocalParticipant.ts +4 -4
  65. package/src/room/participant/Participant.ts +0 -2
  66. package/src/room/participant/RemoteParticipant.ts +8 -0
  67. package/src/room/track/LocalAudioTrack.ts +10 -0
  68. package/src/room/track/LocalTrack.ts +20 -3
  69. package/src/room/track/LocalVideoTrack.ts +15 -1
  70. package/src/room/track/options.ts +41 -8
  71. package/src/room/track/types.ts +5 -0
  72. package/src/room/track/utils.ts +18 -11
  73. package/src/room/utils.ts +3 -0
@@ -309,6 +309,7 @@ var LoggerNames;
309
309
  LoggerNames["E2EE"] = "lk-e2ee";
310
310
  })(LoggerNames || (LoggerNames = {}));
311
311
  let livekitLogger = loglevelExports.getLogger('livekit');
312
+ const livekitLoggers = Object.values(LoggerNames).map(name => loglevelExports.getLogger(name));
312
313
  livekitLogger.setDefaultLevel(LogLevel.info);
313
314
  /**
314
315
  * @internal
@@ -322,13 +323,7 @@ function setLogLevel(level, loggerName) {
322
323
  if (loggerName) {
323
324
  loglevelExports.getLogger(loggerName).setLevel(level);
324
325
  }
325
- for (const logger of Object.entries(loglevelExports.getLoggers()).filter(_ref => {
326
- let [logrName] = _ref;
327
- return logrName.startsWith('livekit');
328
- }).map(_ref2 => {
329
- let [, logr] = _ref2;
330
- return logr;
331
- })) {
326
+ for (const logger of livekitLoggers) {
332
327
  logger.setLevel(level);
333
328
  }
334
329
  }
@@ -336,23 +331,25 @@ function setLogLevel(level, loggerName) {
336
331
  * use this to hook into the logging function to allow sending internal livekit logs to third party services
337
332
  * if set, the browser logs will lose their stacktrace information (see https://github.com/pimterry/loglevel#writing-plugins)
338
333
  */
339
- function setLogExtension(extension) {
340
- let logger = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : livekitLogger;
341
- const originalFactory = logger.methodFactory;
342
- logger.methodFactory = (methodName, configLevel, loggerName) => {
343
- const rawMethod = originalFactory(methodName, configLevel, loggerName);
344
- const logLevel = LogLevel[methodName];
345
- const needLog = logLevel >= configLevel && logLevel < LogLevel.silent;
346
- return (msg, context) => {
347
- if (context) rawMethod(msg, context);else rawMethod(msg);
348
- if (needLog) {
349
- extension(logLevel, msg, context);
350
- }
334
+ function setLogExtension(extension, logger) {
335
+ const loggers = logger ? [logger] : livekitLoggers;
336
+ loggers.forEach(logR => {
337
+ const originalFactory = logR.methodFactory;
338
+ logR.methodFactory = (methodName, configLevel, loggerName) => {
339
+ const rawMethod = originalFactory(methodName, configLevel, loggerName);
340
+ const logLevel = LogLevel[methodName];
341
+ const needLog = logLevel >= configLevel && logLevel < LogLevel.silent;
342
+ return (msg, context) => {
343
+ if (context) rawMethod(msg, context);else rawMethod(msg);
344
+ if (needLog) {
345
+ extension(logLevel, msg, context);
346
+ }
347
+ };
351
348
  };
352
- };
353
- logger.setLevel(logger.getLevel()); // Be sure to call setLevel method in order to apply plugin
349
+ logR.setLevel(logR.getLevel());
350
+ });
354
351
  }
355
- loglevelExports.getLogger('lk-e2ee');
352
+ const workerLogger = loglevelExports.getLogger('lk-e2ee');
356
353
 
357
354
  // Copyright 2021-2023 Buf Technologies, Inc.
358
355
  //
@@ -10537,6 +10534,7 @@ var EngineEvent;
10537
10534
  EngineEvent["RemoteMute"] = "remoteMute";
10538
10535
  EngineEvent["SubscribedQualityUpdate"] = "subscribedQualityUpdate";
10539
10536
  EngineEvent["LocalTrackUnpublished"] = "localTrackUnpublished";
10537
+ EngineEvent["Offline"] = "offline";
10540
10538
  })(EngineEvent || (EngineEvent = {}));
10541
10539
  var TrackEvent;
10542
10540
  (function (TrackEvent) {
@@ -10710,7 +10708,7 @@ function getMatch(exp, ua) {
10710
10708
  return match && match.length >= id && match[id] || '';
10711
10709
  }
10712
10710
 
10713
- var version$1 = "2.0.3";
10711
+ var version$1 = "2.0.5";
10714
10712
 
10715
10713
  const version = version$1;
10716
10714
  const protocolVersion = 12;
@@ -10737,21 +10735,35 @@ CriticalTimers.clearInterval = function () {
10737
10735
  };
10738
10736
 
10739
10737
  class VideoPreset {
10740
- constructor(width, height, maxBitrate, maxFramerate, priority) {
10741
- this.width = width;
10742
- this.height = height;
10743
- this.encoding = {
10744
- maxBitrate,
10745
- maxFramerate,
10746
- priority
10747
- };
10738
+ constructor(widthOrOptions, height, maxBitrate, maxFramerate, priority) {
10739
+ if (typeof widthOrOptions === 'object') {
10740
+ this.width = widthOrOptions.width;
10741
+ this.height = widthOrOptions.height;
10742
+ this.aspectRatio = widthOrOptions.aspectRatio;
10743
+ this.encoding = {
10744
+ maxBitrate: widthOrOptions.maxBitrate,
10745
+ maxFramerate: widthOrOptions.maxFramerate,
10746
+ priority: widthOrOptions.priority
10747
+ };
10748
+ } else if (height !== undefined && maxBitrate !== undefined) {
10749
+ this.width = widthOrOptions;
10750
+ this.height = height;
10751
+ this.aspectRatio = widthOrOptions / height;
10752
+ this.encoding = {
10753
+ maxBitrate,
10754
+ maxFramerate,
10755
+ priority
10756
+ };
10757
+ } else {
10758
+ throw new TypeError('Unsupported options: provide at least width, height and maxBitrate');
10759
+ }
10748
10760
  }
10749
10761
  get resolution() {
10750
10762
  return {
10751
10763
  width: this.width,
10752
10764
  height: this.height,
10753
10765
  frameRate: this.encoding.maxFramerate,
10754
- aspectRatio: this.width / this.height
10766
+ aspectRatio: this.aspectRatio
10755
10767
  };
10756
10768
  }
10757
10769
  }
@@ -13685,20 +13697,26 @@ function getTrackPublicationInfo(tracks) {
13685
13697
  function getLogContextFromTrack(track) {
13686
13698
  if (track instanceof Track) {
13687
13699
  return {
13688
- trackSid: track.sid,
13689
- trackSource: track.source,
13690
- trackMuted: track.isMuted,
13691
- trackEnabled: track.mediaStreamTrack.enabled,
13692
- trackKind: track.kind
13700
+ trackID: track.sid,
13701
+ source: track.source,
13702
+ muted: track.isMuted,
13703
+ enabled: track.mediaStreamTrack.enabled,
13704
+ kind: track.kind,
13705
+ streamID: track.mediaStreamID,
13706
+ streamTrackID: track.mediaStreamTrack.id
13693
13707
  };
13694
13708
  } else {
13695
13709
  return {
13696
- trackSid: track.trackSid,
13697
- trackName: track.trackName,
13698
- track: track.track ? getLogContextFromTrack(track.track) : undefined,
13699
- trackEnabled: track.isEnabled,
13700
- trackEncrypted: track.isEncrypted,
13701
- trackMimeType: track.mimeType
13710
+ trackID: track.trackSid,
13711
+ enabled: track.isEnabled,
13712
+ muted: track.isMuted,
13713
+ trackInfo: Object.assign({
13714
+ mimeType: track.mimeType,
13715
+ name: track.trackName,
13716
+ encrypted: track.isEncrypted,
13717
+ kind: track.kind,
13718
+ source: track.source
13719
+ }, track.track ? getLogContextFromTrack(track.track) : {})
13702
13720
  };
13703
13721
  }
13704
13722
  }
@@ -13815,6 +13833,9 @@ function supportsSetCodecPreferences(transceiver) {
13815
13833
  return false;
13816
13834
  }
13817
13835
  function isBrowserSupported() {
13836
+ if (typeof RTCPeerConnection === 'undefined') {
13837
+ return false;
13838
+ }
13818
13839
  return supportsTransceiver() || supportsAddTrack();
13819
13840
  }
13820
13841
  function isFireFox() {
@@ -14164,7 +14185,16 @@ class DeviceManager {
14164
14185
  // resolve actual device id if it's 'default': Chrome returns it when no
14165
14186
  // device has been chosen
14166
14187
  const devices = yield this.getDevices(kind);
14167
- const device = devices.find(d => d.groupId === groupId && d.deviceId !== defaultId);
14188
+ // `default` devices will have the same groupId as the entry with the actual device id so we store the counts for each group id
14189
+ const groupIdCounts = new Map(devices.map(d => [d.groupId, 0]));
14190
+ devices.forEach(d => {
14191
+ var _a;
14192
+ return groupIdCounts.set(d.groupId, ((_a = groupIdCounts.get(d.groupId)) !== null && _a !== void 0 ? _a : 0) + 1);
14193
+ });
14194
+ const device = devices.find(d => {
14195
+ var _a;
14196
+ return (groupId === d.groupId || ((_a = groupIdCounts.get(d.groupId)) !== null && _a !== void 0 ? _a : 0) > 1) && d.deviceId !== defaultId;
14197
+ });
14168
14198
  return device === null || device === void 0 ? void 0 : device.deviceId;
14169
14199
  });
14170
14200
  }
@@ -14372,18 +14402,25 @@ class LocalTrack extends Track {
14372
14402
  return this;
14373
14403
  });
14374
14404
  }
14375
- replaceTrack(track) {
14376
- let userProvidedTrack = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
14405
+ replaceTrack(track, userProvidedOrOptions) {
14377
14406
  return __awaiter(this, void 0, void 0, function* () {
14378
14407
  if (!this.sender) {
14379
14408
  throw new TrackInvalidError('unable to replace an unpublished track');
14380
14409
  }
14410
+ let userProvidedTrack;
14411
+ let stopProcessor;
14412
+ if (typeof userProvidedOrOptions === 'boolean') {
14413
+ userProvidedTrack = userProvidedOrOptions;
14414
+ } else if (userProvidedOrOptions !== undefined) {
14415
+ userProvidedTrack = userProvidedOrOptions.userProvidedTrack;
14416
+ stopProcessor = userProvidedOrOptions.stopProcessor;
14417
+ }
14418
+ this.providedByUser = userProvidedTrack !== null && userProvidedTrack !== void 0 ? userProvidedTrack : true;
14381
14419
  this.log.debug('replace MediaStreamTrack', this.logContext);
14382
14420
  yield this.setMediaStreamTrack(track);
14383
14421
  // this must be synced *after* setting mediaStreamTrack above, since it relies
14384
14422
  // on the previous state in order to cleanup
14385
- this.providedByUser = userProvidedTrack;
14386
- if (this.processor) {
14423
+ if (stopProcessor && this.processor) {
14387
14424
  yield this.stopProcessor();
14388
14425
  }
14389
14426
  return this;
@@ -14685,7 +14722,8 @@ class E2EEManager extends eventsExports.EventEmitter {
14685
14722
  const msg = {
14686
14723
  kind: 'init',
14687
14724
  data: {
14688
- keyProviderOptions: this.keyProvider.getOptions()
14725
+ keyProviderOptions: this.keyProvider.getOptions(),
14726
+ loglevel: workerLogger.getLevel()
14689
14727
  }
14690
14728
  };
14691
14729
  if (this.worker) {
@@ -15123,6 +15161,7 @@ class SignalClient {
15123
15161
  };
15124
15162
  this.ws.onerror = ev => __awaiter(this, void 0, void 0, function* () {
15125
15163
  if (this.state !== SignalConnectionState.CONNECTED) {
15164
+ this.state = SignalConnectionState.DISCONNECTED;
15126
15165
  clearTimeout(wsTimeout);
15127
15166
  try {
15128
15167
  const resp = yield fetch("http".concat(url.substring(2), "/validate").concat(params));
@@ -15141,7 +15180,7 @@ class SignalClient {
15141
15180
  this.handleWSError(ev);
15142
15181
  });
15143
15182
  this.ws.onmessage = ev => __awaiter(this, void 0, void 0, function* () {
15144
- var _a, _b, _c, _d;
15183
+ var _a, _b, _c;
15145
15184
  // not considered connected until JoinResponse is received
15146
15185
  let resp;
15147
15186
  if (typeof ev.data === 'string') {
@@ -15177,16 +15216,17 @@ class SignalClient {
15177
15216
  abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.removeEventListener('abort', abortHandler);
15178
15217
  this.startPingInterval();
15179
15218
  if (((_b = resp.message) === null || _b === void 0 ? void 0 : _b.case) === 'reconnect') {
15180
- resolve((_c = resp.message) === null || _c === void 0 ? void 0 : _c.value);
15219
+ resolve(resp.message.value);
15181
15220
  } else {
15182
- resolve();
15221
+ this.log.debug('declaring signal reconnected without reconnect response received', this.logContext);
15222
+ resolve(undefined);
15183
15223
  shouldProcessMessage = true;
15184
15224
  }
15185
15225
  } else if (this.isEstablishingConnection && resp.message.case === 'leave') {
15186
15226
  reject(new ConnectionError('Received leave request while trying to (re)connect', 4 /* ConnectionErrorReason.LeaveRequest */));
15187
15227
  } else if (!opts.reconnect) {
15188
15228
  // non-reconnect case, should receive join response first
15189
- reject(new ConnectionError("did not receive join response, got ".concat((_d = resp.message) === null || _d === void 0 ? void 0 : _d.case, " instead")));
15229
+ reject(new ConnectionError("did not receive join response, got ".concat((_c = resp.message) === null || _c === void 0 ? void 0 : _c.case, " instead")));
15190
15230
  }
15191
15231
  if (!shouldProcessMessage) {
15192
15232
  return;
@@ -17341,11 +17381,12 @@ class RTCEngine extends eventsExports.EventEmitter {
17341
17381
  }
17342
17382
  /** @internal */
17343
17383
  get logContext() {
17344
- var _a, _b, _c, _d, _e, _f;
17384
+ var _a, _b, _c, _d, _e, _f, _g, _h;
17345
17385
  return {
17346
17386
  room: (_b = (_a = this.latestJoinResponse) === null || _a === void 0 ? void 0 : _a.room) === null || _b === void 0 ? void 0 : _b.name,
17347
- roomSid: (_d = (_c = this.latestJoinResponse) === null || _c === void 0 ? void 0 : _c.room) === null || _d === void 0 ? void 0 : _d.sid,
17348
- identity: (_f = (_e = this.latestJoinResponse) === null || _e === void 0 ? void 0 : _e.participant) === null || _f === void 0 ? void 0 : _f.identity
17387
+ roomID: (_d = (_c = this.latestJoinResponse) === null || _c === void 0 ? void 0 : _c.room) === null || _d === void 0 ? void 0 : _d.sid,
17388
+ participant: (_f = (_e = this.latestJoinResponse) === null || _e === void 0 ? void 0 : _e.participant) === null || _f === void 0 ? void 0 : _f.identity,
17389
+ pID: (_h = (_g = this.latestJoinResponse) === null || _g === void 0 ? void 0 : _g.participant) === null || _h === void 0 ? void 0 : _h.sid
17349
17390
  };
17350
17391
  }
17351
17392
  join(url, token, opts, abortSignal) {
@@ -17532,6 +17573,12 @@ class RTCEngine extends eventsExports.EventEmitter {
17532
17573
  this.handleDisconnect('peerconnection failed', subscriberState === 'failed' ? ReconnectReason.RR_SUBSCRIBER_FAILED : ReconnectReason.RR_PUBLISHER_FAILED);
17533
17574
  }
17534
17575
  }
17576
+ // detect cases where both signal client and peer connection are severed and assume that user has lost network connection
17577
+ const isSignalSevered = this.client.isDisconnected || this.client.currentState === SignalConnectionState.RECONNECTING;
17578
+ const isPCSevered = [PCTransportState.FAILED, PCTransportState.CLOSING, PCTransportState.CLOSED].includes(connectionState);
17579
+ if (isSignalSevered && isPCSevered && !this._isClosed) {
17580
+ this.emit(EngineEvent.Offline);
17581
+ }
17535
17582
  });
17536
17583
  this.pcManager.onTrack = ev => {
17537
17584
  this.emit(EngineEvent.MediaTrackAdded, ev.track, ev.streams[0], ev.receiver);
@@ -17935,13 +17982,10 @@ class RTCEngine extends eventsExports.EventEmitter {
17935
17982
  }
17936
17983
  this.log.info("resuming signal connection, attempt ".concat(this.reconnectAttempts), this.logContext);
17937
17984
  this.emit(EngineEvent.Resuming);
17985
+ let res;
17938
17986
  try {
17939
17987
  this.setupSignalClientCallbacks();
17940
- const res = yield this.client.reconnect(this.url, this.token, this.participantSid, reason);
17941
- if (res) {
17942
- const rtcConfig = this.makeRTCConfiguration(res);
17943
- this.pcManager.updateConfiguration(rtcConfig);
17944
- }
17988
+ res = yield this.client.reconnect(this.url, this.token, this.participantSid, reason);
17945
17989
  } catch (error) {
17946
17990
  let message = '';
17947
17991
  if (error instanceof Error) {
@@ -17959,6 +18003,12 @@ class RTCEngine extends eventsExports.EventEmitter {
17959
18003
  throw new SignalReconnectError(message);
17960
18004
  }
17961
18005
  this.emit(EngineEvent.SignalResumed);
18006
+ if (res) {
18007
+ const rtcConfig = this.makeRTCConfiguration(res);
18008
+ this.pcManager.updateConfiguration(rtcConfig);
18009
+ } else {
18010
+ this.log.warn('Did not receive reconnect response', this.logContext);
18011
+ }
17962
18012
  if (this.shouldFailNext) {
17963
18013
  this.shouldFailNext = false;
17964
18014
  throw new Error('simulated failure');
@@ -18362,6 +18412,10 @@ class LocalAudioTrack extends LocalTrack {
18362
18412
  return __awaiter(this, void 0, void 0, function* () {
18363
18413
  const unlock = yield this.muteLock.lock();
18364
18414
  try {
18415
+ if (this.isMuted) {
18416
+ this.log.debug('Track already muted', this.logContext);
18417
+ return this;
18418
+ }
18365
18419
  // disabled special handling as it will cause BT headsets to switch communication modes
18366
18420
  if (this.source === Track.Source.Microphone && this.stopOnMute && !this.isUserProvided) {
18367
18421
  this.log.debug('stopping mic track', this.logContext);
@@ -18384,6 +18438,10 @@ class LocalAudioTrack extends LocalTrack {
18384
18438
  return __awaiter(this, void 0, void 0, function* () {
18385
18439
  const unlock = yield this.muteLock.lock();
18386
18440
  try {
18441
+ if (!this.isMuted) {
18442
+ this.log.debug('Track already unmuted', this.logContext);
18443
+ return this;
18444
+ }
18387
18445
  const deviceHasChanged = this._constraints.deviceId && this._mediaStreamTrack.getSettings().deviceId !== unwrapConstraint(this._constraints.deviceId);
18388
18446
  if (this.source === Track.Source.Microphone && (this.stopOnMute || this._mediaStreamTrack.readyState === 'ended' || deviceHasChanged) && !this.isUserProvided) {
18389
18447
  this.log.debug('reacquiring mic track', this.logContext);
@@ -18953,6 +19011,10 @@ class LocalVideoTrack extends LocalTrack {
18953
19011
  return __awaiter(this, void 0, void 0, function* () {
18954
19012
  const unlock = yield this.muteLock.lock();
18955
19013
  try {
19014
+ if (this.isMuted) {
19015
+ this.log.debug('Track already muted', this.logContext);
19016
+ return this;
19017
+ }
18956
19018
  if (this.source === Track.Source.Camera && !this.isUserProvided) {
18957
19019
  this.log.debug('stopping camera track', this.logContext);
18958
19020
  // also stop the track, so that camera indicator is turned off
@@ -18974,6 +19036,10 @@ class LocalVideoTrack extends LocalTrack {
18974
19036
  return __awaiter(this, void 0, void 0, function* () {
18975
19037
  const unlock = yield this.muteLock.lock();
18976
19038
  try {
19039
+ if (!this.isMuted) {
19040
+ this.log.debug('Track already unmuted', this.logContext);
19041
+ return this;
19042
+ }
18977
19043
  if (this.source === Track.Source.Camera && !this.isUserProvided) {
18978
19044
  this.log.debug('reacquiring camera track', this.logContext);
18979
19045
  yield this.restartTrack();
@@ -19260,7 +19326,10 @@ function setPublishingLayersForSender(sender, senderEncodings, qualities, sender
19260
19326
  return;
19261
19327
  }
19262
19328
  if (encodings.length !== senderEncodings.length) {
19263
- log.warn('cannot set publishing layers, encodings mismatch');
19329
+ log.warn('cannot set publishing layers, encodings mismatch', Object.assign(Object.assign({}, logContext), {
19330
+ encodings,
19331
+ senderEncodings
19332
+ }));
19264
19333
  return;
19265
19334
  }
19266
19335
  let hasChanged = false;
@@ -20152,10 +20221,7 @@ function qualityFromProto(q) {
20152
20221
  class Participant extends eventsExports.EventEmitter {
20153
20222
  get logContext() {
20154
20223
  var _a, _b;
20155
- return Object.assign(Object.assign({}, (_b = (_a = this.loggerOptions) === null || _a === void 0 ? void 0 : _a.loggerContextCb) === null || _b === void 0 ? void 0 : _b.call(_a)), {
20156
- participantSid: this.sid,
20157
- participantId: this.identity
20158
- });
20224
+ return Object.assign({}, (_b = (_a = this.loggerOptions) === null || _a === void 0 ? void 0 : _a.loggerContextCb) === null || _b === void 0 ? void 0 : _b.call(_a));
20159
20225
  }
20160
20226
  get isEncrypted() {
20161
20227
  return this.trackPublications.size > 0 && Array.from(this.trackPublications.values()).every(tr => tr.isEncrypted);
@@ -20829,6 +20895,9 @@ class LocalParticipant extends Participant {
20829
20895
  publishTrack(track, options) {
20830
20896
  var _a, _b, _c, _d;
20831
20897
  return __awaiter(this, void 0, void 0, function* () {
20898
+ if (track instanceof LocalAudioTrack) {
20899
+ track.setAudioContext(this.audioContext);
20900
+ }
20832
20901
  yield (_a = this.reconnectFuture) === null || _a === void 0 ? void 0 : _a.promise;
20833
20902
  if (track instanceof LocalTrack && this.pendingPublishPromises.has(track)) {
20834
20903
  yield this.pendingPublishPromises.get(track);
@@ -20878,9 +20947,6 @@ class LocalParticipant extends Participant {
20878
20947
  loggerContextCb: () => this.logContext
20879
20948
  });
20880
20949
  }
20881
- if (track instanceof LocalAudioTrack) {
20882
- track.setAudioContext(this.audioContext);
20883
- }
20884
20950
  // is it already published? if so skip
20885
20951
  let existingPublication;
20886
20952
  this.trackPublications.forEach(publication => {
@@ -21645,6 +21711,12 @@ class RemoteParticipant extends Participant {
21645
21711
  static fromParticipantInfo(signalClient, pi) {
21646
21712
  return new RemoteParticipant(signalClient, pi.sid, pi.identity, pi.name, pi.metadata);
21647
21713
  }
21714
+ get logContext() {
21715
+ return Object.assign(Object.assign({}, super.logContext), {
21716
+ rpID: this.sid,
21717
+ remoteParticipant: this.identity
21718
+ });
21719
+ }
21648
21720
  /** @internal */
21649
21721
  constructor(signalClient, sid, identity, name, metadata, loggerOptions) {
21650
21722
  super(sid, identity || '', name, metadata, loggerOptions);
@@ -21939,6 +22011,13 @@ class Room extends eventsExports.EventEmitter {
21939
22011
  this.isResuming = false;
21940
22012
  this.connect = (url, token, opts) => __awaiter(this, void 0, void 0, function* () {
21941
22013
  var _c;
22014
+ if (!isBrowserSupported()) {
22015
+ if (isReactNative()) {
22016
+ throw Error("WebRTC isn't detected, have you called registerGlobals?");
22017
+ } else {
22018
+ throw Error("LiveKit doesn't seem to be supported on this browser. Try to update your browser and make sure no browser extensions are disabling webRTC.");
22019
+ }
22020
+ }
21942
22021
  // In case a disconnect called happened right before the connect call, make sure the disconnect is completed first by awaiting its lock
21943
22022
  const unlockDisconnect = yield this.disconnectLock.lock();
21944
22023
  if (this.state === ConnectionState.Connected) {
@@ -22180,6 +22259,7 @@ class Room extends eventsExports.EventEmitter {
22180
22259
  });
22181
22260
  };
22182
22261
  this.onPageLeave = () => __awaiter(this, void 0, void 0, function* () {
22262
+ this.log.info('Page leave detected, disconnecting', this.logContext);
22183
22263
  yield this.disconnect();
22184
22264
  });
22185
22265
  /**
@@ -22598,8 +22678,9 @@ class Room extends eventsExports.EventEmitter {
22598
22678
  var _a;
22599
22679
  return {
22600
22680
  room: this.name,
22601
- roomSid: (_a = this.roomInfo) === null || _a === void 0 ? void 0 : _a.sid,
22602
- identity: this.localParticipant.identity
22681
+ roomID: (_a = this.roomInfo) === null || _a === void 0 ? void 0 : _a.sid,
22682
+ participant: this.localParticipant.identity,
22683
+ pID: this.localParticipant.sid
22603
22684
  };
22604
22685
  }
22605
22686
  /**
@@ -22678,7 +22759,11 @@ class Room extends eventsExports.EventEmitter {
22678
22759
  if (this.state === ConnectionState.Reconnecting || this.isResuming) {
22679
22760
  this.sendSyncState();
22680
22761
  }
22681
- }).on(EngineEvent.Restarting, this.handleRestarting).on(EngineEvent.SignalRestarted, this.handleSignalRestarted).on(EngineEvent.DCBufferStatusChanged, (status, kind) => {
22762
+ }).on(EngineEvent.Restarting, this.handleRestarting).on(EngineEvent.SignalRestarted, this.handleSignalRestarted).on(EngineEvent.Offline, () => {
22763
+ if (this.setAndEmitConnectionState(ConnectionState.Reconnecting)) {
22764
+ this.emit(RoomEvent.Reconnecting);
22765
+ }
22766
+ }).on(EngineEvent.DCBufferStatusChanged, (status, kind) => {
22682
22767
  this.emit(RoomEvent.DCBufferStatusChanged, status, kind);
22683
22768
  });
22684
22769
  if (this.localParticipant) {
@@ -22895,8 +22980,8 @@ class Room extends eventsExports.EventEmitter {
22895
22980
  */
22896
22981
  switchActiveDevice(kind, deviceId) {
22897
22982
  let exact = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
22898
- var _a, _b;
22899
- var _c;
22983
+ var _a, _b, _c;
22984
+ var _d;
22900
22985
  return __awaiter(this, void 0, void 0, function* () {
22901
22986
  let deviceHasChanged = false;
22902
22987
  let success = true;
@@ -22935,14 +23020,18 @@ class Room extends eventsExports.EventEmitter {
22935
23020
  if (!supportsSetSinkId() && !this.options.webAudioMix || this.options.webAudioMix && this.audioContext && !('setSinkId' in this.audioContext)) {
22936
23021
  throw new Error('cannot switch audio output, setSinkId not supported');
22937
23022
  }
22938
- (_a = (_c = this.options).audioOutput) !== null && _a !== void 0 ? _a : _c.audioOutput = {};
23023
+ if (this.options.webAudioMix) {
23024
+ // setting `default` for web audio output doesn't work, so we need to normalize the id before
23025
+ deviceId = (_a = yield DeviceManager.getInstance().normalizeDeviceId('audiooutput', deviceId)) !== null && _a !== void 0 ? _a : '';
23026
+ }
23027
+ (_b = (_d = this.options).audioOutput) !== null && _b !== void 0 ? _b : _d.audioOutput = {};
22939
23028
  const prevDeviceId = this.options.audioOutput.deviceId;
22940
23029
  this.options.audioOutput.deviceId = deviceId;
22941
23030
  deviceHasChanged = prevDeviceId !== deviceConstraint;
22942
23031
  try {
22943
23032
  if (this.options.webAudioMix) {
22944
23033
  // @ts-expect-error setSinkId is not yet in the typescript type of AudioContext
22945
- (_b = this.audioContext) === null || _b === void 0 ? void 0 : _b.setSinkId(deviceId);
23034
+ (_c = this.audioContext) === null || _c === void 0 ? void 0 : _c.setSinkId(deviceId);
22946
23035
  } else {
22947
23036
  yield Promise.all(Array.from(this.remoteParticipants.values()).map(p => p.setAudioOutput({
22948
23037
  deviceId
@@ -24065,5 +24154,5 @@ function isFacingModeValue(item) {
24065
24154
  return item === undefined || allowedValues.includes(item);
24066
24155
  }
24067
24156
 
24068
- 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 };
24157
+ 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 };
24069
24158
  //# sourceMappingURL=livekit-client.esm.mjs.map