@livekit/rtc-node 0.13.32 → 0.13.34
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/async_queue.d.ts +2 -3
- package/dist/audio_filter.d.ts +2 -3
- package/dist/audio_frame.d.ts +5 -6
- package/dist/audio_mixer.d.ts +3 -6
- package/dist/audio_resampler.d.ts +3 -6
- package/dist/audio_source.d.ts +5 -6
- package/dist/{audio_stream-4M8XlO4-.d.cts → audio_stream-BNVaONuH.d.cts} +36 -10
- package/dist/audio_stream.d.cts +2 -2
- package/dist/audio_stream.d.ts +61 -18
- package/dist/data_streams/index.d.cts +1 -1
- package/dist/data_streams/index.d.ts +4 -3
- package/dist/data_streams/stream_reader.cjs +97 -58
- package/dist/data_streams/stream_reader.cjs.map +1 -1
- package/dist/data_streams/stream_reader.d.cts +1 -1
- package/dist/data_streams/stream_reader.d.ts +65 -2
- package/dist/data_streams/stream_reader.d.ts.map +1 -1
- package/dist/data_streams/stream_writer.d.cts +1 -1
- package/dist/data_streams/stream_writer.d.ts +5 -7
- package/dist/data_streams/types.cjs.map +1 -1
- package/dist/data_streams/types.d.cts +1 -1
- package/dist/data_streams/types.d.ts +47 -2
- package/dist/data_streams/types.d.ts.map +1 -1
- package/dist/e2ee.cjs +5 -1
- package/dist/e2ee.cjs.map +1 -1
- package/dist/e2ee.d.cts +3 -1
- package/dist/e2ee.d.ts +11 -11
- package/dist/e2ee.d.ts.map +1 -1
- package/dist/ffi_client.d.ts +8 -10
- package/dist/frame_processor.d.ts +8 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +22 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -107
- package/dist/log.d.ts +5 -7
- package/dist/participant.cjs +179 -192
- package/dist/participant.cjs.map +1 -1
- package/dist/participant.d.cts +2 -2
- package/dist/participant.d.ts +169 -18
- package/dist/participant.d.ts.map +1 -1
- package/dist/room.cjs +166 -120
- package/dist/room.cjs.map +1 -1
- package/dist/room.d.cts +2 -2
- package/dist/room.d.ts +228 -18
- package/dist/room.d.ts.map +1 -1
- package/dist/rpc.d.ts +7 -9
- package/dist/tests/e2e_common.cjs +157 -0
- package/dist/tests/e2e_common.cjs.map +1 -0
- package/dist/tests/e2e_common.d.cts +56 -0
- package/dist/tests/e2e_common.d.ts +37 -0
- package/dist/tests/e2e_common.d.ts.map +1 -0
- package/dist/track.d.cts +2 -2
- package/dist/track.d.ts +67 -18
- package/dist/track_publication.d.cts +2 -2
- package/dist/track_publication.d.ts +45 -18
- package/dist/transcription.d.ts +3 -4
- package/dist/{types-_PdPVish.d.ts → types-f7wTlFjs.d.cts} +34 -11
- package/dist/types.d.ts +2 -3
- package/dist/utils.cjs +27 -2
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +8 -1
- package/dist/utils.d.ts +10 -5
- package/dist/utils.d.ts.map +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.d.cts +1 -1
- package/dist/version.d.ts +2 -3
- package/dist/video_frame.d.ts +4 -5
- package/dist/video_source.d.ts +6 -8
- package/dist/video_stream.d.cts +2 -2
- package/dist/video_stream.d.ts +5 -22
- package/package.json +6 -7
- package/src/audio_stream_room_lifecycle.test.ts +4 -1
- package/src/data_streams/stream_reader.ts +132 -82
- package/src/data_streams/types.ts +6 -0
- package/src/e2ee.ts +7 -0
- package/src/index.ts +8 -1
- package/src/participant.ts +252 -223
- package/src/room.ts +233 -134
- package/src/tests/e2e.test.ts +50 -139
- package/src/tests/e2e_common.ts +163 -0
- package/src/tests/e2e_data_streams.test.ts +639 -0
- package/src/utils.ts +30 -0
- package/src/version.ts +1 -1
- package/dist/async_queue.js +0 -56
- package/dist/async_queue.js.map +0 -1
- package/dist/audio_filter.js +0 -24
- package/dist/audio_filter.js.map +0 -1
- package/dist/audio_frame.js +0 -78
- package/dist/audio_frame.js.map +0 -1
- package/dist/audio_mixer.js +0 -269
- package/dist/audio_mixer.js.map +0 -1
- package/dist/audio_resampler.js +0 -154
- package/dist/audio_resampler.js.map +0 -1
- package/dist/audio_source.js +0 -134
- package/dist/audio_source.js.map +0 -1
- package/dist/audio_stream-CTyN1Ldy.d.ts +0 -523
- package/dist/audio_stream.js +0 -122
- package/dist/audio_stream.js.map +0 -1
- package/dist/data_streams/index.js +0 -3
- package/dist/data_streams/index.js.map +0 -1
- package/dist/data_streams/stream_reader.js +0 -124
- package/dist/data_streams/stream_reader.js.map +0 -1
- package/dist/data_streams/stream_writer.js +0 -26
- package/dist/data_streams/stream_writer.js.map +0 -1
- package/dist/data_streams/types.js +0 -1
- package/dist/data_streams/types.js.map +0 -1
- package/dist/e2ee.js +0 -251
- package/dist/e2ee.js.map +0 -1
- package/dist/ffi_client.js +0 -89
- package/dist/ffi_client.js.map +0 -1
- package/dist/frame_processor.js +0 -29
- package/dist/frame_processor.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/log.js +0 -9
- package/dist/log.js.map +0 -1
- package/dist/participant.js +0 -715
- package/dist/participant.js.map +0 -1
- package/dist/room.js +0 -900
- package/dist/room.js.map +0 -1
- package/dist/rpc.js +0 -65
- package/dist/rpc.js.map +0 -1
- package/dist/track.js +0 -234
- package/dist/track.js.map +0 -1
- package/dist/track_publication.js +0 -100
- package/dist/track_publication.js.map +0 -1
- package/dist/transcription.js +0 -1
- package/dist/transcription.js.map +0 -1
- package/dist/types-_PdPVish.d.cts +0 -87
- package/dist/types.js +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils.js +0 -35
- package/dist/utils.js.map +0 -1
- package/dist/version.js +0 -5
- package/dist/version.js.map +0 -1
- package/dist/video_frame.js +0 -207
- package/dist/video_frame.js.map +0 -1
- package/dist/video_source.js +0 -53
- package/dist/video_source.js.map +0 -1
- package/dist/video_stream.js +0 -70
- package/dist/video_stream.js.map +0 -1
package/dist/audio_stream.js
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import { AudioStreamType, NewAudioStreamRequest } from "@livekit/rtc-ffi-bindings";
|
|
2
|
-
import { AudioFrame } from "./audio_frame.js";
|
|
3
|
-
import { FfiClient, FfiClientEvent, FfiHandle } from "./ffi_client.js";
|
|
4
|
-
import { isFrameProcessor } from "./frame_processor.js";
|
|
5
|
-
import { log } from "./log.js";
|
|
6
|
-
class AudioStreamSource {
|
|
7
|
-
constructor(track, sampleRateOrOptions, numChannels) {
|
|
8
|
-
this.disposed = false;
|
|
9
|
-
this.frameProcessor = null;
|
|
10
|
-
this.autoCloseProcessor = true;
|
|
11
|
-
this.onEvent = (ev) => {
|
|
12
|
-
if (!this.controller) {
|
|
13
|
-
throw new Error("Stream controller not initialized");
|
|
14
|
-
}
|
|
15
|
-
if (ev.message.case != "audioStreamEvent" || ev.message.value.streamHandle != this.ffiHandle.handle) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
const streamEvent = ev.message.value.message;
|
|
19
|
-
switch (streamEvent.case) {
|
|
20
|
-
case "frameReceived":
|
|
21
|
-
let frame = AudioFrame.fromOwnedInfo(streamEvent.value.frame);
|
|
22
|
-
if (this.frameProcessor && this.frameProcessor.isEnabled()) {
|
|
23
|
-
try {
|
|
24
|
-
frame = this.frameProcessor.process(frame);
|
|
25
|
-
} catch (err) {
|
|
26
|
-
log.warn(`Frame processing failed, passing through original frame: ${err}`);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
this.controller.enqueue(frame);
|
|
30
|
-
break;
|
|
31
|
-
case "eos":
|
|
32
|
-
this.teardown();
|
|
33
|
-
break;
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
this.track = track;
|
|
37
|
-
if (sampleRateOrOptions !== void 0 && typeof sampleRateOrOptions !== "number") {
|
|
38
|
-
this.sampleRate = sampleRateOrOptions.sampleRate ?? 48e3;
|
|
39
|
-
this.numChannels = sampleRateOrOptions.numChannels ?? 1;
|
|
40
|
-
if (isFrameProcessor(sampleRateOrOptions.noiseCancellation)) {
|
|
41
|
-
this.frameProcessor = sampleRateOrOptions.noiseCancellation;
|
|
42
|
-
this.autoCloseProcessor = sampleRateOrOptions.autoCloseNoiseCancellation ?? true;
|
|
43
|
-
} else {
|
|
44
|
-
this.legacyNcOptions = sampleRateOrOptions.noiseCancellation;
|
|
45
|
-
}
|
|
46
|
-
this.frameSizeMs = sampleRateOrOptions.frameSizeMs;
|
|
47
|
-
} else {
|
|
48
|
-
this.sampleRate = sampleRateOrOptions ?? 48e3;
|
|
49
|
-
this.numChannels = numChannels ?? 1;
|
|
50
|
-
}
|
|
51
|
-
const req = new NewAudioStreamRequest({
|
|
52
|
-
type: AudioStreamType.AUDIO_STREAM_NATIVE,
|
|
53
|
-
trackHandle: track.ffi_handle.handle,
|
|
54
|
-
sampleRate: this.sampleRate,
|
|
55
|
-
numChannels: this.numChannels,
|
|
56
|
-
frameSizeMs: this.frameSizeMs,
|
|
57
|
-
...this.legacyNcOptions ? {
|
|
58
|
-
audioFilterModuleId: this.legacyNcOptions.moduleId,
|
|
59
|
-
audioFilterOptions: JSON.stringify(this.legacyNcOptions.options)
|
|
60
|
-
} : {}
|
|
61
|
-
});
|
|
62
|
-
const res = FfiClient.instance.request({
|
|
63
|
-
message: {
|
|
64
|
-
case: "newAudioStream",
|
|
65
|
-
value: req
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
this.ffiHandle = new FfiHandle(res.stream.handle.id);
|
|
69
|
-
FfiClient.instance.on(FfiClientEvent.FfiEvent, this.onEvent);
|
|
70
|
-
track.registerAudioStream(this);
|
|
71
|
-
}
|
|
72
|
-
/** @internal */
|
|
73
|
-
get processor() {
|
|
74
|
-
return this.frameProcessor;
|
|
75
|
-
}
|
|
76
|
-
start(controller) {
|
|
77
|
-
this.controller = controller;
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Detach from the FFI and release resources: on `eos`, on `cancel()`, or
|
|
81
|
-
* because the track went away (e.g. it was unsubscribed — which never
|
|
82
|
-
* produces an `eos`, so without this the stream would keep delivering
|
|
83
|
-
* frames). Already-buffered frames stay readable and the consumer sees `done`
|
|
84
|
-
* after draining them.
|
|
85
|
-
*
|
|
86
|
-
* @remarks
|
|
87
|
-
* Idempotent, so `eos` arriving after a `cancel()` (or vice versa) doesn't
|
|
88
|
-
* double-dispose the handle while buffered frames are still queued.
|
|
89
|
-
*
|
|
90
|
-
* @internal
|
|
91
|
-
*/
|
|
92
|
-
teardown() {
|
|
93
|
-
var _a;
|
|
94
|
-
FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);
|
|
95
|
-
if (this.disposed) {
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
this.disposed = true;
|
|
99
|
-
this.track.unregisterAudioStream(this);
|
|
100
|
-
this.ffiHandle.dispose();
|
|
101
|
-
if (this.frameProcessor && this.autoCloseProcessor) {
|
|
102
|
-
this.frameProcessor.close();
|
|
103
|
-
}
|
|
104
|
-
try {
|
|
105
|
-
(_a = this.controller) == null ? void 0 : _a.close();
|
|
106
|
-
} catch {
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
cancel() {
|
|
110
|
-
this.teardown();
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
class AudioStream extends ReadableStream {
|
|
114
|
-
constructor(track, sampleRateOrOptions, numChannels) {
|
|
115
|
-
super(new AudioStreamSource(track, sampleRateOrOptions, numChannels));
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
export {
|
|
119
|
-
AudioStream,
|
|
120
|
-
AudioStreamSource
|
|
121
|
-
};
|
|
122
|
-
//# sourceMappingURL=audio_stream.js.map
|
package/dist/audio_stream.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/audio_stream.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { NewAudioStreamResponse } from '@livekit/rtc-ffi-bindings';\nimport { AudioStreamType, NewAudioStreamRequest } from '@livekit/rtc-ffi-bindings';\nimport type { UnderlyingSource } from 'node:stream/web';\nimport { AudioFrame } from './audio_frame.js';\nimport type { FfiEvent } from './ffi_client.js';\nimport { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js';\nimport { type FrameProcessor, isFrameProcessor } from './frame_processor.js';\nimport { log } from './log.js';\nimport type { Track } from './track.js';\n\nexport interface AudioStreamOptions {\n noiseCancellation?: NoiseCancellationOptions | FrameProcessor<AudioFrame>;\n /**\n * When the audio stream closes, whether to run the {@link FrameProcessor}'s\n * `close()` method. If `false`, the processor is left open so it can be\n * reused with another {@link AudioStream}. Only relevant when\n * `noiseCancellation` is a {@link FrameProcessor}. Defaults to `true`.\n */\n autoCloseNoiseCancellation?: boolean;\n sampleRate?: number;\n numChannels?: number;\n frameSizeMs?: number;\n}\n\nexport interface NoiseCancellationOptions {\n moduleId: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n options: Record<string, any>;\n}\n\n/** @internal */\nexport class AudioStreamSource implements UnderlyingSource<AudioFrame> {\n private controller?: ReadableStreamDefaultController<AudioFrame>;\n private ffiHandle: FfiHandle;\n private disposed = false;\n private sampleRate: number;\n private numChannels: number;\n private legacyNcOptions?: NoiseCancellationOptions;\n private frameProcessor: FrameProcessor<AudioFrame> | null = null;\n private autoCloseProcessor = true;\n private frameSizeMs?: number;\n private track: Track;\n\n constructor(\n track: Track,\n sampleRateOrOptions?: number | AudioStreamOptions,\n numChannels?: number,\n ) {\n this.track = track;\n if (sampleRateOrOptions !== undefined && typeof sampleRateOrOptions !== 'number') {\n this.sampleRate = sampleRateOrOptions.sampleRate ?? 48000;\n this.numChannels = sampleRateOrOptions.numChannels ?? 1;\n if (isFrameProcessor(sampleRateOrOptions.noiseCancellation)) {\n this.frameProcessor = sampleRateOrOptions.noiseCancellation;\n this.autoCloseProcessor = sampleRateOrOptions.autoCloseNoiseCancellation ?? true;\n } else {\n this.legacyNcOptions = sampleRateOrOptions.noiseCancellation;\n }\n this.frameSizeMs = sampleRateOrOptions.frameSizeMs;\n } else {\n this.sampleRate = (sampleRateOrOptions as number) ?? 48000;\n this.numChannels = numChannels ?? 1;\n }\n\n const req = new NewAudioStreamRequest({\n type: AudioStreamType.AUDIO_STREAM_NATIVE,\n trackHandle: track.ffi_handle.handle,\n sampleRate: this.sampleRate,\n numChannels: this.numChannels,\n frameSizeMs: this.frameSizeMs,\n ...(this.legacyNcOptions\n ? {\n audioFilterModuleId: this.legacyNcOptions.moduleId,\n audioFilterOptions: JSON.stringify(this.legacyNcOptions.options),\n }\n : {}),\n });\n\n const res = FfiClient.instance.request<NewAudioStreamResponse>({\n message: {\n case: 'newAudioStream',\n value: req,\n },\n });\n\n this.ffiHandle = new FfiHandle(res.stream!.handle!.id!);\n\n FfiClient.instance.on(FfiClientEvent.FfiEvent, this.onEvent);\n track.registerAudioStream(this);\n }\n\n /** @internal */\n get processor(): FrameProcessor<AudioFrame> | null {\n return this.frameProcessor;\n }\n\n private onEvent = (ev: FfiEvent) => {\n if (!this.controller) {\n throw new Error('Stream controller not initialized');\n }\n\n if (\n ev.message.case != 'audioStreamEvent' ||\n ev.message.value.streamHandle != this.ffiHandle.handle\n ) {\n return;\n }\n\n const streamEvent = ev.message.value.message;\n switch (streamEvent.case) {\n case 'frameReceived':\n let frame = AudioFrame.fromOwnedInfo(streamEvent.value.frame!);\n if (this.frameProcessor && this.frameProcessor.isEnabled()) {\n try {\n frame = this.frameProcessor.process(frame);\n } catch (err: unknown) {\n log.warn(`Frame processing failed, passing through original frame: ${err}`);\n }\n }\n this.controller.enqueue(frame);\n break;\n case 'eos':\n // Disposes the native handle so the FD is released on stream end, not\n // just when cancel() is called explicitly by the consumer.\n this.teardown();\n break;\n }\n };\n\n start(controller: ReadableStreamDefaultController<AudioFrame>) {\n this.controller = controller;\n }\n\n /**\n * Detach from the FFI and release resources: on `eos`, on `cancel()`, or\n * because the track went away (e.g. it was unsubscribed — which never\n * produces an `eos`, so without this the stream would keep delivering\n * frames). Already-buffered frames stay readable and the consumer sees `done`\n * after draining them.\n *\n * @remarks\n * Idempotent, so `eos` arriving after a `cancel()` (or vice versa) doesn't\n * double-dispose the handle while buffered frames are still queued.\n *\n * @internal\n */\n teardown() {\n FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);\n if (this.disposed) {\n return;\n }\n this.disposed = true;\n this.track.unregisterAudioStream(this);\n this.ffiHandle.dispose();\n // Close the frame processor on every teardown path so resources are\n // released regardless of how the stream ended.\n if (this.frameProcessor && this.autoCloseProcessor) {\n this.frameProcessor.close();\n }\n try {\n this.controller?.close();\n } catch {\n // Already closed — e.g. cancel(), where the consumer has torn the\n // ReadableStream down before the underlying source is notified.\n }\n }\n\n cancel() {\n this.teardown();\n }\n}\n\nexport class AudioStream extends ReadableStream<AudioFrame> {\n constructor(track: Track);\n constructor(track: Track, sampleRate: number);\n constructor(track: Track, sampleRate: number, numChannels: number);\n constructor(track: Track, options: AudioStreamOptions);\n constructor(\n track: Track,\n sampleRateOrOptions?: number | AudioStreamOptions,\n numChannels?: number,\n ) {\n super(new AudioStreamSource(track, sampleRateOrOptions, numChannels));\n }\n}\n"],"mappings":"AAIA,SAAS,iBAAiB,6BAA6B;AAEvD,SAAS,kBAAkB;AAE3B,SAAS,WAAW,gBAAgB,iBAAiB;AACrD,SAA8B,wBAAwB;AACtD,SAAS,WAAW;AAwBb,MAAM,kBAA0D;AAAA,EAYrE,YACE,OACA,qBACA,aACA;AAbF,SAAQ,WAAW;AAInB,SAAQ,iBAAoD;AAC5D,SAAQ,qBAAqB;AAyD7B,SAAQ,UAAU,CAAC,OAAiB;AAClC,UAAI,CAAC,KAAK,YAAY;AACpB,cAAM,IAAI,MAAM,mCAAmC;AAAA,MACrD;AAEA,UACE,GAAG,QAAQ,QAAQ,sBACnB,GAAG,QAAQ,MAAM,gBAAgB,KAAK,UAAU,QAChD;AACA;AAAA,MACF;AAEA,YAAM,cAAc,GAAG,QAAQ,MAAM;AACrC,cAAQ,YAAY,MAAM;AAAA,QACxB,KAAK;AACH,cAAI,QAAQ,WAAW,cAAc,YAAY,MAAM,KAAM;AAC7D,cAAI,KAAK,kBAAkB,KAAK,eAAe,UAAU,GAAG;AAC1D,gBAAI;AACF,sBAAQ,KAAK,eAAe,QAAQ,KAAK;AAAA,YAC3C,SAAS,KAAc;AACrB,kBAAI,KAAK,4DAA4D,GAAG,EAAE;AAAA,YAC5E;AAAA,UACF;AACA,eAAK,WAAW,QAAQ,KAAK;AAC7B;AAAA,QACF,KAAK;AAGH,eAAK,SAAS;AACd;AAAA,MACJ;AAAA,IACF;AA/EE,SAAK,QAAQ;AACb,QAAI,wBAAwB,UAAa,OAAO,wBAAwB,UAAU;AAChF,WAAK,aAAa,oBAAoB,cAAc;AACpD,WAAK,cAAc,oBAAoB,eAAe;AACtD,UAAI,iBAAiB,oBAAoB,iBAAiB,GAAG;AAC3D,aAAK,iBAAiB,oBAAoB;AAC1C,aAAK,qBAAqB,oBAAoB,8BAA8B;AAAA,MAC9E,OAAO;AACL,aAAK,kBAAkB,oBAAoB;AAAA,MAC7C;AACA,WAAK,cAAc,oBAAoB;AAAA,IACzC,OAAO;AACL,WAAK,aAAc,uBAAkC;AACrD,WAAK,cAAc,eAAe;AAAA,IACpC;AAEA,UAAM,MAAM,IAAI,sBAAsB;AAAA,MACpC,MAAM,gBAAgB;AAAA,MACtB,aAAa,MAAM,WAAW;AAAA,MAC9B,YAAY,KAAK;AAAA,MACjB,aAAa,KAAK;AAAA,MAClB,aAAa,KAAK;AAAA,MAClB,GAAI,KAAK,kBACL;AAAA,QACE,qBAAqB,KAAK,gBAAgB;AAAA,QAC1C,oBAAoB,KAAK,UAAU,KAAK,gBAAgB,OAAO;AAAA,MACjE,IACA,CAAC;AAAA,IACP,CAAC;AAED,UAAM,MAAM,UAAU,SAAS,QAAgC;AAAA,MAC7D,SAAS;AAAA,QACP,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,IACF,CAAC;AAED,SAAK,YAAY,IAAI,UAAU,IAAI,OAAQ,OAAQ,EAAG;AAEtD,cAAU,SAAS,GAAG,eAAe,UAAU,KAAK,OAAO;AAC3D,UAAM,oBAAoB,IAAI;AAAA,EAChC;AAAA;AAAA,EAGA,IAAI,YAA+C;AACjD,WAAO,KAAK;AAAA,EACd;AAAA,EAmCA,MAAM,YAAyD;AAC7D,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,WAAW;AArJb;AAsJI,cAAU,SAAS,IAAI,eAAe,UAAU,KAAK,OAAO;AAC5D,QAAI,KAAK,UAAU;AACjB;AAAA,IACF;AACA,SAAK,WAAW;AAChB,SAAK,MAAM,sBAAsB,IAAI;AACrC,SAAK,UAAU,QAAQ;AAGvB,QAAI,KAAK,kBAAkB,KAAK,oBAAoB;AAClD,WAAK,eAAe,MAAM;AAAA,IAC5B;AACA,QAAI;AACF,iBAAK,eAAL,mBAAiB;AAAA,IACnB,QAAQ;AAAA,IAGR;AAAA,EACF;AAAA,EAEA,SAAS;AACP,SAAK,SAAS;AAAA,EAChB;AACF;AAEO,MAAM,oBAAoB,eAA2B;AAAA,EAK1D,YACE,OACA,qBACA,aACA;AACA,UAAM,IAAI,kBAAkB,OAAO,qBAAqB,WAAW,CAAC;AAAA,EACtE;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/data_streams/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\nexport * from './stream_reader.js';\nexport * from './stream_writer.js';\nexport type * from './types.js';\n"],"mappings":"AAIA,cAAc;AACd,cAAc;","names":[]}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { log } from "../log.js";
|
|
2
|
-
import { bigIntToNumber } from "../utils.js";
|
|
3
|
-
class BaseStreamReader {
|
|
4
|
-
get info() {
|
|
5
|
-
return this._info;
|
|
6
|
-
}
|
|
7
|
-
constructor(info, stream, totalByteSize) {
|
|
8
|
-
this.reader = stream;
|
|
9
|
-
this.totalByteSize = totalByteSize;
|
|
10
|
-
this._info = info;
|
|
11
|
-
this.bytesReceived = 0;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
class ByteStreamReader extends BaseStreamReader {
|
|
15
|
-
handleChunkReceived(chunk) {
|
|
16
|
-
var _a;
|
|
17
|
-
this.bytesReceived += chunk.content.byteLength;
|
|
18
|
-
const currentProgress = this.totalByteSize ? this.bytesReceived / this.totalByteSize : void 0;
|
|
19
|
-
(_a = this.onProgress) == null ? void 0 : _a.call(this, currentProgress);
|
|
20
|
-
}
|
|
21
|
-
[Symbol.asyncIterator]() {
|
|
22
|
-
const reader = this.reader.getReader();
|
|
23
|
-
return {
|
|
24
|
-
next: async () => {
|
|
25
|
-
try {
|
|
26
|
-
const { done, value } = await reader.read();
|
|
27
|
-
if (done) {
|
|
28
|
-
reader.releaseLock();
|
|
29
|
-
return { done: true, value: void 0 };
|
|
30
|
-
} else {
|
|
31
|
-
this.handleChunkReceived(value);
|
|
32
|
-
return { done: false, value: value.content };
|
|
33
|
-
}
|
|
34
|
-
} catch (error) {
|
|
35
|
-
reader.releaseLock();
|
|
36
|
-
log.error("error processing stream update: %s", error);
|
|
37
|
-
return { done: true, value: void 0 };
|
|
38
|
-
}
|
|
39
|
-
},
|
|
40
|
-
return() {
|
|
41
|
-
reader.releaseLock();
|
|
42
|
-
return { done: true, value: void 0 };
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
async readAll() {
|
|
47
|
-
const chunks = /* @__PURE__ */ new Set();
|
|
48
|
-
for await (const chunk of this) {
|
|
49
|
-
chunks.add(chunk);
|
|
50
|
-
}
|
|
51
|
-
return Array.from(chunks);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
class TextStreamReader extends BaseStreamReader {
|
|
55
|
-
/**
|
|
56
|
-
* A TextStreamReader instance can be used as an AsyncIterator that returns the entire string
|
|
57
|
-
* that has been received up to the current point in time.
|
|
58
|
-
*/
|
|
59
|
-
constructor(info, stream, totalChunkCount) {
|
|
60
|
-
super(info, stream, totalChunkCount);
|
|
61
|
-
this.receivedChunks = /* @__PURE__ */ new Map();
|
|
62
|
-
}
|
|
63
|
-
handleChunkReceived(chunk) {
|
|
64
|
-
var _a;
|
|
65
|
-
const index = bigIntToNumber(chunk.chunkIndex);
|
|
66
|
-
const previousChunkAtIndex = this.receivedChunks.get(index);
|
|
67
|
-
if (previousChunkAtIndex && previousChunkAtIndex.version > chunk.version) {
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
this.receivedChunks.set(index, chunk);
|
|
71
|
-
const currentProgress = this.totalByteSize ? this.receivedChunks.size / this.totalByteSize : void 0;
|
|
72
|
-
(_a = this.onProgress) == null ? void 0 : _a.call(this, currentProgress);
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Async iterator implementation to allow usage of `for await...of` syntax.
|
|
76
|
-
* Yields structured chunks from the stream.
|
|
77
|
-
*
|
|
78
|
-
*/
|
|
79
|
-
[Symbol.asyncIterator]() {
|
|
80
|
-
const reader = this.reader.getReader();
|
|
81
|
-
const decoder = new TextDecoder();
|
|
82
|
-
const receivedChunks = this.receivedChunks;
|
|
83
|
-
return {
|
|
84
|
-
next: async () => {
|
|
85
|
-
try {
|
|
86
|
-
const { done, value } = await reader.read();
|
|
87
|
-
if (done) {
|
|
88
|
-
reader.releaseLock();
|
|
89
|
-
receivedChunks.clear();
|
|
90
|
-
return { done: true, value: void 0 };
|
|
91
|
-
} else {
|
|
92
|
-
this.handleChunkReceived(value);
|
|
93
|
-
return {
|
|
94
|
-
done: false,
|
|
95
|
-
value: decoder.decode(value.content)
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
} catch (error) {
|
|
99
|
-
reader.releaseLock();
|
|
100
|
-
receivedChunks.clear();
|
|
101
|
-
log.error("error processing stream update: %s", error);
|
|
102
|
-
return { done: true, value: void 0 };
|
|
103
|
-
}
|
|
104
|
-
},
|
|
105
|
-
return() {
|
|
106
|
-
reader.releaseLock();
|
|
107
|
-
receivedChunks.clear();
|
|
108
|
-
return { done: true, value: void 0 };
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
async readAll() {
|
|
113
|
-
let finalString = "";
|
|
114
|
-
for await (const chunk of this) {
|
|
115
|
-
finalString += chunk;
|
|
116
|
-
}
|
|
117
|
-
return finalString;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
export {
|
|
121
|
-
ByteStreamReader,
|
|
122
|
-
TextStreamReader
|
|
123
|
-
};
|
|
124
|
-
//# sourceMappingURL=stream_reader.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/data_streams/stream_reader.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { DataStream_Chunk } from '@livekit/rtc-ffi-bindings';\nimport { log } from '../log.js';\nimport { bigIntToNumber } from '../utils.js';\nimport type { BaseStreamInfo, ByteStreamInfo, TextStreamInfo } from './types.js';\n\nabstract class BaseStreamReader<T extends BaseStreamInfo> {\n protected reader: ReadableStream<DataStream_Chunk>;\n\n protected totalByteSize?: number;\n\n protected _info: T;\n\n protected bytesReceived: number;\n\n get info() {\n return this._info;\n }\n\n constructor(info: T, stream: ReadableStream<DataStream_Chunk>, totalByteSize?: number) {\n this.reader = stream;\n this.totalByteSize = totalByteSize;\n this._info = info;\n this.bytesReceived = 0;\n }\n\n protected abstract handleChunkReceived(chunk: DataStream_Chunk): void;\n\n onProgress?: (progress: number | undefined) => void;\n\n abstract readAll(): Promise<string | Array<Uint8Array>>;\n}\n\n/**\n * A class to read chunks from a ReadableStream and provide them in a structured format.\n */\nexport class ByteStreamReader extends BaseStreamReader<ByteStreamInfo> {\n protected handleChunkReceived(chunk: DataStream_Chunk) {\n this.bytesReceived += chunk.content!.byteLength;\n const currentProgress = this.totalByteSize\n ? this.bytesReceived / this.totalByteSize\n : undefined;\n this.onProgress?.(currentProgress);\n }\n\n [Symbol.asyncIterator]() {\n const reader = this.reader.getReader();\n\n return {\n next: async (): Promise<IteratorResult<Uint8Array>> => {\n try {\n const { done, value } = await reader.read();\n if (done) {\n // Release the lock when the stream is exhausted so the\n // underlying ReadableStream can be garbage-collected.\n reader.releaseLock();\n return { done: true, value: undefined as unknown };\n } else {\n this.handleChunkReceived(value);\n return { done: false, value: value.content! };\n }\n } catch (error: unknown) {\n // Release the lock on error so it doesn't stay held when the\n // consumer never calls return() (e.g. breaking out of for-await).\n reader.releaseLock();\n log.error('error processing stream update: %s', error);\n return { done: true, value: undefined as unknown };\n }\n },\n\n return(): IteratorResult<Uint8Array> {\n reader.releaseLock();\n return { done: true, value: undefined };\n },\n };\n }\n\n async readAll(): Promise<Array<Uint8Array>> {\n const chunks: Set<Uint8Array> = new Set();\n for await (const chunk of this) {\n chunks.add(chunk);\n }\n return Array.from(chunks);\n }\n}\n\n/**\n * A class to read chunks from a ReadableStream and provide them in a structured format.\n */\nexport class TextStreamReader extends BaseStreamReader<TextStreamInfo> {\n private receivedChunks: Map<number, DataStream_Chunk>;\n\n /**\n * A TextStreamReader instance can be used as an AsyncIterator that returns the entire string\n * that has been received up to the current point in time.\n */\n constructor(\n info: TextStreamInfo,\n stream: ReadableStream<DataStream_Chunk>,\n totalChunkCount?: number,\n ) {\n super(info, stream, totalChunkCount);\n this.receivedChunks = new Map();\n }\n\n protected handleChunkReceived(chunk: DataStream_Chunk) {\n const index = bigIntToNumber(chunk.chunkIndex!);\n const previousChunkAtIndex = this.receivedChunks.get(index!);\n if (previousChunkAtIndex && previousChunkAtIndex.version! > chunk.version!) {\n // we have a newer version already, dropping the old one\n return;\n }\n this.receivedChunks.set(index, chunk);\n const currentProgress = this.totalByteSize\n ? this.receivedChunks.size / this.totalByteSize\n : undefined;\n this.onProgress?.(currentProgress);\n }\n\n /**\n * Async iterator implementation to allow usage of `for await...of` syntax.\n * Yields structured chunks from the stream.\n *\n */\n [Symbol.asyncIterator]() {\n const reader = this.reader.getReader();\n const decoder = new TextDecoder();\n const receivedChunks = this.receivedChunks;\n\n return {\n next: async (): Promise<IteratorResult<string>> => {\n try {\n const { done, value } = await reader.read();\n if (done) {\n // Release the lock when the stream is exhausted so the\n // underlying ReadableStream can be garbage-collected.\n reader.releaseLock();\n // Clear received chunks so the buffered data can be GC'd.\n receivedChunks.clear();\n return { done: true, value: undefined };\n } else {\n this.handleChunkReceived(value);\n return {\n done: false,\n value: decoder.decode(value.content!),\n };\n }\n } catch (error: unknown) {\n // Release the lock on error so it doesn't stay held when the\n // consumer never calls return() (e.g. breaking out of for-await).\n reader.releaseLock();\n receivedChunks.clear();\n log.error('error processing stream update: %s', error);\n return { done: true, value: undefined };\n }\n },\n\n return(): IteratorResult<string> {\n reader.releaseLock();\n // Clear received chunks so the buffered data can be GC'd.\n receivedChunks.clear();\n return { done: true, value: undefined };\n },\n };\n }\n\n async readAll(): Promise<string> {\n let finalString: string = '';\n for await (const chunk of this) {\n finalString += chunk;\n }\n return finalString;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
class BaseStreamWriter {
|
|
2
|
-
constructor(writableStream, info, onClose) {
|
|
3
|
-
this.writableStream = writableStream;
|
|
4
|
-
this.defaultWriter = writableStream.getWriter();
|
|
5
|
-
this.onClose = onClose;
|
|
6
|
-
this.info = info;
|
|
7
|
-
}
|
|
8
|
-
write(chunk) {
|
|
9
|
-
return this.defaultWriter.write(chunk);
|
|
10
|
-
}
|
|
11
|
-
async close() {
|
|
12
|
-
var _a;
|
|
13
|
-
await this.defaultWriter.close();
|
|
14
|
-
this.defaultWriter.releaseLock();
|
|
15
|
-
(_a = this.onClose) == null ? void 0 : _a.call(this);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
class TextStreamWriter extends BaseStreamWriter {
|
|
19
|
-
}
|
|
20
|
-
class ByteStreamWriter extends BaseStreamWriter {
|
|
21
|
-
}
|
|
22
|
-
export {
|
|
23
|
-
ByteStreamWriter,
|
|
24
|
-
TextStreamWriter
|
|
25
|
-
};
|
|
26
|
-
//# sourceMappingURL=stream_writer.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/data_streams/stream_writer.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { BaseStreamInfo, ByteStreamInfo, TextStreamInfo } from './types.js';\n\nclass BaseStreamWriter<T, InfoType extends BaseStreamInfo> {\n protected writableStream: WritableStream<T>;\n\n protected defaultWriter: WritableStreamDefaultWriter<T>;\n\n protected onClose?: () => void;\n\n readonly info: InfoType;\n\n constructor(writableStream: WritableStream<T>, info: InfoType, onClose?: () => void) {\n this.writableStream = writableStream;\n this.defaultWriter = writableStream.getWriter();\n this.onClose = onClose;\n this.info = info;\n }\n\n write(chunk: T): Promise<void> {\n return this.defaultWriter.write(chunk);\n }\n\n async close() {\n await this.defaultWriter.close();\n this.defaultWriter.releaseLock();\n this.onClose?.();\n }\n}\n\nexport class TextStreamWriter extends BaseStreamWriter<string, TextStreamInfo> {}\n\nexport class ByteStreamWriter extends BaseStreamWriter<Uint8Array, ByteStreamInfo> {}\n"],"mappings":"AAKA,MAAM,iBAAqD;AAAA,EASzD,YAAY,gBAAmC,MAAgB,SAAsB;AACnF,SAAK,iBAAiB;AACtB,SAAK,gBAAgB,eAAe,UAAU;AAC9C,SAAK,UAAU;AACf,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAM,OAAyB;AAC7B,WAAO,KAAK,cAAc,MAAM,KAAK;AAAA,EACvC;AAAA,EAEA,MAAM,QAAQ;AAzBhB;AA0BI,UAAM,KAAK,cAAc,MAAM;AAC/B,SAAK,cAAc,YAAY;AAC/B,eAAK,YAAL;AAAA,EACF;AACF;AAEO,MAAM,yBAAyB,iBAAyC;AAAC;AAEzE,MAAM,yBAAyB,iBAA6C;AAAC;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
//# sourceMappingURL=types.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/e2ee.js
DELETED
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
E2eeManagerSetEnabledRequest,
|
|
3
|
-
E2eeRequest,
|
|
4
|
-
EncryptionType,
|
|
5
|
-
FrameCryptorSetEnabledRequest,
|
|
6
|
-
FrameCryptorSetKeyIndexRequest,
|
|
7
|
-
GetKeyRequest,
|
|
8
|
-
GetSharedKeyRequest,
|
|
9
|
-
RatchetKeyRequest,
|
|
10
|
-
RatchetSharedKeyRequest,
|
|
11
|
-
SetKeyRequest,
|
|
12
|
-
SetSharedKeyRequest
|
|
13
|
-
} from "@livekit/rtc-ffi-bindings";
|
|
14
|
-
import { FfiClient } from "./ffi_client.js";
|
|
15
|
-
const DEFAULT_RATCHET_SALT = new TextEncoder().encode("LKFrameEncryptionKey");
|
|
16
|
-
const DEFAULT_RATCHET_WINDOW_SIZE = 16;
|
|
17
|
-
const DEFAULT_FAILURE_TOLERANCE = -1;
|
|
18
|
-
const defaultKeyProviderOptions = {
|
|
19
|
-
ratchetSalt: DEFAULT_RATCHET_SALT,
|
|
20
|
-
ratchetWindowSize: DEFAULT_RATCHET_WINDOW_SIZE,
|
|
21
|
-
failureTolerance: DEFAULT_FAILURE_TOLERANCE
|
|
22
|
-
};
|
|
23
|
-
const defaultE2EEOptions = {
|
|
24
|
-
keyProviderOptions: defaultKeyProviderOptions,
|
|
25
|
-
encryptionType: EncryptionType.GCM
|
|
26
|
-
};
|
|
27
|
-
class KeyProvider {
|
|
28
|
-
/** internal */
|
|
29
|
-
constructor(roomHandle, opts) {
|
|
30
|
-
this.roomHandle = roomHandle;
|
|
31
|
-
this.options = opts;
|
|
32
|
-
}
|
|
33
|
-
setSharedKey(sharedKey, keyIndex) {
|
|
34
|
-
const req = new E2eeRequest({
|
|
35
|
-
roomHandle: this.roomHandle,
|
|
36
|
-
message: {
|
|
37
|
-
case: "setSharedKey",
|
|
38
|
-
value: new SetSharedKeyRequest({
|
|
39
|
-
keyIndex,
|
|
40
|
-
sharedKey
|
|
41
|
-
})
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
FfiClient.instance.request({
|
|
45
|
-
message: {
|
|
46
|
-
case: "e2ee",
|
|
47
|
-
value: req
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
exportSharedKey(keyIndex) {
|
|
52
|
-
const req = new E2eeRequest({
|
|
53
|
-
roomHandle: this.roomHandle,
|
|
54
|
-
message: {
|
|
55
|
-
case: "getSharedKey",
|
|
56
|
-
value: new GetSharedKeyRequest({
|
|
57
|
-
keyIndex
|
|
58
|
-
})
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
const res = FfiClient.instance.request({
|
|
62
|
-
message: {
|
|
63
|
-
case: "e2ee",
|
|
64
|
-
value: req
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
return res.message.value.key;
|
|
68
|
-
}
|
|
69
|
-
ratchetSharedKey(keyIndex) {
|
|
70
|
-
const req = new E2eeRequest({
|
|
71
|
-
roomHandle: this.roomHandle,
|
|
72
|
-
message: {
|
|
73
|
-
case: "ratchetSharedKey",
|
|
74
|
-
value: new RatchetSharedKeyRequest({
|
|
75
|
-
keyIndex
|
|
76
|
-
})
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
const res = FfiClient.instance.request({
|
|
80
|
-
message: {
|
|
81
|
-
case: "e2ee",
|
|
82
|
-
value: req
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
return res.message.value.newKey;
|
|
86
|
-
}
|
|
87
|
-
setKey(participantIdentity, keyIndex) {
|
|
88
|
-
const req = new E2eeRequest({
|
|
89
|
-
roomHandle: this.roomHandle,
|
|
90
|
-
message: {
|
|
91
|
-
case: "setKey",
|
|
92
|
-
value: new SetKeyRequest({
|
|
93
|
-
keyIndex,
|
|
94
|
-
participantIdentity
|
|
95
|
-
})
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
FfiClient.instance.request({
|
|
99
|
-
message: {
|
|
100
|
-
case: "e2ee",
|
|
101
|
-
value: req
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
exportKey(participantIdentity, keyIndex) {
|
|
106
|
-
const req = new E2eeRequest({
|
|
107
|
-
roomHandle: this.roomHandle,
|
|
108
|
-
message: {
|
|
109
|
-
case: "getKey",
|
|
110
|
-
value: new GetKeyRequest({
|
|
111
|
-
keyIndex,
|
|
112
|
-
participantIdentity
|
|
113
|
-
})
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
const res = FfiClient.instance.request({
|
|
117
|
-
message: {
|
|
118
|
-
case: "e2ee",
|
|
119
|
-
value: req
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
return res.message.value.key;
|
|
123
|
-
}
|
|
124
|
-
ratchetKey(participantIdentity, keyIndex) {
|
|
125
|
-
const req = new E2eeRequest({
|
|
126
|
-
roomHandle: this.roomHandle,
|
|
127
|
-
message: {
|
|
128
|
-
case: "ratchetKey",
|
|
129
|
-
value: new RatchetKeyRequest({
|
|
130
|
-
keyIndex,
|
|
131
|
-
participantIdentity
|
|
132
|
-
})
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
const res = FfiClient.instance.request({
|
|
136
|
-
message: {
|
|
137
|
-
case: "e2ee",
|
|
138
|
-
value: req
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
return res.message.value.newKey;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
class FrameCryptor {
|
|
145
|
-
constructor(roomHandle, participantIdentity, keyIndex, enabled) {
|
|
146
|
-
this.roomHandle = BigInt(0);
|
|
147
|
-
this.roomHandle = roomHandle;
|
|
148
|
-
this.participantIdentity = participantIdentity;
|
|
149
|
-
this.keyIndex = keyIndex;
|
|
150
|
-
this.enabled = enabled;
|
|
151
|
-
}
|
|
152
|
-
setEnabled(enabled) {
|
|
153
|
-
this.enabled = enabled;
|
|
154
|
-
const req = new E2eeRequest({
|
|
155
|
-
roomHandle: this.roomHandle,
|
|
156
|
-
message: {
|
|
157
|
-
case: "cryptorSetEnabled",
|
|
158
|
-
value: new FrameCryptorSetEnabledRequest({
|
|
159
|
-
participantIdentity: this.participantIdentity,
|
|
160
|
-
enabled: this.enabled
|
|
161
|
-
})
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
FfiClient.instance.request({
|
|
165
|
-
message: {
|
|
166
|
-
case: "e2ee",
|
|
167
|
-
value: req
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
setKeyIndex(keyIndex) {
|
|
172
|
-
this.keyIndex = keyIndex;
|
|
173
|
-
const req = new E2eeRequest({
|
|
174
|
-
roomHandle: this.roomHandle,
|
|
175
|
-
message: {
|
|
176
|
-
case: "cryptorSetKeyIndex",
|
|
177
|
-
value: new FrameCryptorSetKeyIndexRequest({
|
|
178
|
-
participantIdentity: this.participantIdentity,
|
|
179
|
-
keyIndex: this.keyIndex
|
|
180
|
-
})
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
FfiClient.instance.request({
|
|
184
|
-
message: {
|
|
185
|
-
case: "e2ee",
|
|
186
|
-
value: req
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
class E2EEManager {
|
|
192
|
-
constructor(roomHandle, opts) {
|
|
193
|
-
this.roomHandle = BigInt(0);
|
|
194
|
-
this.roomHandle = roomHandle;
|
|
195
|
-
this.enabled = opts !== void 0;
|
|
196
|
-
opts ??= defaultE2EEOptions;
|
|
197
|
-
const options = { ...defaultE2EEOptions, ...opts };
|
|
198
|
-
this.options = options;
|
|
199
|
-
this.keyProvider = new KeyProvider(roomHandle, options.keyProviderOptions);
|
|
200
|
-
}
|
|
201
|
-
setEnabled(enabled) {
|
|
202
|
-
this.enabled = enabled;
|
|
203
|
-
const req = new E2eeRequest({
|
|
204
|
-
roomHandle: this.roomHandle,
|
|
205
|
-
message: {
|
|
206
|
-
case: "managerSetEnabled",
|
|
207
|
-
value: new E2eeManagerSetEnabledRequest({
|
|
208
|
-
enabled: this.enabled
|
|
209
|
-
})
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
FfiClient.instance.request({
|
|
213
|
-
message: {
|
|
214
|
-
case: "e2ee",
|
|
215
|
-
value: req
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
frameCryptors() {
|
|
220
|
-
const req = new E2eeRequest({
|
|
221
|
-
roomHandle: this.roomHandle,
|
|
222
|
-
message: {
|
|
223
|
-
case: "managerGetFrameCryptors",
|
|
224
|
-
value: {}
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
const res = FfiClient.instance.request({
|
|
228
|
-
message: {
|
|
229
|
-
case: "e2ee",
|
|
230
|
-
value: req
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
const frameCryptors = res.message.value.frameCryptors.map(
|
|
234
|
-
(cryptor) => new FrameCryptor(
|
|
235
|
-
this.roomHandle,
|
|
236
|
-
cryptor.participantIdentity,
|
|
237
|
-
cryptor.keyIndex,
|
|
238
|
-
cryptor.enabled
|
|
239
|
-
)
|
|
240
|
-
);
|
|
241
|
-
return frameCryptors;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
export {
|
|
245
|
-
E2EEManager,
|
|
246
|
-
FrameCryptor,
|
|
247
|
-
KeyProvider,
|
|
248
|
-
defaultE2EEOptions,
|
|
249
|
-
defaultKeyProviderOptions
|
|
250
|
-
};
|
|
251
|
-
//# sourceMappingURL=e2ee.js.map
|
package/dist/e2ee.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/e2ee.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type {\n E2eeManagerGetFrameCryptorsResponse,\n E2eeResponse,\n GetKeyResponse,\n GetSharedKeyResponse,\n RatchetKeyResponse,\n RatchetSharedKeyResponse,\n} from '@livekit/rtc-ffi-bindings';\nimport {\n E2eeManagerSetEnabledRequest,\n E2eeRequest,\n EncryptionType,\n FrameCryptorSetEnabledRequest,\n FrameCryptorSetKeyIndexRequest,\n GetKeyRequest,\n GetSharedKeyRequest,\n RatchetKeyRequest,\n RatchetSharedKeyRequest,\n SetKeyRequest,\n SetSharedKeyRequest,\n} from '@livekit/rtc-ffi-bindings';\nimport { FfiClient } from './ffi_client.js';\n\nconst DEFAULT_RATCHET_SALT = new TextEncoder().encode('LKFrameEncryptionKey');\nconst DEFAULT_RATCHET_WINDOW_SIZE = 16;\nconst DEFAULT_FAILURE_TOLERANCE = -1;\n\nexport interface KeyProviderOptions {\n sharedKey?: Uint8Array;\n ratchetSalt?: Uint8Array;\n ratchetWindowSize?: number;\n failureTolerance?: number;\n}\n\nexport const defaultKeyProviderOptions: KeyProviderOptions = {\n ratchetSalt: DEFAULT_RATCHET_SALT,\n ratchetWindowSize: DEFAULT_RATCHET_WINDOW_SIZE,\n failureTolerance: DEFAULT_FAILURE_TOLERANCE,\n};\n\nexport interface E2EEOptions {\n keyProviderOptions: KeyProviderOptions;\n encryptionType?: EncryptionType;\n}\n\nexport const defaultE2EEOptions: E2EEOptions = {\n keyProviderOptions: defaultKeyProviderOptions,\n encryptionType: EncryptionType.GCM,\n};\n\nexport class KeyProvider {\n private roomHandle: bigint;\n options: KeyProviderOptions;\n\n /** internal */\n constructor(roomHandle: bigint, opts: KeyProviderOptions) {\n this.roomHandle = roomHandle;\n this.options = opts;\n }\n\n setSharedKey(sharedKey: Uint8Array, keyIndex: number) {\n const req = new E2eeRequest({\n roomHandle: this.roomHandle,\n message: {\n case: 'setSharedKey',\n value: new SetSharedKeyRequest({\n keyIndex: keyIndex,\n sharedKey: sharedKey,\n }),\n },\n });\n\n FfiClient.instance.request({\n message: {\n case: 'e2ee',\n value: req,\n },\n });\n }\n\n exportSharedKey(keyIndex: number): Uint8Array {\n const req = new E2eeRequest({\n roomHandle: this.roomHandle,\n message: {\n case: 'getSharedKey',\n value: new GetSharedKeyRequest({\n keyIndex: keyIndex,\n }),\n },\n });\n\n const res = FfiClient.instance.request<E2eeResponse>({\n message: {\n case: 'e2ee',\n value: req,\n },\n });\n\n return (res.message.value as GetSharedKeyResponse).key!;\n }\n\n ratchetSharedKey(keyIndex: number): Uint8Array {\n const req = new E2eeRequest({\n roomHandle: this.roomHandle,\n message: {\n case: 'ratchetSharedKey',\n value: new RatchetSharedKeyRequest({\n keyIndex: keyIndex,\n }),\n },\n });\n\n const res = FfiClient.instance.request<E2eeResponse>({\n message: {\n case: 'e2ee',\n value: req,\n },\n });\n\n return (res.message.value as RatchetSharedKeyResponse).newKey!;\n }\n\n setKey(participantIdentity: string, keyIndex: number) {\n const req = new E2eeRequest({\n roomHandle: this.roomHandle,\n message: {\n case: 'setKey',\n value: new SetKeyRequest({\n keyIndex: keyIndex,\n participantIdentity: participantIdentity,\n }),\n },\n });\n\n FfiClient.instance.request({\n message: {\n case: 'e2ee',\n value: req,\n },\n });\n }\n\n exportKey(participantIdentity: string, keyIndex: number): Uint8Array {\n const req = new E2eeRequest({\n roomHandle: this.roomHandle,\n message: {\n case: 'getKey',\n value: new GetKeyRequest({\n keyIndex: keyIndex,\n participantIdentity: participantIdentity,\n }),\n },\n });\n\n const res = FfiClient.instance.request<E2eeResponse>({\n message: {\n case: 'e2ee',\n value: req,\n },\n });\n\n return (res.message.value as GetKeyResponse).key!;\n }\n\n ratchetKey(participantIdentity: string, keyIndex: number): Uint8Array {\n const req = new E2eeRequest({\n roomHandle: this.roomHandle,\n message: {\n case: 'ratchetKey',\n value: new RatchetKeyRequest({\n keyIndex: keyIndex,\n participantIdentity: participantIdentity,\n }),\n },\n });\n\n const res = FfiClient.instance.request<E2eeResponse>({\n message: {\n case: 'e2ee',\n value: req,\n },\n });\n\n return (res.message.value as RatchetKeyResponse).newKey!;\n }\n}\n\nexport class FrameCryptor {\n private roomHandle = BigInt(0);\n participantIdentity: string;\n keyIndex: number;\n enabled: boolean;\n\n constructor(roomHandle: bigint, participantIdentity: string, keyIndex: number, enabled: boolean) {\n this.roomHandle = roomHandle;\n this.participantIdentity = participantIdentity;\n this.keyIndex = keyIndex;\n this.enabled = enabled;\n }\n\n setEnabled(enabled: boolean) {\n this.enabled = enabled;\n const req = new E2eeRequest({\n roomHandle: this.roomHandle,\n message: {\n case: 'cryptorSetEnabled',\n value: new FrameCryptorSetEnabledRequest({\n participantIdentity: this.participantIdentity,\n enabled: this.enabled,\n }),\n },\n });\n\n FfiClient.instance.request({\n message: {\n case: 'e2ee',\n value: req,\n },\n });\n }\n\n setKeyIndex(keyIndex: number) {\n this.keyIndex = keyIndex;\n const req = new E2eeRequest({\n roomHandle: this.roomHandle,\n message: {\n case: 'cryptorSetKeyIndex',\n value: new FrameCryptorSetKeyIndexRequest({\n participantIdentity: this.participantIdentity,\n keyIndex: this.keyIndex,\n }),\n },\n });\n\n FfiClient.instance.request({\n message: {\n case: 'e2ee',\n value: req,\n },\n });\n }\n}\n\nexport class E2EEManager {\n private roomHandle = BigInt(0);\n private options: E2EEOptions;\n private keyProvider: KeyProvider;\n\n enabled: boolean;\n\n constructor(roomHandle: bigint, opts?: E2EEOptions) {\n this.roomHandle = roomHandle;\n this.enabled = opts !== undefined;\n\n opts ??= defaultE2EEOptions;\n const options = { ...defaultE2EEOptions, ...opts };\n\n this.options = options;\n this.keyProvider = new KeyProvider(roomHandle, options.keyProviderOptions);\n }\n\n setEnabled(enabled: boolean) {\n this.enabled = enabled;\n const req = new E2eeRequest({\n roomHandle: this.roomHandle,\n message: {\n case: 'managerSetEnabled',\n value: new E2eeManagerSetEnabledRequest({\n enabled: this.enabled,\n }),\n },\n });\n\n FfiClient.instance.request({\n message: {\n case: 'e2ee',\n value: req,\n },\n });\n }\n\n frameCryptors(): FrameCryptor[] {\n const req = new E2eeRequest({\n roomHandle: this.roomHandle,\n message: {\n case: 'managerGetFrameCryptors',\n value: {},\n },\n });\n\n const res = FfiClient.instance.request<E2eeResponse>({\n message: {\n case: 'e2ee',\n value: req,\n },\n });\n\n const frameCryptors = (\n res.message.value as E2eeManagerGetFrameCryptorsResponse\n ).frameCryptors.map(\n (cryptor) =>\n new FrameCryptor(\n this.roomHandle,\n cryptor.participantIdentity!,\n cryptor.keyIndex!,\n cryptor.enabled!,\n ),\n );\n\n return frameCryptors;\n }\n}\n"],"mappings":"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","names":[]}
|