livekit-client 2.19.2 → 2.20.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 (123) 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 +23 -23
  4. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  5. package/dist/livekit-client.esm.mjs +179 -111
  6. package/dist/livekit-client.esm.mjs.map +1 -1
  7. package/dist/livekit-client.fm.worker.js +2 -0
  8. package/dist/{livekit-client.pt.worker.js.map → livekit-client.fm.worker.js.map} +1 -1
  9. package/dist/{livekit-client.pt.worker.mjs → livekit-client.fm.worker.mjs} +4 -4
  10. package/dist/livekit-client.fm.worker.mjs.map +1 -0
  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.map +1 -1
  14. package/dist/src/e2ee/E2eeManager.d.ts +1 -1
  15. package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
  16. package/dist/src/e2ee/types.d.ts +5 -5
  17. package/dist/src/e2ee/types.d.ts.map +1 -1
  18. package/dist/src/e2ee/worker/FrameCryptor.d.ts +8 -8
  19. package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
  20. package/dist/src/{packetTrailer/PacketTrailerManager.d.ts → frameMetadata/FrameMetadataManager.d.ts} +8 -4
  21. package/dist/src/{packetTrailer/PacketTrailerManager.d.ts.map → frameMetadata/FrameMetadataManager.d.ts.map} +1 -1
  22. package/dist/src/{packetTrailer/packetTrailer.d.ts → frameMetadata/frameMetadata.d.ts} +7 -7
  23. package/dist/src/frameMetadata/frameMetadata.d.ts.map +1 -0
  24. package/dist/src/{packetTrailer → frameMetadata}/types.d.ts +10 -6
  25. package/dist/src/frameMetadata/types.d.ts.map +1 -0
  26. package/dist/src/frameMetadata/utils.d.ts +9 -0
  27. package/dist/src/{packetTrailer → frameMetadata}/utils.d.ts.map +1 -1
  28. package/dist/src/frameMetadata/worker/frameMetadata.worker.d.ts +2 -0
  29. package/dist/src/frameMetadata/worker/frameMetadata.worker.d.ts.map +1 -0
  30. package/dist/src/index.d.ts +10 -2
  31. package/dist/src/index.d.ts.map +1 -1
  32. package/dist/src/options.d.ts +8 -4
  33. package/dist/src/options.d.ts.map +1 -1
  34. package/dist/src/room/PCTransport.d.ts +1 -0
  35. package/dist/src/room/PCTransport.d.ts.map +1 -1
  36. package/dist/src/room/PCTransportManager.d.ts +1 -0
  37. package/dist/src/room/PCTransportManager.d.ts.map +1 -1
  38. package/dist/src/room/RTCEngine.d.ts +3 -1
  39. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  40. package/dist/src/room/Room.d.ts +2 -2
  41. package/dist/src/room/Room.d.ts.map +1 -1
  42. package/dist/src/room/participant/LocalParticipant.d.ts +2 -2
  43. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  44. package/dist/src/room/participant/publishUtils.d.ts.map +1 -1
  45. package/dist/src/room/token-source/TokenSource.d.ts.map +1 -1
  46. package/dist/src/room/token-source/types.d.ts +1 -0
  47. package/dist/src/room/token-source/types.d.ts.map +1 -1
  48. package/dist/src/room/token-source/utils.d.ts.map +1 -1
  49. package/dist/src/room/track/FrameMetadataExtractor.d.ts +19 -0
  50. package/dist/src/room/track/FrameMetadataExtractor.d.ts.map +1 -0
  51. package/dist/src/room/track/RemoteVideoTrack.d.ts +7 -7
  52. package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
  53. package/dist/src/room/track/options.d.ts +17 -5
  54. package/dist/src/room/track/options.d.ts.map +1 -1
  55. package/dist/ts4.2/e2ee/E2eeManager.d.ts +1 -1
  56. package/dist/ts4.2/e2ee/types.d.ts +5 -5
  57. package/dist/ts4.2/e2ee/worker/FrameCryptor.d.ts +8 -8
  58. package/dist/ts4.2/{packetTrailer/PacketTrailerManager.d.ts → frameMetadata/FrameMetadataManager.d.ts} +8 -4
  59. package/dist/ts4.2/{packetTrailer/packetTrailer.d.ts → frameMetadata/frameMetadata.d.ts} +7 -7
  60. package/dist/ts4.2/{packetTrailer → frameMetadata}/types.d.ts +10 -6
  61. package/dist/ts4.2/frameMetadata/utils.d.ts +9 -0
  62. package/dist/ts4.2/frameMetadata/worker/frameMetadata.worker.d.ts +2 -0
  63. package/dist/ts4.2/index.d.ts +9 -3
  64. package/dist/ts4.2/options.d.ts +8 -4
  65. package/dist/ts4.2/room/PCTransport.d.ts +1 -0
  66. package/dist/ts4.2/room/PCTransportManager.d.ts +1 -0
  67. package/dist/ts4.2/room/RTCEngine.d.ts +3 -1
  68. package/dist/ts4.2/room/Room.d.ts +2 -2
  69. package/dist/ts4.2/room/participant/LocalParticipant.d.ts +2 -2
  70. package/dist/ts4.2/room/token-source/types.d.ts +1 -0
  71. package/dist/ts4.2/room/track/FrameMetadataExtractor.d.ts +19 -0
  72. package/dist/ts4.2/room/track/RemoteVideoTrack.d.ts +7 -7
  73. package/dist/ts4.2/room/track/options.d.ts +17 -5
  74. package/package.json +23 -18
  75. package/src/api/SignalClient.test.ts +4 -4
  76. package/src/api/SignalClient.ts +7 -3
  77. package/src/api/WebSocketStream.test.ts +7 -7
  78. package/src/e2ee/E2eeManager.ts +13 -11
  79. package/src/e2ee/types.ts +5 -5
  80. package/src/e2ee/worker/FrameCryptor.test.ts +5 -5
  81. package/src/e2ee/worker/FrameCryptor.ts +27 -23
  82. package/src/e2ee/worker/e2ee.worker.ts +5 -5
  83. package/src/e2ee/worker/tsconfig.json +4 -1
  84. package/src/{packetTrailer/PacketTrailerManager.test.ts → frameMetadata/FrameMetadataManager.test.ts} +10 -8
  85. package/src/{packetTrailer/PacketTrailerManager.ts → frameMetadata/FrameMetadataManager.ts} +21 -15
  86. package/src/{packetTrailer/packetTrailer.test.ts → frameMetadata/frameMetadata.test.ts} +1 -1
  87. package/src/{packetTrailer/packetTrailer.ts → frameMetadata/frameMetadata.ts} +9 -9
  88. package/src/{packetTrailer → frameMetadata}/types.ts +12 -6
  89. package/src/{packetTrailer → frameMetadata}/utils.test.ts +19 -19
  90. package/src/{packetTrailer → frameMetadata}/utils.ts +11 -11
  91. package/src/{packetTrailer/worker/packetTrailer.worker.ts → frameMetadata/worker/frameMetadata.worker.ts} +5 -5
  92. package/src/{packetTrailer → frameMetadata}/worker/tsconfig.json +4 -1
  93. package/src/index.ts +13 -2
  94. package/src/options.ts +9 -4
  95. package/src/room/PCTransport.ts +4 -0
  96. package/src/room/PCTransportManager.ts +4 -0
  97. package/src/room/RTCEngine.test.ts +143 -9
  98. package/src/room/RTCEngine.ts +111 -31
  99. package/src/room/Room.ts +10 -10
  100. package/src/room/participant/LocalParticipant.test.ts +19 -19
  101. package/src/room/participant/LocalParticipant.ts +21 -16
  102. package/src/room/participant/publishUtils.test.ts +6 -0
  103. package/src/room/participant/publishUtils.ts +4 -1
  104. package/src/room/rpc/client/RpcClientManager.ts +1 -1
  105. package/src/room/rpc/server/RpcServerManager.ts +1 -1
  106. package/src/room/token-source/TokenSource.ts +9 -23
  107. package/src/room/token-source/types.ts +1 -0
  108. package/src/room/token-source/utils.ts +1 -0
  109. package/src/room/track/{PacketTrailerExtractor.ts → FrameMetadataExtractor.ts} +8 -8
  110. package/src/room/track/RemoteVideoTrack.ts +7 -11
  111. package/src/room/track/options.ts +19 -5
  112. package/dist/livekit-client.pt.worker.js +0 -2
  113. package/dist/livekit-client.pt.worker.mjs.map +0 -1
  114. package/dist/src/packetTrailer/packetTrailer.d.ts.map +0 -1
  115. package/dist/src/packetTrailer/types.d.ts.map +0 -1
  116. package/dist/src/packetTrailer/utils.d.ts +0 -9
  117. package/dist/src/packetTrailer/worker/packetTrailer.worker.d.ts +0 -2
  118. package/dist/src/packetTrailer/worker/packetTrailer.worker.d.ts.map +0 -1
  119. package/dist/src/room/track/PacketTrailerExtractor.d.ts +0 -19
  120. package/dist/src/room/track/PacketTrailerExtractor.d.ts.map +0 -1
  121. package/dist/ts4.2/packetTrailer/utils.d.ts +0 -9
  122. package/dist/ts4.2/packetTrailer/worker/packetTrailer.worker.d.ts +0 -2
  123. package/dist/ts4.2/room/track/PacketTrailerExtractor.d.ts +0 -19
@@ -1,7 +1,7 @@
1
- import type { PacketTrailerMetadata } from '../../packetTrailer/types';
1
+ import type { FrameMetadata } from '../../frameMetadata/types';
2
2
  import type { VideoReceiverStats } from '../stats';
3
3
  import type { LoggerOptions } from '../types';
4
- import type { PacketTrailerExtractor } from './PacketTrailerExtractor';
4
+ import type { FrameMetadataExtractor } from './FrameMetadataExtractor';
5
5
  import RemoteTrack from './RemoteTrack';
6
6
  import { Track } from './Track';
7
7
  import type { AdaptiveStreamSettings } from './types';
@@ -12,7 +12,7 @@ export default class RemoteVideoTrack extends RemoteTrack<Track.Kind.Video> {
12
12
  private lastVisible?;
13
13
  private lastDimensions?;
14
14
  /** @internal */
15
- packetTrailerExtractor?: PacketTrailerExtractor;
15
+ frameMetadataExtractor?: FrameMetadataExtractor;
16
16
  constructor(mediaTrack: MediaStreamTrack, sid: string, receiver: RTCRtpReceiver, adaptiveStreamSettings?: AdaptiveStreamSettings, loggerOptions?: LoggerOptions);
17
17
  get isAdaptiveStream(): boolean;
18
18
  /**
@@ -20,13 +20,13 @@ export default class RemoteVideoTrack extends RemoteTrack<Track.Kind.Video> {
20
20
  * Use with the `TrackEvent.TimeSyncUpdate` event to correlate displayed frames
21
21
  * with their capture-time metadata.
22
22
  *
23
- * Requires the room to be configured with the `packetTrailer` worker option
24
- * and the publishing track to have packet trailer features enabled.
23
+ * Requires the room to be configured with the `frameMetadata` worker option
24
+ * and the publishing track to have frame metadata features enabled.
25
25
  *
26
26
  */
27
- lookupFrameMetadata({ rtpTimestamp, }: {
27
+ lookupFrameMetadata({ rtpTimestamp }: {
28
28
  rtpTimestamp: number;
29
- }): PacketTrailerMetadata | undefined;
29
+ }): FrameMetadata | undefined;
30
30
  setStreamState(value: Track.StreamState): void;
31
31
  /**
32
32
  * Note: When using adaptiveStream, you need to use remoteVideoTrack.attach() to add the track to a HTMLVideoElement, otherwise your video tracks might never start
@@ -1,4 +1,4 @@
1
- import type { PacketTrailerPublishOptions } from '../../packetTrailer/types';
1
+ import type { FrameMetadataPublishOptions } from '../../frameMetadata/types';
2
2
  import type { Track } from './Track';
3
3
  import type { AudioProcessorOptions, TrackProcessor, VideoProcessorOptions } from './processor/types';
4
4
  export interface TrackPublishDefaults {
@@ -113,14 +113,18 @@ export interface TrackPublishDefaults {
113
113
  */
114
114
  preConnectBuffer?: boolean;
115
115
  /**
116
- * Packet trailer metadata to append to published video frames.
116
+ * Frame metadata to append to published video frames.
117
117
  *
118
- * Requires either room-level packet trailer worker configuration or E2EE,
119
- * because encoded frame transforms are used to write the trailer.
118
+ * Requires either room-level frame metadata worker configuration or E2EE,
119
+ * because encoded frame transforms are used to write the metadata.
120
120
  *
121
121
  * @experimental
122
122
  */
123
- packetTrailer?: PacketTrailerPublishOptions;
123
+ frameMetadata?: FrameMetadataPublishOptions;
124
+ /**
125
+ * @deprecated Use {@link TrackPublishDefaults.frameMetadata} instead.
126
+ */
127
+ packetTrailer?: FrameMetadataPublishOptions;
124
128
  }
125
129
  /**
126
130
  * Options when publishing tracks
@@ -248,6 +252,14 @@ export interface AudioCaptureOptions {
248
252
  * @see https://w3c.github.io/mediacapture-extensions/#voiceisolation-constraint
249
253
  */
250
254
  voiceIsolation?: ConstrainBoolean;
255
+ /**
256
+ * @experimental
257
+ * when capturing system/screen-share audio, excludes the local participant's own audio
258
+ * from the captured stream to prevent echo. Browser support is not widespread yet
259
+ * (as of mid 2026, Chromium-based browsers only).
260
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints/restrictOwnAudio
261
+ */
262
+ restrictOwnAudio?: ConstrainBoolean;
251
263
  /**
252
264
  * the sample rate or range of sample rates which are acceptable and/or required.
253
265
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "livekit-client",
3
- "version": "2.19.2",
3
+ "version": "2.20.0",
4
4
  "description": "JavaScript/TypeScript client SDK for LiveKit",
5
5
  "main": "./dist/livekit-client.umd.js",
6
6
  "unpkg": "./dist/livekit-client.umd.js",
@@ -17,9 +17,14 @@
17
17
  "require": "./dist/livekit-client.e2ee.worker.js"
18
18
  },
19
19
  "./packet-trailer-worker": {
20
- "types": "./dist/src/packetTrailer/worker/packetTrailer.worker.d.ts",
21
- "import": "./dist/livekit-client.pt.worker.mjs",
22
- "require": "./dist/livekit-client.pt.worker.js"
20
+ "types": "./dist/src/frameMetadata/worker/frameMetadata.worker.d.ts",
21
+ "import": "./dist/livekit-client.fm.worker.mjs",
22
+ "require": "./dist/livekit-client.fm.worker.js"
23
+ },
24
+ "./frame-metadata-worker": {
25
+ "types": "./dist/src/frameMetadata/worker/frameMetadata.worker.d.ts",
26
+ "import": "./dist/livekit-client.fm.worker.mjs",
27
+ "require": "./dist/livekit-client.fm.worker.js"
23
28
  }
24
29
  },
25
30
  "files": [
@@ -35,8 +40,8 @@
35
40
  "./dist/src/e2ee/worker/e2ee.worker.d.ts": [
36
41
  "./dist/ts4.2/e2ee/worker/e2ee.worker.d.ts"
37
42
  ],
38
- "./dist/src/packetTrailer/worker/packetTrailer.worker.d.ts": [
39
- "./dist/ts4.2/packetTrailer/worker/packetTrailer.worker.d.ts"
43
+ "./dist/src/frameMetadata/worker/frameMetadata.worker.d.ts": [
44
+ "./dist/ts4.2/frameMetadata/worker/frameMetadata.worker.d.ts"
40
45
  ]
41
46
  }
42
47
  },
@@ -45,7 +50,7 @@
45
50
  "license": "Apache-2.0",
46
51
  "dependencies": {
47
52
  "@livekit/mutex": "1.1.1",
48
- "@livekit/protocol": "1.45.8",
53
+ "@livekit/protocol": "1.46.6",
49
54
  "events": "^3.3.0",
50
55
  "jose": "^6.1.0",
51
56
  "loglevel": "^1.9.2",
@@ -58,8 +63,8 @@
58
63
  "@types/dom-mediacapture-record": "^1"
59
64
  },
60
65
  "devDependencies": {
61
- "@babel/core": "7.29.0",
62
- "@babel/preset-env": "7.29.5",
66
+ "@babel/core": "7.29.7",
67
+ "@babel/preset-env": "7.29.7",
63
68
  "@bufbuild/protoc-gen-es": "^1.10.0",
64
69
  "@changesets/cli": "2.31.0",
65
70
  "@eslint/js": "10.0.1",
@@ -69,16 +74,16 @@
69
74
  "@rollup/plugin-commonjs": "29.0.2",
70
75
  "@rollup/plugin-json": "6.1.0",
71
76
  "@rollup/plugin-node-resolve": "16.0.3",
72
- "@rollup/plugin-terser": "^0.4.4",
73
- "@size-limit/file": "^11.2.0",
74
- "@size-limit/webpack": "^11.2.0",
77
+ "@rollup/plugin-terser": "^1.0.0",
78
+ "@size-limit/file": "^12.1.0",
79
+ "@size-limit/webpack": "^12.1.0",
75
80
  "@stylistic/eslint-plugin": "^5.10.0",
76
- "@trivago/prettier-plugin-sort-imports": "^5.0.0",
81
+ "@trivago/prettier-plugin-sort-imports": "^6.0.2",
77
82
  "@types/events": "^3.0.3",
78
83
  "@types/sdp-transform": "2.15.0",
79
84
  "@types/ua-parser-js": "0.7.39",
80
- "@typescript-eslint/eslint-plugin": "8.59.3",
81
- "@typescript-eslint/parser": "8.59.3",
85
+ "@typescript-eslint/eslint-plugin": "8.59.4",
86
+ "@typescript-eslint/parser": "8.59.4",
82
87
  "downlevel-dts": "^0.11.0",
83
88
  "eslint": "10.4.0",
84
89
  "eslint-config-airbnb-extended": "^2.3.2",
@@ -101,11 +106,11 @@
101
106
  "typedoc-plugin-no-inherit": "1.6.1",
102
107
  "typescript": "5.9.3",
103
108
  "typescript-eslint": "^8.47.0",
104
- "vite": "7.3.3",
105
- "vitest": "^3.0.0"
109
+ "vite": "7.3.5",
110
+ "vitest": "^4.0.0"
106
111
  },
107
112
  "scripts": {
108
- "build": "rollup --config --bundleConfigAsCjs && rollup --config rollup.config.worker.js --bundleConfigAsCjs && rollup --config rollup.config.pt-worker.js --bundleConfigAsCjs && pnpm downlevel-dts",
113
+ "build": "rollup --config --bundleConfigAsCjs && rollup --config rollup.config.worker.js --bundleConfigAsCjs && rollup --config rollup.config.fm-worker.js --bundleConfigAsCjs && pnpm downlevel-dts",
109
114
  "build:clean": "rm -rf ./dist && pnpm build",
110
115
  "build:watch": "rollup --watch --config --bundleConfigAsCjs",
111
116
  "build:worker:watch": "rollup --watch --config rollup.config.worker.js --bundleConfigAsCjs",
@@ -77,7 +77,7 @@ function mockWebSocketStream(options: MockWebSocketStreamOptions = {}) {
77
77
  onUrl,
78
78
  } = options;
79
79
 
80
- return vi.mocked(WebSocketStream).mockImplementationOnce((url) => {
80
+ return vi.mocked(WebSocketStream).mockImplementationOnce(function (url) {
81
81
  onUrl?.(url);
82
82
  return {
83
83
  url: 'wss://test.livekit.io',
@@ -283,7 +283,7 @@ describe('SignalClient.connect', () => {
283
283
  it('should reject when AbortSignal is triggered', async () => {
284
284
  const abortController = new AbortController();
285
285
 
286
- vi.mocked(WebSocketStream).mockImplementation(() => {
286
+ vi.mocked(WebSocketStream).mockImplementation(function () {
287
287
  // Simulate abort
288
288
  setTimeout(() => abortController.abort(new Error('User aborted connection')), 50);
289
289
 
@@ -344,7 +344,7 @@ describe('SignalClient.connect', () => {
344
344
  extensions: '',
345
345
  };
346
346
 
347
- vi.mocked(WebSocketStream).mockImplementation(() => {
347
+ vi.mocked(WebSocketStream).mockImplementation(function () {
348
348
  return {
349
349
  url: 'wss://test.livekit.io',
350
350
  opened: Promise.resolve(mockConnection),
@@ -526,7 +526,7 @@ describe('SignalClient.connect', () => {
526
526
  closedResolve = resolve;
527
527
  });
528
528
 
529
- vi.mocked(WebSocketStream).mockImplementation(() => {
529
+ vi.mocked(WebSocketStream).mockImplementation(function () {
530
530
  // Simulate close during connection
531
531
  queueMicrotask(() => {
532
532
  closedResolve({ closeCode: 1006, reason: 'Connection lost' });
@@ -376,13 +376,17 @@ export class SignalClient {
376
376
  if (redactedUrl.searchParams.has('access_token')) {
377
377
  redactedUrl.searchParams.set('access_token', '<redacted>');
378
378
  }
379
+
380
+ if (this.ws) {
381
+ const startClose = performance.now();
382
+ await this.close(false);
383
+ this.log.debug(`closed previous ws connection in ${performance.now() - startClose}ms`);
384
+ }
385
+
379
386
  this.log.info(`signal connecting to ${redactedUrl}`, {
380
387
  reconnect: opts.reconnect,
381
388
  reconnectReason: opts.reconnectReason,
382
389
  });
383
- if (this.ws) {
384
- await this.close(false);
385
- }
386
390
  this.ws = new WebSocketStream<ArrayBuffer>(rtcUrl);
387
391
 
388
392
  try {
@@ -129,24 +129,24 @@ describe('WebSocketStream', () => {
129
129
  vi.clearAllMocks();
130
130
 
131
131
  // Store original WebSocket
132
- originalWebSocket = global.WebSocket;
132
+ originalWebSocket = globalThis.WebSocket;
133
133
 
134
134
  // Mock WebSocket globally
135
- global.WebSocket = vi.fn((url: string, protocols?: string | string[]) => {
135
+ globalThis.WebSocket = vi.fn(function (url: string, protocols?: string | string[]) {
136
136
  mockWebSocket = new MockWebSocket(url, protocols);
137
137
  return mockWebSocket as any;
138
138
  }) as any;
139
139
 
140
140
  // Add constants to the mocked WebSocket
141
- (global.WebSocket as any).CONNECTING = MockWebSocket.CONNECTING;
142
- (global.WebSocket as any).OPEN = MockWebSocket.OPEN;
143
- (global.WebSocket as any).CLOSING = MockWebSocket.CLOSING;
144
- (global.WebSocket as any).CLOSED = MockWebSocket.CLOSED;
141
+ (globalThis.WebSocket as any).CONNECTING = MockWebSocket.CONNECTING;
142
+ (globalThis.WebSocket as any).OPEN = MockWebSocket.OPEN;
143
+ (globalThis.WebSocket as any).CLOSING = MockWebSocket.CLOSING;
144
+ (globalThis.WebSocket as any).CLOSED = MockWebSocket.CLOSED;
145
145
  });
146
146
 
147
147
  afterEach(() => {
148
148
  // Restore original WebSocket
149
- global.WebSocket = originalWebSocket;
149
+ globalThis.WebSocket = originalWebSocket;
150
150
  });
151
151
 
152
152
  describe('Constructor and Initialization', () => {
@@ -1,8 +1,8 @@
1
1
  import { Encryption_Type, TrackInfo } from '@livekit/protocol';
2
2
  import { EventEmitter } from 'events';
3
3
  import type TypedEventEmitter from 'typed-emitter';
4
+ import { hasFrameMetadataPublishOptions } from '../frameMetadata/utils';
4
5
  import log, { LogLevel, workerLogger } from '../logger';
5
- import { hasPacketTrailerPublishOptions } from '../packetTrailer/utils';
6
6
  import type RTCEngine from '../room/RTCEngine';
7
7
  import type Room from '../room/Room';
8
8
  import { ConnectionState } from '../room/Room';
@@ -230,7 +230,7 @@ export class E2EEManager
230
230
  }
231
231
  break;
232
232
  case 'packetTrailerMetadata':
233
- this.handlePacketTrailerMetadata(data.trackId, data.rtpTimestamp, data.ssrc, data.metadata);
233
+ this.handleFrameMetadata(data.trackId, data.rtpTimestamp, data.ssrc, data.metadata);
234
234
  break;
235
235
  default:
236
236
  break;
@@ -242,7 +242,7 @@ export class E2EEManager
242
242
  this.emit(EncryptionEvent.EncryptionError, ev.error, undefined);
243
243
  };
244
244
 
245
- private handlePacketTrailerMetadata(
245
+ private handleFrameMetadata(
246
246
  trackId: string,
247
247
  rtpTimestamp: number,
248
248
  ssrc: number,
@@ -260,9 +260,9 @@ export class E2EEManager
260
260
  pub.track &&
261
261
  pub.track.mediaStreamID === trackId &&
262
262
  pub.track instanceof RemoteVideoTrack &&
263
- pub.track.packetTrailerExtractor
263
+ pub.track.frameMetadataExtractor
264
264
  ) {
265
- pub.track.packetTrailerExtractor.storeMetadata(rtpTimestamp, ssrc, metadata);
265
+ pub.track.frameMetadataExtractor.storeMetadata(rtpTimestamp, ssrc, metadata);
266
266
  return;
267
267
  }
268
268
  }
@@ -509,7 +509,9 @@ export class E2EEManager
509
509
  sender,
510
510
  track.mediaStreamID,
511
511
  undefined,
512
- isVideoTrack(track) ? track.publishOptions?.packetTrailer : undefined,
512
+ isVideoTrack(track)
513
+ ? (track.publishOptions?.frameMetadata ?? track.publishOptions?.packetTrailer)
514
+ : undefined,
513
515
  );
514
516
  }
515
517
 
@@ -598,7 +600,7 @@ export class E2EEManager
598
600
  sender: RTCRtpSender,
599
601
  trackId: string,
600
602
  codec?: VideoCodec,
601
- packetTrailer?: TrackPublishOptions['packetTrailer'],
603
+ frameMetadata?: TrackPublishOptions['frameMetadata'],
602
604
  ) {
603
605
  if (E2EE_FLAG in sender || !this.worker) {
604
606
  return;
@@ -615,8 +617,8 @@ export class E2EEManager
615
617
  participantIdentity: this.room.localParticipant.identity,
616
618
  trackId,
617
619
  codec,
618
- hasPacketTrailer: hasPacketTrailerPublishOptions(packetTrailer),
619
- packetTrailer,
620
+ hasPacketTrailer: hasFrameMetadataPublishOptions(frameMetadata),
621
+ packetTrailer: frameMetadata,
620
622
  };
621
623
  // @ts-ignore
622
624
  sender.transform = new RTCRtpScriptTransform(this.worker, options);
@@ -633,8 +635,8 @@ export class E2EEManager
633
635
  trackId,
634
636
  participantIdentity: this.room.localParticipant.identity,
635
637
  isReuse: false,
636
- hasPacketTrailer: hasPacketTrailerPublishOptions(packetTrailer),
637
- packetTrailer,
638
+ hasPacketTrailer: hasFrameMetadataPublishOptions(frameMetadata),
639
+ packetTrailer: frameMetadata,
638
640
  },
639
641
  };
640
642
  this.worker.postMessage(msg, [senderStreams.readable, senderStreams.writable]);
package/src/e2ee/types.ts CHANGED
@@ -1,6 +1,6 @@
1
+ import type { FrameMetadataPayload } from '../frameMetadata/frameMetadata';
2
+ import type { FrameMetadataPublishOptions } from '../frameMetadata/types';
1
3
  import type { LogLevel } from '../logger';
2
- import type { PacketTrailerFramePayload } from '../packetTrailer/packetTrailer';
3
- import type { PacketTrailerPublishOptions } from '../packetTrailer/types';
4
4
  import type { VideoCodec } from '../room/track/options';
5
5
  import type { BaseE2EEManager } from './E2eeManager';
6
6
  import type { BaseKeyProvider } from './KeyProvider';
@@ -62,7 +62,7 @@ export interface EncodeMessage extends BaseMessage {
62
62
  /**
63
63
  * Packet trailer metadata to append on published video frames.
64
64
  */
65
- packetTrailer?: PacketTrailerPublishOptions;
65
+ packetTrailer?: FrameMetadataPublishOptions;
66
66
  };
67
67
  }
68
68
 
@@ -165,7 +165,7 @@ export interface EncryptDataResponseMessage extends BaseMessage {
165
165
 
166
166
  export interface PTMetadataFromE2EEMessage extends BaseMessage {
167
167
  kind: 'packetTrailerMetadata';
168
- data: PacketTrailerFramePayload;
168
+ data: FrameMetadataPayload;
169
169
  }
170
170
 
171
171
  export type E2EEWorkerMessage =
@@ -249,5 +249,5 @@ export type ScriptTransformOptions = {
249
249
  /**
250
250
  * Packet trailer metadata to append on published video frames.
251
251
  */
252
- packetTrailer?: PacketTrailerPublishOptions;
252
+ packetTrailer?: FrameMetadataPublishOptions;
253
253
  };
@@ -1,6 +1,6 @@
1
1
  import { afterEach, describe, expect, it, vitest } from 'vitest';
2
- import { appendPacketTrailer, extractPacketTrailer } from '../../packetTrailer/packetTrailer';
3
- import type { PacketTrailerPublishOptions } from '../../packetTrailer/types';
2
+ import { appendPacketTrailer, extractPacketTrailer } from '../../frameMetadata/frameMetadata';
3
+ import type { FrameMetadataPublishOptions } from '../../frameMetadata/types';
4
4
  import { IV_LENGTH, KEY_PROVIDER_DEFAULTS } from '../constants';
5
5
  import { CryptorEvent } from '../events';
6
6
  import type { KeyProviderOptions } from '../types';
@@ -69,7 +69,7 @@ function prepareParticipantTestDecoder(
69
69
  function prepareParticipantTestEncoder(
70
70
  participantIdentity: string,
71
71
  partialKeyProviderOptions: Partial<KeyProviderOptions>,
72
- packetTrailer?: PacketTrailerPublishOptions,
72
+ packetTrailer?: FrameMetadataPublishOptions,
73
73
  ) {
74
74
  return prepareParticipantTest(
75
75
  'encode',
@@ -83,7 +83,7 @@ function prepareParticipantTest(
83
83
  mode: 'encode' | 'decode',
84
84
  participantIdentity: string,
85
85
  partialKeyProviderOptions: Partial<KeyProviderOptions>,
86
- packetTrailer?: PacketTrailerPublishOptions,
86
+ packetTrailer?: FrameMetadataPublishOptions,
87
87
  ): {
88
88
  keys: ParticipantKeyHandler;
89
89
  cryptor: FrameCryptor;
@@ -536,7 +536,7 @@ describe('FrameCryptor', () => {
536
536
  const postMessage = vitest.fn();
537
537
  vitest.stubGlobal('postMessage', postMessage);
538
538
  encryptionEnabledMap.set(participantIdentity, false);
539
- cryptor.setHasPacketTrailer(true);
539
+ cryptor.setHasFrameMetadata(true);
540
540
 
541
541
  const payload = Uint8Array.from([1, 2, 3, 4]);
542
542
  const trailer = appendPacketTrailer(payload, 1_744_249_600_123_456n, 0);
@@ -1,13 +1,13 @@
1
1
  // TODO code inspired by https://github.com/webrtc/samples/blob/gh-pages/src/content/insertable-streams/endtoend-encryption/js/worker.js
2
2
  import { EventEmitter } from 'events';
3
3
  import type TypedEventEmitter from 'typed-emitter';
4
- import { workerLogger } from '../../logger';
5
4
  import {
6
5
  appendPacketTrailerToEncodedFrame,
7
6
  processPacketTrailer,
8
- } from '../../packetTrailer/packetTrailer';
9
- import type { PacketTrailerPublishOptions } from '../../packetTrailer/types';
10
- import { hasPacketTrailerPublishOptions } from '../../packetTrailer/utils';
7
+ } from '../../frameMetadata/frameMetadata';
8
+ import type { FrameMetadataPublishOptions } from '../../frameMetadata/types';
9
+ import { hasFrameMetadataPublishOptions } from '../../frameMetadata/utils';
10
+ import { workerLogger } from '../../logger';
11
11
  import { type VideoCodec, videoCodecs } from '../../room/track/options';
12
12
  import { mimeTypeToVideoCodecString } from '../../room/track/utils';
13
13
  import { ENCRYPTION_ALGORITHM, IV_LENGTH, UNENCRYPTED_BYTES } from '../constants';
@@ -88,11 +88,11 @@ export class FrameCryptor extends BaseFrameCryptor {
88
88
  * When false, we skip the per-frame trailer extraction path entirely
89
89
  * on decode to avoid unnecessary work on tracks that don't use it.
90
90
  */
91
- private hasPacketTrailer: boolean = false;
91
+ private hasFrameMetadata: boolean = false;
92
92
 
93
- private packetTrailer?: PacketTrailerPublishOptions;
93
+ private frameMetadataOpts?: FrameMetadataPublishOptions;
94
94
 
95
- private packetTrailerFrameId = 0;
95
+ private frameMetadataFrameId = 0;
96
96
 
97
97
  /**
98
98
  * Throttling mechanism for decryption errors to prevent memory leaks
@@ -212,13 +212,13 @@ export class FrameCryptor extends BaseFrameCryptor {
212
212
  * trailer data. When false, {@link decodeFunction} skips the per-frame
213
213
  * trailer extraction branch entirely.
214
214
  */
215
- setHasPacketTrailer(hasPacketTrailer: boolean) {
216
- this.hasPacketTrailer = hasPacketTrailer;
215
+ setHasFrameMetadata(hasFrameMetadata: boolean) {
216
+ this.hasFrameMetadata = hasFrameMetadata;
217
217
  }
218
218
 
219
- setPacketTrailer(packetTrailer?: PacketTrailerPublishOptions) {
220
- this.packetTrailer = packetTrailer;
221
- this.packetTrailerFrameId = 0;
219
+ setFrameMetadataOpts(frameMetadata?: FrameMetadataPublishOptions) {
220
+ this.frameMetadataOpts = frameMetadata;
221
+ this.frameMetadataFrameId = 0;
222
222
  }
223
223
 
224
224
  setupTransform(
@@ -228,14 +228,14 @@ export class FrameCryptor extends BaseFrameCryptor {
228
228
  trackId: string,
229
229
  isReuse: boolean,
230
230
  codec?: VideoCodec,
231
- packetTrailer?: PacketTrailerPublishOptions,
231
+ frameMetadata?: FrameMetadataPublishOptions,
232
232
  ) {
233
233
  if (codec) {
234
234
  workerLogger.info('setting codec on cryptor to', { codec });
235
235
  this.videoCodec = codec;
236
236
  }
237
237
  if (operation === 'encode') {
238
- this.setPacketTrailer(packetTrailer);
238
+ this.setFrameMetadataOpts(frameMetadata);
239
239
  }
240
240
 
241
241
  workerLogger.debug('Setting up frame cryptor transform', {
@@ -406,7 +406,7 @@ export class FrameCryptor extends BaseFrameCryptor {
406
406
  }
407
407
 
408
408
  if (!this.isEnabled()) {
409
- this.appendPacketTrailer(encodedFrame);
409
+ this.appendFrameMetadata(encodedFrame);
410
410
  return controller.enqueue(encodedFrame);
411
411
  }
412
412
  const keySet = this.keys.getKeySet();
@@ -475,7 +475,7 @@ export class FrameCryptor extends BaseFrameCryptor {
475
475
  newData.set(newDataWithoutHeader, frameHeader.byteLength);
476
476
 
477
477
  encodedFrame.data = newData.buffer;
478
- this.appendPacketTrailer(encodedFrame);
478
+ this.appendFrameMetadata(encodedFrame);
479
479
 
480
480
  return controller.enqueue(encodedFrame);
481
481
  } catch (e: any) {
@@ -494,16 +494,20 @@ export class FrameCryptor extends BaseFrameCryptor {
494
494
  }
495
495
  }
496
496
 
497
- private appendPacketTrailer(encodedFrame: RTCEncodedVideoFrame | RTCEncodedAudioFrame) {
498
- if (!hasPacketTrailerPublishOptions(this.packetTrailer) || !isVideoFrame(encodedFrame)) {
497
+ private appendFrameMetadata(encodedFrame: RTCEncodedVideoFrame | RTCEncodedAudioFrame) {
498
+ if (!hasFrameMetadataPublishOptions(this.frameMetadataOpts) || !isVideoFrame(encodedFrame)) {
499
499
  return;
500
500
  }
501
501
 
502
- if (this.packetTrailer?.frameId) {
503
- this.packetTrailerFrameId =
504
- this.packetTrailerFrameId === 0xffffffff ? 1 : this.packetTrailerFrameId + 1;
502
+ if (this.frameMetadataOpts?.frameId) {
503
+ this.frameMetadataFrameId =
504
+ this.frameMetadataFrameId === 0xffffffff ? 1 : this.frameMetadataFrameId + 1;
505
505
  }
506
- appendPacketTrailerToEncodedFrame(encodedFrame, this.packetTrailer, this.packetTrailerFrameId);
506
+ appendPacketTrailerToEncodedFrame(
507
+ encodedFrame,
508
+ this.frameMetadataOpts,
509
+ this.frameMetadataFrameId,
510
+ );
507
511
  }
508
512
 
509
513
  /**
@@ -516,7 +520,7 @@ export class FrameCryptor extends BaseFrameCryptor {
516
520
  encodedFrame: RTCEncodedVideoFrame | RTCEncodedAudioFrame,
517
521
  controller: TransformStreamDefaultController,
518
522
  ) {
519
- if (this.hasPacketTrailer && isVideoFrame(encodedFrame)) {
523
+ if (this.hasFrameMetadata && isVideoFrame(encodedFrame)) {
520
524
  try {
521
525
  const ptResult = processPacketTrailer(encodedFrame, this.trackId);
522
526
  if (ptResult.data) {
@@ -64,7 +64,7 @@ onmessage = (ev) => {
64
64
  break;
65
65
  case 'decode':
66
66
  let cryptor = getTrackCryptor(data.participantIdentity, data.trackId);
67
- cryptor.setHasPacketTrailer(data.hasPacketTrailer);
67
+ cryptor.setHasFrameMetadata(data.hasPacketTrailer);
68
68
  cryptor.setupTransform(
69
69
  kind,
70
70
  data.readableStream,
@@ -76,7 +76,7 @@ onmessage = (ev) => {
76
76
  break;
77
77
  case 'encode':
78
78
  let pubCryptor = getTrackCryptor(data.participantIdentity, data.trackId);
79
- pubCryptor.setHasPacketTrailer(data.hasPacketTrailer);
79
+ pubCryptor.setHasFrameMetadata(data.hasPacketTrailer);
80
80
  pubCryptor.setupTransform(
81
81
  kind,
82
82
  data.readableStream,
@@ -84,7 +84,7 @@ onmessage = (ev) => {
84
84
  data.trackId,
85
85
  data.isReuse,
86
86
  data.codec,
87
- data.packetTrailer,
87
+ data.packetTrailer, // wire format still uses 'packetTrailer' field name
88
88
  );
89
89
  break;
90
90
 
@@ -164,7 +164,7 @@ onmessage = (ev) => {
164
164
  case 'updateCodec':
165
165
  const trackCryptor = getTrackCryptor(data.participantIdentity, data.trackId);
166
166
  trackCryptor.setVideoCodec(data.codec);
167
- trackCryptor.setHasPacketTrailer(data.hasPacketTrailer);
167
+ trackCryptor.setHasFrameMetadata(data.hasPacketTrailer);
168
168
  workerLogger.info('updated codec', {
169
169
  participantIdentity: data.participantIdentity,
170
170
  trackId: data.trackId,
@@ -343,7 +343,7 @@ if (self.RTCTransformEvent) {
343
343
  const { kind, participantIdentity, trackId, codec, hasPacketTrailer } = options;
344
344
  messageQueue.run(async () => {
345
345
  const cryptor = getTrackCryptor(participantIdentity, trackId);
346
- cryptor.setHasPacketTrailer(hasPacketTrailer);
346
+ cryptor.setHasFrameMetadata(hasPacketTrailer);
347
347
  workerLogger.debug('onrtctransform setup', { participantIdentity, trackId, codec });
348
348
  cryptor.setupTransform(
349
349
  kind,
@@ -8,7 +8,10 @@
8
8
  "ES2018.Promise",
9
9
  "WebWorker",
10
10
  "ES2021.WeakRef",
11
- "DOM.AsyncIterable"
11
+ "DOM.AsyncIterable",
12
+ "ES2020.BigInt",
13
+ "ES2018.AsyncIterable",
14
+ "ES2018.AsyncGenerator"
12
15
  ]
13
16
  }
14
17
  }
@@ -1,8 +1,8 @@
1
1
  import { afterEach, describe, expect, it, vi } from 'vitest';
2
2
  import type { TrackInfo } from '@livekit/protocol';
3
- import { PacketTrailerManager } from './PacketTrailerManager';
3
+ import { FrameMetadataManager } from './FrameMetadataManager';
4
4
 
5
- describe('PacketTrailerManager', () => {
5
+ describe('FrameMetadataManager', () => {
6
6
  const originalRTCRtpSender = window.RTCRtpSender;
7
7
  const originalUserAgent = navigator.userAgent;
8
8
  const originalRTCRtpScriptTransform = (window as unknown as { RTCRtpScriptTransform?: unknown })
@@ -63,7 +63,7 @@ describe('PacketTrailerManager', () => {
63
63
  });
64
64
  }
65
65
 
66
- function setupWorkerReceiver(manager: PacketTrailerManager, receiver: RTCRtpReceiver) {
66
+ function setupWorkerReceiver(manager: FrameMetadataManager, receiver: RTCRtpReceiver) {
67
67
  (
68
68
  manager as unknown as {
69
69
  setupWorkerReceiver: (receiver: RTCRtpReceiver, newTrackId: string) => void;
@@ -72,7 +72,7 @@ describe('PacketTrailerManager', () => {
72
72
  }
73
73
 
74
74
  function setupReceiver(
75
- manager: PacketTrailerManager,
75
+ manager: FrameMetadataManager,
76
76
  receiver: RTCRtpReceiver,
77
77
  trackId: string,
78
78
  trackInfo?: TrackInfo,
@@ -103,11 +103,13 @@ describe('PacketTrailerManager', () => {
103
103
  it('uses RTCRtpScriptTransform for packet trailer extraction when supported', () => {
104
104
  useSafariUserAgent();
105
105
  const transform = {};
106
- const RTCRtpScriptTransform = vi.fn(() => transform);
106
+ const RTCRtpScriptTransform = vi.fn(function () {
107
+ return transform;
108
+ });
107
109
  setScriptTransform(RTCRtpScriptTransform);
108
110
 
109
111
  const worker = {} as Worker;
110
- const manager = new PacketTrailerManager({ worker });
112
+ const manager = new FrameMetadataManager({ worker });
111
113
  const receiver = {
112
114
  createEncodedStreams: vi.fn(),
113
115
  } as unknown as RTCRtpReceiver;
@@ -129,7 +131,7 @@ describe('PacketTrailerManager', () => {
129
131
  stubInsertableStreamsSupport();
130
132
 
131
133
  const worker = { postMessage: vi.fn() } as unknown as Worker;
132
- const manager = new PacketTrailerManager({ worker });
134
+ const manager = new FrameMetadataManager({ worker });
133
135
  const { receiver, readable, writable, createEncodedStreams } = makeReceiver();
134
136
 
135
137
  setupReceiver(manager, receiver, 'track-without-trailer');
@@ -153,7 +155,7 @@ describe('PacketTrailerManager', () => {
153
155
  stubInsertableStreamsSupport();
154
156
 
155
157
  const worker = { postMessage: vi.fn() } as unknown as Worker;
156
- const manager = new PacketTrailerManager({ worker });
158
+ const manager = new FrameMetadataManager({ worker });
157
159
  const { receiver } = makeReceiver();
158
160
  const trackInfo = { packetTrailerFeatures: [1] } as unknown as TrackInfo;
159
161