@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.
Files changed (290) hide show
  1. package/dist/audio_filter.cjs +2 -2
  2. package/dist/audio_filter.cjs.map +1 -1
  3. package/dist/audio_filter.js +1 -1
  4. package/dist/audio_filter.js.map +1 -1
  5. package/dist/audio_frame.cjs +11 -7
  6. package/dist/audio_frame.cjs.map +1 -1
  7. package/dist/audio_frame.d.cts +3 -8
  8. package/dist/audio_frame.d.ts +3 -8
  9. package/dist/audio_frame.d.ts.map +1 -1
  10. package/dist/audio_frame.js +10 -6
  11. package/dist/audio_frame.js.map +1 -1
  12. package/dist/audio_mixer.cjs +11 -4
  13. package/dist/audio_mixer.cjs.map +1 -1
  14. package/dist/audio_mixer.d.cts +1 -6
  15. package/dist/audio_mixer.d.ts +1 -6
  16. package/dist/audio_mixer.d.ts.map +1 -1
  17. package/dist/audio_mixer.js +11 -4
  18. package/dist/audio_mixer.js.map +1 -1
  19. package/dist/audio_resampler.cjs +20 -12
  20. package/dist/audio_resampler.cjs.map +1 -1
  21. package/dist/audio_resampler.d.cts +6 -6
  22. package/dist/audio_resampler.d.ts +6 -6
  23. package/dist/audio_resampler.d.ts.map +1 -1
  24. package/dist/audio_resampler.js +12 -4
  25. package/dist/audio_resampler.js.map +1 -1
  26. package/dist/audio_source.cjs +11 -7
  27. package/dist/audio_source.cjs.map +1 -1
  28. package/dist/audio_source.d.cts +1 -7
  29. package/dist/audio_source.d.ts +1 -7
  30. package/dist/audio_source.d.ts.map +1 -1
  31. package/dist/audio_source.js +8 -3
  32. package/dist/audio_source.js.map +1 -1
  33. package/dist/audio_stream.cjs +17 -5
  34. package/dist/audio_stream.cjs.map +1 -1
  35. package/dist/audio_stream.d.cts +1 -14
  36. package/dist/audio_stream.d.ts +1 -14
  37. package/dist/audio_stream.d.ts.map +1 -1
  38. package/dist/audio_stream.js +16 -4
  39. package/dist/audio_stream.js.map +1 -1
  40. package/dist/data_streams/index.d.cts +2 -10
  41. package/dist/data_streams/index.d.ts +2 -10
  42. package/dist/data_streams/stream_reader.cjs +8 -0
  43. package/dist/data_streams/stream_reader.cjs.map +1 -1
  44. package/dist/data_streams/stream_reader.d.cts +2 -10
  45. package/dist/data_streams/stream_reader.d.ts +2 -10
  46. package/dist/data_streams/stream_reader.d.ts.map +1 -1
  47. package/dist/data_streams/stream_reader.js +8 -0
  48. package/dist/data_streams/stream_reader.js.map +1 -1
  49. package/dist/data_streams/stream_writer.d.cts +2 -10
  50. package/dist/data_streams/stream_writer.d.ts +2 -10
  51. package/dist/data_streams/types.cjs.map +1 -1
  52. package/dist/data_streams/types.d.cts +2 -10
  53. package/dist/data_streams/types.d.ts +2 -10
  54. package/dist/data_streams/types.d.ts.map +1 -1
  55. package/dist/e2ee.cjs +21 -21
  56. package/dist/e2ee.cjs.map +1 -1
  57. package/dist/e2ee.d.cts +1 -2
  58. package/dist/e2ee.d.ts +1 -2
  59. package/dist/e2ee.d.ts.map +1 -1
  60. package/dist/e2ee.js +2 -2
  61. package/dist/e2ee.js.map +1 -1
  62. package/dist/ffi_client.cjs +11 -12
  63. package/dist/ffi_client.cjs.map +1 -1
  64. package/dist/ffi_client.d.cts +3 -16
  65. package/dist/ffi_client.d.ts +3 -16
  66. package/dist/ffi_client.d.ts.map +1 -1
  67. package/dist/ffi_client.js +5 -3
  68. package/dist/ffi_client.js.map +1 -1
  69. package/dist/frame_processor.cjs +13 -2
  70. package/dist/frame_processor.cjs.map +1 -1
  71. package/dist/frame_processor.d.cts +5 -8
  72. package/dist/frame_processor.d.ts +5 -8
  73. package/dist/frame_processor.d.ts.map +1 -1
  74. package/dist/frame_processor.js +10 -1
  75. package/dist/frame_processor.js.map +1 -1
  76. package/dist/index.cjs +25 -23
  77. package/dist/index.cjs.map +1 -1
  78. package/dist/index.d.cts +3 -16
  79. package/dist/index.d.ts +3 -16
  80. package/dist/index.d.ts.map +1 -1
  81. package/dist/index.js +9 -7
  82. package/dist/index.js.map +1 -1
  83. package/dist/log.cjs +1 -10
  84. package/dist/log.cjs.map +1 -1
  85. package/dist/log.d.cts +4 -0
  86. package/dist/log.d.ts +4 -0
  87. package/dist/log.d.ts.map +1 -1
  88. package/dist/log.js +1 -10
  89. package/dist/log.js.map +1 -1
  90. package/dist/participant.cjs +38 -38
  91. package/dist/participant.cjs.map +1 -1
  92. package/dist/participant.d.cts +2 -15
  93. package/dist/participant.d.ts +2 -15
  94. package/dist/participant.d.ts.map +1 -1
  95. package/dist/participant.js +12 -12
  96. package/dist/participant.js.map +1 -1
  97. package/dist/room.cjs +48 -30
  98. package/dist/room.cjs.map +1 -1
  99. package/dist/room.d.cts +11 -16
  100. package/dist/room.d.ts +11 -16
  101. package/dist/room.d.ts.map +1 -1
  102. package/dist/room.js +44 -26
  103. package/dist/room.js.map +1 -1
  104. package/dist/rpc.cjs.map +1 -1
  105. package/dist/rpc.d.cts +1 -2
  106. package/dist/rpc.d.ts +1 -2
  107. package/dist/rpc.d.ts.map +1 -1
  108. package/dist/rpc.js.map +1 -1
  109. package/dist/{stream_reader-Ch2zvjU3.d.cts → stream_reader-CuG4b8Y-.d.cts} +1 -1
  110. package/dist/{stream_reader-DRyR29vo.d.ts → stream_reader-CuG4b8Y-.d.ts} +1 -1
  111. package/dist/track.cjs +3 -3
  112. package/dist/track.cjs.map +1 -1
  113. package/dist/track.d.cts +1 -14
  114. package/dist/track.d.ts +1 -14
  115. package/dist/track.d.ts.map +1 -1
  116. package/dist/track.js +1 -1
  117. package/dist/track.js.map +1 -1
  118. package/dist/track_publication.cjs +4 -4
  119. package/dist/track_publication.cjs.map +1 -1
  120. package/dist/track_publication.d.cts +1 -14
  121. package/dist/track_publication.d.ts +1 -14
  122. package/dist/track_publication.d.ts.map +1 -1
  123. package/dist/track_publication.js +2 -2
  124. package/dist/track_publication.js.map +1 -1
  125. package/dist/version.cjs +1 -1
  126. package/dist/version.cjs.map +1 -1
  127. package/dist/version.d.cts +1 -1
  128. package/dist/version.d.ts +1 -1
  129. package/dist/version.js +1 -1
  130. package/dist/version.js.map +1 -1
  131. package/dist/video_frame.cjs +42 -42
  132. package/dist/video_frame.cjs.map +1 -1
  133. package/dist/video_frame.d.cts +1 -6
  134. package/dist/video_frame.d.ts +1 -6
  135. package/dist/video_frame.d.ts.map +1 -1
  136. package/dist/video_frame.js +2 -2
  137. package/dist/video_frame.js.map +1 -1
  138. package/dist/video_source.cjs +5 -5
  139. package/dist/video_source.cjs.map +1 -1
  140. package/dist/video_source.d.cts +1 -14
  141. package/dist/video_source.d.ts +1 -14
  142. package/dist/video_source.d.ts.map +1 -1
  143. package/dist/video_source.js +2 -2
  144. package/dist/video_source.js.map +1 -1
  145. package/dist/video_stream.cjs +12 -4
  146. package/dist/video_stream.cjs.map +1 -1
  147. package/dist/video_stream.d.cts +1 -14
  148. package/dist/video_stream.d.ts +1 -14
  149. package/dist/video_stream.d.ts.map +1 -1
  150. package/dist/video_stream.js +10 -2
  151. package/dist/video_stream.js.map +1 -1
  152. package/package.json +9 -35
  153. package/src/audio_filter.ts +2 -2
  154. package/src/audio_frame.ts +26 -7
  155. package/src/audio_mixer.ts +15 -4
  156. package/src/audio_resampler.ts +14 -4
  157. package/src/audio_source.ts +13 -5
  158. package/src/audio_stream.ts +21 -5
  159. package/src/data_streams/stream_reader.ts +19 -1
  160. package/src/data_streams/types.ts +1 -1
  161. package/src/e2ee.ts +3 -3
  162. package/src/ffi_client.ts +7 -5
  163. package/src/frame_processor.ts +21 -0
  164. package/src/index.ts +6 -5
  165. package/src/log.ts +14 -10
  166. package/src/participant.ts +17 -17
  167. package/src/room.ts +65 -38
  168. package/src/rpc.ts +1 -1
  169. package/src/tests/e2e.test.ts +517 -0
  170. package/src/track.ts +4 -4
  171. package/src/track_publication.ts +6 -6
  172. package/src/version.ts +1 -1
  173. package/src/video_frame.ts +3 -3
  174. package/src/video_source.ts +3 -3
  175. package/src/video_stream.ts +15 -3
  176. package/Cargo.toml +0 -25
  177. package/build.rs +0 -9
  178. package/dist/napi/native.cjs +0 -301
  179. package/dist/napi/native.d.cjs +0 -17
  180. package/dist/napi/native.d.cjs.map +0 -1
  181. package/dist/napi/native.d.d.cts +0 -21
  182. package/dist/napi/native.d.d.ts +0 -21
  183. package/dist/napi/native.d.js +0 -1
  184. package/dist/napi/native.d.js.map +0 -1
  185. package/dist/napi/native.d.ts +0 -19
  186. package/dist/napi/native.js +0 -15
  187. package/dist/native.cjs +0 -301
  188. package/dist/native.d.ts +0 -19
  189. package/dist/native.js +0 -15
  190. package/dist/proto/audio_frame_pb.cjs +0 -1357
  191. package/dist/proto/audio_frame_pb.cjs.map +0 -1
  192. package/dist/proto/audio_frame_pb.d.cts +0 -1183
  193. package/dist/proto/audio_frame_pb.d.ts +0 -1183
  194. package/dist/proto/audio_frame_pb.d.ts.map +0 -1
  195. package/dist/proto/audio_frame_pb.js +0 -1283
  196. package/dist/proto/audio_frame_pb.js.map +0 -1
  197. package/dist/proto/data_stream_pb.cjs +0 -1638
  198. package/dist/proto/data_stream_pb.cjs.map +0 -1
  199. package/dist/proto/data_stream_pb.d.cts +0 -1449
  200. package/dist/proto/data_stream_pb.d.ts +0 -1449
  201. package/dist/proto/data_stream_pb.d.ts.map +0 -1
  202. package/dist/proto/data_stream_pb.js +0 -1559
  203. package/dist/proto/data_stream_pb.js.map +0 -1
  204. package/dist/proto/e2ee_pb.cjs +0 -746
  205. package/dist/proto/e2ee_pb.cjs.map +0 -1
  206. package/dist/proto/e2ee_pb.d.cts +0 -653
  207. package/dist/proto/e2ee_pb.d.ts +0 -653
  208. package/dist/proto/e2ee_pb.d.ts.map +0 -1
  209. package/dist/proto/e2ee_pb.js +0 -696
  210. package/dist/proto/e2ee_pb.js.map +0 -1
  211. package/dist/proto/ffi_pb.cjs +0 -477
  212. package/dist/proto/ffi_pb.cjs.map +0 -1
  213. package/dist/proto/ffi_pb.d.cts +0 -1321
  214. package/dist/proto/ffi_pb.d.ts +0 -1321
  215. package/dist/proto/ffi_pb.d.ts.map +0 -1
  216. package/dist/proto/ffi_pb.js +0 -444
  217. package/dist/proto/ffi_pb.js.map +0 -1
  218. package/dist/proto/handle_pb.cjs +0 -53
  219. package/dist/proto/handle_pb.cjs.map +0 -1
  220. package/dist/proto/handle_pb.d.cts +0 -31
  221. package/dist/proto/handle_pb.d.ts +0 -31
  222. package/dist/proto/handle_pb.d.ts.map +0 -1
  223. package/dist/proto/handle_pb.js +0 -29
  224. package/dist/proto/handle_pb.js.map +0 -1
  225. package/dist/proto/participant_pb.cjs +0 -173
  226. package/dist/proto/participant_pb.cjs.map +0 -1
  227. package/dist/proto/participant_pb.d.cts +0 -218
  228. package/dist/proto/participant_pb.d.ts +0 -218
  229. package/dist/proto/participant_pb.d.ts.map +0 -1
  230. package/dist/proto/participant_pb.js +0 -145
  231. package/dist/proto/participant_pb.js.map +0 -1
  232. package/dist/proto/room_pb.cjs +0 -3374
  233. package/dist/proto/room_pb.cjs.map +0 -1
  234. package/dist/proto/room_pb.d.cts +0 -3028
  235. package/dist/proto/room_pb.d.ts +0 -3028
  236. package/dist/proto/room_pb.d.ts.map +0 -1
  237. package/dist/proto/room_pb.js +0 -3232
  238. package/dist/proto/room_pb.js.map +0 -1
  239. package/dist/proto/rpc_pb.cjs +0 -328
  240. package/dist/proto/rpc_pb.cjs.map +0 -1
  241. package/dist/proto/rpc_pb.d.cts +0 -267
  242. package/dist/proto/rpc_pb.d.ts +0 -267
  243. package/dist/proto/rpc_pb.d.ts.map +0 -1
  244. package/dist/proto/rpc_pb.js +0 -294
  245. package/dist/proto/rpc_pb.js.map +0 -1
  246. package/dist/proto/stats_pb.cjs +0 -1370
  247. package/dist/proto/stats_pb.cjs.map +0 -1
  248. package/dist/proto/stats_pb.d.cts +0 -1764
  249. package/dist/proto/stats_pb.d.ts +0 -1764
  250. package/dist/proto/stats_pb.d.ts.map +0 -1
  251. package/dist/proto/stats_pb.js +0 -1300
  252. package/dist/proto/stats_pb.js.map +0 -1
  253. package/dist/proto/track_pb.cjs +0 -630
  254. package/dist/proto/track_pb.cjs.map +0 -1
  255. package/dist/proto/track_pb.d.cts +0 -542
  256. package/dist/proto/track_pb.d.ts +0 -542
  257. package/dist/proto/track_pb.d.ts.map +0 -1
  258. package/dist/proto/track_pb.js +0 -584
  259. package/dist/proto/track_pb.js.map +0 -1
  260. package/dist/proto/track_publication_pb.cjs +0 -194
  261. package/dist/proto/track_publication_pb.cjs.map +0 -1
  262. package/dist/proto/track_publication_pb.d.cts +0 -135
  263. package/dist/proto/track_publication_pb.d.ts +0 -135
  264. package/dist/proto/track_publication_pb.d.ts.map +0 -1
  265. package/dist/proto/track_publication_pb.js +0 -164
  266. package/dist/proto/track_publication_pb.js.map +0 -1
  267. package/dist/proto/video_frame_pb.cjs +0 -723
  268. package/dist/proto/video_frame_pb.cjs.map +0 -1
  269. package/dist/proto/video_frame_pb.d.cts +0 -667
  270. package/dist/proto/video_frame_pb.d.ts +0 -667
  271. package/dist/proto/video_frame_pb.d.ts.map +0 -1
  272. package/dist/proto/video_frame_pb.js +0 -673
  273. package/dist/proto/video_frame_pb.js.map +0 -1
  274. package/src/lib.rs +0 -9
  275. package/src/napi/native.cjs +0 -301
  276. package/src/napi/native.d.ts +0 -19
  277. package/src/napi/native.js +0 -15
  278. package/src/nodejs.rs +0 -134
  279. package/src/proto/audio_frame_pb.ts +0 -2270
  280. package/src/proto/data_stream_pb.ts +0 -2674
  281. package/src/proto/e2ee_pb.ts +0 -1231
  282. package/src/proto/ffi_pb.ts +0 -1700
  283. package/src/proto/handle_pb.ts +0 -69
  284. package/src/proto/participant_pb.ts +0 -351
  285. package/src/proto/room_pb.ts +0 -5661
  286. package/src/proto/rpc_pb.ts +0 -539
  287. package/src/proto/stats_pb.ts +0 -3050
  288. package/src/proto/track_pb.ts +0 -1040
  289. package/src/proto/track_publication_pb.ts +0 -284
  290. package/src/proto/video_frame_pb.ts +0 -1236
@@ -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 './proto/audio_frame_pb.js';
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 './proto/audio_frame_pb.js';
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
  }
@@ -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 './proto/audio_frame_pb.js';
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 './proto/audio_frame_pb.js';
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
  }
@@ -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 instanceof FrameProcessor) {
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.ffiHandle.dispose();
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 '../proto/room_pb.js';
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 './proto/e2ee_pb.js';
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 './proto/e2ee_pb.js';
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 './napi/native.js';
15
- import { FfiEvent, FfiRequest, FfiResponse } from './proto/ffi_pb.js';
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 };
@@ -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 './proto/e2ee_pb.js';
18
- export { DisconnectReason, ParticipantKind } from './proto/participant_pb.js';
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 './proto/room_pb.js';
28
- export { StreamState, TrackKind, TrackSource } from './proto/track_pb.js';
29
- export { VideoBufferType, VideoCodec, VideoRotation } from './proto/video_frame_pb.js';
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
- const devOptions: LoggerOptions = {
12
- ...defaultOptions,
13
- transport: {
14
- target: 'pino-pretty',
15
- options: {
16
- colorize: true,
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(isProduction ? defaultOptions : devOptions);
25
+ const log = pino(defaultOptions);
22
26
  log.level = isProduction ? 'info' : 'debug';
23
27
 
24
28
  export type LogLevel = LevelWithSilent;
@@ -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 './proto/participant_pb.js';
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 './proto/room_pb.js';
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 './proto/rpc_pb.js';
65
+ } from '@livekit/rtc-ffi-bindings';
77
66
  import {
78
67
  PerformRpcRequest,
79
68
  RegisterRpcMethodRequest,
80
69
  RpcMethodInvocationResponseRequest,
81
70
  UnregisterRpcMethodRequest,
82
- } from './proto/rpc_pb.js';
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 error:', err);
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:', err);
454
+ log.error(err, 'Sink error');
455
455
  },
456
456
  });
457
457