livekit-client 2.17.3 → 2.18.1
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 +8 -7
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +7823 -5772
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/src/api/SignalClient.d.ts +12 -4
- package/dist/src/api/SignalClient.d.ts.map +1 -1
- package/dist/src/e2ee/constants.d.ts.map +1 -1
- package/dist/src/e2ee/types.d.ts +6 -0
- package/dist/src/e2ee/types.d.ts.map +1 -1
- package/dist/src/e2ee/utils.d.ts +2 -1
- package/dist/src/e2ee/utils.d.ts.map +1 -1
- package/dist/src/e2ee/worker/DataCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
- package/dist/src/index.d.ts +5 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +5 -0
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/PCTransportManager.d.ts +1 -1
- package/dist/src/room/PCTransportManager.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +27 -9
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +13 -3
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts.map +1 -1
- package/dist/src/room/data-track/LocalDataTrack.d.ts +48 -0
- package/dist/src/room/data-track/LocalDataTrack.d.ts.map +1 -0
- package/dist/src/room/data-track/RemoteDataTrack.d.ts +46 -0
- package/dist/src/room/data-track/RemoteDataTrack.d.ts.map +1 -0
- package/dist/src/room/data-track/depacketizer.d.ts +6 -6
- package/dist/src/room/data-track/depacketizer.d.ts.map +1 -1
- package/dist/src/room/data-track/frame.d.ts +14 -0
- package/dist/src/room/data-track/frame.d.ts.map +1 -1
- package/dist/src/room/data-track/handle.d.ts +2 -2
- package/dist/src/room/data-track/handle.d.ts.map +1 -1
- package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts +104 -0
- package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts.map +1 -0
- package/dist/src/room/data-track/incoming/errors.d.ts +24 -0
- package/dist/src/room/data-track/incoming/errors.d.ts.map +1 -0
- package/dist/src/room/data-track/incoming/pipeline.d.ts +38 -0
- package/dist/src/room/data-track/incoming/pipeline.d.ts.map +1 -0
- package/dist/src/room/data-track/incoming/types.d.ts +20 -0
- package/dist/src/room/data-track/incoming/types.d.ts.map +1 -0
- package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +63 -28
- package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/errors.d.ts +20 -10
- package/dist/src/room/data-track/outgoing/errors.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/pipeline.d.ts +9 -8
- package/dist/src/room/data-track/outgoing/pipeline.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/types.d.ts +16 -7
- package/dist/src/room/data-track/outgoing/types.d.ts.map +1 -1
- package/dist/src/room/data-track/packet/errors.d.ts +2 -4
- package/dist/src/room/data-track/packet/errors.d.ts.map +1 -1
- package/dist/src/room/data-track/packet/extensions.d.ts +4 -4
- package/dist/src/room/data-track/packet/extensions.d.ts.map +1 -1
- package/dist/src/room/data-track/packet/index.d.ts +5 -5
- package/dist/src/room/data-track/packet/index.d.ts.map +1 -1
- package/dist/src/room/data-track/packet/serializable.d.ts +4 -4
- package/dist/src/room/data-track/packet/serializable.d.ts.map +1 -1
- package/dist/src/room/data-track/packetizer.d.ts +6 -6
- package/dist/src/room/data-track/packetizer.d.ts.map +1 -1
- package/dist/src/room/data-track/track-interfaces.d.ts +23 -0
- package/dist/src/room/data-track/track-interfaces.d.ts.map +1 -0
- package/dist/src/room/data-track/types.d.ts +15 -0
- package/dist/src/room/data-track/types.d.ts.map +1 -0
- package/dist/src/room/events.d.ts +24 -3
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +11 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/RemoteParticipant.d.ts +14 -1
- package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
- package/dist/src/room/token-source/TokenSource.d.ts +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/utils.d.ts +2 -1
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/src/utils/abort-signal-polyfill.d.ts +13 -0
- package/dist/src/utils/abort-signal-polyfill.d.ts.map +1 -0
- package/dist/src/utils/deferrable-map.d.ts +32 -0
- package/dist/src/utils/deferrable-map.d.ts.map +1 -0
- package/dist/src/utils/subscribeToEvents.d.ts +3 -0
- package/dist/src/utils/subscribeToEvents.d.ts.map +1 -1
- package/dist/ts4.2/api/SignalClient.d.ts +12 -4
- package/dist/ts4.2/e2ee/types.d.ts +6 -0
- package/dist/ts4.2/e2ee/utils.d.ts +2 -1
- package/dist/ts4.2/index.d.ts +5 -4
- package/dist/ts4.2/room/PCTransport.d.ts +5 -0
- package/dist/ts4.2/room/PCTransportManager.d.ts +1 -1
- package/dist/ts4.2/room/RTCEngine.d.ts +27 -9
- package/dist/ts4.2/room/Room.d.ts +13 -3
- package/dist/ts4.2/room/data-track/LocalDataTrack.d.ts +48 -0
- package/dist/ts4.2/room/data-track/RemoteDataTrack.d.ts +46 -0
- package/dist/ts4.2/room/data-track/depacketizer.d.ts +6 -6
- package/dist/ts4.2/room/data-track/frame.d.ts +14 -0
- package/dist/ts4.2/room/data-track/handle.d.ts +2 -2
- package/dist/ts4.2/room/data-track/incoming/IncomingDataTrackManager.d.ts +110 -0
- package/dist/ts4.2/room/data-track/incoming/errors.d.ts +24 -0
- package/dist/ts4.2/room/data-track/incoming/pipeline.d.ts +38 -0
- package/dist/ts4.2/room/data-track/incoming/types.d.ts +20 -0
- package/dist/ts4.2/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +63 -29
- package/dist/ts4.2/room/data-track/outgoing/errors.d.ts +20 -10
- package/dist/ts4.2/room/data-track/outgoing/pipeline.d.ts +9 -8
- package/dist/ts4.2/room/data-track/outgoing/types.d.ts +16 -7
- package/dist/ts4.2/room/data-track/packet/errors.d.ts +2 -4
- package/dist/ts4.2/room/data-track/packet/extensions.d.ts +4 -4
- package/dist/ts4.2/room/data-track/packet/index.d.ts +5 -6
- package/dist/ts4.2/room/data-track/packet/serializable.d.ts +4 -4
- package/dist/ts4.2/room/data-track/packetizer.d.ts +6 -6
- package/dist/ts4.2/room/data-track/track-interfaces.d.ts +23 -0
- package/dist/ts4.2/room/data-track/types.d.ts +15 -0
- package/dist/ts4.2/room/events.d.ts +24 -3
- package/dist/ts4.2/room/participant/LocalParticipant.d.ts +11 -1
- package/dist/ts4.2/room/participant/RemoteParticipant.d.ts +14 -1
- package/dist/ts4.2/room/token-source/TokenSource.d.ts +1 -1
- package/dist/ts4.2/room/token-source/types.d.ts +1 -0
- package/dist/ts4.2/room/utils.d.ts +2 -1
- package/dist/ts4.2/utils/abort-signal-polyfill.d.ts +13 -0
- package/dist/ts4.2/utils/deferrable-map.d.ts +32 -0
- package/dist/ts4.2/utils/subscribeToEvents.d.ts +3 -0
- package/package.json +4 -2
- package/src/api/SignalClient.test.ts +9 -4
- package/src/api/SignalClient.ts +116 -9
- package/src/e2ee/constants.ts +1 -0
- package/src/e2ee/types.ts +6 -0
- package/src/e2ee/utils.ts +4 -3
- package/src/e2ee/worker/DataCryptor.ts +1 -4
- package/src/e2ee/worker/FrameCryptor.ts +1 -4
- package/src/e2ee/worker/ParticipantKeyHandler.ts +1 -1
- package/src/index.ts +6 -4
- package/src/room/PCTransport.ts +41 -1
- package/src/room/PCTransportManager.ts +1 -1
- package/src/room/RTCEngine.ts +274 -112
- package/src/room/Room.ts +152 -15
- package/src/room/data-stream/outgoing/OutgoingDataStreamManager.ts +9 -9
- package/src/room/data-track/LocalDataTrack.ts +126 -0
- package/src/room/data-track/RemoteDataTrack.ts +80 -0
- package/src/room/data-track/depacketizer.ts +23 -26
- package/src/room/data-track/frame.ts +28 -2
- package/src/room/data-track/handle.ts +2 -8
- package/src/room/data-track/incoming/IncomingDataTrackManager.test.ts +555 -0
- package/src/room/data-track/incoming/IncomingDataTrackManager.ts +589 -0
- package/src/room/data-track/incoming/errors.ts +57 -0
- package/src/room/data-track/incoming/pipeline.ts +121 -0
- package/src/room/data-track/incoming/types.ts +22 -0
- package/src/room/data-track/outgoing/OutgoingDataTrackManager.test.ts +240 -27
- package/src/room/data-track/outgoing/OutgoingDataTrackManager.ts +165 -84
- package/src/room/data-track/outgoing/errors.ts +40 -11
- package/src/room/data-track/outgoing/pipeline.ts +25 -23
- package/src/room/data-track/outgoing/types.ts +14 -6
- package/src/room/data-track/packet/errors.ts +2 -14
- package/src/room/data-track/packet/extensions.ts +21 -26
- package/src/room/data-track/packet/index.test.ts +22 -33
- package/src/room/data-track/packet/index.ts +4 -6
- package/src/room/data-track/packet/serializable.ts +4 -4
- package/src/room/data-track/packetizer.test.ts +2 -2
- package/src/room/data-track/packetizer.ts +7 -10
- package/src/room/data-track/track-interfaces.ts +53 -0
- package/src/room/data-track/types.ts +31 -0
- package/src/room/events.ts +26 -1
- package/src/room/participant/LocalParticipant.ts +57 -6
- package/src/room/participant/RemoteParticipant.ts +26 -1
- package/src/room/token-source/TokenSource.ts +8 -2
- package/src/room/token-source/types.ts +4 -0
- package/src/room/utils.ts +5 -1
- package/src/utils/abort-signal-polyfill.ts +63 -0
- package/src/utils/deferrable-map.ts +109 -0
- package/src/utils/subscribeToEvents.ts +18 -1
- package/dist/src/room/data-track/e2ee.d.ts +0 -12
- package/dist/src/room/data-track/e2ee.d.ts.map +0 -1
- package/dist/src/room/data-track/track.d.ts +0 -30
- package/dist/src/room/data-track/track.d.ts.map +0 -1
- package/dist/src/utils/throws.d.ts +0 -36
- package/dist/src/utils/throws.d.ts.map +0 -1
- package/dist/ts4.2/room/data-track/e2ee.d.ts +0 -12
- package/dist/ts4.2/room/data-track/track.d.ts +0 -30
- package/dist/ts4.2/utils/throws.d.ts +0 -39
- package/src/room/data-track/e2ee.ts +0 -14
- package/src/room/data-track/track.ts +0 -50
- package/src/utils/throws.ts +0 -42
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DataTrackInfo } from './types';
|
|
2
|
+
export declare const TrackSymbol: symbol;
|
|
3
|
+
export interface ITrack {
|
|
4
|
+
readonly trackSymbol: typeof TrackSymbol;
|
|
5
|
+
}
|
|
6
|
+
/** An interface representing a track (of any type) which is local and sending data to the SFU. */
|
|
7
|
+
export interface ILocalTrack extends ITrack {
|
|
8
|
+
readonly isLocal: true;
|
|
9
|
+
isPublished(): boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare const RemoteTrackSymbol: symbol;
|
|
12
|
+
/** An interface representing a track (of any type) which is remote and receiving data from the SFU. */
|
|
13
|
+
export interface IRemoteTrack extends ITrack {
|
|
14
|
+
readonly isLocal: false;
|
|
15
|
+
}
|
|
16
|
+
export declare const DataTrackSymbol: symbol;
|
|
17
|
+
/** An interface representing a data track, either local or remote. */
|
|
18
|
+
export interface IDataTrack extends ITrack {
|
|
19
|
+
readonly typeSymbol: typeof DataTrackSymbol;
|
|
20
|
+
readonly info?: DataTrackInfo;
|
|
21
|
+
}
|
|
22
|
+
export declare function isDataTrack(subject: unknown): subject is IDataTrack;
|
|
23
|
+
//# sourceMappingURL=track-interfaces.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { DataTrackInfo as ProtocolDataTrackInfo } from '@livekit/protocol';
|
|
2
|
+
import type { DataTrackHandle } from './handle';
|
|
3
|
+
export type DataTrackSid = string;
|
|
4
|
+
/** Information about a published data track. */
|
|
5
|
+
export type DataTrackInfo = {
|
|
6
|
+
sid: DataTrackSid;
|
|
7
|
+
pubHandle: DataTrackHandle;
|
|
8
|
+
name: string;
|
|
9
|
+
usesE2ee: boolean;
|
|
10
|
+
};
|
|
11
|
+
export declare const DataTrackInfo: {
|
|
12
|
+
from(protocolInfo: ProtocolDataTrackInfo): DataTrackInfo;
|
|
13
|
+
toProtobuf(info: DataTrackInfo): ProtocolDataTrackInfo;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -291,7 +291,7 @@ export declare enum RoomEvent {
|
|
|
291
291
|
EncryptionError = "encryptionError",
|
|
292
292
|
/**
|
|
293
293
|
* Emits whenever the current buffer status of a data channel changes
|
|
294
|
-
* args: (isLow: boolean, kind: [[
|
|
294
|
+
* args: (isLow: boolean, kind: [[DataChannelKind]])
|
|
295
295
|
*/
|
|
296
296
|
DCBufferStatusChanged = "dcBufferStatusChanged",
|
|
297
297
|
/**
|
|
@@ -307,7 +307,23 @@ export declare enum RoomEvent {
|
|
|
307
307
|
/**
|
|
308
308
|
* fired when the client receives connection metrics from other participants
|
|
309
309
|
*/
|
|
310
|
-
MetricsReceived = "metricsReceived"
|
|
310
|
+
MetricsReceived = "metricsReceived",
|
|
311
|
+
/**
|
|
312
|
+
* Emits when a new data track has been published by a downstream participant.
|
|
313
|
+
*/
|
|
314
|
+
DataTrackPublished = "dataTrackPublished",
|
|
315
|
+
/**
|
|
316
|
+
* Emits when a new data track has been unpublished by a downstream participant.
|
|
317
|
+
*/
|
|
318
|
+
DataTrackUnpublished = "dataTrackUnpublished",
|
|
319
|
+
/**
|
|
320
|
+
* Emits when a new data track has been published locally.
|
|
321
|
+
*/
|
|
322
|
+
LocalDataTrackPublished = "localDataTrackPublished",
|
|
323
|
+
/**
|
|
324
|
+
* Emits when a new data track has been unpublished locally.
|
|
325
|
+
*/
|
|
326
|
+
LocalDataTrackUnpublished = "localDataTrackUnpublished"
|
|
311
327
|
}
|
|
312
328
|
export declare enum ParticipantEvent {
|
|
313
329
|
/**
|
|
@@ -528,7 +544,12 @@ export declare enum EngineEvent {
|
|
|
528
544
|
Offline = "offline",
|
|
529
545
|
SignalRequestResponse = "signalRequestResponse",
|
|
530
546
|
SignalConnected = "signalConnected",
|
|
531
|
-
RoomMoved = "roomMoved"
|
|
547
|
+
RoomMoved = "roomMoved",
|
|
548
|
+
PublishDataTrackResponse = "publishDataTrackResponse",
|
|
549
|
+
UnPublishDataTrackResponse = "unPublishDataTrackResponse",
|
|
550
|
+
DataTrackSubscriberHandles = "dataTrackSubscriberHandles",
|
|
551
|
+
DataTrackPacketReceived = "dataTrackPacketReceived",
|
|
552
|
+
Joined = "joined"
|
|
532
553
|
}
|
|
533
554
|
export declare enum TrackEvent {
|
|
534
555
|
Message = "message",
|
|
@@ -4,6 +4,9 @@ import TypedPromise from '../../utils/TypedPromise';
|
|
|
4
4
|
import type RTCEngine from '../RTCEngine';
|
|
5
5
|
import type OutgoingDataStreamManager from '../data-stream/outgoing/OutgoingDataStreamManager';
|
|
6
6
|
import type { TextStreamWriter } from '../data-stream/outgoing/StreamWriter';
|
|
7
|
+
import LocalDataTrack from '../data-track/LocalDataTrack';
|
|
8
|
+
import type OutgoingDataTrackManager from '../data-track/outgoing/OutgoingDataTrackManager';
|
|
9
|
+
import type { DataTrackOptions } from '../data-track/outgoing/types';
|
|
7
10
|
import type { PerformRpcParams, RpcInvocationData } from '../rpc';
|
|
8
11
|
import { RpcError } from '../rpc';
|
|
9
12
|
import LocalTrack from '../track/LocalTrack';
|
|
@@ -38,12 +41,13 @@ export default class LocalParticipant extends Participant {
|
|
|
38
41
|
private firstActiveAgent?;
|
|
39
42
|
private rpcHandlers;
|
|
40
43
|
private roomOutgoingDataStreamManager;
|
|
44
|
+
private roomOutgoingDataTrackManager;
|
|
41
45
|
private pendingSignalRequests;
|
|
42
46
|
private enabledPublishVideoCodecs;
|
|
43
47
|
private pendingAcks;
|
|
44
48
|
private pendingResponses;
|
|
45
49
|
/** @internal */
|
|
46
|
-
constructor(sid: string, identity: string, engine: RTCEngine, options: InternalRoomOptions, roomRpcHandlers: Map<string, (data: RpcInvocationData) => Promise<string>>, roomOutgoingDataStreamManager: OutgoingDataStreamManager);
|
|
50
|
+
constructor(sid: string, identity: string, engine: RTCEngine, options: InternalRoomOptions, roomRpcHandlers: Map<string, (data: RpcInvocationData) => Promise<string>>, roomOutgoingDataStreamManager: OutgoingDataStreamManager, roomOutgoingDataTrackManager: OutgoingDataTrackManager);
|
|
47
51
|
get lastCameraError(): Error | undefined;
|
|
48
52
|
get lastMicrophoneError(): Error | undefined;
|
|
49
53
|
get isE2EEEnabled(): boolean;
|
|
@@ -261,5 +265,11 @@ export default class LocalParticipant extends Participant {
|
|
|
261
265
|
private handleTrackEnded;
|
|
262
266
|
private getPublicationForTrack;
|
|
263
267
|
private waitForPendingPublicationOfSource;
|
|
268
|
+
/** Publishes a data track.
|
|
269
|
+
*
|
|
270
|
+
* Returns the published data track if successful. Use {@link LocalDataTrack#tryPush}
|
|
271
|
+
* to send data frames on the track.
|
|
272
|
+
*/
|
|
273
|
+
publishDataTrack(options: DataTrackOptions): Promise<LocalDataTrack>;
|
|
264
274
|
}
|
|
265
275
|
//# sourceMappingURL=LocalParticipant.d.ts.map
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ParticipantInfo } from '@livekit/protocol';
|
|
2
2
|
import type { SignalClient } from '../../api/SignalClient';
|
|
3
|
+
import { DeferrableMap } from '../../utils/deferrable-map';
|
|
4
|
+
import type RemoteDataTrack from '../data-track/RemoteDataTrack';
|
|
3
5
|
import RemoteTrackPublication from '../track/RemoteTrackPublication';
|
|
4
6
|
import { Track } from '../track/Track';
|
|
5
7
|
import type { AudioOutputOptions } from '../track/options';
|
|
@@ -11,13 +13,20 @@ export default class RemoteParticipant extends Participant {
|
|
|
11
13
|
audioTrackPublications: Map<string, RemoteTrackPublication>;
|
|
12
14
|
videoTrackPublications: Map<string, RemoteTrackPublication>;
|
|
13
15
|
trackPublications: Map<string, RemoteTrackPublication>;
|
|
16
|
+
/** A map of data track name to the corresponding {@link RemoteDataTrack}.
|
|
17
|
+
* @example
|
|
18
|
+
* // An already existing data track:
|
|
19
|
+
* const track = remoteParticipant.dataTracks.get("data track name");
|
|
20
|
+
* // Wait for a data track which will be published soon:
|
|
21
|
+
* const track = await remoteParticipant.dataTracks.getDeferred("data track name"); */
|
|
22
|
+
dataTracks: DeferrableMap<RemoteDataTrack['info']['name'], RemoteDataTrack>;
|
|
14
23
|
signalClient: SignalClient;
|
|
15
24
|
private volumeMap;
|
|
16
25
|
private audioOutput?;
|
|
17
26
|
/** @internal */
|
|
18
27
|
static fromParticipantInfo(signalClient: SignalClient, pi: ParticipantInfo, loggerOptions: LoggerOptions): RemoteParticipant;
|
|
19
28
|
protected get logContext(): {
|
|
20
|
-
|
|
29
|
+
remoteParticipantID: string;
|
|
21
30
|
remoteParticipant: string;
|
|
22
31
|
};
|
|
23
32
|
/** @internal */
|
|
@@ -53,6 +62,10 @@ export default class RemoteParticipant extends Participant {
|
|
|
53
62
|
*/
|
|
54
63
|
setAudioOutput(output: AudioOutputOptions): Promise<void>;
|
|
55
64
|
/** @internal */
|
|
65
|
+
addRemoteDataTrack(remoteDataTrack: RemoteDataTrack): void;
|
|
66
|
+
/** @internal */
|
|
67
|
+
removeRemoteDataTrack(remoteDataTrackSid: RemoteDataTrack['info']['sid']): void;
|
|
68
|
+
/** @internal */
|
|
56
69
|
emit<E extends keyof ParticipantEventCallbacks>(event: E, ...args: Parameters<ParticipantEventCallbacks[E]>): boolean;
|
|
57
70
|
}
|
|
58
71
|
//# sourceMappingURL=RemoteParticipant.d.ts.map
|
|
@@ -11,7 +11,7 @@ declare abstract class TokenSourceCached extends TokenSourceConfigurable {
|
|
|
11
11
|
private isSameAsCachedFetchOptions;
|
|
12
12
|
private shouldReturnCachedValueFromFetch;
|
|
13
13
|
getCachedResponseJwtPayload(): import("./types").TokenPayload | null;
|
|
14
|
-
fetch(options: TokenSourceFetchOptions): Promise<TokenSourceResponseObject>;
|
|
14
|
+
fetch(options: TokenSourceFetchOptions, force?: boolean): Promise<TokenSourceResponseObject>;
|
|
15
15
|
protected abstract update(options: TokenSourceFetchOptions): Promise<TokenSourceResponse>;
|
|
16
16
|
}
|
|
17
17
|
type LiteralOrFn = TokenSourceResponseObject | (() => TokenSourceResponseObject | Promise<TokenSourceResponseObject>);
|
|
@@ -62,6 +62,7 @@ export type TokenSourceFetchOptions = {
|
|
|
62
62
|
*/
|
|
63
63
|
export declare abstract class TokenSourceConfigurable {
|
|
64
64
|
abstract fetch(options: TokenSourceFetchOptions): Promise<TokenSourceResponseObject>;
|
|
65
|
+
abstract fetch(options: TokenSourceFetchOptions, force?: boolean): Promise<TokenSourceResponseObject>;
|
|
65
66
|
}
|
|
66
67
|
/** A TokenSource is a mechanism for fetching credentials required to connect to a LiveKit Room. */
|
|
67
68
|
export type TokenSourceBase = TokenSourceFixed | TokenSourceConfigurable;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ChatMessage as ChatMessageModel, ClientInfo, DisconnectReason, Transcription as TranscriptionModel } from '@livekit/protocol';
|
|
2
|
+
import type { Throws } from '@livekit/throws-transformer/throws';
|
|
2
3
|
import TypedPromise from '../utils/TypedPromise';
|
|
3
4
|
import type { BrowserDetails } from '../utils/browserParser';
|
|
4
|
-
import type { Throws } from '../utils/throws';
|
|
5
5
|
import type { ConnectionError } from './errors';
|
|
6
6
|
import type LocalParticipant from './participant/LocalParticipant';
|
|
7
7
|
import type Participant from './participant/Participant';
|
|
@@ -145,4 +145,5 @@ export declare function isLocalParticipant(p: Participant): p is LocalParticipan
|
|
|
145
145
|
export declare function isRemoteParticipant(p: Participant): p is RemoteParticipant;
|
|
146
146
|
export declare function splitUtf8(s: string, n: number): Uint8Array[];
|
|
147
147
|
export declare function extractMaxAgeFromRequestHeaders(headers: Headers): number | undefined;
|
|
148
|
+
export declare function isCompressionStreamSupported(): boolean;
|
|
148
149
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Implementation of AbortSignal.any
|
|
3
|
+
* Creates a signal that will be aborted when any of the given signals is aborted.
|
|
4
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/any
|
|
5
|
+
*/
|
|
6
|
+
export declare function abortSignalAny(signals: Array<AbortSignal>): AbortSignal;
|
|
7
|
+
/**
|
|
8
|
+
* Implementation of AbortSignal.timeout
|
|
9
|
+
* Creates a signal that will be aborted after the specified timeout.
|
|
10
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout
|
|
11
|
+
*/
|
|
12
|
+
export declare function abortSignalTimeout(ms: number): AbortSignal;
|
|
13
|
+
//# sourceMappingURL=abort-signal-polyfill.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Throws } from '@livekit/throws-transformer/throws';
|
|
2
|
+
/** An error which is thrown if a {@link DeferrableMap#getDeferred} call is aborted midway
|
|
3
|
+
* through. */
|
|
4
|
+
export declare class DeferrableMapAbortError extends DOMException {
|
|
5
|
+
reason: unknown;
|
|
6
|
+
constructor(message: string, reason?: unknown);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A Map-like container keyed by unique strings that supports the ability to wait
|
|
10
|
+
* for future keys to show up in the map.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* // An already existing key:
|
|
14
|
+
* const value = map.get("key");
|
|
15
|
+
* // Wait for a key which will be added soon:
|
|
16
|
+
* const value = await map.getDeferred("key");
|
|
17
|
+
*/
|
|
18
|
+
export declare class DeferrableMap<K, V> extends Map<K, V> {
|
|
19
|
+
private pending;
|
|
20
|
+
set(key: K, value: V): this;
|
|
21
|
+
get [Symbol.toStringTag](): string;
|
|
22
|
+
/**
|
|
23
|
+
* Returns the value for `key` immediately if it exists, otherwise returns a
|
|
24
|
+
* promise that resolves once `set(key, value)` is called.
|
|
25
|
+
*
|
|
26
|
+
* If an `AbortSignal` is provided and it is aborted before the key appears,
|
|
27
|
+
* the returned promise rejects with an {@link DeferrableMapAbortError}.
|
|
28
|
+
*/
|
|
29
|
+
getDeferred(key: K): Promise<V>;
|
|
30
|
+
getDeferred(key: K, signal: AbortSignal): Promise<Throws<V, DeferrableMapAbortError>>;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=deferrable-map.d.ts.map
|
|
@@ -6,6 +6,9 @@ export declare function subscribeToEvents<Callbacks extends EventMap, EventNames
|
|
|
6
6
|
/** Listen for the next occurrance of an event to be emitted, or return the last event that was
|
|
7
7
|
* buffered (but hasn't been processed yet). */
|
|
8
8
|
waitFor<EventPayload extends Parameters<Callbacks[EventName]>[0], EventName extends EventNames = EventNames>(eventName: EventName): Promise<EventPayload>;
|
|
9
|
+
/** Are there events of the given name which are waiting to be processed? Use this to assert
|
|
10
|
+
* that no unexpected events have been emitted. */
|
|
11
|
+
areThereBufferedEvents<EventPayload extends Parameters<Callbacks[EventName]>[0], EventName extends EventNames = EventNames>(eventName: EventName): boolean;
|
|
9
12
|
/** Cleanup any lingering subscriptions. */
|
|
10
13
|
unsubscribe: () => void;
|
|
11
14
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "livekit-client",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.18.1",
|
|
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",
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"@changesets/cli": "2.29.8",
|
|
57
57
|
"@eslint/js": "9.39.2",
|
|
58
58
|
"@livekit/changesets-changelog-github": "^0.0.4",
|
|
59
|
+
"@livekit/throws-transformer": "^0.1.3",
|
|
59
60
|
"@rollup/plugin-babel": "6.1.0",
|
|
60
61
|
"@rollup/plugin-commonjs": "28.0.9",
|
|
61
62
|
"@rollup/plugin-json": "6.1.0",
|
|
@@ -86,6 +87,7 @@
|
|
|
86
87
|
"rollup-plugin-delete": "^2.1.0",
|
|
87
88
|
"rollup-plugin-typescript2": "0.36.0",
|
|
88
89
|
"size-limit": "^11.2.0",
|
|
90
|
+
"tsx": "^4.21.0",
|
|
89
91
|
"typedoc": "0.28.16",
|
|
90
92
|
"typedoc-plugin-no-inherit": "1.6.1",
|
|
91
93
|
"typescript": "5.8.3",
|
|
@@ -107,7 +109,7 @@
|
|
|
107
109
|
"deploy": "gh-pages -d examples/demo/dist",
|
|
108
110
|
"format": "prettier --write src examples/**/*.ts",
|
|
109
111
|
"format:check": "prettier --check src examples/**/*.ts",
|
|
110
|
-
"throws:check": "pnpm dlx
|
|
112
|
+
"throws:check": "pnpm --package=@livekit/throws-transformer dlx throws-check 'src/!(*.test).ts' 'src/**/!(*.test).ts'",
|
|
111
113
|
"ci:publish": "pnpm build:clean && pnpm compat && changeset publish",
|
|
112
114
|
"downlevel-dts": "downlevel-dts ./dist/src ./dist/ts4.2 --to=4.2",
|
|
113
115
|
"compat": "eslint --config ./eslint.config.dist.mjs --no-inline-config ./dist/livekit-client.esm.mjs",
|
|
@@ -300,8 +300,10 @@ describe('SignalClient.connect', () => {
|
|
|
300
300
|
|
|
301
301
|
describe('Failure Case - WebSocket Connection Errors', () => {
|
|
302
302
|
it('should reject with NotAllowed error for 4xx HTTP status', async () => {
|
|
303
|
+
const openedPromise = Promise.reject(new Error('Connection failed'));
|
|
304
|
+
openedPromise.catch(() => {}); // prevent unhandled rejection before join attaches its handler
|
|
303
305
|
mockWebSocketStream({
|
|
304
|
-
opened:
|
|
306
|
+
opened: openedPromise,
|
|
305
307
|
readyState: 3,
|
|
306
308
|
});
|
|
307
309
|
|
|
@@ -321,8 +323,10 @@ describe('SignalClient.connect', () => {
|
|
|
321
323
|
});
|
|
322
324
|
|
|
323
325
|
it('should reject with ServerUnreachable when fetch fails', async () => {
|
|
326
|
+
const openedPromise = Promise.reject(new Error('Connection failed'));
|
|
327
|
+
openedPromise.catch(() => {}); // prevent unhandled rejection before join attaches its handler
|
|
324
328
|
mockWebSocketStream({
|
|
325
|
-
opened:
|
|
329
|
+
opened: openedPromise,
|
|
326
330
|
readyState: 3,
|
|
327
331
|
});
|
|
328
332
|
|
|
@@ -338,9 +342,10 @@ describe('SignalClient.connect', () => {
|
|
|
338
342
|
|
|
339
343
|
it('should handle ConnectionError from WebSocket rejection', async () => {
|
|
340
344
|
const customError = ConnectionError.internal('Custom error', { status: 500 });
|
|
341
|
-
|
|
345
|
+
const openedPromise = Promise.reject(customError);
|
|
346
|
+
openedPromise.catch(() => {}); // prevent unhandled rejection before join attaches its handler
|
|
342
347
|
mockWebSocketStream({
|
|
343
|
-
opened:
|
|
348
|
+
opened: openedPromise,
|
|
344
349
|
readyState: 3,
|
|
345
350
|
});
|
|
346
351
|
|
package/src/api/SignalClient.ts
CHANGED
|
@@ -5,7 +5,9 @@ import {
|
|
|
5
5
|
ClientInfo,
|
|
6
6
|
ConnectionQualityUpdate,
|
|
7
7
|
ConnectionSettings,
|
|
8
|
+
DataTrackSubscriberHandles,
|
|
8
9
|
DisconnectReason,
|
|
10
|
+
Encryption_Type,
|
|
9
11
|
JoinRequest,
|
|
10
12
|
JoinResponse,
|
|
11
13
|
LeaveRequest,
|
|
@@ -14,6 +16,8 @@ import {
|
|
|
14
16
|
MuteTrackRequest,
|
|
15
17
|
ParticipantInfo,
|
|
16
18
|
Ping,
|
|
19
|
+
PublishDataTrackRequest,
|
|
20
|
+
PublishDataTrackResponse,
|
|
17
21
|
ReconnectReason,
|
|
18
22
|
ReconnectResponse,
|
|
19
23
|
RequestResponse,
|
|
@@ -35,6 +39,10 @@ import {
|
|
|
35
39
|
TrackPublishedResponse,
|
|
36
40
|
TrackUnpublishedResponse,
|
|
37
41
|
TrickleRequest,
|
|
42
|
+
UnpublishDataTrackRequest,
|
|
43
|
+
UnpublishDataTrackResponse,
|
|
44
|
+
UpdateDataSubscription,
|
|
45
|
+
UpdateDataSubscription_Update,
|
|
38
46
|
UpdateLocalAudioTrack,
|
|
39
47
|
UpdateParticipantMetadata,
|
|
40
48
|
UpdateSubscription,
|
|
@@ -42,13 +50,16 @@ import {
|
|
|
42
50
|
UpdateVideoLayers,
|
|
43
51
|
VideoLayer,
|
|
44
52
|
WrappedJoinRequest,
|
|
53
|
+
WrappedJoinRequest_Compression,
|
|
45
54
|
protoInt64,
|
|
46
55
|
} from '@livekit/protocol';
|
|
47
56
|
import log, { LoggerNames, getLogger } from '../logger';
|
|
57
|
+
import type { DataTrackHandle } from '../room/data-track/handle';
|
|
58
|
+
import { type DataTrackSid } from '../room/data-track/types';
|
|
48
59
|
import { ConnectionError } from '../room/errors';
|
|
49
60
|
import CriticalTimers from '../room/timers';
|
|
50
61
|
import type { LoggerOptions } from '../room/types';
|
|
51
|
-
import { getClientInfo, isReactNative, sleep } from '../room/utils';
|
|
62
|
+
import { getClientInfo, isCompressionStreamSupported, isReactNative, sleep } from '../room/utils';
|
|
52
63
|
import { AsyncQueue } from '../utils/AsyncQueue';
|
|
53
64
|
import { type WebSocketConnection, WebSocketStream } from './WebSocketStream';
|
|
54
65
|
import {
|
|
@@ -174,6 +185,14 @@ export class SignalClient {
|
|
|
174
185
|
|
|
175
186
|
onMediaSectionsRequirement?: (requirement: MediaSectionsRequirement) => void;
|
|
176
187
|
|
|
188
|
+
onPublishDataTrackResponse?: (event: PublishDataTrackResponse) => void;
|
|
189
|
+
|
|
190
|
+
onUnPublishDataTrackResponse?: (event: UnpublishDataTrackResponse) => void;
|
|
191
|
+
|
|
192
|
+
onDataTrackSubscriberHandles?: (event: DataTrackSubscriberHandles) => void;
|
|
193
|
+
|
|
194
|
+
onJoined?: (event: JoinResponse) => void;
|
|
195
|
+
|
|
177
196
|
connectOptions?: ConnectOpts;
|
|
178
197
|
|
|
179
198
|
ws?: WebSocketStream;
|
|
@@ -248,12 +267,13 @@ export class SignalClient {
|
|
|
248
267
|
opts: SignalOptions,
|
|
249
268
|
abortSignal?: AbortSignal,
|
|
250
269
|
useV0Path: boolean = false,
|
|
270
|
+
publisherOffer?: SessionDescription,
|
|
251
271
|
): Promise<JoinResponse> {
|
|
252
272
|
// during a full reconnect, we'd want to start the sequence even if currently
|
|
253
273
|
// connected
|
|
254
274
|
this.state = SignalConnectionState.CONNECTING;
|
|
255
275
|
this.options = opts;
|
|
256
|
-
const res = await this.connect(url, token, opts, abortSignal, useV0Path);
|
|
276
|
+
const res = await this.connect(url, token, opts, abortSignal, useV0Path, publisherOffer);
|
|
257
277
|
return res as JoinResponse;
|
|
258
278
|
}
|
|
259
279
|
|
|
@@ -296,6 +316,7 @@ export class SignalClient {
|
|
|
296
316
|
abortSignal?: AbortSignal,
|
|
297
317
|
/** setting this to true results in dual peer connection mode being used */
|
|
298
318
|
useV0Path: boolean = false,
|
|
319
|
+
publisherOffer?: SessionDescription,
|
|
299
320
|
): Promise<JoinResponse | ReconnectResponse | undefined> {
|
|
300
321
|
const unlock = await this.connectionLock.lock();
|
|
301
322
|
|
|
@@ -305,7 +326,7 @@ export class SignalClient {
|
|
|
305
326
|
const clientInfo = getClientInfo();
|
|
306
327
|
const params = useV0Path
|
|
307
328
|
? createConnectionParams(token, clientInfo, opts)
|
|
308
|
-
: createJoinRequestConnectionParams(token, clientInfo, opts);
|
|
329
|
+
: await createJoinRequestConnectionParams(token, clientInfo, opts, publisherOffer);
|
|
309
330
|
const rtcUrl = createRtcUrl(url, params, useV0Path).toString();
|
|
310
331
|
const validateUrl = createValidateUrl(rtcUrl).toString();
|
|
311
332
|
|
|
@@ -437,8 +458,9 @@ export class SignalClient {
|
|
|
437
458
|
return;
|
|
438
459
|
}
|
|
439
460
|
|
|
440
|
-
// Handle join response
|
|
461
|
+
// Handle join response
|
|
441
462
|
if (firstSignalResponse.message?.case === 'join') {
|
|
463
|
+
// Set up ping configuration
|
|
442
464
|
this.pingTimeoutDuration = firstSignalResponse.message.value.pingTimeout;
|
|
443
465
|
this.pingIntervalDuration = firstSignalResponse.message.value.pingInterval;
|
|
444
466
|
|
|
@@ -449,6 +471,10 @@ export class SignalClient {
|
|
|
449
471
|
interval: this.pingIntervalDuration,
|
|
450
472
|
});
|
|
451
473
|
}
|
|
474
|
+
|
|
475
|
+
if (this.onJoined) {
|
|
476
|
+
this.onJoined(firstSignalResponse.message.value);
|
|
477
|
+
}
|
|
452
478
|
}
|
|
453
479
|
|
|
454
480
|
// Handle successful connection
|
|
@@ -685,7 +711,40 @@ export class SignalClient {
|
|
|
685
711
|
});
|
|
686
712
|
}
|
|
687
713
|
|
|
688
|
-
|
|
714
|
+
sendPublishDataTrackRequest(handle: DataTrackHandle, name: string, usesE2ee: boolean) {
|
|
715
|
+
return this.sendRequest({
|
|
716
|
+
case: 'publishDataTrackRequest',
|
|
717
|
+
value: new PublishDataTrackRequest({
|
|
718
|
+
pubHandle: handle,
|
|
719
|
+
name: name,
|
|
720
|
+
encryption: usesE2ee ? Encryption_Type.GCM : Encryption_Type.NONE,
|
|
721
|
+
}),
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
sendUnPublishDataTrackRequest(handle: DataTrackHandle) {
|
|
726
|
+
return this.sendRequest({
|
|
727
|
+
case: 'unpublishDataTrackRequest',
|
|
728
|
+
value: new UnpublishDataTrackRequest({ pubHandle: handle }),
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
sendUpdateDataSubscription(sid: DataTrackSid, subscribe: boolean) {
|
|
733
|
+
return this.sendRequest({
|
|
734
|
+
case: 'updateDataSubscription',
|
|
735
|
+
value: new UpdateDataSubscription({
|
|
736
|
+
// FIXME: consider refactoring to allow caller to pass an array of events through
|
|
737
|
+
updates: [
|
|
738
|
+
new UpdateDataSubscription_Update({
|
|
739
|
+
trackSid: sid,
|
|
740
|
+
subscribe,
|
|
741
|
+
}),
|
|
742
|
+
],
|
|
743
|
+
}),
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
private async sendRequest(message: SignalMessage, fromQueue: boolean = false) {
|
|
689
748
|
// capture all requests while reconnecting and put them in a queue
|
|
690
749
|
// unless the request originates from the queue, then don't enqueue again
|
|
691
750
|
const canQueue = !fromQueue && !canPassThroughQueue(message);
|
|
@@ -827,6 +886,18 @@ export class SignalClient {
|
|
|
827
886
|
if (this.onMediaSectionsRequirement) {
|
|
828
887
|
this.onMediaSectionsRequirement(msg.value);
|
|
829
888
|
}
|
|
889
|
+
} else if (msg.case === 'publishDataTrackResponse') {
|
|
890
|
+
if (this.onPublishDataTrackResponse) {
|
|
891
|
+
this.onPublishDataTrackResponse(msg.value);
|
|
892
|
+
}
|
|
893
|
+
} else if (msg.case === 'unpublishDataTrackResponse') {
|
|
894
|
+
if (this.onUnPublishDataTrackResponse) {
|
|
895
|
+
this.onUnPublishDataTrackResponse(msg.value);
|
|
896
|
+
}
|
|
897
|
+
} else if (msg.case === 'dataTrackSubscriberHandles') {
|
|
898
|
+
if (this.onDataTrackSubscriberHandles) {
|
|
899
|
+
this.onDataTrackSubscriberHandles(msg.value);
|
|
900
|
+
}
|
|
830
901
|
} else {
|
|
831
902
|
this.log.debug('unsupported message', { ...this.logContext, msgCase: msg.case });
|
|
832
903
|
}
|
|
@@ -1125,11 +1196,12 @@ function createConnectionParams(
|
|
|
1125
1196
|
return params;
|
|
1126
1197
|
}
|
|
1127
1198
|
|
|
1128
|
-
function createJoinRequestConnectionParams(
|
|
1199
|
+
async function createJoinRequestConnectionParams(
|
|
1129
1200
|
token: string,
|
|
1130
1201
|
info: ClientInfo,
|
|
1131
1202
|
opts: ConnectOpts,
|
|
1132
|
-
|
|
1203
|
+
publisherOffer?: SessionDescription,
|
|
1204
|
+
): Promise<URLSearchParams> {
|
|
1133
1205
|
const params = new URLSearchParams();
|
|
1134
1206
|
params.set('access_token', token);
|
|
1135
1207
|
|
|
@@ -1141,14 +1213,49 @@ function createJoinRequestConnectionParams(
|
|
|
1141
1213
|
}),
|
|
1142
1214
|
reconnect: !!opts.reconnect,
|
|
1143
1215
|
participantSid: opts.sid ? opts.sid : undefined,
|
|
1216
|
+
publisherOffer: publisherOffer,
|
|
1144
1217
|
});
|
|
1145
1218
|
if (opts.reconnectReason) {
|
|
1146
1219
|
joinRequest.reconnectReason = opts.reconnectReason;
|
|
1147
1220
|
}
|
|
1221
|
+
const joinRequestBytes = joinRequest.toBinary();
|
|
1222
|
+
let requestBytes: Uint8Array;
|
|
1223
|
+
let compression: WrappedJoinRequest_Compression;
|
|
1224
|
+
if (isCompressionStreamSupported()) {
|
|
1225
|
+
const stream = new CompressionStream('gzip');
|
|
1226
|
+
const writer = stream.writable.getWriter();
|
|
1227
|
+
writer.write(new Uint8Array(joinRequestBytes));
|
|
1228
|
+
writer.close();
|
|
1229
|
+
const chunks: Uint8Array[] = [];
|
|
1230
|
+
const reader = stream.readable.getReader();
|
|
1231
|
+
while (true) {
|
|
1232
|
+
const { done, value } = await reader.read();
|
|
1233
|
+
if (done) break;
|
|
1234
|
+
chunks.push(value);
|
|
1235
|
+
}
|
|
1236
|
+
const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
|
|
1237
|
+
const result = new Uint8Array(totalLength);
|
|
1238
|
+
let offset = 0;
|
|
1239
|
+
for (const chunk of chunks) {
|
|
1240
|
+
result.set(chunk, offset);
|
|
1241
|
+
offset += chunk.length;
|
|
1242
|
+
}
|
|
1243
|
+
requestBytes = result;
|
|
1244
|
+
compression = WrappedJoinRequest_Compression.GZIP;
|
|
1245
|
+
} else {
|
|
1246
|
+
requestBytes = joinRequestBytes;
|
|
1247
|
+
compression = WrappedJoinRequest_Compression.NONE;
|
|
1248
|
+
}
|
|
1148
1249
|
const wrappedJoinRequest = new WrappedJoinRequest({
|
|
1149
|
-
joinRequest:
|
|
1250
|
+
joinRequest: requestBytes,
|
|
1251
|
+
compression,
|
|
1150
1252
|
});
|
|
1151
|
-
|
|
1253
|
+
const wrappedBytes = wrappedJoinRequest.toBinary();
|
|
1254
|
+
const bytesToBase64 = (bytes: Uint8Array) => {
|
|
1255
|
+
const binString = Array.from(bytes, (byte) => String.fromCodePoint(byte)).join('');
|
|
1256
|
+
return btoa(binString);
|
|
1257
|
+
};
|
|
1258
|
+
params.set('join_request', bytesToBase64(wrappedBytes).replace(/\+/g, '-').replace(/\//g, '_'));
|
|
1152
1259
|
|
|
1153
1260
|
return params;
|
|
1154
1261
|
}
|
package/src/e2ee/constants.ts
CHANGED
package/src/e2ee/types.ts
CHANGED
|
@@ -183,6 +183,12 @@ export type KeyProviderOptions = {
|
|
|
183
183
|
ratchetWindowSize: number;
|
|
184
184
|
failureTolerance: number;
|
|
185
185
|
keyringSize: number;
|
|
186
|
+
/**
|
|
187
|
+
* Size of the encryption key in bits.
|
|
188
|
+
* Defaults to 128. Note that 128 is currently the only value
|
|
189
|
+
* supported by non-web SDKs.
|
|
190
|
+
*/
|
|
191
|
+
keySize: 128 | 256;
|
|
186
192
|
};
|
|
187
193
|
|
|
188
194
|
export type KeyInfo = {
|
package/src/e2ee/utils.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type DataPacket, EncryptedPacketPayload } from '@livekit/protocol';
|
|
2
2
|
import { ENCRYPTION_ALGORITHM } from './constants';
|
|
3
|
+
import type { KeyProviderOptions } from './types';
|
|
3
4
|
|
|
4
5
|
export function isE2EESupported() {
|
|
5
6
|
return isInsertableStreamSupported() || isScriptTransformSupported();
|
|
@@ -92,8 +93,8 @@ function getAlgoOptions(algorithmName: string, salt: string) {
|
|
|
92
93
|
* Derives a set of keys from the master key.
|
|
93
94
|
* See https://tools.ietf.org/html/draft-omara-sframe-00#section-4.3.1
|
|
94
95
|
*/
|
|
95
|
-
export async function deriveKeys(material: CryptoKey,
|
|
96
|
-
const algorithmOptions = getAlgoOptions(material.algorithm.name,
|
|
96
|
+
export async function deriveKeys(material: CryptoKey, options: KeyProviderOptions) {
|
|
97
|
+
const algorithmOptions = getAlgoOptions(material.algorithm.name, options.ratchetSalt);
|
|
97
98
|
|
|
98
99
|
// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveKey#HKDF
|
|
99
100
|
// https://developer.mozilla.org/en-US/docs/Web/API/HkdfParams
|
|
@@ -102,7 +103,7 @@ export async function deriveKeys(material: CryptoKey, salt: string) {
|
|
|
102
103
|
material,
|
|
103
104
|
{
|
|
104
105
|
name: ENCRYPTION_ALGORITHM,
|
|
105
|
-
length:
|
|
106
|
+
length: options.keySize,
|
|
106
107
|
},
|
|
107
108
|
false,
|
|
108
109
|
['encrypt', 'decrypt'],
|
|
@@ -93,10 +93,7 @@ export class DataCryptor {
|
|
|
93
93
|
// if not, it might be that a different frame has already ratcheted and we try with that one first
|
|
94
94
|
ratchetResult = await keys.ratchetKey(keyIndex, false);
|
|
95
95
|
|
|
96
|
-
ratchetedKeySet = await deriveKeys(
|
|
97
|
-
ratchetResult.cryptoKey,
|
|
98
|
-
keys.keyProviderOptions.ratchetSalt,
|
|
99
|
-
);
|
|
96
|
+
ratchetedKeySet = await deriveKeys(ratchetResult.cryptoKey, keys.keyProviderOptions);
|
|
100
97
|
}
|
|
101
98
|
|
|
102
99
|
const decryptedData = await DataCryptor.decrypt(
|
|
@@ -603,10 +603,7 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
|
603
603
|
// if not, it might be that a different frame has already ratcheted and we try with that one first
|
|
604
604
|
ratchetResult = await this.keys.ratchetKey(keyIndex, false);
|
|
605
605
|
|
|
606
|
-
ratchetedKeySet = await deriveKeys(
|
|
607
|
-
ratchetResult.cryptoKey,
|
|
608
|
-
this.keyProviderOptions.ratchetSalt,
|
|
609
|
-
);
|
|
606
|
+
ratchetedKeySet = await deriveKeys(ratchetResult.cryptoKey, this.keyProviderOptions);
|
|
610
607
|
}
|
|
611
608
|
|
|
612
609
|
const frame = await this.decryptFrame(encodedFrame, keyIndex, initialMaterial || keySet, {
|
|
@@ -173,7 +173,7 @@ export class ParticipantKeyHandler extends (EventEmitter as new () => TypedEvent
|
|
|
173
173
|
ratchetedResult: RatchetResult | null = null,
|
|
174
174
|
updateCurrentKeyIndex = true,
|
|
175
175
|
) {
|
|
176
|
-
const keySet = await deriveKeys(material, this.keyProviderOptions
|
|
176
|
+
const keySet = await deriveKeys(material, this.keyProviderOptions);
|
|
177
177
|
const newIndex = keyIndex >= 0 ? keyIndex % this.cryptoKeyRing.length : this.currentKeyIndex;
|
|
178
178
|
workerLogger.debug(`setting new key with index ${keyIndex}`, {
|
|
179
179
|
usage: material.usages,
|