livekit-client 2.22.0 → 2.22.2

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 (106) 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 +364 -40
  4. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  5. package/dist/livekit-client.esm.mjs +1847 -179
  6. package/dist/livekit-client.esm.mjs.map +1 -1
  7. package/dist/livekit-client.fm.worker.js +1 -1
  8. package/dist/livekit-client.fm.worker.js.map +1 -1
  9. package/dist/livekit-client.fm.worker.mjs +187 -1
  10. package/dist/livekit-client.fm.worker.mjs.map +1 -1
  11. package/dist/livekit-client.umd.js +1 -1
  12. package/dist/livekit-client.umd.js.map +1 -1
  13. package/dist/src/api/SignalClient.d.ts +25 -1
  14. package/dist/src/api/SignalClient.d.ts.map +1 -1
  15. package/dist/src/api/SignalClientStateMachine.d.ts +85 -0
  16. package/dist/src/api/SignalClientStateMachine.d.ts.map +1 -0
  17. package/dist/src/api/WebSocketStream.d.ts.map +1 -1
  18. package/dist/src/api/utils.d.ts.map +1 -1
  19. package/dist/src/e2ee/E2eeManager.d.ts +7 -0
  20. package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
  21. package/dist/src/e2ee/constants.d.ts +5 -0
  22. package/dist/src/e2ee/constants.d.ts.map +1 -1
  23. package/dist/src/e2ee/types.d.ts +9 -2
  24. package/dist/src/e2ee/types.d.ts.map +1 -1
  25. package/dist/src/e2ee/worker/FrameCryptor.d.ts +42 -1
  26. package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
  27. package/dist/src/index.d.ts +3 -2
  28. package/dist/src/index.d.ts.map +1 -1
  29. package/dist/src/logger.d.ts +2 -1
  30. package/dist/src/logger.d.ts.map +1 -1
  31. package/dist/src/options.d.ts +22 -0
  32. package/dist/src/options.d.ts.map +1 -1
  33. package/dist/src/room/PCTransport.d.ts +2 -1
  34. package/dist/src/room/PCTransport.d.ts.map +1 -1
  35. package/dist/src/room/PCTransportManager.d.ts +12 -0
  36. package/dist/src/room/PCTransportManager.d.ts.map +1 -1
  37. package/dist/src/room/RTCEngine.d.ts +7 -2
  38. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  39. package/dist/src/room/Room.d.ts +8 -1
  40. package/dist/src/room/Room.d.ts.map +1 -1
  41. package/dist/src/room/data-stream/incoming/StreamReader.d.ts +17 -17
  42. package/dist/src/room/data-stream/incoming/StreamReader.d.ts.map +1 -1
  43. package/dist/src/room/events.d.ts +1 -1
  44. package/dist/src/room/statsSummary.d.ts +13 -0
  45. package/dist/src/room/statsSummary.d.ts.map +1 -0
  46. package/dist/src/room/token-source/utils.d.ts.map +1 -1
  47. package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
  48. package/dist/src/room/track/Track.d.ts +10 -0
  49. package/dist/src/room/track/Track.d.ts.map +1 -1
  50. package/dist/src/utils/machineInspector.d.ts +54 -0
  51. package/dist/src/utils/machineInspector.d.ts.map +1 -0
  52. package/dist/ts4.2/api/SignalClient.d.ts +25 -1
  53. package/dist/ts4.2/api/SignalClientStateMachine.d.ts +85 -0
  54. package/dist/ts4.2/e2ee/E2eeManager.d.ts +7 -0
  55. package/dist/ts4.2/e2ee/constants.d.ts +5 -0
  56. package/dist/ts4.2/e2ee/types.d.ts +9 -2
  57. package/dist/ts4.2/e2ee/worker/FrameCryptor.d.ts +42 -1
  58. package/dist/ts4.2/index.d.ts +3 -2
  59. package/dist/ts4.2/logger.d.ts +2 -1
  60. package/dist/ts4.2/options.d.ts +22 -0
  61. package/dist/ts4.2/room/PCTransport.d.ts +2 -1
  62. package/dist/ts4.2/room/PCTransportManager.d.ts +12 -0
  63. package/dist/ts4.2/room/RTCEngine.d.ts +7 -2
  64. package/dist/ts4.2/room/Room.d.ts +8 -1
  65. package/dist/ts4.2/room/data-stream/incoming/StreamReader.d.ts +17 -17
  66. package/dist/ts4.2/room/events.d.ts +1 -1
  67. package/dist/ts4.2/room/statsSummary.d.ts +13 -0
  68. package/dist/ts4.2/room/track/Track.d.ts +10 -0
  69. package/dist/ts4.2/utils/machineInspector.d.ts +54 -0
  70. package/package.json +7 -1
  71. package/src/api/SignalClient.test.ts +320 -8
  72. package/src/api/SignalClient.ts +261 -82
  73. package/src/api/SignalClientStateMachine.test.ts +472 -0
  74. package/src/api/SignalClientStateMachine.ts +180 -0
  75. package/src/api/WebSocketStream.ts +19 -3
  76. package/src/api/utils.test.ts +20 -1
  77. package/src/api/utils.ts +5 -0
  78. package/src/e2ee/E2eeManager.ts +38 -14
  79. package/src/e2ee/constants.ts +6 -0
  80. package/src/e2ee/subscriberBlackScreen.test.ts +544 -0
  81. package/src/e2ee/types.ts +9 -2
  82. package/src/e2ee/worker/FrameCryptor.race.test.ts +9 -26
  83. package/src/e2ee/worker/FrameCryptor.test.ts +0 -1
  84. package/src/e2ee/worker/FrameCryptor.ts +185 -52
  85. package/src/e2ee/worker/e2ee.worker.ts +38 -6
  86. package/src/index.ts +5 -0
  87. package/src/logger.ts +1 -0
  88. package/src/options.ts +24 -0
  89. package/src/room/PCTransport.ts +2 -1
  90. package/src/room/PCTransportManager.test.ts +35 -0
  91. package/src/room/PCTransportManager.ts +12 -4
  92. package/src/room/RTCEngine.ts +16 -7
  93. package/src/room/Room.ts +70 -5
  94. package/src/room/data-stream/incoming/IncomingDataStreamManager.test.ts +171 -0
  95. package/src/room/data-stream/incoming/IncomingDataStreamManager.ts +17 -18
  96. package/src/room/data-stream/incoming/StreamReader.ts +20 -50
  97. package/src/room/events.ts +1 -1
  98. package/src/room/statsSummary.ts +187 -0
  99. package/src/room/token-source/test-tokens.ts +20 -0
  100. package/src/room/token-source/utils.test.ts +27 -0
  101. package/src/room/token-source/utils.ts +12 -5
  102. package/src/room/track/LocalAudioTrack.ts +9 -3
  103. package/src/room/track/Track.ts +27 -0
  104. package/src/room/utils.test.ts +24 -1
  105. package/src/room/utils.ts +1 -1
  106. package/src/utils/machineInspector.ts +90 -0
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from 'vitest';
2
- import { createRtcUrl, createValidateUrl } from './utils';
2
+ import { createRtcUrl, createValidateUrl, getAbortReasonAsString } from './utils';
3
3
 
4
4
  describe('createRtcUrl', () => {
5
5
  it('should create a basic RTC URL', () => {
@@ -125,3 +125,22 @@ describe('createValidateUrl', () => {
125
125
  expect(parsedResult.pathname).toBe('/sub/path/rtc/validate');
126
126
  });
127
127
  });
128
+
129
+ describe('getAbortReasonAsString', () => {
130
+ it('uses an error message, which is how the connect timeout describes itself', () => {
131
+ // the timeout hands the abort handler an Error, not a signal
132
+ expect(
133
+ getAbortReasonAsString(new Error('room connection has timed out (signal)'), 'fallback'),
134
+ ).toBe('room connection has timed out (signal)');
135
+ });
136
+
137
+ it("reads an abort signal's reason", () => {
138
+ const controller = new AbortController();
139
+ controller.abort('user navigated away');
140
+ expect(getAbortReasonAsString(controller.signal, 'fallback')).toBe('user navigated away');
141
+ });
142
+
143
+ it('falls back when there is nothing to describe', () => {
144
+ expect(getAbortReasonAsString(undefined, 'fallback')).toBe('fallback');
145
+ });
146
+ });
package/src/api/utils.ts CHANGED
@@ -45,6 +45,11 @@ export function getAbortReasonAsString(
45
45
  signal: AbortSignal | Error | unknown,
46
46
  defaultMessage = 'Unknown reason',
47
47
  ) {
48
+ // the connect timeout hands this an Error rather than a signal, and its message is the only
49
+ // description of what went wrong — without this a timeout reports itself as a generic abort
50
+ if (signal instanceof Error) {
51
+ return signal.message;
52
+ }
48
53
  if (!(signal instanceof AbortSignal)) {
49
54
  return defaultMessage;
50
55
  }
@@ -12,6 +12,7 @@ import { EngineEvent, ParticipantEvent, RoomEvent } from '../room/events';
12
12
  import type RemoteTrack from '../room/track/RemoteTrack';
13
13
  import RemoteVideoTrack from '../room/track/RemoteVideoTrack';
14
14
  import type { Track } from '../room/track/Track';
15
+ import type { TrackPublication } from '../room/track/TrackPublication';
15
16
  import type { TrackPublishOptions, VideoCodec } from '../room/track/options';
16
17
  import { mimeTypeToVideoCodecString } from '../room/track/utils';
17
18
  import {
@@ -23,7 +24,7 @@ import {
23
24
  } from '../room/utils';
24
25
  import type { NonSharedUint8Array } from '../type-polyfills/non-shared-typed-arrays';
25
26
  import type { BaseKeyProvider } from './KeyProvider';
26
- import { E2EE_FLAG } from './constants';
27
+ import { E2EE_FLAG, E2EE_TRACK_ID } from './constants';
27
28
  import { type E2EEManagerCallbacks, EncryptionEvent, KeyProviderEvent } from './events';
28
29
  import type {
29
30
  DecryptDataRequestMessage,
@@ -279,20 +280,14 @@ export class E2EEManager
279
280
 
280
281
  private setupEventListeners(room: Room, keyProvider: BaseKeyProvider) {
281
282
  room.on(RoomEvent.TrackPublished, (pub, participant) =>
282
- this.setParticipantCryptorEnabled(
283
- pub.trackInfo!.encryption !== Encryption_Type.NONE,
284
- participant.identity,
285
- ),
283
+ this.setParticipantCryptorEnabledForPublication(pub, participant.identity),
286
284
  );
287
285
  room
288
286
  .on(RoomEvent.ConnectionStateChanged, (state) => {
289
287
  if (state === ConnectionState.Connected) {
290
288
  room.remoteParticipants.forEach((participant) => {
291
289
  participant.trackPublications.forEach((pub) => {
292
- this.setParticipantCryptorEnabled(
293
- pub.trackInfo!.encryption !== Encryption_Type.NONE,
294
- participant.identity,
295
- );
290
+ this.setParticipantCryptorEnabledForPublication(pub, participant.identity);
296
291
  });
297
292
  });
298
293
  }
@@ -482,6 +477,29 @@ export class E2EEManager
482
477
  this.worker.postMessage(msg);
483
478
  }
484
479
 
480
+ /**
481
+ * Derive the participant's encryption state from one of its publications.
482
+ * Publications without trackInfo are skipped rather than thrown on: throwing
483
+ * inside the forEach above would leave every remaining participant without an
484
+ * encryption state, and a cryptor with unknown state can no longer decrypt.
485
+ */
486
+ private setParticipantCryptorEnabledForPublication(
487
+ pub: TrackPublication,
488
+ participantIdentity: string,
489
+ ) {
490
+ if (!pub.trackInfo) {
491
+ log.warn('skipping e2ee enabled update for publication without trackInfo', {
492
+ participant: participantIdentity,
493
+ trackSid: pub.trackSid,
494
+ });
495
+ return;
496
+ }
497
+ this.setParticipantCryptorEnabled(
498
+ pub.trackInfo.encryption !== Encryption_Type.NONE,
499
+ participantIdentity,
500
+ );
501
+ }
502
+
485
503
  private setupE2EEReceiver(track: RemoteTrack, remoteId: string, trackInfo?: TrackInfo) {
486
504
  if (!track.receiver) {
487
505
  return;
@@ -541,21 +559,27 @@ export class E2EEManager
541
559
  codec,
542
560
  hasPacketTrailer,
543
561
  };
544
- // @ts-ignore
545
562
  receiver.transform = new RTCRtpScriptTransform(this.worker, options);
546
563
  } else {
547
- if (E2EE_FLAG in receiver && codec) {
548
- // update track-specific state when the transceiver is reused
564
+ if (E2EE_FLAG in receiver && E2EE_TRACK_ID in receiver) {
565
+ // The transceiver is being reused for a new track. We cannot set up a new
566
+ // pipeline from here: this receiver's encoded streams were transferred to
567
+ // the worker on first setup and a transferred stream can't be transferred
568
+ // again, while createEncodedStreams() may only be called once per receiver.
569
+ // So hand the worker the new track/participant and let it re-point (and if
570
+ // necessary rebuild) the cryptor that still owns those streams.
549
571
  const msg: UpdateCodecMessage = {
550
572
  kind: 'updateCodec',
551
573
  data: {
552
574
  trackId,
575
+ previousTrackId: receiver[E2EE_TRACK_ID] as string,
553
576
  codec,
554
577
  participantIdentity,
555
578
  hasPacketTrailer,
556
579
  },
557
580
  };
558
581
  this.worker.postMessage(msg);
582
+ receiver[E2EE_TRACK_ID] = trackId;
559
583
  return;
560
584
  }
561
585
  // @ts-ignore
@@ -582,7 +606,6 @@ export class E2EEManager
582
606
  trackId: trackId,
583
607
  codec,
584
608
  participantIdentity: participantIdentity,
585
- isReuse: E2EE_FLAG in receiver,
586
609
  hasPacketTrailer,
587
610
  },
588
611
  };
@@ -591,6 +614,8 @@ export class E2EEManager
591
614
 
592
615
  // @ts-ignore
593
616
  receiver[E2EE_FLAG] = true;
617
+ // @ts-ignore
618
+ receiver[E2EE_TRACK_ID] = trackId;
594
619
  }
595
620
 
596
621
  /**
@@ -636,7 +661,6 @@ export class E2EEManager
636
661
  codec,
637
662
  trackId,
638
663
  participantIdentity: this.room.localParticipant.identity,
639
- isReuse: false,
640
664
  hasPacketTrailer: hasFrameMetadataPublishOptions(frameMetadata),
641
665
  packetTrailer: frameMetadata,
642
666
  },
@@ -29,6 +29,12 @@ export const IV_LENGTH = 12;
29
29
  // flag set to indicate that e2ee has been setup for sender/receiver;
30
30
  export const E2EE_FLAG = 'lk_e2ee';
31
31
 
32
+ /**
33
+ * trackId a receiver's/sender's encoded stream pipeline was last set up for.
34
+ * Needed to recover the right cryptor when a transceiver gets reused.
35
+ */
36
+ export const E2EE_TRACK_ID = 'lk_e2ee_track_id';
37
+
32
38
  export const SALT = 'LKFrameEncryptionKey';
33
39
 
34
40
  export const KEY_PROVIDER_DEFAULTS: KeyProviderOptions = {