livekit-client 2.0.3 → 2.0.4

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 (55) 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 +1 -0
  4. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  5. package/dist/livekit-client.esm.mjs +90 -26
  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/types.d.ts +2 -0
  12. package/dist/src/e2ee/types.d.ts.map +1 -1
  13. package/dist/src/index.d.ts +2 -2
  14. package/dist/src/index.d.ts.map +1 -1
  15. package/dist/src/logger.d.ts +2 -0
  16. package/dist/src/logger.d.ts.map +1 -1
  17. package/dist/src/room/DeviceManager.d.ts.map +1 -1
  18. package/dist/src/room/RTCEngine.d.ts +1 -0
  19. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  20. package/dist/src/room/Room.d.ts.map +1 -1
  21. package/dist/src/room/events.d.ts +2 -1
  22. package/dist/src/room/events.d.ts.map +1 -1
  23. package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
  24. package/dist/src/room/track/LocalTrack.d.ts +3 -1
  25. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  26. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
  27. package/dist/src/room/track/options.d.ts +10 -0
  28. package/dist/src/room/track/options.d.ts.map +1 -1
  29. package/dist/src/room/track/types.d.ts +4 -0
  30. package/dist/src/room/track/types.d.ts.map +1 -1
  31. package/dist/ts4.2/src/e2ee/types.d.ts +2 -0
  32. package/dist/ts4.2/src/index.d.ts +2 -2
  33. package/dist/ts4.2/src/logger.d.ts +2 -0
  34. package/dist/ts4.2/src/room/RTCEngine.d.ts +1 -0
  35. package/dist/ts4.2/src/room/events.d.ts +2 -1
  36. package/dist/ts4.2/src/room/track/LocalTrack.d.ts +3 -1
  37. package/dist/ts4.2/src/room/track/options.d.ts +10 -0
  38. package/dist/ts4.2/src/room/track/types.d.ts +4 -0
  39. package/package.json +1 -1
  40. package/src/api/SignalClient.ts +1 -0
  41. package/src/e2ee/E2eeManager.ts +2 -1
  42. package/src/e2ee/types.ts +2 -0
  43. package/src/e2ee/worker/e2ee.worker.ts +1 -0
  44. package/src/index.ts +2 -1
  45. package/src/logger.ts +2 -0
  46. package/src/room/DeviceManager.ts +10 -1
  47. package/src/room/RTCEngine.ts +14 -0
  48. package/src/room/Room.ts +11 -0
  49. package/src/room/events.ts +1 -0
  50. package/src/room/participant/LocalParticipant.ts +4 -4
  51. package/src/room/track/LocalAudioTrack.ts +10 -0
  52. package/src/room/track/LocalTrack.ts +20 -3
  53. package/src/room/track/LocalVideoTrack.ts +10 -0
  54. package/src/room/track/options.ts +41 -8
  55. 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
  //
@@ -10537,6 +10537,7 @@ var EngineEvent;
10537
10537
  EngineEvent["RemoteMute"] = "remoteMute";
10538
10538
  EngineEvent["SubscribedQualityUpdate"] = "subscribedQualityUpdate";
10539
10539
  EngineEvent["LocalTrackUnpublished"] = "localTrackUnpublished";
10540
+ EngineEvent["Offline"] = "offline";
10540
10541
  })(EngineEvent || (EngineEvent = {}));
10541
10542
  var TrackEvent;
10542
10543
  (function (TrackEvent) {
@@ -10710,7 +10711,7 @@ function getMatch(exp, ua) {
10710
10711
  return match && match.length >= id && match[id] || '';
10711
10712
  }
10712
10713
 
10713
- var version$1 = "2.0.3";
10714
+ var version$1 = "2.0.4";
10714
10715
 
10715
10716
  const version = version$1;
10716
10717
  const protocolVersion = 12;
@@ -10737,21 +10738,35 @@ CriticalTimers.clearInterval = function () {
10737
10738
  };
10738
10739
 
10739
10740
  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
- };
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
+ }
10748
10763
  }
10749
10764
  get resolution() {
10750
10765
  return {
10751
10766
  width: this.width,
10752
10767
  height: this.height,
10753
10768
  frameRate: this.encoding.maxFramerate,
10754
- aspectRatio: this.width / this.height
10769
+ aspectRatio: this.aspectRatio
10755
10770
  };
10756
10771
  }
10757
10772
  }
@@ -14164,7 +14179,16 @@ class DeviceManager {
14164
14179
  // resolve actual device id if it's 'default': Chrome returns it when no
14165
14180
  // device has been chosen
14166
14181
  const devices = yield this.getDevices(kind);
14167
- 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
+ });
14168
14192
  return device === null || device === void 0 ? void 0 : device.deviceId;
14169
14193
  });
14170
14194
  }
@@ -14372,18 +14396,25 @@ class LocalTrack extends Track {
14372
14396
  return this;
14373
14397
  });
14374
14398
  }
14375
- replaceTrack(track) {
14376
- let userProvidedTrack = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
14399
+ replaceTrack(track, userProvidedOrOptions) {
14377
14400
  return __awaiter(this, void 0, void 0, function* () {
14378
14401
  if (!this.sender) {
14379
14402
  throw new TrackInvalidError('unable to replace an unpublished track');
14380
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;
14381
14413
  this.log.debug('replace MediaStreamTrack', this.logContext);
14382
14414
  yield this.setMediaStreamTrack(track);
14383
14415
  // this must be synced *after* setting mediaStreamTrack above, since it relies
14384
14416
  // on the previous state in order to cleanup
14385
- this.providedByUser = userProvidedTrack;
14386
- if (this.processor) {
14417
+ if (stopProcessor && this.processor) {
14387
14418
  yield this.stopProcessor();
14388
14419
  }
14389
14420
  return this;
@@ -14685,7 +14716,8 @@ class E2EEManager extends eventsExports.EventEmitter {
14685
14716
  const msg = {
14686
14717
  kind: 'init',
14687
14718
  data: {
14688
- keyProviderOptions: this.keyProvider.getOptions()
14719
+ keyProviderOptions: this.keyProvider.getOptions(),
14720
+ loglevel: workerLogger.getLevel()
14689
14721
  }
14690
14722
  };
14691
14723
  if (this.worker) {
@@ -15123,6 +15155,7 @@ class SignalClient {
15123
15155
  };
15124
15156
  this.ws.onerror = ev => __awaiter(this, void 0, void 0, function* () {
15125
15157
  if (this.state !== SignalConnectionState.CONNECTED) {
15158
+ this.state = SignalConnectionState.DISCONNECTED;
15126
15159
  clearTimeout(wsTimeout);
15127
15160
  try {
15128
15161
  const resp = yield fetch("http".concat(url.substring(2), "/validate").concat(params));
@@ -17532,6 +17565,12 @@ class RTCEngine extends eventsExports.EventEmitter {
17532
17565
  this.handleDisconnect('peerconnection failed', subscriberState === 'failed' ? ReconnectReason.RR_SUBSCRIBER_FAILED : ReconnectReason.RR_PUBLISHER_FAILED);
17533
17566
  }
17534
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
+ }
17535
17574
  });
17536
17575
  this.pcManager.onTrack = ev => {
17537
17576
  this.emit(EngineEvent.MediaTrackAdded, ev.track, ev.streams[0], ev.receiver);
@@ -18362,6 +18401,10 @@ class LocalAudioTrack extends LocalTrack {
18362
18401
  return __awaiter(this, void 0, void 0, function* () {
18363
18402
  const unlock = yield this.muteLock.lock();
18364
18403
  try {
18404
+ if (this.isMuted) {
18405
+ this.log.debug('Track already muted', this.logContext);
18406
+ return this;
18407
+ }
18365
18408
  // disabled special handling as it will cause BT headsets to switch communication modes
18366
18409
  if (this.source === Track.Source.Microphone && this.stopOnMute && !this.isUserProvided) {
18367
18410
  this.log.debug('stopping mic track', this.logContext);
@@ -18384,6 +18427,10 @@ class LocalAudioTrack extends LocalTrack {
18384
18427
  return __awaiter(this, void 0, void 0, function* () {
18385
18428
  const unlock = yield this.muteLock.lock();
18386
18429
  try {
18430
+ if (!this.isMuted) {
18431
+ this.log.debug('Track already unmuted', this.logContext);
18432
+ return this;
18433
+ }
18387
18434
  const deviceHasChanged = this._constraints.deviceId && this._mediaStreamTrack.getSettings().deviceId !== unwrapConstraint(this._constraints.deviceId);
18388
18435
  if (this.source === Track.Source.Microphone && (this.stopOnMute || this._mediaStreamTrack.readyState === 'ended' || deviceHasChanged) && !this.isUserProvided) {
18389
18436
  this.log.debug('reacquiring mic track', this.logContext);
@@ -18953,6 +19000,10 @@ class LocalVideoTrack extends LocalTrack {
18953
19000
  return __awaiter(this, void 0, void 0, function* () {
18954
19001
  const unlock = yield this.muteLock.lock();
18955
19002
  try {
19003
+ if (this.isMuted) {
19004
+ this.log.debug('Track already muted', this.logContext);
19005
+ return this;
19006
+ }
18956
19007
  if (this.source === Track.Source.Camera && !this.isUserProvided) {
18957
19008
  this.log.debug('stopping camera track', this.logContext);
18958
19009
  // also stop the track, so that camera indicator is turned off
@@ -18974,6 +19025,10 @@ class LocalVideoTrack extends LocalTrack {
18974
19025
  return __awaiter(this, void 0, void 0, function* () {
18975
19026
  const unlock = yield this.muteLock.lock();
18976
19027
  try {
19028
+ if (!this.isMuted) {
19029
+ this.log.debug('Track already unmuted', this.logContext);
19030
+ return this;
19031
+ }
18977
19032
  if (this.source === Track.Source.Camera && !this.isUserProvided) {
18978
19033
  this.log.debug('reacquiring camera track', this.logContext);
18979
19034
  yield this.restartTrack();
@@ -20829,6 +20884,9 @@ class LocalParticipant extends Participant {
20829
20884
  publishTrack(track, options) {
20830
20885
  var _a, _b, _c, _d;
20831
20886
  return __awaiter(this, void 0, void 0, function* () {
20887
+ if (track instanceof LocalAudioTrack) {
20888
+ track.setAudioContext(this.audioContext);
20889
+ }
20832
20890
  yield (_a = this.reconnectFuture) === null || _a === void 0 ? void 0 : _a.promise;
20833
20891
  if (track instanceof LocalTrack && this.pendingPublishPromises.has(track)) {
20834
20892
  yield this.pendingPublishPromises.get(track);
@@ -20878,9 +20936,6 @@ class LocalParticipant extends Participant {
20878
20936
  loggerContextCb: () => this.logContext
20879
20937
  });
20880
20938
  }
20881
- if (track instanceof LocalAudioTrack) {
20882
- track.setAudioContext(this.audioContext);
20883
- }
20884
20939
  // is it already published? if so skip
20885
20940
  let existingPublication;
20886
20941
  this.trackPublications.forEach(publication => {
@@ -22180,6 +22235,7 @@ class Room extends eventsExports.EventEmitter {
22180
22235
  });
22181
22236
  };
22182
22237
  this.onPageLeave = () => __awaiter(this, void 0, void 0, function* () {
22238
+ this.log.info('Page leave detected, disconnecting', this.logContext);
22183
22239
  yield this.disconnect();
22184
22240
  });
22185
22241
  /**
@@ -22678,7 +22734,11 @@ class Room extends eventsExports.EventEmitter {
22678
22734
  if (this.state === ConnectionState.Reconnecting || this.isResuming) {
22679
22735
  this.sendSyncState();
22680
22736
  }
22681
- }).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) => {
22682
22742
  this.emit(RoomEvent.DCBufferStatusChanged, status, kind);
22683
22743
  });
22684
22744
  if (this.localParticipant) {
@@ -22895,8 +22955,8 @@ class Room extends eventsExports.EventEmitter {
22895
22955
  */
22896
22956
  switchActiveDevice(kind, deviceId) {
22897
22957
  let exact = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
22898
- var _a, _b;
22899
- var _c;
22958
+ var _a, _b, _c;
22959
+ var _d;
22900
22960
  return __awaiter(this, void 0, void 0, function* () {
22901
22961
  let deviceHasChanged = false;
22902
22962
  let success = true;
@@ -22935,14 +22995,18 @@ class Room extends eventsExports.EventEmitter {
22935
22995
  if (!supportsSetSinkId() && !this.options.webAudioMix || this.options.webAudioMix && this.audioContext && !('setSinkId' in this.audioContext)) {
22936
22996
  throw new Error('cannot switch audio output, setSinkId not supported');
22937
22997
  }
22938
- (_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 = {};
22939
23003
  const prevDeviceId = this.options.audioOutput.deviceId;
22940
23004
  this.options.audioOutput.deviceId = deviceId;
22941
23005
  deviceHasChanged = prevDeviceId !== deviceConstraint;
22942
23006
  try {
22943
23007
  if (this.options.webAudioMix) {
22944
23008
  // @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);
23009
+ (_c = this.audioContext) === null || _c === void 0 ? void 0 : _c.setSinkId(deviceId);
22946
23010
  } else {
22947
23011
  yield Promise.all(Array.from(this.remoteParticipants.values()).map(p => p.setAudioOutput({
22948
23012
  deviceId
@@ -24065,5 +24129,5 @@ function isFacingModeValue(item) {
24065
24129
  return item === undefined || allowedValues.includes(item);
24066
24130
  }
24067
24131
 
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 };
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 };
24069
24133
  //# sourceMappingURL=livekit-client.esm.mjs.map