livekit-client 2.5.0 → 2.5.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 (61) hide show
  1. package/README.md +4 -0
  2. package/dist/livekit-client.e2ee.worker.js +1 -1
  3. package/dist/livekit-client.e2ee.worker.js.map +1 -1
  4. package/dist/livekit-client.e2ee.worker.mjs +4 -2
  5. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  6. package/dist/livekit-client.esm.mjs +517 -269
  7. package/dist/livekit-client.esm.mjs.map +1 -1
  8. package/dist/livekit-client.umd.js +1 -1
  9. package/dist/livekit-client.umd.js.map +1 -1
  10. package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
  11. package/dist/src/room/PCTransport.d.ts.map +1 -1
  12. package/dist/src/room/PCTransportManager.d.ts +1 -0
  13. package/dist/src/room/PCTransportManager.d.ts.map +1 -1
  14. package/dist/src/room/Room.d.ts +8 -3
  15. package/dist/src/room/Room.d.ts.map +1 -1
  16. package/dist/src/room/events.d.ts +10 -2
  17. package/dist/src/room/events.d.ts.map +1 -1
  18. package/dist/src/room/participant/LocalParticipant.d.ts +4 -1
  19. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  20. package/dist/src/room/participant/Participant.d.ts +1 -0
  21. package/dist/src/room/participant/Participant.d.ts.map +1 -1
  22. package/dist/src/room/timers.d.ts +4 -4
  23. package/dist/src/room/timers.d.ts.map +1 -1
  24. package/dist/src/room/track/LocalTrack.d.ts +1 -1
  25. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  26. package/dist/src/room/track/create.d.ts +7 -0
  27. package/dist/src/room/track/create.d.ts.map +1 -1
  28. package/dist/src/room/track/options.d.ts +1 -1
  29. package/dist/src/room/types.d.ts +2 -0
  30. package/dist/src/room/types.d.ts.map +1 -1
  31. package/dist/src/room/utils.d.ts +1 -1
  32. package/dist/src/room/utils.d.ts.map +1 -1
  33. package/dist/ts4.2/src/room/PCTransportManager.d.ts +1 -0
  34. package/dist/ts4.2/src/room/Room.d.ts +8 -3
  35. package/dist/ts4.2/src/room/events.d.ts +10 -2
  36. package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +4 -1
  37. package/dist/ts4.2/src/room/participant/Participant.d.ts +1 -0
  38. package/dist/ts4.2/src/room/timers.d.ts +4 -4
  39. package/dist/ts4.2/src/room/track/LocalTrack.d.ts +1 -1
  40. package/dist/ts4.2/src/room/track/create.d.ts +7 -0
  41. package/dist/ts4.2/src/room/track/options.d.ts +1 -1
  42. package/dist/ts4.2/src/room/types.d.ts +2 -0
  43. package/dist/ts4.2/src/room/utils.d.ts +1 -1
  44. package/package.json +9 -9
  45. package/src/connectionHelper/checks/Checker.ts +1 -1
  46. package/src/e2ee/worker/FrameCryptor.ts +3 -1
  47. package/src/room/PCTransport.ts +3 -1
  48. package/src/room/PCTransportManager.ts +12 -4
  49. package/src/room/RTCEngine.ts +1 -1
  50. package/src/room/Room.ts +69 -7
  51. package/src/room/events.ts +10 -0
  52. package/src/room/participant/LocalParticipant.ts +126 -84
  53. package/src/room/participant/Participant.ts +1 -0
  54. package/src/room/timers.ts +15 -6
  55. package/src/room/track/LocalTrack.ts +4 -2
  56. package/src/room/track/LocalVideoTrack.test.ts +60 -0
  57. package/src/room/track/LocalVideoTrack.ts +1 -1
  58. package/src/room/track/create.ts +27 -8
  59. package/src/room/track/options.ts +1 -1
  60. package/src/room/types.ts +2 -0
  61. package/src/room/utils.ts +10 -0
@@ -4,13 +4,22 @@
4
4
  * that the timer fires on time.
5
5
  */
6
6
  export default class CriticalTimers {
7
- // eslint-disable-next-line @typescript-eslint/no-implied-eval
8
- static setTimeout = (...args: Parameters<typeof setTimeout>) => setTimeout(...args);
7
+ static setTimeout: (...args: Parameters<typeof setTimeout>) => ReturnType<typeof setTimeout> = (
8
+ ...args: Parameters<typeof setTimeout>
9
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
10
+ ) => setTimeout(...args);
9
11
 
10
- // eslint-disable-next-line @typescript-eslint/no-implied-eval
11
- static setInterval = (...args: Parameters<typeof setInterval>) => setInterval(...args);
12
+ static setInterval: (...args: Parameters<typeof setInterval>) => ReturnType<typeof setInterval> =
13
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
14
+ (...args: Parameters<typeof setInterval>) => setInterval(...args);
12
15
 
13
- static clearTimeout = (...args: Parameters<typeof clearTimeout>) => clearTimeout(...args);
16
+ static clearTimeout: (
17
+ ...args: Parameters<typeof clearTimeout>
18
+ ) => ReturnType<typeof clearTimeout> = (...args: Parameters<typeof clearTimeout>) =>
19
+ clearTimeout(...args);
14
20
 
15
- static clearInterval = (...args: Parameters<typeof clearInterval>) => clearInterval(...args);
21
+ static clearInterval: (
22
+ ...args: Parameters<typeof clearInterval>
23
+ ) => ReturnType<typeof clearInterval> = (...args: Parameters<typeof clearInterval>) =>
24
+ clearInterval(...args);
16
25
  }
@@ -215,7 +215,7 @@ export default abstract class LocalTrack<
215
215
  /**
216
216
  * @returns DeviceID of the device that is currently being used for this track
217
217
  */
218
- async getDeviceId(): Promise<string | undefined> {
218
+ async getDeviceId(normalize = true): Promise<string | undefined> {
219
219
  // screen share doesn't have a usable device id
220
220
  if (this.source === Track.Source.ScreenShare) {
221
221
  return;
@@ -223,7 +223,9 @@ export default abstract class LocalTrack<
223
223
  const { deviceId, groupId } = this._mediaStreamTrack.getSettings();
224
224
  const kind = this.kind === Track.Kind.Audio ? 'audioinput' : 'videoinput';
225
225
 
226
- return DeviceManager.getInstance().normalizeDeviceId(kind, deviceId, groupId);
226
+ return normalize
227
+ ? DeviceManager.getInstance().normalizeDeviceId(kind, deviceId, groupId)
228
+ : deviceId;
227
229
  }
228
230
 
229
231
  async mute() {
@@ -47,6 +47,66 @@ describe('videoLayersFromEncodings', () => {
47
47
  expect(layers[2].height).toBe(720);
48
48
  });
49
49
 
50
+ it('returns qualities starting from lowest for SVC', () => {
51
+ const layers = videoLayersFromEncodings(
52
+ 1280,
53
+ 720,
54
+ [
55
+ {
56
+ /** @ts-ignore */
57
+ scalabilityMode: 'L2T2',
58
+ },
59
+ ],
60
+ true,
61
+ );
62
+
63
+ expect(layers).toHaveLength(2);
64
+ expect(layers[0].quality).toBe(VideoQuality.MEDIUM);
65
+ expect(layers[0].width).toBe(1280);
66
+ expect(layers[1].quality).toBe(VideoQuality.LOW);
67
+ expect(layers[1].width).toBe(640);
68
+ });
69
+
70
+ it('returns qualities starting from lowest for SVC (three layers)', () => {
71
+ const layers = videoLayersFromEncodings(
72
+ 1280,
73
+ 720,
74
+ [
75
+ {
76
+ /** @ts-ignore */
77
+ scalabilityMode: 'L3T3',
78
+ },
79
+ ],
80
+ true,
81
+ );
82
+
83
+ expect(layers).toHaveLength(3);
84
+ expect(layers[0].quality).toBe(VideoQuality.HIGH);
85
+ expect(layers[0].width).toBe(1280);
86
+ expect(layers[1].quality).toBe(VideoQuality.MEDIUM);
87
+ expect(layers[1].width).toBe(640);
88
+ expect(layers[2].quality).toBe(VideoQuality.LOW);
89
+ expect(layers[2].width).toBe(320);
90
+ });
91
+
92
+ it('returns qualities starting from lowest for SVC (single layer)', () => {
93
+ const layers = videoLayersFromEncodings(
94
+ 1280,
95
+ 720,
96
+ [
97
+ {
98
+ /** @ts-ignore */
99
+ scalabilityMode: 'L1T2',
100
+ },
101
+ ],
102
+ true,
103
+ );
104
+
105
+ expect(layers).toHaveLength(1);
106
+ expect(layers[0].quality).toBe(VideoQuality.LOW);
107
+ expect(layers[0].width).toBe(1280);
108
+ });
109
+
50
110
  it('handles portrait', () => {
51
111
  const layers = videoLayersFromEncodings(720, 1280, [
52
112
  {
@@ -607,7 +607,7 @@ export function videoLayersFromEncodings(
607
607
  for (let i = 0; i < sm.spatial; i += 1) {
608
608
  layers.push(
609
609
  new VideoLayer({
610
- quality: VideoQuality.HIGH - i,
610
+ quality: Math.min(VideoQuality.HIGH, sm.spatial - 1) - i,
611
611
  width: Math.ceil(width / resRatio ** i),
612
612
  height: Math.ceil(height / resRatio ** i),
613
613
  bitrate: encodings[0].maxBitrate
@@ -14,13 +14,32 @@ import type {
14
14
  VideoCaptureOptions,
15
15
  } from './options';
16
16
  import { ScreenSharePresets } from './options';
17
- import type { TrackProcessor } from './processor/types';
17
+ import type {
18
+ AudioProcessorOptions,
19
+ TrackProcessor,
20
+ VideoProcessorOptions,
21
+ } from './processor/types';
18
22
  import {
19
23
  constraintsForOptions,
20
24
  mergeDefaultOptions,
21
25
  screenCaptureToDisplayMediaStreamOptions,
22
26
  } from './utils';
23
27
 
28
+ /** @internal */
29
+ export function extractProcessorsFromOptions(options: CreateLocalTracksOptions) {
30
+ let audioProcessor: TrackProcessor<Track.Kind.Audio, AudioProcessorOptions> | undefined;
31
+ let videoProcessor: TrackProcessor<Track.Kind.Video, VideoProcessorOptions> | undefined;
32
+
33
+ if (typeof options.audio === 'object' && options.audio.processor) {
34
+ audioProcessor = options.audio.processor;
35
+ }
36
+ if (typeof options.video === 'object' && options.video.processor) {
37
+ videoProcessor = options.video.processor;
38
+ }
39
+
40
+ return { audioProcessor, videoProcessor };
41
+ }
42
+
24
43
  /**
25
44
  * Creates a local video and audio track at the same time. When acquiring both
26
45
  * audio and video tracks together, it'll display a single permission prompt to
@@ -35,6 +54,7 @@ export async function createLocalTracks(
35
54
  options.audio ??= true;
36
55
  options.video ??= true;
37
56
 
57
+ const { audioProcessor, videoProcessor } = extractProcessorsFromOptions(options);
38
58
  const opts = mergeDefaultOptions(options, audioDefaults, videoDefaults);
39
59
  const constraints = constraintsForOptions(opts);
40
60
 
@@ -55,7 +75,7 @@ export async function createLocalTracks(
55
75
  return Promise.all(
56
76
  stream.getTracks().map(async (mediaStreamTrack) => {
57
77
  const isAudio = mediaStreamTrack.kind === 'audio';
58
- let trackOptions = isAudio ? options!.audio : options!.video;
78
+ let trackOptions = isAudio ? opts!.audio : opts!.video;
59
79
  if (typeof trackOptions === 'boolean' || !trackOptions) {
60
80
  trackOptions = {};
61
81
  }
@@ -80,13 +100,12 @@ export async function createLocalTracks(
80
100
  track.source = Track.Source.Microphone;
81
101
  }
82
102
  track.mediaStream = stream;
83
- if (trackOptions.processor) {
84
- if (track instanceof LocalAudioTrack) {
85
- await track.setProcessor(trackOptions.processor as TrackProcessor<Track.Kind.Audio>);
86
- } else if (track instanceof LocalVideoTrack) {
87
- await track.setProcessor(trackOptions.processor as TrackProcessor<Track.Kind.Video>);
88
- }
103
+ if (track instanceof LocalAudioTrack && audioProcessor) {
104
+ await track.setProcessor(audioProcessor);
105
+ } else if (track instanceof LocalVideoTrack && videoProcessor) {
106
+ await track.setProcessor(videoProcessor);
89
107
  }
108
+
90
109
  return track;
91
110
  }),
92
111
  );
@@ -64,7 +64,7 @@ export interface TrackPublishDefaults {
64
64
  simulcast?: boolean;
65
65
 
66
66
  /**
67
- * scalability mode for svc codecs, defaults to 'L3T3'.
67
+ * scalability mode for svc codecs, defaults to 'L3T3_KEY'.
68
68
  * for svc codecs, simulcast is disabled.
69
69
  */
70
70
  scalabilityMode?: ScalabilityMode;
package/src/room/types.ts CHANGED
@@ -65,4 +65,6 @@ export interface TranscriptionSegment {
65
65
  startTime: number;
66
66
  endTime: number;
67
67
  final: boolean;
68
+ firstReceivedTime: number;
69
+ lastReceivedTime: number;
68
70
  }
package/src/room/utils.ts CHANGED
@@ -532,8 +532,16 @@ export function toHttpUrl(url: string): string {
532
532
 
533
533
  export function extractTranscriptionSegments(
534
534
  transcription: TranscriptionModel,
535
+ firstReceivedTimesMap: Map<string, number>,
535
536
  ): TranscriptionSegment[] {
536
537
  return transcription.segments.map(({ id, text, language, startTime, endTime, final }) => {
538
+ const firstReceivedTime = firstReceivedTimesMap.get(id) ?? Date.now();
539
+ const lastReceivedTime = Date.now();
540
+ if (final) {
541
+ firstReceivedTimesMap.delete(id);
542
+ } else {
543
+ firstReceivedTimesMap.set(id, firstReceivedTime);
544
+ }
537
545
  return {
538
546
  id,
539
547
  text,
@@ -541,6 +549,8 @@ export function extractTranscriptionSegments(
541
549
  endTime: Number.parseInt(endTime.toString()),
542
550
  final,
543
551
  language,
552
+ firstReceivedTime,
553
+ lastReceivedTime,
544
554
  };
545
555
  });
546
556
  }