@livekit/rtc-node 0.13.24 → 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 (281) 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 +9 -5
  6. package/dist/audio_frame.cjs.map +1 -1
  7. package/dist/audio_frame.d.cts +2 -7
  8. package/dist/audio_frame.d.ts +2 -7
  9. package/dist/audio_frame.d.ts.map +1 -1
  10. package/dist/audio_frame.js +8 -4
  11. package/dist/audio_frame.js.map +1 -1
  12. package/dist/audio_mixer.cjs +1 -1
  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.js +1 -1
  17. package/dist/audio_mixer.js.map +1 -1
  18. package/dist/audio_resampler.cjs +20 -12
  19. package/dist/audio_resampler.cjs.map +1 -1
  20. package/dist/audio_resampler.d.cts +6 -6
  21. package/dist/audio_resampler.d.ts +6 -6
  22. package/dist/audio_resampler.d.ts.map +1 -1
  23. package/dist/audio_resampler.js +12 -4
  24. package/dist/audio_resampler.js.map +1 -1
  25. package/dist/audio_source.cjs +11 -7
  26. package/dist/audio_source.cjs.map +1 -1
  27. package/dist/audio_source.d.cts +1 -7
  28. package/dist/audio_source.d.ts +1 -7
  29. package/dist/audio_source.d.ts.map +1 -1
  30. package/dist/audio_source.js +8 -3
  31. package/dist/audio_source.js.map +1 -1
  32. package/dist/audio_stream.cjs +16 -6
  33. package/dist/audio_stream.cjs.map +1 -1
  34. package/dist/audio_stream.d.cts +1 -14
  35. package/dist/audio_stream.d.ts +1 -14
  36. package/dist/audio_stream.d.ts.map +1 -1
  37. package/dist/audio_stream.js +15 -5
  38. package/dist/audio_stream.js.map +1 -1
  39. package/dist/data_streams/index.d.cts +2 -10
  40. package/dist/data_streams/index.d.ts +2 -10
  41. package/dist/data_streams/stream_reader.cjs +8 -0
  42. package/dist/data_streams/stream_reader.cjs.map +1 -1
  43. package/dist/data_streams/stream_reader.d.cts +2 -10
  44. package/dist/data_streams/stream_reader.d.ts +2 -10
  45. package/dist/data_streams/stream_reader.d.ts.map +1 -1
  46. package/dist/data_streams/stream_reader.js +8 -0
  47. package/dist/data_streams/stream_reader.js.map +1 -1
  48. package/dist/data_streams/stream_writer.d.cts +2 -10
  49. package/dist/data_streams/stream_writer.d.ts +2 -10
  50. package/dist/data_streams/types.cjs.map +1 -1
  51. package/dist/data_streams/types.d.cts +2 -10
  52. package/dist/data_streams/types.d.ts +2 -10
  53. package/dist/data_streams/types.d.ts.map +1 -1
  54. package/dist/e2ee.cjs +21 -21
  55. package/dist/e2ee.cjs.map +1 -1
  56. package/dist/e2ee.d.cts +1 -2
  57. package/dist/e2ee.d.ts +1 -2
  58. package/dist/e2ee.d.ts.map +1 -1
  59. package/dist/e2ee.js +2 -2
  60. package/dist/e2ee.js.map +1 -1
  61. package/dist/ffi_client.cjs +11 -12
  62. package/dist/ffi_client.cjs.map +1 -1
  63. package/dist/ffi_client.d.cts +3 -16
  64. package/dist/ffi_client.d.ts +3 -16
  65. package/dist/ffi_client.d.ts.map +1 -1
  66. package/dist/ffi_client.js +5 -3
  67. package/dist/ffi_client.js.map +1 -1
  68. package/dist/frame_processor.cjs +13 -2
  69. package/dist/frame_processor.cjs.map +1 -1
  70. package/dist/frame_processor.d.cts +5 -8
  71. package/dist/frame_processor.d.ts +5 -8
  72. package/dist/frame_processor.d.ts.map +1 -1
  73. package/dist/frame_processor.js +10 -1
  74. package/dist/frame_processor.js.map +1 -1
  75. package/dist/index.cjs +25 -23
  76. package/dist/index.cjs.map +1 -1
  77. package/dist/index.d.cts +3 -16
  78. package/dist/index.d.ts +3 -16
  79. package/dist/index.d.ts.map +1 -1
  80. package/dist/index.js +9 -7
  81. package/dist/index.js.map +1 -1
  82. package/dist/participant.cjs +38 -38
  83. package/dist/participant.cjs.map +1 -1
  84. package/dist/participant.d.cts +2 -15
  85. package/dist/participant.d.ts +2 -15
  86. package/dist/participant.d.ts.map +1 -1
  87. package/dist/participant.js +12 -12
  88. package/dist/participant.js.map +1 -1
  89. package/dist/room.cjs +14 -14
  90. package/dist/room.cjs.map +1 -1
  91. package/dist/room.d.cts +2 -15
  92. package/dist/room.d.ts +2 -15
  93. package/dist/room.d.ts.map +1 -1
  94. package/dist/room.js +10 -10
  95. package/dist/room.js.map +1 -1
  96. package/dist/rpc.cjs.map +1 -1
  97. package/dist/rpc.d.cts +1 -2
  98. package/dist/rpc.d.ts +1 -2
  99. package/dist/rpc.d.ts.map +1 -1
  100. package/dist/rpc.js.map +1 -1
  101. package/dist/{stream_reader-Ch2zvjU3.d.cts → stream_reader-CuG4b8Y-.d.cts} +1 -1
  102. package/dist/{stream_reader-DRyR29vo.d.ts → stream_reader-CuG4b8Y-.d.ts} +1 -1
  103. package/dist/track.cjs +3 -3
  104. package/dist/track.cjs.map +1 -1
  105. package/dist/track.d.cts +1 -14
  106. package/dist/track.d.ts +1 -14
  107. package/dist/track.d.ts.map +1 -1
  108. package/dist/track.js +1 -1
  109. package/dist/track.js.map +1 -1
  110. package/dist/track_publication.cjs +4 -4
  111. package/dist/track_publication.cjs.map +1 -1
  112. package/dist/track_publication.d.cts +1 -14
  113. package/dist/track_publication.d.ts +1 -14
  114. package/dist/track_publication.d.ts.map +1 -1
  115. package/dist/track_publication.js +2 -2
  116. package/dist/track_publication.js.map +1 -1
  117. package/dist/version.cjs +1 -1
  118. package/dist/version.cjs.map +1 -1
  119. package/dist/version.d.cts +1 -1
  120. package/dist/version.d.ts +1 -1
  121. package/dist/version.js +1 -1
  122. package/dist/version.js.map +1 -1
  123. package/dist/video_frame.cjs +42 -42
  124. package/dist/video_frame.cjs.map +1 -1
  125. package/dist/video_frame.d.cts +1 -6
  126. package/dist/video_frame.d.ts +1 -6
  127. package/dist/video_frame.d.ts.map +1 -1
  128. package/dist/video_frame.js +2 -2
  129. package/dist/video_frame.js.map +1 -1
  130. package/dist/video_source.cjs +5 -5
  131. package/dist/video_source.cjs.map +1 -1
  132. package/dist/video_source.d.cts +1 -14
  133. package/dist/video_source.d.ts +1 -14
  134. package/dist/video_source.d.ts.map +1 -1
  135. package/dist/video_source.js +2 -2
  136. package/dist/video_source.js.map +1 -1
  137. package/dist/video_stream.cjs +12 -4
  138. package/dist/video_stream.cjs.map +1 -1
  139. package/dist/video_stream.d.cts +1 -14
  140. package/dist/video_stream.d.ts +1 -14
  141. package/dist/video_stream.d.ts.map +1 -1
  142. package/dist/video_stream.js +10 -2
  143. package/dist/video_stream.js.map +1 -1
  144. package/package.json +7 -37
  145. package/src/audio_filter.ts +2 -2
  146. package/src/audio_frame.ts +17 -5
  147. package/src/audio_mixer.ts +1 -1
  148. package/src/audio_resampler.ts +14 -4
  149. package/src/audio_source.ts +13 -5
  150. package/src/audio_stream.ts +21 -6
  151. package/src/data_streams/stream_reader.ts +19 -1
  152. package/src/data_streams/types.ts +1 -1
  153. package/src/e2ee.ts +3 -3
  154. package/src/ffi_client.ts +7 -5
  155. package/src/frame_processor.ts +21 -0
  156. package/src/index.ts +6 -5
  157. package/src/participant.ts +17 -17
  158. package/src/room.ts +22 -22
  159. package/src/rpc.ts +1 -1
  160. package/src/tests/e2e.test.ts +11 -8
  161. package/src/track.ts +4 -4
  162. package/src/track_publication.ts +6 -6
  163. package/src/version.ts +1 -1
  164. package/src/video_frame.ts +3 -3
  165. package/src/video_source.ts +3 -3
  166. package/src/video_stream.ts +15 -3
  167. package/Cargo.toml +0 -25
  168. package/build.rs +0 -9
  169. package/dist/napi/native.cjs +0 -301
  170. package/dist/napi/native.d.cjs +0 -17
  171. package/dist/napi/native.d.cjs.map +0 -1
  172. package/dist/napi/native.d.d.cts +0 -21
  173. package/dist/napi/native.d.d.ts +0 -21
  174. package/dist/napi/native.d.js +0 -1
  175. package/dist/napi/native.d.js.map +0 -1
  176. package/dist/napi/native.d.ts +0 -19
  177. package/dist/napi/native.js +0 -15
  178. package/dist/native.cjs +0 -301
  179. package/dist/native.d.ts +0 -19
  180. package/dist/native.js +0 -15
  181. package/dist/proto/audio_frame_pb.cjs +0 -1357
  182. package/dist/proto/audio_frame_pb.cjs.map +0 -1
  183. package/dist/proto/audio_frame_pb.d.cts +0 -1183
  184. package/dist/proto/audio_frame_pb.d.ts +0 -1183
  185. package/dist/proto/audio_frame_pb.d.ts.map +0 -1
  186. package/dist/proto/audio_frame_pb.js +0 -1283
  187. package/dist/proto/audio_frame_pb.js.map +0 -1
  188. package/dist/proto/data_stream_pb.cjs +0 -1638
  189. package/dist/proto/data_stream_pb.cjs.map +0 -1
  190. package/dist/proto/data_stream_pb.d.cts +0 -1449
  191. package/dist/proto/data_stream_pb.d.ts +0 -1449
  192. package/dist/proto/data_stream_pb.d.ts.map +0 -1
  193. package/dist/proto/data_stream_pb.js +0 -1559
  194. package/dist/proto/data_stream_pb.js.map +0 -1
  195. package/dist/proto/e2ee_pb.cjs +0 -746
  196. package/dist/proto/e2ee_pb.cjs.map +0 -1
  197. package/dist/proto/e2ee_pb.d.cts +0 -653
  198. package/dist/proto/e2ee_pb.d.ts +0 -653
  199. package/dist/proto/e2ee_pb.d.ts.map +0 -1
  200. package/dist/proto/e2ee_pb.js +0 -696
  201. package/dist/proto/e2ee_pb.js.map +0 -1
  202. package/dist/proto/ffi_pb.cjs +0 -477
  203. package/dist/proto/ffi_pb.cjs.map +0 -1
  204. package/dist/proto/ffi_pb.d.cts +0 -1321
  205. package/dist/proto/ffi_pb.d.ts +0 -1321
  206. package/dist/proto/ffi_pb.d.ts.map +0 -1
  207. package/dist/proto/ffi_pb.js +0 -444
  208. package/dist/proto/ffi_pb.js.map +0 -1
  209. package/dist/proto/handle_pb.cjs +0 -53
  210. package/dist/proto/handle_pb.cjs.map +0 -1
  211. package/dist/proto/handle_pb.d.cts +0 -31
  212. package/dist/proto/handle_pb.d.ts +0 -31
  213. package/dist/proto/handle_pb.d.ts.map +0 -1
  214. package/dist/proto/handle_pb.js +0 -29
  215. package/dist/proto/handle_pb.js.map +0 -1
  216. package/dist/proto/participant_pb.cjs +0 -173
  217. package/dist/proto/participant_pb.cjs.map +0 -1
  218. package/dist/proto/participant_pb.d.cts +0 -218
  219. package/dist/proto/participant_pb.d.ts +0 -218
  220. package/dist/proto/participant_pb.d.ts.map +0 -1
  221. package/dist/proto/participant_pb.js +0 -145
  222. package/dist/proto/participant_pb.js.map +0 -1
  223. package/dist/proto/room_pb.cjs +0 -3374
  224. package/dist/proto/room_pb.cjs.map +0 -1
  225. package/dist/proto/room_pb.d.cts +0 -3028
  226. package/dist/proto/room_pb.d.ts +0 -3028
  227. package/dist/proto/room_pb.d.ts.map +0 -1
  228. package/dist/proto/room_pb.js +0 -3232
  229. package/dist/proto/room_pb.js.map +0 -1
  230. package/dist/proto/rpc_pb.cjs +0 -328
  231. package/dist/proto/rpc_pb.cjs.map +0 -1
  232. package/dist/proto/rpc_pb.d.cts +0 -267
  233. package/dist/proto/rpc_pb.d.ts +0 -267
  234. package/dist/proto/rpc_pb.d.ts.map +0 -1
  235. package/dist/proto/rpc_pb.js +0 -294
  236. package/dist/proto/rpc_pb.js.map +0 -1
  237. package/dist/proto/stats_pb.cjs +0 -1370
  238. package/dist/proto/stats_pb.cjs.map +0 -1
  239. package/dist/proto/stats_pb.d.cts +0 -1764
  240. package/dist/proto/stats_pb.d.ts +0 -1764
  241. package/dist/proto/stats_pb.d.ts.map +0 -1
  242. package/dist/proto/stats_pb.js +0 -1300
  243. package/dist/proto/stats_pb.js.map +0 -1
  244. package/dist/proto/track_pb.cjs +0 -630
  245. package/dist/proto/track_pb.cjs.map +0 -1
  246. package/dist/proto/track_pb.d.cts +0 -542
  247. package/dist/proto/track_pb.d.ts +0 -542
  248. package/dist/proto/track_pb.d.ts.map +0 -1
  249. package/dist/proto/track_pb.js +0 -584
  250. package/dist/proto/track_pb.js.map +0 -1
  251. package/dist/proto/track_publication_pb.cjs +0 -194
  252. package/dist/proto/track_publication_pb.cjs.map +0 -1
  253. package/dist/proto/track_publication_pb.d.cts +0 -135
  254. package/dist/proto/track_publication_pb.d.ts +0 -135
  255. package/dist/proto/track_publication_pb.d.ts.map +0 -1
  256. package/dist/proto/track_publication_pb.js +0 -164
  257. package/dist/proto/track_publication_pb.js.map +0 -1
  258. package/dist/proto/video_frame_pb.cjs +0 -723
  259. package/dist/proto/video_frame_pb.cjs.map +0 -1
  260. package/dist/proto/video_frame_pb.d.cts +0 -667
  261. package/dist/proto/video_frame_pb.d.ts +0 -667
  262. package/dist/proto/video_frame_pb.d.ts.map +0 -1
  263. package/dist/proto/video_frame_pb.js +0 -673
  264. package/dist/proto/video_frame_pb.js.map +0 -1
  265. package/src/lib.rs +0 -9
  266. package/src/napi/native.cjs +0 -301
  267. package/src/napi/native.d.ts +0 -19
  268. package/src/napi/native.js +0 -15
  269. package/src/nodejs.rs +0 -134
  270. package/src/proto/audio_frame_pb.ts +0 -2270
  271. package/src/proto/data_stream_pb.ts +0 -2674
  272. package/src/proto/e2ee_pb.ts +0 -1231
  273. package/src/proto/ffi_pb.ts +0 -1700
  274. package/src/proto/handle_pb.ts +0 -69
  275. package/src/proto/participant_pb.ts +0 -351
  276. package/src/proto/room_pb.ts +0 -5661
  277. package/src/proto/rpc_pb.ts +0 -539
  278. package/src/proto/stats_pb.ts +0 -3050
  279. package/src/proto/track_pb.ts +0 -1040
  280. package/src/proto/track_publication_pb.ts +0 -284
  281. package/src/proto/video_frame_pb.ts +0 -1236
@@ -1,10 +1,10 @@
1
- import { FfiClient, FfiHandle } from "./ffi_client.js";
2
1
  import {
3
2
  CaptureVideoFrameRequest,
4
3
  NewVideoSourceRequest,
5
4
  VideoRotation,
6
5
  VideoSourceType
7
- } from "./proto/video_frame_pb.js";
6
+ } from "@livekit/rtc-ffi-bindings";
7
+ import { FfiClient, FfiHandle } from "./ffi_client.js";
8
8
  class VideoSource {
9
9
  constructor(width, height) {
10
10
  /** @internal */
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/video_source.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { FfiClient, FfiHandle } from './ffi_client.js';\nimport type {\n CaptureVideoFrameResponse,\n NewVideoSourceResponse,\n VideoSourceInfo,\n} from './proto/video_frame_pb.js';\nimport {\n CaptureVideoFrameRequest,\n NewVideoSourceRequest,\n VideoRotation,\n VideoSourceType,\n} from './proto/video_frame_pb.js';\nimport type { VideoFrame } from './video_frame.js';\n\nexport class VideoSource {\n /** @internal */\n info?: VideoSourceInfo;\n /** @internal */\n ffiHandle: FfiHandle;\n /** @internal */\n closed = false;\n\n width: number;\n height: number;\n\n constructor(width: number, height: number) {\n this.width = width;\n this.height = height;\n\n const req = new NewVideoSourceRequest({\n type: VideoSourceType.VIDEO_SOURCE_NATIVE,\n resolution: {\n width: width,\n height: height,\n },\n });\n\n const res = FfiClient.instance.request<NewVideoSourceResponse>({\n message: {\n case: 'newVideoSource',\n value: req,\n },\n });\n\n this.info = res.source?.info;\n this.ffiHandle = new FfiHandle(res.source!.handle!.id!);\n }\n\n captureFrame(\n frame: VideoFrame,\n timestampUs = BigInt(0),\n rotation = VideoRotation.VIDEO_ROTATION_0,\n ) {\n if (this.closed) {\n throw new Error('VideoSource is closed');\n }\n const req = new CaptureVideoFrameRequest({\n sourceHandle: this.ffiHandle.handle,\n buffer: frame.protoInfo(),\n rotation,\n timestampUs,\n });\n\n FfiClient.instance.request<CaptureVideoFrameResponse>({\n message: { case: 'captureVideoFrame', value: req },\n });\n }\n\n async close() {\n this.ffiHandle.dispose();\n this.closed = true;\n }\n}\n"],"mappings":"AAGA,SAAS,WAAW,iBAAiB;AAMrC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGA,MAAM,YAAY;AAAA,EAWvB,YAAY,OAAe,QAAgB;AAL3C;AAAA,kBAAS;AAvBX;AA6BI,SAAK,QAAQ;AACb,SAAK,SAAS;AAEd,UAAM,MAAM,IAAI,sBAAsB;AAAA,MACpC,MAAM,gBAAgB;AAAA,MACtB,YAAY;AAAA,QACV;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,MAAM,UAAU,SAAS,QAAgC;AAAA,MAC7D,SAAS;AAAA,QACP,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,IACF,CAAC;AAED,SAAK,QAAO,SAAI,WAAJ,mBAAY;AACxB,SAAK,YAAY,IAAI,UAAU,IAAI,OAAQ,OAAQ,EAAG;AAAA,EACxD;AAAA,EAEA,aACE,OACA,cAAc,OAAO,CAAC,GACtB,WAAW,cAAc,kBACzB;AACA,QAAI,KAAK,QAAQ;AACf,YAAM,IAAI,MAAM,uBAAuB;AAAA,IACzC;AACA,UAAM,MAAM,IAAI,yBAAyB;AAAA,MACvC,cAAc,KAAK,UAAU;AAAA,MAC7B,QAAQ,MAAM,UAAU;AAAA,MACxB;AAAA,MACA;AAAA,IACF,CAAC;AAED,cAAU,SAAS,QAAmC;AAAA,MACpD,SAAS,EAAE,MAAM,qBAAqB,OAAO,IAAI;AAAA,IACnD,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,QAAQ;AACZ,SAAK,UAAU,QAAQ;AACvB,SAAK,SAAS;AAAA,EAChB;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/video_source.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type {\n CaptureVideoFrameResponse,\n NewVideoSourceResponse,\n VideoSourceInfo,\n} from '@livekit/rtc-ffi-bindings';\nimport {\n CaptureVideoFrameRequest,\n NewVideoSourceRequest,\n VideoRotation,\n VideoSourceType,\n} from '@livekit/rtc-ffi-bindings';\nimport { FfiClient, FfiHandle } from './ffi_client.js';\nimport type { VideoFrame } from './video_frame.js';\n\nexport class VideoSource {\n /** @internal */\n info?: VideoSourceInfo;\n /** @internal */\n ffiHandle: FfiHandle;\n /** @internal */\n closed = false;\n\n width: number;\n height: number;\n\n constructor(width: number, height: number) {\n this.width = width;\n this.height = height;\n\n const req = new NewVideoSourceRequest({\n type: VideoSourceType.VIDEO_SOURCE_NATIVE,\n resolution: {\n width: width,\n height: height,\n },\n });\n\n const res = FfiClient.instance.request<NewVideoSourceResponse>({\n message: {\n case: 'newVideoSource',\n value: req,\n },\n });\n\n this.info = res.source?.info;\n this.ffiHandle = new FfiHandle(res.source!.handle!.id!);\n }\n\n captureFrame(\n frame: VideoFrame,\n timestampUs = BigInt(0),\n rotation = VideoRotation.VIDEO_ROTATION_0,\n ) {\n if (this.closed) {\n throw new Error('VideoSource is closed');\n }\n const req = new CaptureVideoFrameRequest({\n sourceHandle: this.ffiHandle.handle,\n buffer: frame.protoInfo(),\n rotation,\n timestampUs,\n });\n\n FfiClient.instance.request<CaptureVideoFrameResponse>({\n message: { case: 'captureVideoFrame', value: req },\n });\n }\n\n async close() {\n this.ffiHandle.dispose();\n this.closed = true;\n }\n}\n"],"mappings":"AAQA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,WAAW,iBAAiB;AAG9B,MAAM,YAAY;AAAA,EAWvB,YAAY,OAAe,QAAgB;AAL3C;AAAA,kBAAS;AAvBX;AA6BI,SAAK,QAAQ;AACb,SAAK,SAAS;AAEd,UAAM,MAAM,IAAI,sBAAsB;AAAA,MACpC,MAAM,gBAAgB;AAAA,MACtB,YAAY;AAAA,QACV;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,MAAM,UAAU,SAAS,QAAgC;AAAA,MAC7D,SAAS;AAAA,QACP,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,IACF,CAAC;AAED,SAAK,QAAO,SAAI,WAAJ,mBAAY;AACxB,SAAK,YAAY,IAAI,UAAU,IAAI,OAAQ,OAAQ,EAAG;AAAA,EACxD;AAAA,EAEA,aACE,OACA,cAAc,OAAO,CAAC,GACtB,WAAW,cAAc,kBACzB;AACA,QAAI,KAAK,QAAQ;AACf,YAAM,IAAI,MAAM,uBAAuB;AAAA,IACzC;AACA,UAAM,MAAM,IAAI,yBAAyB;AAAA,MACvC,cAAc,KAAK,UAAU;AAAA,MAC7B,QAAQ,MAAM,UAAU;AAAA,MACxB;AAAA,MACA;AAAA,IACF,CAAC;AAED,cAAU,SAAS,QAAmC;AAAA,MACpD,SAAS,EAAE,MAAM,qBAAqB,OAAO,IAAI;AAAA,IACnD,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,QAAQ;AACZ,SAAK,UAAU,QAAQ;AACvB,SAAK,SAAS;AAAA,EAChB;AACF;","names":[]}
@@ -21,11 +21,12 @@ __export(video_stream_exports, {
21
21
  VideoStream: () => VideoStream
22
22
  });
23
23
  module.exports = __toCommonJS(video_stream_exports);
24
+ var import_rtc_ffi_bindings = require("@livekit/rtc-ffi-bindings");
24
25
  var import_ffi_client = require("./ffi_client.cjs");
25
- var import_video_frame_pb = require("./proto/video_frame_pb.cjs");
26
26
  var import_video_frame = require("./video_frame.cjs");
27
27
  class VideoStreamSource {
28
28
  constructor(track) {
29
+ this.disposed = false;
29
30
  this.onEvent = (ev) => {
30
31
  if (!this.controller) {
31
32
  throw new Error("Stream controller not initialized");
@@ -50,11 +51,15 @@ class VideoStreamSource {
50
51
  case "eos":
51
52
  import_ffi_client.FfiClient.instance.off(import_ffi_client.FfiClientEvent.FfiEvent, this.onEvent);
52
53
  this.controller.close();
54
+ if (!this.disposed) {
55
+ this.disposed = true;
56
+ this.ffiHandle.dispose();
57
+ }
53
58
  break;
54
59
  }
55
60
  };
56
- const req = new import_video_frame_pb.NewVideoStreamRequest({
57
- type: import_video_frame_pb.VideoStreamType.VIDEO_STREAM_NATIVE,
61
+ const req = new import_rtc_ffi_bindings.NewVideoStreamRequest({
62
+ type: import_rtc_ffi_bindings.VideoStreamType.VIDEO_STREAM_NATIVE,
58
63
  trackHandle: track.ffi_handle.handle
59
64
  });
60
65
  const res = import_ffi_client.FfiClient.instance.request({
@@ -71,7 +76,10 @@ class VideoStreamSource {
71
76
  }
72
77
  cancel() {
73
78
  import_ffi_client.FfiClient.instance.off(import_ffi_client.FfiClientEvent.FfiEvent, this.onEvent);
74
- this.ffiHandle.dispose();
79
+ if (!this.disposed) {
80
+ this.disposed = true;
81
+ this.ffiHandle.dispose();
82
+ }
75
83
  }
76
84
  }
77
85
  class VideoStream extends ReadableStream {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/video_stream.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { UnderlyingSource } from 'node:stream/web';\nimport type { FfiEvent } from './ffi_client.js';\nimport { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js';\nimport type { NewVideoStreamResponse, VideoRotation } from './proto/video_frame_pb.js';\nimport { NewVideoStreamRequest, VideoStreamType } from './proto/video_frame_pb.js';\nimport type { Track } from './track.js';\nimport { VideoFrame } from './video_frame.js';\n\nexport type VideoFrameEvent = {\n frame: VideoFrame;\n timestampUs: bigint;\n rotation: VideoRotation;\n};\n\nclass VideoStreamSource implements UnderlyingSource<VideoFrameEvent> {\n private controller?: ReadableStreamDefaultController<VideoFrameEvent>;\n private ffiHandle: FfiHandle;\n\n constructor(track: Track) {\n const req = new NewVideoStreamRequest({\n type: VideoStreamType.VIDEO_STREAM_NATIVE,\n trackHandle: track.ffi_handle.handle,\n });\n\n const res = FfiClient.instance.request<NewVideoStreamResponse>({\n message: {\n case: 'newVideoStream',\n value: req,\n },\n });\n\n this.ffiHandle = new FfiHandle(res.stream!.handle!.id!);\n FfiClient.instance.on(FfiClientEvent.FfiEvent, this.onEvent);\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 != 'videoStreamEvent' ||\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 const rotation = streamEvent.value.rotation;\n const timestampUs = streamEvent.value.timestampUs;\n const frame = VideoFrame.fromOwnedInfo(streamEvent.value.buffer!);\n const value = { rotation, timestampUs, frame };\n const videoFrameEvent = {\n frame: value.frame,\n timestampUs: value.timestampUs!,\n rotation: value.rotation!,\n };\n this.controller.enqueue(videoFrameEvent);\n break;\n case 'eos':\n FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);\n this.controller.close();\n break;\n }\n };\n\n start(controller: ReadableStreamDefaultController<VideoFrameEvent>) {\n this.controller = controller;\n }\n\n cancel() {\n FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);\n this.ffiHandle.dispose();\n }\n}\n\nexport class VideoStream extends ReadableStream<VideoFrameEvent> {\n constructor(track: Track) {\n super(new VideoStreamSource(track));\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,wBAAqD;AAErD,4BAAuD;AAEvD,yBAA2B;AAQ3B,MAAM,kBAA+D;AAAA,EAInE,YAAY,OAAc;AAiB1B,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,gBAAM,WAAW,YAAY,MAAM;AACnC,gBAAM,cAAc,YAAY,MAAM;AACtC,gBAAM,QAAQ,8BAAW,cAAc,YAAY,MAAM,MAAO;AAChE,gBAAM,QAAQ,EAAE,UAAU,aAAa,MAAM;AAC7C,gBAAM,kBAAkB;AAAA,YACtB,OAAO,MAAM;AAAA,YACb,aAAa,MAAM;AAAA,YACnB,UAAU,MAAM;AAAA,UAClB;AACA,eAAK,WAAW,QAAQ,eAAe;AACvC;AAAA,QACF,KAAK;AACH,sCAAU,SAAS,IAAI,iCAAe,UAAU,KAAK,OAAO;AAC5D,eAAK,WAAW,MAAM;AACtB;AAAA,MACJ;AAAA,IACF;AA/CE,UAAM,MAAM,IAAI,4CAAsB;AAAA,MACpC,MAAM,sCAAgB;AAAA,MACtB,aAAa,MAAM,WAAW;AAAA,IAChC,CAAC;AAED,UAAM,MAAM,4BAAU,SAAS,QAAgC;AAAA,MAC7D,SAAS;AAAA,QACP,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,IACF,CAAC;AAED,SAAK,YAAY,IAAI,4BAAU,IAAI,OAAQ,OAAQ,EAAG;AACtD,gCAAU,SAAS,GAAG,iCAAe,UAAU,KAAK,OAAO;AAAA,EAC7D;AAAA,EAmCA,MAAM,YAA8D;AAClE,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,SAAS;AACP,gCAAU,SAAS,IAAI,iCAAe,UAAU,KAAK,OAAO;AAC5D,SAAK,UAAU,QAAQ;AAAA,EACzB;AACF;AAEO,MAAM,oBAAoB,eAAgC;AAAA,EAC/D,YAAY,OAAc;AACxB,UAAM,IAAI,kBAAkB,KAAK,CAAC;AAAA,EACpC;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/video_stream.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { NewVideoStreamResponse, VideoRotation } from '@livekit/rtc-ffi-bindings';\nimport { NewVideoStreamRequest, VideoStreamType } from '@livekit/rtc-ffi-bindings';\nimport type { UnderlyingSource } from 'node:stream/web';\nimport type { FfiEvent } from './ffi_client.js';\nimport { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js';\nimport type { Track } from './track.js';\nimport { VideoFrame } from './video_frame.js';\n\nexport type VideoFrameEvent = {\n frame: VideoFrame;\n timestampUs: bigint;\n rotation: VideoRotation;\n};\n\nclass VideoStreamSource implements UnderlyingSource<VideoFrameEvent> {\n private controller?: ReadableStreamDefaultController<VideoFrameEvent>;\n private ffiHandle: FfiHandle;\n private disposed = false;\n\n constructor(track: Track) {\n const req = new NewVideoStreamRequest({\n type: VideoStreamType.VIDEO_STREAM_NATIVE,\n trackHandle: track.ffi_handle.handle,\n });\n\n const res = FfiClient.instance.request<NewVideoStreamResponse>({\n message: {\n case: 'newVideoStream',\n value: req,\n },\n });\n\n this.ffiHandle = new FfiHandle(res.stream!.handle!.id!);\n FfiClient.instance.on(FfiClientEvent.FfiEvent, this.onEvent);\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 != 'videoStreamEvent' ||\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 const rotation = streamEvent.value.rotation;\n const timestampUs = streamEvent.value.timestampUs;\n const frame = VideoFrame.fromOwnedInfo(streamEvent.value.buffer!);\n const value = { rotation, timestampUs, frame };\n const videoFrameEvent = {\n frame: value.frame,\n timestampUs: value.timestampUs!,\n rotation: value.rotation!,\n };\n this.controller.enqueue(videoFrameEvent);\n break;\n case 'eos':\n FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);\n this.controller.close();\n // Dispose the native handle so the FD is released on stream end,\n // not just when cancel() is called explicitly by the consumer.\n // Guard against double-dispose if cancel() is called after EOS\n // while buffered frames are still in the ReadableStream queue.\n if (!this.disposed) {\n this.disposed = true;\n this.ffiHandle.dispose();\n }\n break;\n }\n };\n\n start(controller: ReadableStreamDefaultController<VideoFrameEvent>) {\n this.controller = controller;\n }\n\n cancel() {\n FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);\n if (!this.disposed) {\n this.disposed = true;\n this.ffiHandle.dispose();\n }\n }\n}\n\nexport class VideoStream extends ReadableStream<VideoFrameEvent> {\n constructor(track: Track) {\n super(new VideoStreamSource(track));\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,8BAAuD;AAGvD,wBAAqD;AAErD,yBAA2B;AAQ3B,MAAM,kBAA+D;AAAA,EAKnE,YAAY,OAAc;AAF1B,SAAQ,WAAW;AAmBnB,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,gBAAM,WAAW,YAAY,MAAM;AACnC,gBAAM,cAAc,YAAY,MAAM;AACtC,gBAAM,QAAQ,8BAAW,cAAc,YAAY,MAAM,MAAO;AAChE,gBAAM,QAAQ,EAAE,UAAU,aAAa,MAAM;AAC7C,gBAAM,kBAAkB;AAAA,YACtB,OAAO,MAAM;AAAA,YACb,aAAa,MAAM;AAAA,YACnB,UAAU,MAAM;AAAA,UAClB;AACA,eAAK,WAAW,QAAQ,eAAe;AACvC;AAAA,QACF,KAAK;AACH,sCAAU,SAAS,IAAI,iCAAe,UAAU,KAAK,OAAO;AAC5D,eAAK,WAAW,MAAM;AAKtB,cAAI,CAAC,KAAK,UAAU;AAClB,iBAAK,WAAW;AAChB,iBAAK,UAAU,QAAQ;AAAA,UACzB;AACA;AAAA,MACJ;AAAA,IACF;AAvDE,UAAM,MAAM,IAAI,8CAAsB;AAAA,MACpC,MAAM,wCAAgB;AAAA,MACtB,aAAa,MAAM,WAAW;AAAA,IAChC,CAAC;AAED,UAAM,MAAM,4BAAU,SAAS,QAAgC;AAAA,MAC7D,SAAS;AAAA,QACP,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,IACF,CAAC;AAED,SAAK,YAAY,IAAI,4BAAU,IAAI,OAAQ,OAAQ,EAAG;AACtD,gCAAU,SAAS,GAAG,iCAAe,UAAU,KAAK,OAAO;AAAA,EAC7D;AAAA,EA2CA,MAAM,YAA8D;AAClE,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,SAAS;AACP,gCAAU,SAAS,IAAI,iCAAe,UAAU,KAAK,OAAO;AAC5D,QAAI,CAAC,KAAK,UAAU;AAClB,WAAK,WAAW;AAChB,WAAK,UAAU,QAAQ;AAAA,IACzB;AAAA,EACF;AACF;AAEO,MAAM,oBAAoB,eAAgC;AAAA,EAC/D,YAAY,OAAc;AACxB,UAAM,IAAI,kBAAkB,KAAK,CAAC;AAAA,EACpC;AACF;","names":[]}
@@ -1,23 +1,10 @@
1
- import { VideoRotation } from './proto/video_frame_pb.cjs';
1
+ import { VideoRotation } from '@livekit/rtc-ffi-bindings';
2
2
  import { Track } from './track.cjs';
3
3
  import { VideoFrame } from './video_frame.cjs';
4
- import '@bufbuild/protobuf';
5
- import './proto/track_pb.cjs';
6
- import './proto/stats_pb.cjs';
7
- import './proto/e2ee_pb.cjs';
8
- import './proto/handle_pb.cjs';
9
4
  import './audio_source.cjs';
10
5
  import './audio_frame.cjs';
11
- import './proto/audio_frame_pb.cjs';
12
- import './napi/native.d.cjs';
13
6
  import './ffi_client.cjs';
14
7
  import '@livekit/typed-emitter';
15
- import './proto/ffi_pb.cjs';
16
- import './proto/room_pb.cjs';
17
- import './proto/participant_pb.cjs';
18
- import './proto/data_stream_pb.cjs';
19
- import './proto/rpc_pb.cjs';
20
- import './proto/track_publication_pb.cjs';
21
8
  import './video_source.cjs';
22
9
 
23
10
  type VideoFrameEvent = {
@@ -1,23 +1,10 @@
1
- import { VideoRotation } from './proto/video_frame_pb.js';
1
+ import { VideoRotation } from '@livekit/rtc-ffi-bindings';
2
2
  import { Track } from './track.js';
3
3
  import { VideoFrame } from './video_frame.js';
4
- import '@bufbuild/protobuf';
5
- import './proto/track_pb.js';
6
- import './proto/stats_pb.js';
7
- import './proto/e2ee_pb.js';
8
- import './proto/handle_pb.js';
9
4
  import './audio_source.js';
10
5
  import './audio_frame.js';
11
- import './proto/audio_frame_pb.js';
12
- import './napi/native.d.js';
13
6
  import './ffi_client.js';
14
7
  import '@livekit/typed-emitter';
15
- import './proto/ffi_pb.js';
16
- import './proto/room_pb.js';
17
- import './proto/participant_pb.js';
18
- import './proto/data_stream_pb.js';
19
- import './proto/rpc_pb.js';
20
- import './proto/track_publication_pb.js';
21
8
  import './video_source.js';
22
9
 
23
10
  type VideoFrameEvent = {
@@ -1 +1 @@
1
- {"version":3,"file":"video_stream.d.ts","sourceRoot":"","sources":["../src/video_stream.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAA0B,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAEvF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,aAAa,CAAC;CACzB,CAAC;AAkEF,qBAAa,WAAY,SAAQ,cAAc,CAAC,eAAe,CAAC;gBAClD,KAAK,EAAE,KAAK;CAGzB"}
1
+ {"version":3,"file":"video_stream.d.ts","sourceRoot":"","sources":["../src/video_stream.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAA0B,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAKvF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,aAAa,CAAC;CACzB,CAAC;AA8EF,qBAAa,WAAY,SAAQ,cAAc,CAAC,eAAe,CAAC;gBAClD,KAAK,EAAE,KAAK;CAGzB"}
@@ -1,8 +1,9 @@
1
+ import { NewVideoStreamRequest, VideoStreamType } from "@livekit/rtc-ffi-bindings";
1
2
  import { FfiClient, FfiClientEvent, FfiHandle } from "./ffi_client.js";
2
- import { NewVideoStreamRequest, VideoStreamType } from "./proto/video_frame_pb.js";
3
3
  import { VideoFrame } from "./video_frame.js";
4
4
  class VideoStreamSource {
5
5
  constructor(track) {
6
+ this.disposed = false;
6
7
  this.onEvent = (ev) => {
7
8
  if (!this.controller) {
8
9
  throw new Error("Stream controller not initialized");
@@ -27,6 +28,10 @@ class VideoStreamSource {
27
28
  case "eos":
28
29
  FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);
29
30
  this.controller.close();
31
+ if (!this.disposed) {
32
+ this.disposed = true;
33
+ this.ffiHandle.dispose();
34
+ }
30
35
  break;
31
36
  }
32
37
  };
@@ -48,7 +53,10 @@ class VideoStreamSource {
48
53
  }
49
54
  cancel() {
50
55
  FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);
51
- this.ffiHandle.dispose();
56
+ if (!this.disposed) {
57
+ this.disposed = true;
58
+ this.ffiHandle.dispose();
59
+ }
52
60
  }
53
61
  }
54
62
  class VideoStream extends ReadableStream {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/video_stream.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { UnderlyingSource } from 'node:stream/web';\nimport type { FfiEvent } from './ffi_client.js';\nimport { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js';\nimport type { NewVideoStreamResponse, VideoRotation } from './proto/video_frame_pb.js';\nimport { NewVideoStreamRequest, VideoStreamType } from './proto/video_frame_pb.js';\nimport type { Track } from './track.js';\nimport { VideoFrame } from './video_frame.js';\n\nexport type VideoFrameEvent = {\n frame: VideoFrame;\n timestampUs: bigint;\n rotation: VideoRotation;\n};\n\nclass VideoStreamSource implements UnderlyingSource<VideoFrameEvent> {\n private controller?: ReadableStreamDefaultController<VideoFrameEvent>;\n private ffiHandle: FfiHandle;\n\n constructor(track: Track) {\n const req = new NewVideoStreamRequest({\n type: VideoStreamType.VIDEO_STREAM_NATIVE,\n trackHandle: track.ffi_handle.handle,\n });\n\n const res = FfiClient.instance.request<NewVideoStreamResponse>({\n message: {\n case: 'newVideoStream',\n value: req,\n },\n });\n\n this.ffiHandle = new FfiHandle(res.stream!.handle!.id!);\n FfiClient.instance.on(FfiClientEvent.FfiEvent, this.onEvent);\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 != 'videoStreamEvent' ||\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 const rotation = streamEvent.value.rotation;\n const timestampUs = streamEvent.value.timestampUs;\n const frame = VideoFrame.fromOwnedInfo(streamEvent.value.buffer!);\n const value = { rotation, timestampUs, frame };\n const videoFrameEvent = {\n frame: value.frame,\n timestampUs: value.timestampUs!,\n rotation: value.rotation!,\n };\n this.controller.enqueue(videoFrameEvent);\n break;\n case 'eos':\n FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);\n this.controller.close();\n break;\n }\n };\n\n start(controller: ReadableStreamDefaultController<VideoFrameEvent>) {\n this.controller = controller;\n }\n\n cancel() {\n FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);\n this.ffiHandle.dispose();\n }\n}\n\nexport class VideoStream extends ReadableStream<VideoFrameEvent> {\n constructor(track: Track) {\n super(new VideoStreamSource(track));\n }\n}\n"],"mappings":"AAKA,SAAS,WAAW,gBAAgB,iBAAiB;AAErD,SAAS,uBAAuB,uBAAuB;AAEvD,SAAS,kBAAkB;AAQ3B,MAAM,kBAA+D;AAAA,EAInE,YAAY,OAAc;AAiB1B,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,gBAAM,WAAW,YAAY,MAAM;AACnC,gBAAM,cAAc,YAAY,MAAM;AACtC,gBAAM,QAAQ,WAAW,cAAc,YAAY,MAAM,MAAO;AAChE,gBAAM,QAAQ,EAAE,UAAU,aAAa,MAAM;AAC7C,gBAAM,kBAAkB;AAAA,YACtB,OAAO,MAAM;AAAA,YACb,aAAa,MAAM;AAAA,YACnB,UAAU,MAAM;AAAA,UAClB;AACA,eAAK,WAAW,QAAQ,eAAe;AACvC;AAAA,QACF,KAAK;AACH,oBAAU,SAAS,IAAI,eAAe,UAAU,KAAK,OAAO;AAC5D,eAAK,WAAW,MAAM;AACtB;AAAA,MACJ;AAAA,IACF;AA/CE,UAAM,MAAM,IAAI,sBAAsB;AAAA,MACpC,MAAM,gBAAgB;AAAA,MACtB,aAAa,MAAM,WAAW;AAAA,IAChC,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;AACtD,cAAU,SAAS,GAAG,eAAe,UAAU,KAAK,OAAO;AAAA,EAC7D;AAAA,EAmCA,MAAM,YAA8D;AAClE,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,SAAS;AACP,cAAU,SAAS,IAAI,eAAe,UAAU,KAAK,OAAO;AAC5D,SAAK,UAAU,QAAQ;AAAA,EACzB;AACF;AAEO,MAAM,oBAAoB,eAAgC;AAAA,EAC/D,YAAY,OAAc;AACxB,UAAM,IAAI,kBAAkB,KAAK,CAAC;AAAA,EACpC;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/video_stream.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { NewVideoStreamResponse, VideoRotation } from '@livekit/rtc-ffi-bindings';\nimport { NewVideoStreamRequest, VideoStreamType } from '@livekit/rtc-ffi-bindings';\nimport type { UnderlyingSource } from 'node:stream/web';\nimport type { FfiEvent } from './ffi_client.js';\nimport { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js';\nimport type { Track } from './track.js';\nimport { VideoFrame } from './video_frame.js';\n\nexport type VideoFrameEvent = {\n frame: VideoFrame;\n timestampUs: bigint;\n rotation: VideoRotation;\n};\n\nclass VideoStreamSource implements UnderlyingSource<VideoFrameEvent> {\n private controller?: ReadableStreamDefaultController<VideoFrameEvent>;\n private ffiHandle: FfiHandle;\n private disposed = false;\n\n constructor(track: Track) {\n const req = new NewVideoStreamRequest({\n type: VideoStreamType.VIDEO_STREAM_NATIVE,\n trackHandle: track.ffi_handle.handle,\n });\n\n const res = FfiClient.instance.request<NewVideoStreamResponse>({\n message: {\n case: 'newVideoStream',\n value: req,\n },\n });\n\n this.ffiHandle = new FfiHandle(res.stream!.handle!.id!);\n FfiClient.instance.on(FfiClientEvent.FfiEvent, this.onEvent);\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 != 'videoStreamEvent' ||\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 const rotation = streamEvent.value.rotation;\n const timestampUs = streamEvent.value.timestampUs;\n const frame = VideoFrame.fromOwnedInfo(streamEvent.value.buffer!);\n const value = { rotation, timestampUs, frame };\n const videoFrameEvent = {\n frame: value.frame,\n timestampUs: value.timestampUs!,\n rotation: value.rotation!,\n };\n this.controller.enqueue(videoFrameEvent);\n break;\n case 'eos':\n FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);\n this.controller.close();\n // Dispose the native handle so the FD is released on stream end,\n // not just when cancel() is called explicitly by the consumer.\n // Guard against double-dispose if cancel() is called after EOS\n // while buffered frames are still in the ReadableStream queue.\n if (!this.disposed) {\n this.disposed = true;\n this.ffiHandle.dispose();\n }\n break;\n }\n };\n\n start(controller: ReadableStreamDefaultController<VideoFrameEvent>) {\n this.controller = controller;\n }\n\n cancel() {\n FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);\n if (!this.disposed) {\n this.disposed = true;\n this.ffiHandle.dispose();\n }\n }\n}\n\nexport class VideoStream extends ReadableStream<VideoFrameEvent> {\n constructor(track: Track) {\n super(new VideoStreamSource(track));\n }\n}\n"],"mappings":"AAIA,SAAS,uBAAuB,uBAAuB;AAGvD,SAAS,WAAW,gBAAgB,iBAAiB;AAErD,SAAS,kBAAkB;AAQ3B,MAAM,kBAA+D;AAAA,EAKnE,YAAY,OAAc;AAF1B,SAAQ,WAAW;AAmBnB,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,gBAAM,WAAW,YAAY,MAAM;AACnC,gBAAM,cAAc,YAAY,MAAM;AACtC,gBAAM,QAAQ,WAAW,cAAc,YAAY,MAAM,MAAO;AAChE,gBAAM,QAAQ,EAAE,UAAU,aAAa,MAAM;AAC7C,gBAAM,kBAAkB;AAAA,YACtB,OAAO,MAAM;AAAA,YACb,aAAa,MAAM;AAAA,YACnB,UAAU,MAAM;AAAA,UAClB;AACA,eAAK,WAAW,QAAQ,eAAe;AACvC;AAAA,QACF,KAAK;AACH,oBAAU,SAAS,IAAI,eAAe,UAAU,KAAK,OAAO;AAC5D,eAAK,WAAW,MAAM;AAKtB,cAAI,CAAC,KAAK,UAAU;AAClB,iBAAK,WAAW;AAChB,iBAAK,UAAU,QAAQ;AAAA,UACzB;AACA;AAAA,MACJ;AAAA,IACF;AAvDE,UAAM,MAAM,IAAI,sBAAsB;AAAA,MACpC,MAAM,gBAAgB;AAAA,MACtB,aAAa,MAAM,WAAW;AAAA,IAChC,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;AACtD,cAAU,SAAS,GAAG,eAAe,UAAU,KAAK,OAAO;AAAA,EAC7D;AAAA,EA2CA,MAAM,YAA8D;AAClE,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,SAAS;AACP,cAAU,SAAS,IAAI,eAAe,UAAU,KAAK,OAAO;AAC5D,QAAI,CAAC,KAAK,UAAU;AAClB,WAAK,WAAW;AAChB,WAAK,UAAU,QAAQ;AAAA,IACzB;AAAA,EACF;AACF;AAEO,MAAM,oBAAoB,eAAgC;AAAA,EAC/D,YAAY,OAAc;AACxB,UAAM,IAAI,kBAAkB,KAAK,CAAC;AAAA,EACpC;AACF;","names":[]}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "LiveKit RTC Node",
4
4
  "license": "Apache-2.0",
5
5
  "author": "LiveKit",
6
- "version": "0.13.24",
6
+ "version": "0.13.25",
7
7
  "main": "dist/index.js",
8
8
  "require": "dist/index.cjs",
9
9
  "types": "dist/index.d.ts",
@@ -27,62 +27,32 @@
27
27
  },
28
28
  "files": [
29
29
  "dist",
30
- "src",
31
- "build.rs",
32
- "Cargo.toml",
33
- "Cargo.lock"
30
+ "src"
34
31
  ],
35
- "napi": {
36
- "name": "rtc-node",
37
- "triples": {
38
- "defaults": false,
39
- "additional": [
40
- "aarch64-apple-darwin",
41
- "x86_64-apple-darwin",
42
- "aarch64-unknown-linux-gnu",
43
- "x86_64-unknown-linux-gnu",
44
- "x86_64-pc-windows-msvc"
45
- ]
46
- }
47
- },
48
32
  "dependencies": {
49
- "@bufbuild/protobuf": "^1.10.1",
50
33
  "@datastructures-js/deque": "1.0.8",
51
34
  "@livekit/mutex": "^1.0.0",
52
35
  "@livekit/typed-emitter": "^3.0.0",
36
+ "@livekit/rtc-ffi-bindings": "0.12.52-patch.0",
53
37
  "pino": "^9.0.0",
54
38
  "pino-pretty": "^13.0.0"
55
39
  },
56
40
  "devDependencies": {
57
- "@bufbuild/protoc-gen-es": "^1.10.1",
58
- "@napi-rs/cli": "^2.18.0",
41
+ "@bufbuild/protobuf": "^1.10.1",
59
42
  "@types/node": "^22.13.10",
60
43
  "vitest": "^3.0.0",
61
44
  "prettier": "^3.0.3",
62
45
  "tsup": "^8.3.5",
63
46
  "typescript": "5.8.2",
64
- "livekit-server-sdk": "2.15.0"
65
- },
66
- "optionalDependencies": {
67
- "@livekit/rtc-node-darwin-x64": "0.13.24",
68
- "@livekit/rtc-node-darwin-arm64": "0.13.24",
69
- "@livekit/rtc-node-linux-x64-gnu": "0.13.24",
70
- "@livekit/rtc-node-linux-arm64-gnu": "0.13.24",
71
- "@livekit/rtc-node-win32-x64-msvc": "0.13.24"
47
+ "livekit-server-sdk": "2.15.1"
72
48
  },
73
49
  "engines": {
74
50
  "node": ">= 18"
75
51
  },
76
52
  "scripts": {
77
53
  "prebuild": "node -p \"'export const SDK_VERSION = ' + JSON.stringify(require('./package.json').version) + ';'\" > src/version.ts",
78
- "build:ts": "pnpm prebuild && tsup --onSuccess \"tsc --declaration --emitDeclarationOnly\" && cp -r src/napi dist/ && cp -r src/napi/* dist/",
79
- "build": "pnpm build:ts && napi build --platform --release --dts native.d.ts --js native.cjs --pipe \"prettier -w\" src/napi",
80
- "artifacts": "pnpm build:ts && napi artifacts",
81
- "build:debug": "napi build --platform",
54
+ "build": "pnpm prebuild && tsup --onSuccess \"tsc --declaration --emitDeclarationOnly\"",
82
55
  "lint": "eslint -f unix \"src/**/*.ts\" --ignore-pattern \"src/proto/*\"",
83
- "test": "vitest run",
84
- "test:e2e": "vitest run src/tests/e2e.test.ts",
85
- "universal": "napi universal",
86
- "version": "napi version"
56
+ "test": "vitest run src"
87
57
  }
88
58
  }
@@ -1,9 +1,9 @@
1
1
  // SPDX-FileCopyrightText: 2024 LiveKit, Inc.
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
+ import type { LoadAudioFilterPluginResponse } from '@livekit/rtc-ffi-bindings';
5
+ import { LoadAudioFilterPluginRequest } from '@livekit/rtc-ffi-bindings';
4
6
  import { FfiClient } from './ffi_client.js';
5
- import type { LoadAudioFilterPluginResponse } from './proto/audio_frame_pb.js';
6
- import { LoadAudioFilterPluginRequest } from './proto/audio_frame_pb.js';
7
7
 
8
8
  export class AudioFilter {
9
9
  constructor(moduleId: string, path: string, dependencies: string[] = []) {
@@ -1,9 +1,9 @@
1
1
  // SPDX-FileCopyrightText: 2024 LiveKit, Inc.
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
+ import type { OwnedAudioFrameBuffer } from '@livekit/rtc-ffi-bindings';
5
+ import { AudioFrameBufferInfo } from '@livekit/rtc-ffi-bindings';
4
6
  import { FfiClient, FfiHandle } from './ffi_client.js';
5
- import type { OwnedAudioFrameBuffer } from './proto/audio_frame_pb.js';
6
- import { AudioFrameBufferInfo } from './proto/audio_frame_pb.js';
7
7
 
8
8
  export class AudioFrame {
9
9
  data: Int16Array;
@@ -32,9 +32,14 @@ export class AudioFrame {
32
32
  this._userdata = userdata;
33
33
  }
34
34
 
35
- static create(sampleRate: number, channels: number, samplesPerChannel: number): AudioFrame {
35
+ static create(
36
+ sampleRate: number,
37
+ channels: number,
38
+ samplesPerChannel: number,
39
+ userdata?: Record<string, unknown>,
40
+ ): AudioFrame {
36
41
  const data = new Int16Array(channels * samplesPerChannel);
37
- return new AudioFrame(data, sampleRate, channels, samplesPerChannel);
42
+ return new AudioFrame(data, sampleRate, channels, samplesPerChannel, userdata);
38
43
  }
39
44
 
40
45
  /** @internal */
@@ -103,5 +108,12 @@ export const combineAudioFrames = (buffer: AudioFrame | AudioFrame[]): AudioFram
103
108
  }
104
109
 
105
110
  const data = new Int16Array(buffer.map((x) => [...x.data]).flat());
106
- return new AudioFrame(data, sampleRate, channels, totalSamplesPerChannel);
111
+
112
+ // Merge userdata from all frames
113
+ const mergedUserdata: Record<string, unknown> = {};
114
+ for (const frame of buffer) {
115
+ Object.assign(mergedUserdata, frame.userdata);
116
+ }
117
+
118
+ return new AudioFrame(data, sampleRate, channels, totalSamplesPerChannel, mergedUserdata);
107
119
  };
@@ -239,7 +239,7 @@ export class AudioMixer {
239
239
 
240
240
  for (const result of results) {
241
241
  if (result.status !== 'fulfilled') {
242
- log.warn('AudioMixer: Stream contribution failed:', result.reason);
242
+ log.warn({ reason: result.reason }, 'AudioMixer: Stream contribution failed');
243
243
  continue;
244
244
  }
245
245
 
@@ -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,7 +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();
109
- this.frameProcessor?.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
+ }
110
119
  break;
111
120
  }
112
121
  };
@@ -117,7 +126,13 @@ class AudioStreamSource implements UnderlyingSource<AudioFrame> {
117
126
 
118
127
  cancel() {
119
128
  FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);
120
- 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
+ }
121
136
  }
122
137
  }
123
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;