livekit-client 2.19.1 → 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.
- package/dist/livekit-client.e2ee.worker.js +1 -1
- package/dist/livekit-client.e2ee.worker.js.map +1 -1
- package/dist/livekit-client.e2ee.worker.mjs +204 -145
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +664 -526
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.fm.worker.js +2 -0
- package/dist/{livekit-client.pt.worker.js.map → livekit-client.fm.worker.js.map} +1 -1
- package/dist/{livekit-client.pt.worker.mjs → livekit-client.fm.worker.mjs} +133 -99
- package/dist/livekit-client.fm.worker.mjs.map +1 -0
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/src/api/SignalClient.d.ts.map +1 -1
- package/dist/src/e2ee/E2eeManager.d.ts +1 -1
- package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
- package/dist/src/e2ee/types.d.ts +5 -5
- package/dist/src/e2ee/types.d.ts.map +1 -1
- package/dist/src/e2ee/worker/FrameCryptor.d.ts +20 -10
- package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
- package/dist/src/{packetTrailer/PacketTrailerManager.d.ts → frameMetadata/FrameMetadataManager.d.ts} +8 -4
- package/dist/src/{packetTrailer/PacketTrailerManager.d.ts.map → frameMetadata/FrameMetadataManager.d.ts.map} +1 -1
- package/dist/src/{packetTrailer/packetTrailer.d.ts → frameMetadata/frameMetadata.d.ts} +7 -7
- package/dist/src/frameMetadata/frameMetadata.d.ts.map +1 -0
- package/dist/src/{packetTrailer → frameMetadata}/types.d.ts +10 -6
- package/dist/src/frameMetadata/types.d.ts.map +1 -0
- package/dist/src/frameMetadata/utils.d.ts +9 -0
- package/dist/src/{packetTrailer → frameMetadata}/utils.d.ts.map +1 -1
- package/dist/src/frameMetadata/worker/frameMetadata.worker.d.ts +2 -0
- package/dist/src/frameMetadata/worker/frameMetadata.worker.d.ts.map +1 -0
- package/dist/src/index.d.ts +10 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/options.d.ts +8 -4
- package/dist/src/options.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +1 -0
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/PCTransportManager.d.ts +1 -0
- package/dist/src/room/PCTransportManager.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +11 -1
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +2 -2
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +2 -2
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/publishUtils.d.ts.map +1 -1
- package/dist/src/room/rpc/client/RpcClientManager.d.ts.map +1 -1
- package/dist/src/room/token-source/TokenSource.d.ts.map +1 -1
- package/dist/src/room/token-source/types.d.ts +1 -0
- package/dist/src/room/token-source/types.d.ts.map +1 -1
- package/dist/src/room/token-source/utils.d.ts.map +1 -1
- package/dist/src/room/track/FrameMetadataExtractor.d.ts +19 -0
- package/dist/src/room/track/FrameMetadataExtractor.d.ts.map +1 -0
- package/dist/src/room/track/RemoteVideoTrack.d.ts +7 -7
- package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +17 -5
- package/dist/src/room/track/options.d.ts.map +1 -1
- package/dist/ts4.2/e2ee/E2eeManager.d.ts +1 -1
- package/dist/ts4.2/e2ee/types.d.ts +5 -5
- package/dist/ts4.2/e2ee/worker/FrameCryptor.d.ts +19 -9
- package/dist/ts4.2/{packetTrailer/PacketTrailerManager.d.ts → frameMetadata/FrameMetadataManager.d.ts} +8 -4
- package/dist/ts4.2/{packetTrailer/packetTrailer.d.ts → frameMetadata/frameMetadata.d.ts} +7 -7
- package/dist/ts4.2/{packetTrailer → frameMetadata}/types.d.ts +10 -6
- package/dist/ts4.2/frameMetadata/utils.d.ts +9 -0
- package/dist/ts4.2/frameMetadata/worker/frameMetadata.worker.d.ts +2 -0
- package/dist/ts4.2/index.d.ts +9 -3
- package/dist/ts4.2/options.d.ts +8 -4
- package/dist/ts4.2/room/PCTransport.d.ts +1 -0
- package/dist/ts4.2/room/PCTransportManager.d.ts +1 -0
- package/dist/ts4.2/room/RTCEngine.d.ts +11 -1
- package/dist/ts4.2/room/Room.d.ts +2 -2
- package/dist/ts4.2/room/participant/LocalParticipant.d.ts +2 -2
- package/dist/ts4.2/room/token-source/types.d.ts +1 -0
- package/dist/ts4.2/room/track/FrameMetadataExtractor.d.ts +19 -0
- package/dist/ts4.2/room/track/RemoteVideoTrack.d.ts +7 -7
- package/dist/ts4.2/room/track/options.d.ts +17 -5
- package/package.json +25 -20
- package/src/api/SignalClient.test.ts +4 -4
- package/src/api/SignalClient.ts +7 -3
- package/src/api/WebSocketStream.test.ts +7 -7
- package/src/e2ee/E2eeManager.ts +13 -11
- package/src/e2ee/types.ts +5 -5
- package/src/e2ee/worker/FrameCryptor.test.ts +5 -5
- package/src/e2ee/worker/FrameCryptor.ts +69 -30
- package/src/e2ee/worker/e2ee.worker.ts +5 -5
- package/src/e2ee/worker/tsconfig.json +4 -1
- package/src/{packetTrailer/PacketTrailerManager.test.ts → frameMetadata/FrameMetadataManager.test.ts} +10 -8
- package/src/{packetTrailer/PacketTrailerManager.ts → frameMetadata/FrameMetadataManager.ts} +21 -15
- package/src/{packetTrailer/packetTrailer.test.ts → frameMetadata/frameMetadata.test.ts} +1 -1
- package/src/{packetTrailer/packetTrailer.ts → frameMetadata/frameMetadata.ts} +9 -9
- package/src/{packetTrailer → frameMetadata}/types.ts +12 -6
- package/src/{packetTrailer → frameMetadata}/utils.test.ts +19 -19
- package/src/{packetTrailer → frameMetadata}/utils.ts +11 -11
- package/src/{packetTrailer/worker/packetTrailer.worker.ts → frameMetadata/worker/frameMetadata.worker.ts} +5 -5
- package/src/{packetTrailer → frameMetadata}/worker/tsconfig.json +4 -1
- package/src/index.ts +13 -2
- package/src/options.ts +9 -4
- package/src/room/PCTransport.ts +4 -0
- package/src/room/PCTransportManager.ts +4 -0
- package/src/room/RTCEngine.test.ts +143 -9
- package/src/room/RTCEngine.ts +156 -48
- package/src/room/Room.ts +10 -10
- package/src/room/participant/LocalParticipant.test.ts +19 -19
- package/src/room/participant/LocalParticipant.ts +21 -16
- package/src/room/participant/publishUtils.test.ts +6 -0
- package/src/room/participant/publishUtils.ts +4 -1
- package/src/room/rpc/client/RpcClientManager.ts +6 -3
- package/src/room/rpc/server/RpcServerManager.ts +1 -1
- package/src/room/token-source/TokenSource.ts +9 -23
- package/src/room/token-source/types.ts +1 -0
- package/src/room/token-source/utils.ts +1 -0
- package/src/room/track/{PacketTrailerExtractor.ts → FrameMetadataExtractor.ts} +8 -8
- package/src/room/track/RemoteVideoTrack.ts +7 -11
- package/src/room/track/options.ts +19 -5
- package/dist/livekit-client.pt.worker.js +0 -2
- package/dist/livekit-client.pt.worker.mjs.map +0 -1
- package/dist/src/packetTrailer/packetTrailer.d.ts.map +0 -1
- package/dist/src/packetTrailer/types.d.ts.map +0 -1
- package/dist/src/packetTrailer/utils.d.ts +0 -9
- package/dist/src/packetTrailer/worker/packetTrailer.worker.d.ts +0 -2
- package/dist/src/packetTrailer/worker/packetTrailer.worker.d.ts.map +0 -1
- package/dist/src/room/track/PacketTrailerExtractor.d.ts +0 -19
- package/dist/src/room/track/PacketTrailerExtractor.d.ts.map +0 -1
- package/dist/ts4.2/packetTrailer/utils.d.ts +0 -9
- package/dist/ts4.2/packetTrailer/worker/packetTrailer.worker.d.ts +0 -2
- package/dist/ts4.2/room/track/PacketTrailerExtractor.d.ts +0 -19
|
@@ -120,16 +120,25 @@ export default class RTCEngine extends RTCEngine_base {
|
|
|
120
120
|
private configure;
|
|
121
121
|
private setupSignalClientCallbacks;
|
|
122
122
|
private makeRTCConfiguration;
|
|
123
|
+
/**
|
|
124
|
+
* Populate the publisher PC so its first offer carries the data channels + recvonly media
|
|
125
|
+
* sections. Required for every V1 connection: Firefox only binds receive decoders for media
|
|
126
|
+
* present in that first offer, and the offer-with-join path needs the sections to
|
|
127
|
+
* build a meaningful initial offer. Must be called on a configured pcManager.
|
|
128
|
+
*/
|
|
129
|
+
private applyInitialPublisherLayout;
|
|
123
130
|
private addMediaSections;
|
|
124
131
|
private createDataChannels;
|
|
125
132
|
private handleDataChannel;
|
|
126
133
|
private handleDataMessage;
|
|
127
134
|
private handleDataTrackMessage;
|
|
128
135
|
private handleDataError;
|
|
136
|
+
private handleDataChannelClose;
|
|
129
137
|
private handleBufferedAmountLow;
|
|
130
138
|
createSender(track: LocalTrack, opts: TrackPublishOptions, encodings?: RTCRtpEncodingParameters[]): Promise<RTCRtpSender>;
|
|
131
139
|
createSimulcastSender(track: LocalVideoTrack, simulcastTrack: SimulcastTrackInfo, opts: TrackPublishOptions, encodings?: RTCRtpEncodingParameters[]): Promise<RTCRtpSender | undefined>;
|
|
132
|
-
private
|
|
140
|
+
private get frameMetadataWorker();
|
|
141
|
+
private setupFrameMetadataSender;
|
|
133
142
|
private createTransceiverRTCRtpSender;
|
|
134
143
|
private createSimulcastTransceiverSender;
|
|
135
144
|
private createRTCRtpSender;
|
|
@@ -162,6 +171,7 @@ export default class RTCEngine extends RTCEngine_base {
|
|
|
162
171
|
sendSyncState(remoteTracks: RemoteTrackPublication[], localTracks: LocalTrackPublication[], localDataTrackInfos: Array<DataTrackInfo>): void;
|
|
163
172
|
failNext(): void;
|
|
164
173
|
failNextV1Path(): void;
|
|
174
|
+
private onRtpMapAvailable;
|
|
165
175
|
private dataChannelsInfo;
|
|
166
176
|
private clearReconnectTimeout;
|
|
167
177
|
private clearPendingReconnect;
|
|
@@ -68,7 +68,7 @@ declare class Room extends Room_base {
|
|
|
68
68
|
private connectFuture?;
|
|
69
69
|
private disconnectLock;
|
|
70
70
|
private e2eeManager;
|
|
71
|
-
private
|
|
71
|
+
private frameMetadataManager;
|
|
72
72
|
private e2eeStateMutex;
|
|
73
73
|
private connectionReconcileInterval?;
|
|
74
74
|
private regionUrlProvider?;
|
|
@@ -135,7 +135,7 @@ declare class Room extends Room_base {
|
|
|
135
135
|
*/
|
|
136
136
|
setE2EEEnabled(enabled: boolean): Promise<void>;
|
|
137
137
|
private setupE2EE;
|
|
138
|
-
private
|
|
138
|
+
private setupFrameMetadata;
|
|
139
139
|
private get logContext();
|
|
140
140
|
/**
|
|
141
141
|
* if the current room has a participant with `recorder: true` in its JWT grant
|
|
@@ -146,8 +146,8 @@ export default class LocalParticipant extends Participant {
|
|
|
146
146
|
private waitUntilEngineConnected;
|
|
147
147
|
private hasPermissionsToPublish;
|
|
148
148
|
private publish;
|
|
149
|
-
private
|
|
150
|
-
private
|
|
149
|
+
private canPublishFrameMetadata;
|
|
150
|
+
private normalizeRequestedFrameMetadataOptions;
|
|
151
151
|
get isLocal(): boolean;
|
|
152
152
|
/** @internal
|
|
153
153
|
* publish additional codec to existing track
|
|
@@ -48,6 +48,7 @@ export type TokenSourceFetchOptions = {
|
|
|
48
48
|
};
|
|
49
49
|
agentName?: string;
|
|
50
50
|
agentMetadata?: string;
|
|
51
|
+
deployment?: string;
|
|
51
52
|
};
|
|
52
53
|
/** A Configurable TokenSource is a token source that takes a
|
|
53
54
|
* {@link TokenSourceFetchOptions} object as input and returns a deterministic
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { FrameMetadata } from '../../frameMetadata/types';
|
|
2
|
+
/**
|
|
3
|
+
* Caches frame metadata extracted from received video frames,
|
|
4
|
+
* keyed by RTP timestamp so it can be looked up when the frame is displayed.
|
|
5
|
+
*
|
|
6
|
+
* Metadata is populated either by the frame metadata worker managed by
|
|
7
|
+
* `FrameMetadataManager` (non-E2EE) or by the E2EE FrameCryptor worker
|
|
8
|
+
* after decryption (E2EE).
|
|
9
|
+
*
|
|
10
|
+
* @experimental
|
|
11
|
+
*/
|
|
12
|
+
export declare class FrameMetadataExtractor {
|
|
13
|
+
private metadataMap;
|
|
14
|
+
private activeSsrc;
|
|
15
|
+
storeMetadata(rtpTimestamp: number, ssrc: number, metadata: FrameMetadata): void;
|
|
16
|
+
lookupMetadata(rtpTimestamp: number): FrameMetadata | undefined;
|
|
17
|
+
dispose(): void;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=FrameMetadataExtractor.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FrameMetadata } from '../../frameMetadata/types';
|
|
2
2
|
import type { VideoReceiverStats } from '../stats';
|
|
3
3
|
import type { LoggerOptions } from '../types';
|
|
4
|
-
import type {
|
|
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
|
-
|
|
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 `
|
|
24
|
-
* and the publishing track to have
|
|
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
|
-
}):
|
|
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 {
|
|
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
|
-
*
|
|
116
|
+
* Frame metadata to append to published video frames.
|
|
117
117
|
*
|
|
118
|
-
* Requires either room-level
|
|
119
|
-
* because encoded frame transforms are used to write the
|
|
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
|
-
|
|
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.
|
|
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/
|
|
21
|
-
"import": "./dist/livekit-client.
|
|
22
|
-
"require": "./dist/livekit-client.
|
|
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/
|
|
39
|
-
"./dist/ts4.2/
|
|
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.
|
|
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.
|
|
62
|
-
"@babel/preset-env": "7.29.
|
|
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,18 +74,18 @@
|
|
|
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.
|
|
73
|
-
"@size-limit/file": "^
|
|
74
|
-
"@size-limit/webpack": "^
|
|
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": "^
|
|
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.
|
|
81
|
-
"@typescript-eslint/parser": "8.59.
|
|
85
|
+
"@typescript-eslint/eslint-plugin": "8.59.4",
|
|
86
|
+
"@typescript-eslint/parser": "8.59.4",
|
|
82
87
|
"downlevel-dts": "^0.11.0",
|
|
83
|
-
"eslint": "10.
|
|
88
|
+
"eslint": "10.4.0",
|
|
84
89
|
"eslint-config-airbnb-extended": "^2.3.2",
|
|
85
90
|
"eslint-config-prettier": "10.1.8",
|
|
86
91
|
"eslint-plugin-compat": "^6.0.2",
|
|
@@ -92,7 +97,7 @@
|
|
|
92
97
|
"jsdom": "^26.1.0",
|
|
93
98
|
"prettier": "^3.4.2",
|
|
94
99
|
"publint": "^0.3.21",
|
|
95
|
-
"rollup": "4.60.
|
|
100
|
+
"rollup": "4.60.4",
|
|
96
101
|
"rollup-plugin-delete": "^2.1.0",
|
|
97
102
|
"rollup-plugin-typescript2": "0.37.0",
|
|
98
103
|
"size-limit": "^11.2.0",
|
|
@@ -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.
|
|
105
|
-
"vitest": "^
|
|
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.
|
|
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' });
|
package/src/api/SignalClient.ts
CHANGED
|
@@ -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 =
|
|
132
|
+
originalWebSocket = globalThis.WebSocket;
|
|
133
133
|
|
|
134
134
|
// Mock WebSocket globally
|
|
135
|
-
|
|
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
|
-
(
|
|
142
|
-
(
|
|
143
|
-
(
|
|
144
|
-
(
|
|
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
|
-
|
|
149
|
+
globalThis.WebSocket = originalWebSocket;
|
|
150
150
|
});
|
|
151
151
|
|
|
152
152
|
describe('Constructor and Initialization', () => {
|
package/src/e2ee/E2eeManager.ts
CHANGED
|
@@ -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.
|
|
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
|
|
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.
|
|
263
|
+
pub.track.frameMetadataExtractor
|
|
264
264
|
) {
|
|
265
|
-
pub.track.
|
|
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)
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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?:
|
|
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:
|
|
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?:
|
|
252
|
+
packetTrailer?: FrameMetadataPublishOptions;
|
|
253
253
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { afterEach, describe, expect, it, vitest } from 'vitest';
|
|
2
|
-
import { appendPacketTrailer, extractPacketTrailer } from '../../
|
|
3
|
-
import type {
|
|
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?:
|
|
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?:
|
|
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.
|
|
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);
|