livekit-client 2.11.3 → 2.12.0

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 (60) 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 +30 -23
  4. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  5. package/dist/livekit-client.esm.mjs +126 -27
  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 +2 -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/KeyProvider.d.ts +8 -5
  13. package/dist/src/e2ee/KeyProvider.d.ts.map +1 -1
  14. package/dist/src/e2ee/constants.d.ts.map +1 -1
  15. package/dist/src/e2ee/events.d.ts +8 -3
  16. package/dist/src/e2ee/events.d.ts.map +1 -1
  17. package/dist/src/e2ee/types.d.ts +5 -3
  18. package/dist/src/e2ee/types.d.ts.map +1 -1
  19. package/dist/src/e2ee/utils.d.ts +1 -1
  20. package/dist/src/e2ee/utils.d.ts.map +1 -1
  21. package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
  22. package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts +5 -6
  23. package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts.map +1 -1
  24. package/dist/src/room/RTCEngine.d.ts +2 -1
  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 +11 -1
  29. package/dist/src/room/events.d.ts.map +1 -1
  30. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  31. package/dist/src/room/track/RemoteAudioTrack.d.ts.map +1 -1
  32. package/dist/src/version.d.ts +1 -1
  33. package/dist/ts4.2/src/api/SignalClient.d.ts +2 -1
  34. package/dist/ts4.2/src/e2ee/KeyProvider.d.ts +8 -5
  35. package/dist/ts4.2/src/e2ee/events.d.ts +8 -3
  36. package/dist/ts4.2/src/e2ee/types.d.ts +5 -3
  37. package/dist/ts4.2/src/e2ee/utils.d.ts +1 -1
  38. package/dist/ts4.2/src/e2ee/worker/ParticipantKeyHandler.d.ts +5 -6
  39. package/dist/ts4.2/src/room/RTCEngine.d.ts +2 -1
  40. package/dist/ts4.2/src/room/Room.d.ts +1 -0
  41. package/dist/ts4.2/src/room/events.d.ts +11 -1
  42. package/dist/ts4.2/src/version.d.ts +1 -1
  43. package/package.json +2 -2
  44. package/src/api/SignalClient.ts +10 -0
  45. package/src/e2ee/E2eeManager.ts +8 -12
  46. package/src/e2ee/KeyProvider.ts +13 -6
  47. package/src/e2ee/constants.ts +0 -1
  48. package/src/e2ee/events.ts +12 -3
  49. package/src/e2ee/types.ts +8 -3
  50. package/src/e2ee/utils.ts +1 -2
  51. package/src/e2ee/worker/FrameCryptor.ts +8 -4
  52. package/src/e2ee/worker/ParticipantKeyHandler.test.ts +104 -4
  53. package/src/e2ee/worker/ParticipantKeyHandler.ts +23 -26
  54. package/src/e2ee/worker/e2ee.worker.ts +9 -4
  55. package/src/room/RTCEngine.ts +7 -0
  56. package/src/room/Room.ts +27 -2
  57. package/src/room/events.ts +11 -0
  58. package/src/room/participant/LocalParticipant.ts +0 -5
  59. package/src/room/track/RemoteAudioTrack.ts +3 -2
  60. package/src/version.ts +1 -1
@@ -3884,6 +3884,9 @@ const DisconnectReason = /* @__PURE__ */proto3.makeEnum("livekit.DisconnectReaso
3884
3884
  }, {
3885
3885
  no: 13,
3886
3886
  name: "SIP_TRUNK_FAILURE"
3887
+ }, {
3888
+ no: 14,
3889
+ name: "CONNECTION_TIMEOUT"
3887
3890
  }]);
3888
3891
  const ReconnectReason = /* @__PURE__ */proto3.makeEnum("livekit.ReconnectReason", [{
3889
3892
  no: 0,
@@ -3929,6 +3932,9 @@ const AudioTrackFeature = /* @__PURE__ */proto3.makeEnum("livekit.AudioTrackFeat
3929
3932
  }, {
3930
3933
  no: 5,
3931
3934
  name: "TF_ENHANCED_NOISE_CANCELLATION"
3935
+ }, {
3936
+ no: 6,
3937
+ name: "TF_PRECONNECT_BUFFER"
3932
3938
  }]);
3933
3939
  const Room$1 = /* @__PURE__ */proto3.makeMessageType("livekit.Room", () => [{
3934
3940
  no: 1,
@@ -4929,6 +4935,9 @@ const ClientInfo_SDK = /* @__PURE__ */proto3.makeEnum("livekit.ClientInfo.SDK",
4929
4935
  }, {
4930
4936
  no: 12,
4931
4937
  name: "NODE"
4938
+ }, {
4939
+ no: 13,
4940
+ name: "UNREAL"
4932
4941
  }]);
4933
4942
  const ClientConfiguration = /* @__PURE__ */proto3.makeMessageType("livekit.ClientConfiguration", () => [{
4934
4943
  no: 1,
@@ -5419,6 +5428,12 @@ const SignalResponse = /* @__PURE__ */proto3.makeMessageType("livekit.SignalResp
5419
5428
  kind: "message",
5420
5429
  T: TrackSubscribed,
5421
5430
  oneof: "message"
5431
+ }, {
5432
+ no: 24,
5433
+ name: "room_moved",
5434
+ kind: "message",
5435
+ T: RoomMovedResponse,
5436
+ oneof: "message"
5422
5437
  }]);
5423
5438
  const SimulcastCodec = /* @__PURE__ */proto3.makeMessageType("livekit.SimulcastCodec", () => [{
5424
5439
  no: 1,
@@ -5525,6 +5540,12 @@ const AddTrackRequest = /* @__PURE__ */proto3.makeMessageType("livekit.AddTrackR
5525
5540
  name: "backup_codec_policy",
5526
5541
  kind: "enum",
5527
5542
  T: proto3.getEnumType(BackupCodecPolicy$1)
5543
+ }, {
5544
+ no: 17,
5545
+ name: "audio_features",
5546
+ kind: "enum",
5547
+ T: proto3.getEnumType(AudioTrackFeature),
5548
+ repeated: true
5528
5549
  }]);
5529
5550
  const TrickleRequest = /* @__PURE__ */proto3.makeMessageType("livekit.TrickleRequest", () => [{
5530
5551
  no: 1,
@@ -6045,6 +6066,29 @@ const SubscriptionPermissionUpdate = /* @__PURE__ */proto3.makeMessageType("live
6045
6066
  T: 8
6046
6067
  /* ScalarType.BOOL */
6047
6068
  }]);
6069
+ const RoomMovedResponse = /* @__PURE__ */proto3.makeMessageType("livekit.RoomMovedResponse", () => [{
6070
+ no: 1,
6071
+ name: "room",
6072
+ kind: "message",
6073
+ T: Room$1
6074
+ }, {
6075
+ no: 2,
6076
+ name: "token",
6077
+ kind: "scalar",
6078
+ T: 9
6079
+ /* ScalarType.STRING */
6080
+ }, {
6081
+ no: 3,
6082
+ name: "participant",
6083
+ kind: "message",
6084
+ T: ParticipantInfo
6085
+ }, {
6086
+ no: 4,
6087
+ name: "other_participants",
6088
+ kind: "message",
6089
+ T: ParticipantInfo,
6090
+ repeated: true
6091
+ }]);
6048
6092
  const SyncState = /* @__PURE__ */proto3.makeMessageType("livekit.SyncState", () => [{
6049
6093
  no: 1,
6050
6094
  name: "answer",
@@ -10156,18 +10200,22 @@ const KEY_PROVIDER_DEFAULTS = {
10156
10200
  ratchetSalt: SALT,
10157
10201
  ratchetWindowSize: 8,
10158
10202
  failureTolerance: DECRYPTION_FAILURE_TOLERANCE,
10159
- keyringSize: 16,
10160
- allowKeyExtraction: false
10203
+ keyringSize: 16
10161
10204
  };
10162
10205
 
10163
10206
  var KeyProviderEvent;
10164
10207
  (function (KeyProviderEvent) {
10165
10208
  KeyProviderEvent["SetKey"] = "setKey";
10209
+ /** Event for requesting to ratchet the key used to encrypt the stream */
10166
10210
  KeyProviderEvent["RatchetRequest"] = "ratchetRequest";
10211
+ /** Emitted when a key is ratcheted. Could be after auto-ratcheting on decryption failure or
10212
+ * following a `RatchetRequest`, will contain the ratcheted key material */
10167
10213
  KeyProviderEvent["KeyRatcheted"] = "keyRatcheted";
10168
10214
  })(KeyProviderEvent || (KeyProviderEvent = {}));
10169
10215
  var KeyHandlerEvent;
10170
10216
  (function (KeyHandlerEvent) {
10217
+ /** Emitted when a key has been ratcheted. Is emitted when any key has been ratcheted
10218
+ * i.e. when the FrameCryptor tried to ratchet when decryption is failing */
10171
10219
  KeyHandlerEvent["KeyRatcheted"] = "keyRatcheted";
10172
10220
  })(KeyHandlerEvent || (KeyHandlerEvent = {}));
10173
10221
  var EncryptionEvent;
@@ -10201,10 +10249,9 @@ function importKey(keyBytes_1) {
10201
10249
  name: ENCRYPTION_ALGORITHM
10202
10250
  };
10203
10251
  let usage = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'encrypt';
10204
- let extractable = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
10205
10252
  return function* () {
10206
10253
  // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey
10207
- return crypto.subtle.importKey('raw', keyBytes, algorithm, extractable, usage === 'derive' ? ['deriveBits', 'deriveKey'] : ['encrypt', 'decrypt']);
10254
+ return crypto.subtle.importKey('raw', keyBytes, algorithm, false, usage === 'derive' ? ['deriveBits', 'deriveKey'] : ['encrypt', 'decrypt']);
10208
10255
  }();
10209
10256
  });
10210
10257
  }
@@ -10337,14 +10384,18 @@ class BaseKeyProvider extends eventsExports.EventEmitter {
10337
10384
  let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
10338
10385
  super();
10339
10386
  /**
10340
- * callback being invoked after a ratchet request has been performed on a participant
10341
- * that surfaces the new key material.
10342
- * @param material
10387
+ * Callback being invoked after a key has been ratcheted.
10388
+ * Can happen when:
10389
+ * - A decryption failure occurs and the key is auto-ratcheted
10390
+ * - A ratchet request is sent (see {@link ratchetKey()})
10391
+ * @param ratchetResult Contains the ratcheted chain key (exportable to other participants) and the derived new key material.
10392
+ * @param participantId
10343
10393
  * @param keyIndex
10344
10394
  */
10345
- this.onKeyRatcheted = (material, keyIndex) => {
10395
+ this.onKeyRatcheted = (ratchetResult, participantId, keyIndex) => {
10346
10396
  livekitLogger.debug('key ratcheted event received', {
10347
- material,
10397
+ ratchetResult,
10398
+ participantId,
10348
10399
  keyIndex
10349
10400
  });
10350
10401
  };
@@ -10579,6 +10630,15 @@ var RoomEvent;
10579
10630
  * args: ([[ConnectionState]])
10580
10631
  */
10581
10632
  RoomEvent["ConnectionStateChanged"] = "connectionStateChanged";
10633
+ /**
10634
+ * When participant has been moved to a different room by the service request.
10635
+ * The behavior looks like the participant has been disconnected and reconnected to a different room
10636
+ * seamlessly without connection state transition.
10637
+ * A new token will be provided for reconnecting to the new room if needed.
10638
+ *
10639
+ * args: ([[room: string, token: string]])
10640
+ */
10641
+ RoomEvent["Moved"] = "moved";
10582
10642
  /**
10583
10643
  * When input or output devices on the machine have changed.
10584
10644
  */
@@ -11030,6 +11090,7 @@ var EngineEvent;
11030
11090
  EngineEvent["Offline"] = "offline";
11031
11091
  EngineEvent["SignalRequestResponse"] = "signalRequestResponse";
11032
11092
  EngineEvent["SignalConnected"] = "signalConnected";
11093
+ EngineEvent["RoomMoved"] = "roomMoved";
11033
11094
  })(EngineEvent || (EngineEvent = {}));
11034
11095
  var TrackEvent;
11035
11096
  (function (TrackEvent) {
@@ -11188,10 +11249,10 @@ function getOSVersion(ua) {
11188
11249
  return ua.includes('mac os') ? getMatch(/\(.+?(\d+_\d+(:?_\d+)?)/, ua, 1).replace(/_/g, '.') : undefined;
11189
11250
  }
11190
11251
 
11191
- var version$1 = "2.11.3";
11252
+ var version$1 = "2.12.0";
11192
11253
 
11193
11254
  const version = version$1;
11194
- const protocolVersion = 15;
11255
+ const protocolVersion = 16;
11195
11256
 
11196
11257
  /**
11197
11258
  * Timers that can be overridden with platform specific implementations
@@ -12342,6 +12403,18 @@ function getNewAudioContext() {
12342
12403
  return audioContext;
12343
12404
  }
12344
12405
  }
12406
+ /**
12407
+ * @internal
12408
+ */
12409
+ function kindToSource(kind) {
12410
+ if (kind === 'audioinput') {
12411
+ return Track.Source.Microphone;
12412
+ } else if (kind === 'videoinput') {
12413
+ return Track.Source.Camera;
12414
+ } else {
12415
+ return Track.Source.Unknown;
12416
+ }
12417
+ }
12345
12418
  /**
12346
12419
  * @internal
12347
12420
  */
@@ -12537,7 +12610,7 @@ class E2EEManager extends eventsExports.EventEmitter {
12537
12610
  }
12538
12611
  break;
12539
12612
  case 'ratchetKey':
12540
- this.keyProvider.emit(KeyProviderEvent.KeyRatcheted, data.material, data.keyIndex);
12613
+ this.keyProvider.emit(KeyProviderEvent.KeyRatcheted, data.ratchetResult, data.participantIdentity, data.keyIndex);
12541
12614
  break;
12542
12615
  }
12543
12616
  };
@@ -12636,9 +12709,9 @@ class E2EEManager extends eventsExports.EventEmitter {
12636
12709
  room.localParticipant.on(ParticipantEvent.LocalTrackPublished, publication => __awaiter(this, void 0, void 0, function* () {
12637
12710
  this.setupE2EESender(publication.track, publication.track.sender);
12638
12711
  }));
12639
- keyProvider.on(KeyProviderEvent.SetKey, keyInfo => this.postKey(keyInfo)).on(KeyProviderEvent.RatchetRequest, (participantId, keyIndex) => this.postRatchetRequest(participantId, keyIndex, keyProvider.getOptions().allowKeyExtraction));
12712
+ keyProvider.on(KeyProviderEvent.SetKey, keyInfo => this.postKey(keyInfo)).on(KeyProviderEvent.RatchetRequest, (participantId, keyIndex) => this.postRatchetRequest(participantId, keyIndex));
12640
12713
  }
12641
- postRatchetRequest(participantIdentity, keyIndex, extractable) {
12714
+ postRatchetRequest(participantIdentity, keyIndex) {
12642
12715
  if (!this.worker) {
12643
12716
  throw Error('could not ratchet key, worker is missing');
12644
12717
  }
@@ -12646,8 +12719,7 @@ class E2EEManager extends eventsExports.EventEmitter {
12646
12719
  kind: 'ratchetRequest',
12647
12720
  data: {
12648
12721
  participantIdentity: participantIdentity,
12649
- keyIndex,
12650
- extractable
12722
+ keyIndex
12651
12723
  }
12652
12724
  };
12653
12725
  this.worker.postMessage(msg);
@@ -13531,6 +13603,13 @@ class SignalClient {
13531
13603
  if (this.onLocalTrackSubscribed) {
13532
13604
  this.onLocalTrackSubscribed(msg.value.trackSid);
13533
13605
  }
13606
+ } else if (msg.case === 'roomMoved') {
13607
+ if (this.onTokenRefresh) {
13608
+ this.onTokenRefresh(msg.value.token);
13609
+ }
13610
+ if (this.onRoomMoved) {
13611
+ this.onRoomMoved(msg.value);
13612
+ }
13534
13613
  } else {
13535
13614
  this.log.debug('unsupported message', Object.assign(Object.assign({}, this.logContext), {
13536
13615
  msgCase: msg.case
@@ -17635,6 +17714,11 @@ class RTCEngine extends eventsExports.EventEmitter {
17635
17714
  this.client.onSubscribedQualityUpdate = update => {
17636
17715
  this.emit(EngineEvent.SubscribedQualityUpdate, update);
17637
17716
  };
17717
+ this.client.onRoomMoved = res => {
17718
+ var _a;
17719
+ this.participantSid = (_a = res.participant) === null || _a === void 0 ? void 0 : _a.sid;
17720
+ this.emit(EngineEvent.RoomMoved, res);
17721
+ };
17638
17722
  this.client.onClose = () => {
17639
17723
  this.handleDisconnect('signal', ReconnectReason.RR_SIGNAL_DISCONNECTED);
17640
17724
  };
@@ -18788,8 +18872,9 @@ class RemoteAudioTrack extends RemoteTrack {
18788
18872
  super.attach(element);
18789
18873
  }
18790
18874
  if (this.sinkId && supportsSetSinkId(element)) {
18791
- /* @ts-ignore */
18792
- element.setSinkId(this.sinkId);
18875
+ element.setSinkId(this.sinkId).catch(e => {
18876
+ this.log.error('Failed to set sink id on remote audio track', e, this.logContext);
18877
+ });
18793
18878
  }
18794
18879
  if (this.audioContext && needsNewWebAudioConnection) {
18795
18880
  this.log.debug('using audio context mapping', this.logContext);
@@ -21591,11 +21676,6 @@ class LocalParticipant extends Participant {
21591
21676
  }
21592
21677
  /** @internal */
21593
21678
  updateInfo(info) {
21594
- if (info.sid !== this.sid) {
21595
- // drop updates that specify a wrong sid.
21596
- // the sid for local participant is only explicitly set on join and full reconnect
21597
- return false;
21598
- }
21599
21679
  if (!super.updateInfo(info)) {
21600
21680
  return false;
21601
21681
  }
@@ -22810,7 +22890,7 @@ class Room extends eventsExports.EventEmitter {
22810
22890
  }
22811
22891
  };
22812
22892
  this.handleDeviceChange = () => __awaiter(this, void 0, void 0, function* () {
22813
- var _a, _b;
22893
+ var _a, _b, _c;
22814
22894
  const previousDevices = DeviceManager.getInstance().previousDevices;
22815
22895
  // check for available devices, but don't request permissions in order to avoid prompts for kinds that haven't been used before
22816
22896
  const availableDevices = yield DeviceManager.getInstance().getDevices(undefined, false);
@@ -22827,15 +22907,20 @@ class Room extends eventsExports.EventEmitter {
22827
22907
  }
22828
22908
  }
22829
22909
  }
22830
- // inputs are automatically handled via TrackEvent.Ended causing a TrackEvent.Restarted. Here we only need to worry about audiooutputs changing
22831
22910
  const kinds = ['audiooutput', 'audioinput', 'videoinput'];
22832
22911
  for (let kind of kinds) {
22912
+ const targetSource = kindToSource(kind);
22913
+ const targetPublication = this.localParticipant.getTrackPublication(targetSource);
22914
+ if (targetPublication && ((_a = targetPublication.track) === null || _a === void 0 ? void 0 : _a.isUserProvided)) {
22915
+ // if the track is user provided, we don't want to switch devices on behalf of the user
22916
+ continue;
22917
+ }
22833
22918
  const devicesOfKind = availableDevices.filter(d => d.kind === kind);
22834
22919
  const activeDevice = this.getActiveDevice(kind);
22835
- if (activeDevice === ((_a = previousDevices.filter(info => info.kind === kind)[0]) === null || _a === void 0 ? void 0 : _a.deviceId)) {
22920
+ if (activeDevice === ((_b = previousDevices.filter(info => info.kind === kind)[0]) === null || _b === void 0 ? void 0 : _b.deviceId)) {
22836
22921
  // in Safari the first device is always the default, so we assume a user on the default device would like to switch to the default once it changes
22837
22922
  // FF doesn't emit an event when the default device changes, so we perform the same best effort and switch to the new device once connected and if it's the first in the array
22838
- if (devicesOfKind.length > 0 && ((_b = devicesOfKind[0]) === null || _b === void 0 ? void 0 : _b.deviceId) !== activeDevice) {
22923
+ if (devicesOfKind.length > 0 && ((_c = devicesOfKind[0]) === null || _c === void 0 ? void 0 : _c.deviceId) !== activeDevice) {
22839
22924
  yield this.switchActiveDevice(kind, devicesOfKind[0].deviceId);
22840
22925
  continue;
22841
22926
  }
@@ -23214,6 +23299,20 @@ class Room extends eventsExports.EventEmitter {
23214
23299
  }
23215
23300
  this.localParticipant.emit(ParticipantEvent.LocalTrackSubscribed, trackPublication);
23216
23301
  this.emitWhenConnected(RoomEvent.LocalTrackSubscribed, trackPublication, this.localParticipant);
23302
+ }).on(EngineEvent.RoomMoved, roomMoved => {
23303
+ this.log.debug('room moved', roomMoved);
23304
+ if (roomMoved.room) {
23305
+ this.handleRoomUpdate(roomMoved.room);
23306
+ }
23307
+ this.remoteParticipants.forEach((participant, identity) => {
23308
+ this.handleParticipantDisconnected(identity, participant);
23309
+ });
23310
+ this.emit(RoomEvent.Moved, roomMoved.room.name, roomMoved.token);
23311
+ if (roomMoved.participant) {
23312
+ this.handleParticipantUpdates([roomMoved.participant, ...roomMoved.otherParticipants]);
23313
+ } else {
23314
+ this.handleParticipantUpdates(roomMoved.otherParticipants);
23315
+ }
23217
23316
  });
23218
23317
  if (this.localParticipant) {
23219
23318
  this.localParticipant.setupEngine(this.engine);