@livekit/rtc-node 0.13.23 → 0.13.25
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/audio_filter.cjs +2 -2
- package/dist/audio_filter.cjs.map +1 -1
- package/dist/audio_filter.js +1 -1
- package/dist/audio_filter.js.map +1 -1
- package/dist/audio_frame.cjs +11 -7
- package/dist/audio_frame.cjs.map +1 -1
- package/dist/audio_frame.d.cts +3 -8
- package/dist/audio_frame.d.ts +3 -8
- package/dist/audio_frame.d.ts.map +1 -1
- package/dist/audio_frame.js +10 -6
- package/dist/audio_frame.js.map +1 -1
- package/dist/audio_mixer.cjs +11 -4
- package/dist/audio_mixer.cjs.map +1 -1
- package/dist/audio_mixer.d.cts +1 -6
- package/dist/audio_mixer.d.ts +1 -6
- package/dist/audio_mixer.d.ts.map +1 -1
- package/dist/audio_mixer.js +11 -4
- package/dist/audio_mixer.js.map +1 -1
- package/dist/audio_resampler.cjs +20 -12
- package/dist/audio_resampler.cjs.map +1 -1
- package/dist/audio_resampler.d.cts +6 -6
- package/dist/audio_resampler.d.ts +6 -6
- package/dist/audio_resampler.d.ts.map +1 -1
- package/dist/audio_resampler.js +12 -4
- package/dist/audio_resampler.js.map +1 -1
- package/dist/audio_source.cjs +11 -7
- package/dist/audio_source.cjs.map +1 -1
- package/dist/audio_source.d.cts +1 -7
- package/dist/audio_source.d.ts +1 -7
- package/dist/audio_source.d.ts.map +1 -1
- package/dist/audio_source.js +8 -3
- package/dist/audio_source.js.map +1 -1
- package/dist/audio_stream.cjs +17 -5
- package/dist/audio_stream.cjs.map +1 -1
- package/dist/audio_stream.d.cts +1 -14
- package/dist/audio_stream.d.ts +1 -14
- package/dist/audio_stream.d.ts.map +1 -1
- package/dist/audio_stream.js +16 -4
- package/dist/audio_stream.js.map +1 -1
- package/dist/data_streams/index.d.cts +2 -10
- package/dist/data_streams/index.d.ts +2 -10
- package/dist/data_streams/stream_reader.cjs +8 -0
- package/dist/data_streams/stream_reader.cjs.map +1 -1
- package/dist/data_streams/stream_reader.d.cts +2 -10
- package/dist/data_streams/stream_reader.d.ts +2 -10
- package/dist/data_streams/stream_reader.d.ts.map +1 -1
- package/dist/data_streams/stream_reader.js +8 -0
- package/dist/data_streams/stream_reader.js.map +1 -1
- package/dist/data_streams/stream_writer.d.cts +2 -10
- package/dist/data_streams/stream_writer.d.ts +2 -10
- package/dist/data_streams/types.cjs.map +1 -1
- package/dist/data_streams/types.d.cts +2 -10
- package/dist/data_streams/types.d.ts +2 -10
- package/dist/data_streams/types.d.ts.map +1 -1
- package/dist/e2ee.cjs +21 -21
- package/dist/e2ee.cjs.map +1 -1
- package/dist/e2ee.d.cts +1 -2
- package/dist/e2ee.d.ts +1 -2
- package/dist/e2ee.d.ts.map +1 -1
- package/dist/e2ee.js +2 -2
- package/dist/e2ee.js.map +1 -1
- package/dist/ffi_client.cjs +11 -12
- package/dist/ffi_client.cjs.map +1 -1
- package/dist/ffi_client.d.cts +3 -16
- package/dist/ffi_client.d.ts +3 -16
- package/dist/ffi_client.d.ts.map +1 -1
- package/dist/ffi_client.js +5 -3
- package/dist/ffi_client.js.map +1 -1
- package/dist/frame_processor.cjs +13 -2
- package/dist/frame_processor.cjs.map +1 -1
- package/dist/frame_processor.d.cts +5 -8
- package/dist/frame_processor.d.ts +5 -8
- package/dist/frame_processor.d.ts.map +1 -1
- package/dist/frame_processor.js +10 -1
- package/dist/frame_processor.js.map +1 -1
- package/dist/index.cjs +25 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -16
- package/dist/index.d.ts +3 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -7
- package/dist/index.js.map +1 -1
- package/dist/log.cjs +1 -10
- package/dist/log.cjs.map +1 -1
- package/dist/log.d.cts +4 -0
- package/dist/log.d.ts +4 -0
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +1 -10
- package/dist/log.js.map +1 -1
- package/dist/participant.cjs +38 -38
- package/dist/participant.cjs.map +1 -1
- package/dist/participant.d.cts +2 -15
- package/dist/participant.d.ts +2 -15
- package/dist/participant.d.ts.map +1 -1
- package/dist/participant.js +12 -12
- package/dist/participant.js.map +1 -1
- package/dist/room.cjs +48 -30
- package/dist/room.cjs.map +1 -1
- package/dist/room.d.cts +11 -16
- package/dist/room.d.ts +11 -16
- package/dist/room.d.ts.map +1 -1
- package/dist/room.js +44 -26
- package/dist/room.js.map +1 -1
- package/dist/rpc.cjs.map +1 -1
- package/dist/rpc.d.cts +1 -2
- package/dist/rpc.d.ts +1 -2
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js.map +1 -1
- package/dist/{stream_reader-Ch2zvjU3.d.cts → stream_reader-CuG4b8Y-.d.cts} +1 -1
- package/dist/{stream_reader-DRyR29vo.d.ts → stream_reader-CuG4b8Y-.d.ts} +1 -1
- package/dist/track.cjs +3 -3
- package/dist/track.cjs.map +1 -1
- package/dist/track.d.cts +1 -14
- package/dist/track.d.ts +1 -14
- package/dist/track.d.ts.map +1 -1
- package/dist/track.js +1 -1
- package/dist/track.js.map +1 -1
- package/dist/track_publication.cjs +4 -4
- package/dist/track_publication.cjs.map +1 -1
- package/dist/track_publication.d.cts +1 -14
- package/dist/track_publication.d.ts +1 -14
- package/dist/track_publication.d.ts.map +1 -1
- package/dist/track_publication.js +2 -2
- package/dist/track_publication.js.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 +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/video_frame.cjs +42 -42
- package/dist/video_frame.cjs.map +1 -1
- package/dist/video_frame.d.cts +1 -6
- package/dist/video_frame.d.ts +1 -6
- package/dist/video_frame.d.ts.map +1 -1
- package/dist/video_frame.js +2 -2
- package/dist/video_frame.js.map +1 -1
- package/dist/video_source.cjs +5 -5
- package/dist/video_source.cjs.map +1 -1
- package/dist/video_source.d.cts +1 -14
- package/dist/video_source.d.ts +1 -14
- package/dist/video_source.d.ts.map +1 -1
- package/dist/video_source.js +2 -2
- package/dist/video_source.js.map +1 -1
- package/dist/video_stream.cjs +12 -4
- package/dist/video_stream.cjs.map +1 -1
- package/dist/video_stream.d.cts +1 -14
- package/dist/video_stream.d.ts +1 -14
- package/dist/video_stream.d.ts.map +1 -1
- package/dist/video_stream.js +10 -2
- package/dist/video_stream.js.map +1 -1
- package/package.json +9 -35
- package/src/audio_filter.ts +2 -2
- package/src/audio_frame.ts +26 -7
- package/src/audio_mixer.ts +15 -4
- package/src/audio_resampler.ts +14 -4
- package/src/audio_source.ts +13 -5
- package/src/audio_stream.ts +21 -5
- package/src/data_streams/stream_reader.ts +19 -1
- package/src/data_streams/types.ts +1 -1
- package/src/e2ee.ts +3 -3
- package/src/ffi_client.ts +7 -5
- package/src/frame_processor.ts +21 -0
- package/src/index.ts +6 -5
- package/src/log.ts +14 -10
- package/src/participant.ts +17 -17
- package/src/room.ts +65 -38
- package/src/rpc.ts +1 -1
- package/src/tests/e2e.test.ts +517 -0
- package/src/track.ts +4 -4
- package/src/track_publication.ts +6 -6
- package/src/version.ts +1 -1
- package/src/video_frame.ts +3 -3
- package/src/video_source.ts +3 -3
- package/src/video_stream.ts +15 -3
- package/Cargo.toml +0 -25
- package/build.rs +0 -9
- package/dist/napi/native.cjs +0 -301
- package/dist/napi/native.d.cjs +0 -17
- package/dist/napi/native.d.cjs.map +0 -1
- package/dist/napi/native.d.d.cts +0 -21
- package/dist/napi/native.d.d.ts +0 -21
- package/dist/napi/native.d.js +0 -1
- package/dist/napi/native.d.js.map +0 -1
- package/dist/napi/native.d.ts +0 -19
- package/dist/napi/native.js +0 -15
- package/dist/native.cjs +0 -301
- package/dist/native.d.ts +0 -19
- package/dist/native.js +0 -15
- package/dist/proto/audio_frame_pb.cjs +0 -1357
- package/dist/proto/audio_frame_pb.cjs.map +0 -1
- package/dist/proto/audio_frame_pb.d.cts +0 -1183
- package/dist/proto/audio_frame_pb.d.ts +0 -1183
- package/dist/proto/audio_frame_pb.d.ts.map +0 -1
- package/dist/proto/audio_frame_pb.js +0 -1283
- package/dist/proto/audio_frame_pb.js.map +0 -1
- package/dist/proto/data_stream_pb.cjs +0 -1638
- package/dist/proto/data_stream_pb.cjs.map +0 -1
- package/dist/proto/data_stream_pb.d.cts +0 -1449
- package/dist/proto/data_stream_pb.d.ts +0 -1449
- package/dist/proto/data_stream_pb.d.ts.map +0 -1
- package/dist/proto/data_stream_pb.js +0 -1559
- package/dist/proto/data_stream_pb.js.map +0 -1
- package/dist/proto/e2ee_pb.cjs +0 -746
- package/dist/proto/e2ee_pb.cjs.map +0 -1
- package/dist/proto/e2ee_pb.d.cts +0 -653
- package/dist/proto/e2ee_pb.d.ts +0 -653
- package/dist/proto/e2ee_pb.d.ts.map +0 -1
- package/dist/proto/e2ee_pb.js +0 -696
- package/dist/proto/e2ee_pb.js.map +0 -1
- package/dist/proto/ffi_pb.cjs +0 -477
- package/dist/proto/ffi_pb.cjs.map +0 -1
- package/dist/proto/ffi_pb.d.cts +0 -1321
- package/dist/proto/ffi_pb.d.ts +0 -1321
- package/dist/proto/ffi_pb.d.ts.map +0 -1
- package/dist/proto/ffi_pb.js +0 -444
- package/dist/proto/ffi_pb.js.map +0 -1
- package/dist/proto/handle_pb.cjs +0 -53
- package/dist/proto/handle_pb.cjs.map +0 -1
- package/dist/proto/handle_pb.d.cts +0 -31
- package/dist/proto/handle_pb.d.ts +0 -31
- package/dist/proto/handle_pb.d.ts.map +0 -1
- package/dist/proto/handle_pb.js +0 -29
- package/dist/proto/handle_pb.js.map +0 -1
- package/dist/proto/participant_pb.cjs +0 -173
- package/dist/proto/participant_pb.cjs.map +0 -1
- package/dist/proto/participant_pb.d.cts +0 -218
- package/dist/proto/participant_pb.d.ts +0 -218
- package/dist/proto/participant_pb.d.ts.map +0 -1
- package/dist/proto/participant_pb.js +0 -145
- package/dist/proto/participant_pb.js.map +0 -1
- package/dist/proto/room_pb.cjs +0 -3374
- package/dist/proto/room_pb.cjs.map +0 -1
- package/dist/proto/room_pb.d.cts +0 -3028
- package/dist/proto/room_pb.d.ts +0 -3028
- package/dist/proto/room_pb.d.ts.map +0 -1
- package/dist/proto/room_pb.js +0 -3232
- package/dist/proto/room_pb.js.map +0 -1
- package/dist/proto/rpc_pb.cjs +0 -328
- package/dist/proto/rpc_pb.cjs.map +0 -1
- package/dist/proto/rpc_pb.d.cts +0 -267
- package/dist/proto/rpc_pb.d.ts +0 -267
- package/dist/proto/rpc_pb.d.ts.map +0 -1
- package/dist/proto/rpc_pb.js +0 -294
- package/dist/proto/rpc_pb.js.map +0 -1
- package/dist/proto/stats_pb.cjs +0 -1370
- package/dist/proto/stats_pb.cjs.map +0 -1
- package/dist/proto/stats_pb.d.cts +0 -1764
- package/dist/proto/stats_pb.d.ts +0 -1764
- package/dist/proto/stats_pb.d.ts.map +0 -1
- package/dist/proto/stats_pb.js +0 -1300
- package/dist/proto/stats_pb.js.map +0 -1
- package/dist/proto/track_pb.cjs +0 -630
- package/dist/proto/track_pb.cjs.map +0 -1
- package/dist/proto/track_pb.d.cts +0 -542
- package/dist/proto/track_pb.d.ts +0 -542
- package/dist/proto/track_pb.d.ts.map +0 -1
- package/dist/proto/track_pb.js +0 -584
- package/dist/proto/track_pb.js.map +0 -1
- package/dist/proto/track_publication_pb.cjs +0 -194
- package/dist/proto/track_publication_pb.cjs.map +0 -1
- package/dist/proto/track_publication_pb.d.cts +0 -135
- package/dist/proto/track_publication_pb.d.ts +0 -135
- package/dist/proto/track_publication_pb.d.ts.map +0 -1
- package/dist/proto/track_publication_pb.js +0 -164
- package/dist/proto/track_publication_pb.js.map +0 -1
- package/dist/proto/video_frame_pb.cjs +0 -723
- package/dist/proto/video_frame_pb.cjs.map +0 -1
- package/dist/proto/video_frame_pb.d.cts +0 -667
- package/dist/proto/video_frame_pb.d.ts +0 -667
- package/dist/proto/video_frame_pb.d.ts.map +0 -1
- package/dist/proto/video_frame_pb.js +0 -673
- package/dist/proto/video_frame_pb.js.map +0 -1
- package/src/lib.rs +0 -9
- package/src/napi/native.cjs +0 -301
- package/src/napi/native.d.ts +0 -19
- package/src/napi/native.js +0 -15
- package/src/nodejs.rs +0 -134
- package/src/proto/audio_frame_pb.ts +0 -2270
- package/src/proto/data_stream_pb.ts +0 -2674
- package/src/proto/e2ee_pb.ts +0 -1231
- package/src/proto/ffi_pb.ts +0 -1700
- package/src/proto/handle_pb.ts +0 -69
- package/src/proto/participant_pb.ts +0 -351
- package/src/proto/room_pb.ts +0 -5661
- package/src/proto/rpc_pb.ts +0 -539
- package/src/proto/stats_pb.ts +0 -3050
- package/src/proto/track_pb.ts +0 -1040
- package/src/proto/track_publication_pb.ts +0 -284
- package/src/proto/video_frame_pb.ts +0 -1236
package/src/audio_resampler.ts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
import { AudioFrame } from './audio_frame.js';
|
|
5
|
-
import { FfiClient, FfiHandle } from './ffi_client.js';
|
|
6
4
|
import type {
|
|
7
5
|
FlushSoxResamplerResponse,
|
|
8
6
|
NewSoxResamplerResponse,
|
|
9
7
|
PushSoxResamplerResponse,
|
|
10
|
-
} from '
|
|
8
|
+
} from '@livekit/rtc-ffi-bindings';
|
|
11
9
|
import {
|
|
12
10
|
FlushSoxResamplerRequest,
|
|
13
11
|
NewSoxResamplerRequest,
|
|
14
12
|
PushSoxResamplerRequest,
|
|
15
13
|
SoxQualityRecipe,
|
|
16
14
|
SoxResamplerDataType,
|
|
17
|
-
} from '
|
|
15
|
+
} from '@livekit/rtc-ffi-bindings';
|
|
16
|
+
import { AudioFrame } from './audio_frame.js';
|
|
17
|
+
import { FfiClient, FfiHandle } from './ffi_client.js';
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Resampler quality. Higher quality settings result in better audio quality but require more
|
|
@@ -97,6 +97,14 @@ export class AudioResampler {
|
|
|
97
97
|
return this.#channels;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Releases the underlying native resampler handle. Must be called when
|
|
102
|
+
* the resampler is no longer needed to avoid leaking the FD.
|
|
103
|
+
*/
|
|
104
|
+
close() {
|
|
105
|
+
this.#ffiHandle.dispose();
|
|
106
|
+
}
|
|
107
|
+
|
|
100
108
|
/**
|
|
101
109
|
* Push audio data into the resampler and retrieve any available resampled data.
|
|
102
110
|
*
|
|
@@ -131,12 +139,14 @@ export class AudioResampler {
|
|
|
131
139
|
}
|
|
132
140
|
|
|
133
141
|
const outputData = FfiClient.instance.copyBuffer(res.outputPtr, res.size!);
|
|
142
|
+
|
|
134
143
|
return [
|
|
135
144
|
new AudioFrame(
|
|
136
145
|
new Int16Array(outputData.buffer),
|
|
137
146
|
this.#outputRate,
|
|
138
147
|
this.#channels,
|
|
139
148
|
Math.trunc(outputData.length / this.#channels / 2),
|
|
149
|
+
data.userdata,
|
|
140
150
|
),
|
|
141
151
|
];
|
|
142
152
|
}
|
package/src/audio_source.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
import type { AudioFrame } from './audio_frame.js';
|
|
5
|
-
import { FfiClient } from './ffi_client.js';
|
|
6
|
-
import { FfiHandle } from './napi/native.js';
|
|
7
4
|
import type {
|
|
8
5
|
AudioSourceInfo,
|
|
9
6
|
CaptureAudioFrameCallback,
|
|
10
7
|
CaptureAudioFrameResponse,
|
|
11
8
|
ClearAudioBufferResponse,
|
|
12
9
|
NewAudioSourceResponse,
|
|
13
|
-
} from '
|
|
10
|
+
} from '@livekit/rtc-ffi-bindings';
|
|
14
11
|
import {
|
|
15
12
|
AudioSourceType,
|
|
16
13
|
CaptureAudioFrameRequest,
|
|
17
14
|
ClearAudioBufferRequest,
|
|
15
|
+
FfiHandle,
|
|
18
16
|
NewAudioSourceRequest,
|
|
19
|
-
} from '
|
|
17
|
+
} from '@livekit/rtc-ffi-bindings';
|
|
18
|
+
import type { AudioFrame } from './audio_frame.js';
|
|
19
|
+
import { FfiClient } from './ffi_client.js';
|
|
20
20
|
|
|
21
21
|
export class AudioSource {
|
|
22
22
|
/** @internal */
|
|
@@ -145,6 +145,14 @@ export class AudioSource {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
async close() {
|
|
148
|
+
// Clear any pending playout timeout so its callback doesn't fire after
|
|
149
|
+
// the handle is disposed, which would reference freed native state.
|
|
150
|
+
if (this.timeout) {
|
|
151
|
+
clearTimeout(this.timeout);
|
|
152
|
+
this.timeout = undefined;
|
|
153
|
+
}
|
|
154
|
+
// Resolve any pending waitForPlayout() promise so callers don't hang.
|
|
155
|
+
this.release();
|
|
148
156
|
this.ffiHandle.dispose();
|
|
149
157
|
this.closed = true;
|
|
150
158
|
}
|
package/src/audio_stream.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
import type { NewAudioStreamResponse } from '@livekit/rtc-ffi-bindings';
|
|
5
|
+
import { AudioStreamType, NewAudioStreamRequest } from '@livekit/rtc-ffi-bindings';
|
|
4
6
|
import type { UnderlyingSource } from 'node:stream/web';
|
|
5
7
|
import { AudioFrame } from './audio_frame.js';
|
|
6
8
|
import type { FfiEvent } from './ffi_client.js';
|
|
7
9
|
import { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js';
|
|
8
|
-
import { FrameProcessor } from './frame_processor.js';
|
|
10
|
+
import { type FrameProcessor, isFrameProcessor } from './frame_processor.js';
|
|
9
11
|
import { log } from './log.js';
|
|
10
|
-
import type { NewAudioStreamResponse } from './proto/audio_frame_pb.js';
|
|
11
|
-
import { AudioStreamType, NewAudioStreamRequest } from './proto/audio_frame_pb.js';
|
|
12
12
|
import type { Track } from './track.js';
|
|
13
13
|
|
|
14
14
|
export interface AudioStreamOptions {
|
|
@@ -27,6 +27,7 @@ export interface NoiseCancellationOptions {
|
|
|
27
27
|
class AudioStreamSource implements UnderlyingSource<AudioFrame> {
|
|
28
28
|
private controller?: ReadableStreamDefaultController<AudioFrame>;
|
|
29
29
|
private ffiHandle: FfiHandle;
|
|
30
|
+
private disposed = false;
|
|
30
31
|
private sampleRate: number;
|
|
31
32
|
private numChannels: number;
|
|
32
33
|
private legacyNcOptions?: NoiseCancellationOptions;
|
|
@@ -41,7 +42,7 @@ class AudioStreamSource implements UnderlyingSource<AudioFrame> {
|
|
|
41
42
|
if (sampleRateOrOptions !== undefined && typeof sampleRateOrOptions !== 'number') {
|
|
42
43
|
this.sampleRate = sampleRateOrOptions.sampleRate ?? 48000;
|
|
43
44
|
this.numChannels = sampleRateOrOptions.numChannels ?? 1;
|
|
44
|
-
if (sampleRateOrOptions.noiseCancellation
|
|
45
|
+
if (isFrameProcessor(sampleRateOrOptions.noiseCancellation)) {
|
|
45
46
|
this.frameProcessor = sampleRateOrOptions.noiseCancellation;
|
|
46
47
|
} else {
|
|
47
48
|
this.legacyNcOptions = sampleRateOrOptions.noiseCancellation;
|
|
@@ -106,6 +107,15 @@ class AudioStreamSource implements UnderlyingSource<AudioFrame> {
|
|
|
106
107
|
case 'eos':
|
|
107
108
|
FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);
|
|
108
109
|
this.controller.close();
|
|
110
|
+
// Dispose the native handle so the FD is released on stream end,
|
|
111
|
+
// not just when cancel() is called explicitly by the consumer.
|
|
112
|
+
// Guard against double-dispose if cancel() is called after EOS
|
|
113
|
+
// while buffered frames are still in the ReadableStream queue.
|
|
114
|
+
if (!this.disposed) {
|
|
115
|
+
this.disposed = true;
|
|
116
|
+
this.ffiHandle.dispose();
|
|
117
|
+
this.frameProcessor?.close();
|
|
118
|
+
}
|
|
109
119
|
break;
|
|
110
120
|
}
|
|
111
121
|
};
|
|
@@ -116,7 +126,13 @@ class AudioStreamSource implements UnderlyingSource<AudioFrame> {
|
|
|
116
126
|
|
|
117
127
|
cancel() {
|
|
118
128
|
FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);
|
|
119
|
-
this.
|
|
129
|
+
if (!this.disposed) {
|
|
130
|
+
this.disposed = true;
|
|
131
|
+
this.ffiHandle.dispose();
|
|
132
|
+
// Also close the frame processor on cancel for symmetry with the EOS path,
|
|
133
|
+
// so resources are released regardless of how the stream ends.
|
|
134
|
+
this.frameProcessor?.close();
|
|
135
|
+
}
|
|
120
136
|
}
|
|
121
137
|
}
|
|
122
138
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
import type { DataStream_Chunk } from '@livekit/rtc-ffi-bindings';
|
|
4
5
|
import { log } from '../log.js';
|
|
5
|
-
import type { DataStream_Chunk } from '../proto/room_pb.js';
|
|
6
6
|
import { bigIntToNumber } from '../utils.js';
|
|
7
7
|
import type { BaseStreamInfo, ByteStreamInfo, TextStreamInfo } from './types.js';
|
|
8
8
|
|
|
@@ -53,12 +53,18 @@ export class ByteStreamReader extends BaseStreamReader<ByteStreamInfo> {
|
|
|
53
53
|
try {
|
|
54
54
|
const { done, value } = await reader.read();
|
|
55
55
|
if (done) {
|
|
56
|
+
// Release the lock when the stream is exhausted so the
|
|
57
|
+
// underlying ReadableStream can be garbage-collected.
|
|
58
|
+
reader.releaseLock();
|
|
56
59
|
return { done: true, value: undefined as unknown };
|
|
57
60
|
} else {
|
|
58
61
|
this.handleChunkReceived(value);
|
|
59
62
|
return { done: false, value: value.content! };
|
|
60
63
|
}
|
|
61
64
|
} catch (error: unknown) {
|
|
65
|
+
// Release the lock on error so it doesn't stay held when the
|
|
66
|
+
// consumer never calls return() (e.g. breaking out of for-await).
|
|
67
|
+
reader.releaseLock();
|
|
62
68
|
log.error('error processing stream update: %s', error);
|
|
63
69
|
return { done: true, value: undefined as unknown };
|
|
64
70
|
}
|
|
@@ -121,12 +127,18 @@ export class TextStreamReader extends BaseStreamReader<TextStreamInfo> {
|
|
|
121
127
|
[Symbol.asyncIterator]() {
|
|
122
128
|
const reader = this.reader.getReader();
|
|
123
129
|
const decoder = new TextDecoder();
|
|
130
|
+
const receivedChunks = this.receivedChunks;
|
|
124
131
|
|
|
125
132
|
return {
|
|
126
133
|
next: async (): Promise<IteratorResult<string>> => {
|
|
127
134
|
try {
|
|
128
135
|
const { done, value } = await reader.read();
|
|
129
136
|
if (done) {
|
|
137
|
+
// Release the lock when the stream is exhausted so the
|
|
138
|
+
// underlying ReadableStream can be garbage-collected.
|
|
139
|
+
reader.releaseLock();
|
|
140
|
+
// Clear received chunks so the buffered data can be GC'd.
|
|
141
|
+
receivedChunks.clear();
|
|
130
142
|
return { done: true, value: undefined };
|
|
131
143
|
} else {
|
|
132
144
|
this.handleChunkReceived(value);
|
|
@@ -136,6 +148,10 @@ export class TextStreamReader extends BaseStreamReader<TextStreamInfo> {
|
|
|
136
148
|
};
|
|
137
149
|
}
|
|
138
150
|
} catch (error: unknown) {
|
|
151
|
+
// Release the lock on error so it doesn't stay held when the
|
|
152
|
+
// consumer never calls return() (e.g. breaking out of for-await).
|
|
153
|
+
reader.releaseLock();
|
|
154
|
+
receivedChunks.clear();
|
|
139
155
|
log.error('error processing stream update: %s', error);
|
|
140
156
|
return { done: true, value: undefined };
|
|
141
157
|
}
|
|
@@ -143,6 +159,8 @@ export class TextStreamReader extends BaseStreamReader<TextStreamInfo> {
|
|
|
143
159
|
|
|
144
160
|
return(): IteratorResult<string> {
|
|
145
161
|
reader.releaseLock();
|
|
162
|
+
// Clear received chunks so the buffered data can be GC'd.
|
|
163
|
+
receivedChunks.clear();
|
|
146
164
|
return { done: true, value: undefined };
|
|
147
165
|
},
|
|
148
166
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
import type { DataStream_Chunk, DataStream_Header } from '
|
|
4
|
+
import type { DataStream_Chunk, DataStream_Header } from '@livekit/rtc-ffi-bindings';
|
|
5
5
|
import type { ByteStreamReader, TextStreamReader } from './stream_reader.js';
|
|
6
6
|
|
|
7
7
|
export interface StreamController<T extends DataStream_Chunk> {
|
package/src/e2ee.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
import { FfiClient } from './ffi_client.js';
|
|
5
4
|
import type {
|
|
6
5
|
E2eeManagerGetFrameCryptorsResponse,
|
|
7
6
|
E2eeResponse,
|
|
@@ -9,7 +8,7 @@ import type {
|
|
|
9
8
|
GetSharedKeyResponse,
|
|
10
9
|
RatchetKeyResponse,
|
|
11
10
|
RatchetSharedKeyResponse,
|
|
12
|
-
} from '
|
|
11
|
+
} from '@livekit/rtc-ffi-bindings';
|
|
13
12
|
import {
|
|
14
13
|
E2eeManagerSetEnabledRequest,
|
|
15
14
|
E2eeRequest,
|
|
@@ -22,7 +21,8 @@ import {
|
|
|
22
21
|
RatchetSharedKeyRequest,
|
|
23
22
|
SetKeyRequest,
|
|
24
23
|
SetSharedKeyRequest,
|
|
25
|
-
} from '
|
|
24
|
+
} from '@livekit/rtc-ffi-bindings';
|
|
25
|
+
import { FfiClient } from './ffi_client.js';
|
|
26
26
|
|
|
27
27
|
const DEFAULT_RATCHET_SALT = new TextEncoder().encode('LKFrameEncryptionKey');
|
|
28
28
|
const DEFAULT_RATCHET_WINDOW_SIZE = 16;
|
package/src/ffi_client.ts
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
import type { PartialMessage } from '@bufbuild/protobuf';
|
|
5
|
-
import type { TypedEventEmitter as TypedEmitter } from '@livekit/typed-emitter';
|
|
6
|
-
import EventEmitter from 'events';
|
|
7
4
|
import {
|
|
5
|
+
FfiEvent,
|
|
8
6
|
FfiHandle,
|
|
7
|
+
FfiRequest,
|
|
8
|
+
FfiResponse,
|
|
9
|
+
type PartialMessage,
|
|
9
10
|
livekitCopyBuffer,
|
|
10
11
|
livekitDispose,
|
|
11
12
|
livekitFfiRequest,
|
|
12
13
|
livekitInitialize,
|
|
13
14
|
livekitRetrievePtr,
|
|
14
|
-
} from '
|
|
15
|
-
import {
|
|
15
|
+
} from '@livekit/rtc-ffi-bindings';
|
|
16
|
+
import type { TypedEventEmitter as TypedEmitter } from '@livekit/typed-emitter';
|
|
17
|
+
import EventEmitter from 'events';
|
|
16
18
|
import { SDK_VERSION } from './version.js';
|
|
17
19
|
|
|
18
20
|
export { FfiHandle, type FfiEvent, type FfiResponse, FfiRequest, livekitDispose as dispose };
|
package/src/frame_processor.ts
CHANGED
|
@@ -15,7 +15,28 @@ export type FrameProcessorCredentials = {
|
|
|
15
15
|
url: string;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
export const FrameProcessorSymbol = Symbol.for('lk.frame-processor');
|
|
19
|
+
|
|
20
|
+
export function isFrameProcessor<
|
|
21
|
+
T extends FrameProcessor<AudioFrame> | FrameProcessor<VideoFrame> | unknown,
|
|
22
|
+
>(
|
|
23
|
+
maybeProcessor: unknown,
|
|
24
|
+
): maybeProcessor is T extends FrameProcessor<AudioFrame>
|
|
25
|
+
? FrameProcessor<AudioFrame>
|
|
26
|
+
: T extends FrameProcessor<VideoFrame>
|
|
27
|
+
? FrameProcessor<VideoFrame>
|
|
28
|
+
: FrameProcessor<AudioFrame> | FrameProcessor<VideoFrame> {
|
|
29
|
+
return (
|
|
30
|
+
maybeProcessor !== null &&
|
|
31
|
+
typeof maybeProcessor === 'object' &&
|
|
32
|
+
'symbol' in maybeProcessor &&
|
|
33
|
+
maybeProcessor.symbol === FrameProcessorSymbol
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
18
37
|
export abstract class FrameProcessor<Frame extends VideoFrame | AudioFrame> {
|
|
38
|
+
readonly symbol = FrameProcessorSymbol;
|
|
39
|
+
|
|
19
40
|
abstract isEnabled(): boolean;
|
|
20
41
|
abstract setEnabled(enabled: boolean): void;
|
|
21
42
|
|
package/src/index.ts
CHANGED
|
@@ -14,8 +14,8 @@ export { E2EEManager, FrameCryptor, KeyProvider } from './e2ee.js';
|
|
|
14
14
|
export type { E2EEOptions, KeyProviderOptions } from './e2ee.js';
|
|
15
15
|
export { dispose } from './ffi_client.js';
|
|
16
16
|
export { LocalParticipant, Participant, RemoteParticipant } from './participant.js';
|
|
17
|
-
export { EncryptionState, EncryptionType } from '
|
|
18
|
-
export { DisconnectReason, ParticipantKind } from '
|
|
17
|
+
export { EncryptionState, EncryptionType } from '@livekit/rtc-ffi-bindings';
|
|
18
|
+
export { DisconnectReason, ParticipantKind } from '@livekit/rtc-ffi-bindings';
|
|
19
19
|
export {
|
|
20
20
|
ConnectionQuality,
|
|
21
21
|
ConnectionState,
|
|
@@ -24,9 +24,9 @@ export {
|
|
|
24
24
|
IceServer,
|
|
25
25
|
IceTransportType,
|
|
26
26
|
TrackPublishOptions,
|
|
27
|
-
} from '
|
|
28
|
-
export { StreamState, TrackKind, TrackSource } from '
|
|
29
|
-
export { VideoBufferType, VideoCodec, VideoRotation } from '
|
|
27
|
+
} from '@livekit/rtc-ffi-bindings';
|
|
28
|
+
export { StreamState, TrackKind, TrackSource } from '@livekit/rtc-ffi-bindings';
|
|
29
|
+
export { VideoBufferType, VideoCodec, VideoRotation } from '@livekit/rtc-ffi-bindings';
|
|
30
30
|
export { ConnectError, Room, RoomEvent, type RoomOptions, type RtcConfiguration } from './room.js';
|
|
31
31
|
export { RpcError, type PerformRpcParams, type RpcInvocationData } from './rpc.js';
|
|
32
32
|
export {
|
|
@@ -54,4 +54,5 @@ export {
|
|
|
54
54
|
FrameProcessor,
|
|
55
55
|
type FrameProcessorStreamInfo,
|
|
56
56
|
type FrameProcessorCredentials,
|
|
57
|
+
isFrameProcessor,
|
|
57
58
|
} from './frame_processor.js';
|
package/src/log.ts
CHANGED
|
@@ -8,17 +8,21 @@ const isProduction = process.env.NODE_ENV === 'production';
|
|
|
8
8
|
|
|
9
9
|
const defaultOptions: LoggerOptions = { name: 'lk-rtc' };
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
/**
|
|
12
|
+
* temporarily disabling the transport option as there might be a memory leak in some corner cases related to it
|
|
13
|
+
* see https://github.com/pinojs/pino/issues/2370
|
|
14
|
+
*/
|
|
15
|
+
// const devOptions: LoggerOptions = {
|
|
16
|
+
// ...defaultOptions,
|
|
17
|
+
// transport: {
|
|
18
|
+
// target: 'pino-pretty',
|
|
19
|
+
// options: {
|
|
20
|
+
// colorize: true,
|
|
21
|
+
// },
|
|
22
|
+
// },
|
|
23
|
+
// };
|
|
20
24
|
|
|
21
|
-
const log = pino(
|
|
25
|
+
const log = pino(defaultOptions);
|
|
22
26
|
log.level = isProduction ? 'info' : 'debug';
|
|
23
27
|
|
|
24
28
|
export type LogLevel = LevelWithSilent;
|
package/src/participant.ts
CHANGED
|
@@ -2,23 +2,12 @@
|
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
import { Mutex } from '@livekit/mutex';
|
|
5
|
-
import type { PathLike } from 'node:fs';
|
|
6
|
-
import { open, stat } from 'node:fs/promises';
|
|
7
|
-
import {
|
|
8
|
-
type ByteStreamInfo,
|
|
9
|
-
type ByteStreamOptions,
|
|
10
|
-
ByteStreamWriter,
|
|
11
|
-
type TextStreamInfo,
|
|
12
|
-
TextStreamWriter,
|
|
13
|
-
} from './data_streams/index.js';
|
|
14
|
-
import { FfiClient, FfiHandle } from './ffi_client.js';
|
|
15
|
-
import { log } from './log.js';
|
|
16
5
|
import {
|
|
17
6
|
DisconnectReason,
|
|
18
7
|
type OwnedParticipant,
|
|
19
8
|
type ParticipantInfo,
|
|
20
9
|
ParticipantKind,
|
|
21
|
-
} from '
|
|
10
|
+
} from '@livekit/rtc-ffi-bindings';
|
|
22
11
|
import {
|
|
23
12
|
ChatMessage as ChatMessageModel,
|
|
24
13
|
DataStream_ByteHeader,
|
|
@@ -66,20 +55,31 @@ import {
|
|
|
66
55
|
type UnpublishTrackCallback,
|
|
67
56
|
UnpublishTrackRequest,
|
|
68
57
|
type UnpublishTrackResponse,
|
|
69
|
-
} from '
|
|
58
|
+
} from '@livekit/rtc-ffi-bindings';
|
|
70
59
|
import type {
|
|
71
60
|
PerformRpcCallback,
|
|
72
61
|
PerformRpcResponse,
|
|
73
62
|
RegisterRpcMethodResponse,
|
|
74
63
|
RpcMethodInvocationResponseResponse,
|
|
75
64
|
UnregisterRpcMethodResponse,
|
|
76
|
-
} from '
|
|
65
|
+
} from '@livekit/rtc-ffi-bindings';
|
|
77
66
|
import {
|
|
78
67
|
PerformRpcRequest,
|
|
79
68
|
RegisterRpcMethodRequest,
|
|
80
69
|
RpcMethodInvocationResponseRequest,
|
|
81
70
|
UnregisterRpcMethodRequest,
|
|
82
|
-
} from '
|
|
71
|
+
} from '@livekit/rtc-ffi-bindings';
|
|
72
|
+
import type { PathLike } from 'node:fs';
|
|
73
|
+
import { open, stat } from 'node:fs/promises';
|
|
74
|
+
import {
|
|
75
|
+
type ByteStreamInfo,
|
|
76
|
+
type ByteStreamOptions,
|
|
77
|
+
ByteStreamWriter,
|
|
78
|
+
type TextStreamInfo,
|
|
79
|
+
TextStreamWriter,
|
|
80
|
+
} from './data_streams/index.js';
|
|
81
|
+
import { FfiClient, FfiHandle } from './ffi_client.js';
|
|
82
|
+
import { log } from './log.js';
|
|
83
83
|
import { type PerformRpcParams, RpcError, type RpcInvocationData } from './rpc.js';
|
|
84
84
|
import type { LocalTrack } from './track.js';
|
|
85
85
|
import type { RemoteTrackPublication, TrackPublication } from './track_publication.js';
|
|
@@ -336,7 +336,7 @@ export class LocalParticipant extends Participant {
|
|
|
336
336
|
await sendTrailer(trailerReq);
|
|
337
337
|
},
|
|
338
338
|
abort(err) {
|
|
339
|
-
log.error('Sink
|
|
339
|
+
log.error(err, 'Sink Error');
|
|
340
340
|
},
|
|
341
341
|
});
|
|
342
342
|
|
|
@@ -451,7 +451,7 @@ export class LocalParticipant extends Participant {
|
|
|
451
451
|
await sendTrailer(trailerReq);
|
|
452
452
|
},
|
|
453
453
|
abort(err) {
|
|
454
|
-
log.error('Sink error
|
|
454
|
+
log.error(err, 'Sink error');
|
|
455
455
|
},
|
|
456
456
|
});
|
|
457
457
|
|