livekit-client 1.14.0 → 1.14.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) 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 +25 -44
  4. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  5. package/dist/livekit-client.esm.mjs +418 -206
  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/e2ee/E2eeManager.d.ts.map +1 -1
  10. package/dist/src/e2ee/utils.d.ts +0 -1
  11. package/dist/src/e2ee/utils.d.ts.map +1 -1
  12. package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
  13. package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts.map +1 -1
  14. package/dist/src/proto/livekit_models_pb.d.ts +87 -11
  15. package/dist/src/proto/livekit_models_pb.d.ts.map +1 -1
  16. package/dist/src/proto/livekit_rtc_pb.d.ts +0 -4
  17. package/dist/src/proto/livekit_rtc_pb.d.ts.map +1 -1
  18. package/dist/src/room/PCTransport.d.ts +20 -1
  19. package/dist/src/room/PCTransport.d.ts.map +1 -1
  20. package/dist/src/room/RTCEngine.d.ts +1 -1
  21. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  22. package/dist/src/room/Room.d.ts.map +1 -1
  23. package/dist/src/room/defaults.d.ts +1 -0
  24. package/dist/src/room/defaults.d.ts.map +1 -1
  25. package/dist/src/room/events.d.ts +1 -1
  26. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  27. package/dist/src/room/timers.d.ts +1 -1
  28. package/dist/src/room/timers.d.ts.map +1 -1
  29. package/dist/src/room/track/LocalAudioTrack.d.ts +1 -1
  30. package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
  31. package/dist/src/room/track/LocalTrack.d.ts +3 -3
  32. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  33. package/dist/src/room/track/LocalVideoTrack.d.ts +2 -1
  34. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
  35. package/dist/src/room/track/RemoteTrack.d.ts.map +1 -1
  36. package/dist/src/room/track/options.d.ts +6 -1
  37. package/dist/src/room/track/options.d.ts.map +1 -1
  38. package/dist/src/room/track/utils.d.ts +2 -1
  39. package/dist/src/room/track/utils.d.ts.map +1 -1
  40. package/dist/src/room/utils.d.ts.map +1 -1
  41. package/dist/src/utils/cloneDeep.d.ts +2 -0
  42. package/dist/src/utils/cloneDeep.d.ts.map +1 -0
  43. package/dist/src/version.d.ts +1 -1
  44. package/dist/src/version.d.ts.map +1 -1
  45. package/dist/ts4.2/src/e2ee/utils.d.ts +0 -1
  46. package/dist/ts4.2/src/proto/livekit_models_pb.d.ts +87 -11
  47. package/dist/ts4.2/src/proto/livekit_rtc_pb.d.ts +0 -4
  48. package/dist/ts4.2/src/room/PCTransport.d.ts +20 -1
  49. package/dist/ts4.2/src/room/RTCEngine.d.ts +1 -1
  50. package/dist/ts4.2/src/room/defaults.d.ts +1 -0
  51. package/dist/ts4.2/src/room/events.d.ts +1 -1
  52. package/dist/ts4.2/src/room/timers.d.ts +1 -1
  53. package/dist/ts4.2/src/room/track/LocalAudioTrack.d.ts +1 -1
  54. package/dist/ts4.2/src/room/track/LocalTrack.d.ts +3 -3
  55. package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +2 -1
  56. package/dist/ts4.2/src/room/track/options.d.ts +6 -1
  57. package/dist/ts4.2/src/room/track/utils.d.ts +1 -0
  58. package/dist/ts4.2/src/utils/cloneDeep.d.ts +2 -0
  59. package/dist/ts4.2/src/version.d.ts +1 -1
  60. package/package.json +14 -14
  61. package/src/connectionHelper/checks/webrtc.ts +1 -1
  62. package/src/e2ee/E2eeManager.ts +2 -1
  63. package/src/e2ee/utils.ts +0 -10
  64. package/src/e2ee/worker/FrameCryptor.ts +13 -14
  65. package/src/e2ee/worker/ParticipantKeyHandler.ts +4 -5
  66. package/src/e2ee/worker/e2ee.worker.ts +3 -1
  67. package/src/proto/livekit_models_pb.ts +140 -15
  68. package/src/proto/livekit_rtc_pb.ts +1 -7
  69. package/src/room/PCTransport.ts +116 -1
  70. package/src/room/RTCEngine.ts +49 -85
  71. package/src/room/Room.ts +15 -11
  72. package/src/room/defaults.ts +4 -2
  73. package/src/room/events.ts +1 -1
  74. package/src/room/participant/LocalParticipant.ts +45 -56
  75. package/src/room/track/LocalAudioTrack.ts +1 -1
  76. package/src/room/track/LocalTrack.ts +8 -5
  77. package/src/room/track/LocalVideoTrack.ts +2 -1
  78. package/src/room/track/RemoteTrack.ts +8 -6
  79. package/src/room/track/options.ts +7 -7
  80. package/src/room/track/utils.ts +17 -8
  81. package/src/room/utils.ts +3 -0
  82. package/src/utils/cloneDeep.test.ts +54 -0
  83. package/src/utils/cloneDeep.ts +11 -0
  84. package/src/version.ts +1 -1
@@ -34,7 +34,7 @@ export default abstract class LocalTrack extends Track {
34
34
 
35
35
  protected processorElement?: HTMLMediaElement;
36
36
 
37
- protected processor?: TrackProcessor<typeof this.kind>;
37
+ protected processor?: TrackProcessor<this['kind']>;
38
38
 
39
39
  protected processorLock: Mutex;
40
40
 
@@ -163,6 +163,12 @@ export default abstract class LocalTrack extends Track {
163
163
  throw new Error('cannot get dimensions for audio tracks');
164
164
  }
165
165
 
166
+ if (getBrowser()?.os === 'iOS') {
167
+ // browsers report wrong initial resolution on iOS.
168
+ // when slightly delaying the call to .getSettings(), the correct resolution is being reported
169
+ await sleep(10);
170
+ }
171
+
166
172
  const started = Date.now();
167
173
  while (Date.now() - started < timeout) {
168
174
  const dims = this.dimensions;
@@ -396,10 +402,7 @@ export default abstract class LocalTrack extends Track {
396
402
  * @param showProcessedStreamLocally
397
403
  * @returns
398
404
  */
399
- async setProcessor(
400
- processor: TrackProcessor<typeof this.kind>,
401
- showProcessedStreamLocally = true,
402
- ) {
405
+ async setProcessor(processor: TrackProcessor<this['kind']>, showProcessedStreamLocally = true) {
403
406
  const unlock = await this.processorLock.lock();
404
407
  try {
405
408
  log.debug('setting up processor');
@@ -284,7 +284,8 @@ export default class LocalVideoTrack extends LocalTrack {
284
284
 
285
285
  /**
286
286
  * @internal
287
- * Sets codecs that should be publishing
287
+ * Sets codecs that should be publishing, returns new codecs that have not yet
288
+ * been published
288
289
  */
289
290
  async setPublishingCodecs(codecs: SubscribedCodec[]): Promise<VideoCodec[]> {
290
291
  log.debug('setting publishing codecs', {
@@ -29,14 +29,16 @@ export default abstract class RemoteTrack extends Track {
29
29
  /** @internal */
30
30
  setMediaStream(stream: MediaStream) {
31
31
  // this is needed to determine when the track is finished
32
- // we send each track down in its own MediaStream, so we can assume the
33
- // current track is the only one that can be removed.
34
32
  this.mediaStream = stream;
35
- stream.onremovetrack = () => {
36
- this.receiver = undefined;
37
- this._currentBitrate = 0;
38
- this.emit(TrackEvent.Ended, this);
33
+ const onRemoveTrack = (event: MediaStreamTrackEvent) => {
34
+ if (event.track === this._mediaStreamTrack) {
35
+ stream.removeEventListener('removetrack', onRemoveTrack);
36
+ this.receiver = undefined;
37
+ this._currentBitrate = 0;
38
+ this.emit(TrackEvent.Ended, this);
39
+ }
39
40
  };
41
+ stream.addEventListener('removetrack', onRemoveTrack);
40
42
  }
41
43
 
42
44
  start() {
@@ -109,6 +109,13 @@ export interface TrackPublishOptions extends TrackPublishDefaults {
109
109
  * Source of track, camera, microphone, or screen
110
110
  */
111
111
  source?: Track.Source;
112
+
113
+ /**
114
+ * Set stream name for the track. Audio and video tracks with the same stream name
115
+ * will be placed in the same `MediaStream` and offer better synchronization.
116
+ * By default, camera and microphone will be placed in a stream; as would screen_share and screen_share_audio
117
+ */
118
+ stream?: string;
112
119
  }
113
120
 
114
121
  export interface CreateLocalTracksOptions {
@@ -294,13 +301,6 @@ export function isBackupCodec(codec: string): codec is BackupVideoCodec {
294
301
  return !!backupCodecs.find((backup) => backup === codec);
295
302
  }
296
303
 
297
- export function isCodecEqual(c1: string | undefined, c2: string | undefined): boolean {
298
- return (
299
- c1?.toLowerCase().replace(/audio\/|video\//y, '') ===
300
- c2?.toLowerCase().replace(/audio\/|video\//y, '')
301
- );
302
- }
303
-
304
304
  /**
305
305
  * scalability modes for svc.
306
306
  */
@@ -1,10 +1,13 @@
1
+ import { cloneDeep } from '../../utils/cloneDeep';
1
2
  import { isSafari, sleep } from '../utils';
2
3
  import { Track } from './Track';
3
- import type {
4
- AudioCaptureOptions,
5
- CreateLocalTracksOptions,
6
- ScreenShareCaptureOptions,
7
- VideoCaptureOptions,
4
+ import {
5
+ type AudioCaptureOptions,
6
+ type CreateLocalTracksOptions,
7
+ type ScreenShareCaptureOptions,
8
+ type VideoCaptureOptions,
9
+ VideoCodec,
10
+ videoCodecs,
8
11
  } from './options';
9
12
  import type { AudioTrack } from './types';
10
13
 
@@ -13,9 +16,7 @@ export function mergeDefaultOptions(
13
16
  audioDefaults?: AudioCaptureOptions,
14
17
  videoDefaults?: VideoCaptureOptions,
15
18
  ): CreateLocalTracksOptions {
16
- const opts: CreateLocalTracksOptions = {
17
- ...options,
18
- };
19
+ const opts: CreateLocalTracksOptions = cloneDeep(options) ?? {};
19
20
  if (opts.audio === true) opts.audio = {};
20
21
  if (opts.video === true) opts.video = {};
21
22
 
@@ -181,3 +182,11 @@ export function screenCaptureToDisplayMediaStreamOptions(
181
182
  systemAudio: options.systemAudio,
182
183
  };
183
184
  }
185
+
186
+ export function mimeTypeToVideoCodecString(mimeType: string) {
187
+ const codec = mimeType.split('/')[1].toLowerCase() as VideoCodec;
188
+ if (!videoCodecs.includes(codec)) {
189
+ throw Error(`Video codec not supported: ${codec}`);
190
+ }
191
+ return codec;
192
+ }
package/src/room/utils.ts CHANGED
@@ -61,6 +61,9 @@ export function supportsAV1(): boolean {
61
61
 
62
62
  export function supportsVP9(): boolean {
63
63
  if (!('getCapabilities' in RTCRtpSender)) {
64
+ return false;
65
+ }
66
+ if (isFireFox()) {
64
67
  // technically speaking FireFox supports VP9, but SVC publishing is broken
65
68
  // https://bugzilla.mozilla.org/show_bug.cgi?id=1633876
66
69
  return false;
@@ -0,0 +1,54 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import { cloneDeep } from './cloneDeep';
3
+
4
+ describe('cloneDeep', () => {
5
+ beforeEach(() => {
6
+ global.structuredClone = vi.fn((val) => {
7
+ return JSON.parse(JSON.stringify(val));
8
+ });
9
+ });
10
+
11
+ afterEach(() => {
12
+ vi.restoreAllMocks();
13
+ });
14
+
15
+ it('should clone a simple object', () => {
16
+ const structuredCloneSpy = vi.spyOn(global, 'structuredClone');
17
+
18
+ const original = { name: 'John', age: 30 };
19
+ const cloned = cloneDeep(original);
20
+
21
+ expect(cloned).toEqual(original);
22
+ expect(cloned).not.toBe(original);
23
+ expect(structuredCloneSpy).toHaveBeenCalledTimes(1);
24
+ });
25
+
26
+ it('should clone an object with nested properties', () => {
27
+ const structuredCloneSpy = vi.spyOn(global, 'structuredClone');
28
+
29
+ const original = { name: 'John', age: 30, children: [{ name: 'Mark', age: 7 }] };
30
+ const cloned = cloneDeep(original);
31
+
32
+ expect(cloned).toEqual(original);
33
+ expect(cloned).not.toBe(original);
34
+ expect(cloned?.children).not.toBe(original.children);
35
+ expect(structuredCloneSpy).toHaveBeenCalledTimes(1);
36
+ });
37
+
38
+ it('should use JSON namespace as a fallback', () => {
39
+ const structuredCloneSpy = vi.spyOn(global, 'structuredClone');
40
+ const serializeSpy = vi.spyOn(JSON, 'stringify');
41
+ const deserializeSpy = vi.spyOn(JSON, 'parse');
42
+
43
+ global.structuredClone = undefined as any;
44
+
45
+ const original = { name: 'John', age: 30 };
46
+ const cloned = cloneDeep(original);
47
+
48
+ expect(cloned).toEqual(original);
49
+ expect(cloned).not.toBe(original);
50
+ expect(structuredCloneSpy).not.toHaveBeenCalled();
51
+ expect(serializeSpy).toHaveBeenCalledTimes(1);
52
+ expect(deserializeSpy).toHaveBeenCalledTimes(1);
53
+ });
54
+ });
@@ -0,0 +1,11 @@
1
+ export function cloneDeep<T>(value: T) {
2
+ if (typeof value === 'undefined') {
3
+ return;
4
+ }
5
+
6
+ if (typeof structuredClone === 'function') {
7
+ return structuredClone(value);
8
+ } else {
9
+ return JSON.parse(JSON.stringify(value)) as T;
10
+ }
11
+ }
package/src/version.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { version as v } from '../package.json';
2
2
 
3
3
  export const version = v;
4
- export const protocolVersion = 9;
4
+ export const protocolVersion = 10;