@livekit/rtc-node 0.13.24 → 0.13.26

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 (283) 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 +10 -4
  13. package/dist/audio_mixer.cjs.map +1 -1
  14. package/dist/audio_mixer.d.cts +4 -7
  15. package/dist/audio_mixer.d.ts +4 -7
  16. package/dist/audio_mixer.d.ts.map +1 -1
  17. package/dist/audio_mixer.js +10 -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 +16 -6
  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 +15 -5
  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 +30 -15
  63. package/dist/ffi_client.cjs.map +1 -1
  64. package/dist/ffi_client.d.cts +6 -17
  65. package/dist/ffi_client.d.ts +6 -17
  66. package/dist/ffi_client.d.ts.map +1 -1
  67. package/dist/ffi_client.js +24 -6
  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/participant.cjs +146 -101
  84. package/dist/participant.cjs.map +1 -1
  85. package/dist/participant.d.cts +4 -16
  86. package/dist/participant.d.ts +4 -16
  87. package/dist/participant.d.ts.map +1 -1
  88. package/dist/participant.js +120 -75
  89. package/dist/participant.js.map +1 -1
  90. package/dist/room.cjs +116 -58
  91. package/dist/room.cjs.map +1 -1
  92. package/dist/room.d.cts +6 -15
  93. package/dist/room.d.ts +6 -15
  94. package/dist/room.d.ts.map +1 -1
  95. package/dist/room.js +113 -55
  96. package/dist/room.js.map +1 -1
  97. package/dist/rpc.cjs.map +1 -1
  98. package/dist/rpc.d.cts +1 -2
  99. package/dist/rpc.d.ts +1 -2
  100. package/dist/rpc.d.ts.map +1 -1
  101. package/dist/rpc.js.map +1 -1
  102. package/dist/{stream_reader-Ch2zvjU3.d.cts → stream_reader-CuG4b8Y-.d.cts} +1 -1
  103. package/dist/{stream_reader-DRyR29vo.d.ts → stream_reader-CuG4b8Y-.d.ts} +1 -1
  104. package/dist/track.cjs +3 -3
  105. package/dist/track.cjs.map +1 -1
  106. package/dist/track.d.cts +1 -14
  107. package/dist/track.d.ts +1 -14
  108. package/dist/track.d.ts.map +1 -1
  109. package/dist/track.js +1 -1
  110. package/dist/track.js.map +1 -1
  111. package/dist/track_publication.cjs +4 -4
  112. package/dist/track_publication.cjs.map +1 -1
  113. package/dist/track_publication.d.cts +1 -14
  114. package/dist/track_publication.d.ts +1 -14
  115. package/dist/track_publication.d.ts.map +1 -1
  116. package/dist/track_publication.js +2 -2
  117. package/dist/track_publication.js.map +1 -1
  118. package/dist/version.cjs +1 -1
  119. package/dist/version.cjs.map +1 -1
  120. package/dist/version.d.cts +1 -1
  121. package/dist/version.d.ts +1 -1
  122. package/dist/version.js +1 -1
  123. package/dist/version.js.map +1 -1
  124. package/dist/video_frame.cjs +42 -42
  125. package/dist/video_frame.cjs.map +1 -1
  126. package/dist/video_frame.d.cts +1 -6
  127. package/dist/video_frame.d.ts +1 -6
  128. package/dist/video_frame.d.ts.map +1 -1
  129. package/dist/video_frame.js +2 -2
  130. package/dist/video_frame.js.map +1 -1
  131. package/dist/video_source.cjs +5 -5
  132. package/dist/video_source.cjs.map +1 -1
  133. package/dist/video_source.d.cts +1 -14
  134. package/dist/video_source.d.ts +1 -14
  135. package/dist/video_source.d.ts.map +1 -1
  136. package/dist/video_source.js +2 -2
  137. package/dist/video_source.js.map +1 -1
  138. package/dist/video_stream.cjs +12 -4
  139. package/dist/video_stream.cjs.map +1 -1
  140. package/dist/video_stream.d.cts +1 -14
  141. package/dist/video_stream.d.ts +1 -14
  142. package/dist/video_stream.d.ts.map +1 -1
  143. package/dist/video_stream.js +10 -2
  144. package/dist/video_stream.js.map +1 -1
  145. package/package.json +7 -37
  146. package/src/audio_filter.ts +2 -2
  147. package/src/audio_frame.ts +17 -5
  148. package/src/audio_mixer.test.ts +102 -0
  149. package/src/audio_mixer.ts +10 -4
  150. package/src/audio_resampler.ts +14 -4
  151. package/src/audio_source.ts +13 -5
  152. package/src/audio_stream.ts +21 -6
  153. package/src/data_streams/stream_reader.ts +19 -1
  154. package/src/data_streams/types.ts +1 -1
  155. package/src/e2ee.ts +3 -3
  156. package/src/ffi_client.ts +33 -8
  157. package/src/frame_processor.ts +21 -0
  158. package/src/index.ts +6 -5
  159. package/src/participant.ts +117 -66
  160. package/src/room.ts +161 -69
  161. package/src/rpc.ts +1 -1
  162. package/src/tests/e2e.test.ts +179 -8
  163. package/src/track.ts +4 -4
  164. package/src/track_publication.ts +6 -6
  165. package/src/version.ts +1 -1
  166. package/src/video_frame.ts +3 -3
  167. package/src/video_source.ts +3 -3
  168. package/src/video_stream.ts +15 -3
  169. package/Cargo.toml +0 -25
  170. package/build.rs +0 -9
  171. package/dist/napi/native.cjs +0 -301
  172. package/dist/napi/native.d.cjs +0 -17
  173. package/dist/napi/native.d.cjs.map +0 -1
  174. package/dist/napi/native.d.d.cts +0 -21
  175. package/dist/napi/native.d.d.ts +0 -21
  176. package/dist/napi/native.d.js +0 -1
  177. package/dist/napi/native.d.js.map +0 -1
  178. package/dist/napi/native.d.ts +0 -19
  179. package/dist/napi/native.js +0 -15
  180. package/dist/native.cjs +0 -301
  181. package/dist/native.d.ts +0 -19
  182. package/dist/native.js +0 -15
  183. package/dist/proto/audio_frame_pb.cjs +0 -1357
  184. package/dist/proto/audio_frame_pb.cjs.map +0 -1
  185. package/dist/proto/audio_frame_pb.d.cts +0 -1183
  186. package/dist/proto/audio_frame_pb.d.ts +0 -1183
  187. package/dist/proto/audio_frame_pb.d.ts.map +0 -1
  188. package/dist/proto/audio_frame_pb.js +0 -1283
  189. package/dist/proto/audio_frame_pb.js.map +0 -1
  190. package/dist/proto/data_stream_pb.cjs +0 -1638
  191. package/dist/proto/data_stream_pb.cjs.map +0 -1
  192. package/dist/proto/data_stream_pb.d.cts +0 -1449
  193. package/dist/proto/data_stream_pb.d.ts +0 -1449
  194. package/dist/proto/data_stream_pb.d.ts.map +0 -1
  195. package/dist/proto/data_stream_pb.js +0 -1559
  196. package/dist/proto/data_stream_pb.js.map +0 -1
  197. package/dist/proto/e2ee_pb.cjs +0 -746
  198. package/dist/proto/e2ee_pb.cjs.map +0 -1
  199. package/dist/proto/e2ee_pb.d.cts +0 -653
  200. package/dist/proto/e2ee_pb.d.ts +0 -653
  201. package/dist/proto/e2ee_pb.d.ts.map +0 -1
  202. package/dist/proto/e2ee_pb.js +0 -696
  203. package/dist/proto/e2ee_pb.js.map +0 -1
  204. package/dist/proto/ffi_pb.cjs +0 -477
  205. package/dist/proto/ffi_pb.cjs.map +0 -1
  206. package/dist/proto/ffi_pb.d.cts +0 -1321
  207. package/dist/proto/ffi_pb.d.ts +0 -1321
  208. package/dist/proto/ffi_pb.d.ts.map +0 -1
  209. package/dist/proto/ffi_pb.js +0 -444
  210. package/dist/proto/ffi_pb.js.map +0 -1
  211. package/dist/proto/handle_pb.cjs +0 -53
  212. package/dist/proto/handle_pb.cjs.map +0 -1
  213. package/dist/proto/handle_pb.d.cts +0 -31
  214. package/dist/proto/handle_pb.d.ts +0 -31
  215. package/dist/proto/handle_pb.d.ts.map +0 -1
  216. package/dist/proto/handle_pb.js +0 -29
  217. package/dist/proto/handle_pb.js.map +0 -1
  218. package/dist/proto/participant_pb.cjs +0 -173
  219. package/dist/proto/participant_pb.cjs.map +0 -1
  220. package/dist/proto/participant_pb.d.cts +0 -218
  221. package/dist/proto/participant_pb.d.ts +0 -218
  222. package/dist/proto/participant_pb.d.ts.map +0 -1
  223. package/dist/proto/participant_pb.js +0 -145
  224. package/dist/proto/participant_pb.js.map +0 -1
  225. package/dist/proto/room_pb.cjs +0 -3374
  226. package/dist/proto/room_pb.cjs.map +0 -1
  227. package/dist/proto/room_pb.d.cts +0 -3028
  228. package/dist/proto/room_pb.d.ts +0 -3028
  229. package/dist/proto/room_pb.d.ts.map +0 -1
  230. package/dist/proto/room_pb.js +0 -3232
  231. package/dist/proto/room_pb.js.map +0 -1
  232. package/dist/proto/rpc_pb.cjs +0 -328
  233. package/dist/proto/rpc_pb.cjs.map +0 -1
  234. package/dist/proto/rpc_pb.d.cts +0 -267
  235. package/dist/proto/rpc_pb.d.ts +0 -267
  236. package/dist/proto/rpc_pb.d.ts.map +0 -1
  237. package/dist/proto/rpc_pb.js +0 -294
  238. package/dist/proto/rpc_pb.js.map +0 -1
  239. package/dist/proto/stats_pb.cjs +0 -1370
  240. package/dist/proto/stats_pb.cjs.map +0 -1
  241. package/dist/proto/stats_pb.d.cts +0 -1764
  242. package/dist/proto/stats_pb.d.ts +0 -1764
  243. package/dist/proto/stats_pb.d.ts.map +0 -1
  244. package/dist/proto/stats_pb.js +0 -1300
  245. package/dist/proto/stats_pb.js.map +0 -1
  246. package/dist/proto/track_pb.cjs +0 -630
  247. package/dist/proto/track_pb.cjs.map +0 -1
  248. package/dist/proto/track_pb.d.cts +0 -542
  249. package/dist/proto/track_pb.d.ts +0 -542
  250. package/dist/proto/track_pb.d.ts.map +0 -1
  251. package/dist/proto/track_pb.js +0 -584
  252. package/dist/proto/track_pb.js.map +0 -1
  253. package/dist/proto/track_publication_pb.cjs +0 -194
  254. package/dist/proto/track_publication_pb.cjs.map +0 -1
  255. package/dist/proto/track_publication_pb.d.cts +0 -135
  256. package/dist/proto/track_publication_pb.d.ts +0 -135
  257. package/dist/proto/track_publication_pb.d.ts.map +0 -1
  258. package/dist/proto/track_publication_pb.js +0 -164
  259. package/dist/proto/track_publication_pb.js.map +0 -1
  260. package/dist/proto/video_frame_pb.cjs +0 -723
  261. package/dist/proto/video_frame_pb.cjs.map +0 -1
  262. package/dist/proto/video_frame_pb.d.cts +0 -667
  263. package/dist/proto/video_frame_pb.d.ts +0 -667
  264. package/dist/proto/video_frame_pb.d.ts.map +0 -1
  265. package/dist/proto/video_frame_pb.js +0 -673
  266. package/dist/proto/video_frame_pb.js.map +0 -1
  267. package/src/lib.rs +0 -9
  268. package/src/napi/native.cjs +0 -301
  269. package/src/napi/native.d.ts +0 -19
  270. package/src/napi/native.js +0 -15
  271. package/src/nodejs.rs +0 -134
  272. package/src/proto/audio_frame_pb.ts +0 -2270
  273. package/src/proto/data_stream_pb.ts +0 -2674
  274. package/src/proto/e2ee_pb.ts +0 -1231
  275. package/src/proto/ffi_pb.ts +0 -1700
  276. package/src/proto/handle_pb.ts +0 -69
  277. package/src/proto/participant_pb.ts +0 -351
  278. package/src/proto/room_pb.ts +0 -5661
  279. package/src/proto/rpc_pb.ts +0 -539
  280. package/src/proto/stats_pb.ts +0 -3050
  281. package/src/proto/track_pb.ts +0 -1040
  282. package/src/proto/track_publication_pb.ts +0 -284
  283. package/src/proto/video_frame_pb.ts +0 -1236
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/video_frame.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { FfiClient, FfiHandle, FfiRequest } from './ffi_client.js';\nimport type { OwnedVideoBuffer, VideoConvertResponse } from './proto/video_frame_pb.js';\nimport {\n VideoBufferInfo,\n VideoBufferInfo_ComponentInfo,\n VideoBufferType,\n} from './proto/video_frame_pb.js';\n\nexport class VideoFrame {\n data: Uint8Array;\n width: number;\n height: number;\n type: VideoBufferType;\n\n constructor(data: Uint8Array, width: number, height: number, type: VideoBufferType) {\n this.data = data;\n this.width = width;\n this.height = height;\n this.type = type;\n }\n\n /** @internal */\n get dataPtr(): bigint {\n return FfiClient.instance.retrievePtr(new Uint8Array(this.data.buffer));\n }\n\n /** @internal */\n protoInfo(): VideoBufferInfo {\n const info = new VideoBufferInfo({\n width: this.width,\n height: this.height,\n type: this.type,\n dataPtr: this.dataPtr,\n });\n\n switch (this.type) {\n case VideoBufferType.ARGB:\n case VideoBufferType.RGBA:\n case VideoBufferType.ABGR:\n case VideoBufferType.BGRA:\n info.stride = this.width * 4;\n break;\n case VideoBufferType.RGB24:\n info.stride = this.width * 3;\n break;\n default:\n info.stride = 0;\n }\n\n info.components.push(...getPlaneInfos(this.dataPtr, this.type, this.width, this.height));\n\n return info;\n }\n\n /** @internal */\n static fromOwnedInfo(owned: OwnedVideoBuffer): VideoFrame {\n const info = owned.info!;\n const frame = new VideoFrame(\n FfiClient.instance.copyBuffer(\n info.dataPtr!,\n getPlaneLength(info.type!, info.width!, info.height!),\n ),\n info.width!,\n info.height!,\n info.type!,\n );\n // Dispose of the handle to prevent memory leaks\n new FfiHandle(owned.handle!.id!).dispose();\n return frame;\n }\n\n getPlane(planeNth: number): Uint8Array | void {\n const planeInfos = getPlaneInfos(this.dataPtr, this.type, this.width, this.height);\n if (planeNth >= planeInfos.length) return;\n\n const planeInfo = planeInfos[planeNth]!;\n return FfiClient.instance.copyBuffer(planeInfo.dataPtr!, planeInfo.size!);\n }\n\n convert(dstType: VideoBufferType, flipY = false): VideoFrame {\n const req = new FfiRequest({\n message: {\n case: 'videoConvert',\n value: {\n flipY,\n dstType,\n buffer: this.protoInfo(),\n },\n },\n });\n const resp = FfiClient.instance.request<VideoConvertResponse>(req);\n\n switch (resp.message.case) {\n case 'buffer':\n return VideoFrame.fromOwnedInfo(resp.message.value);\n case 'error':\n default:\n throw resp.message.value;\n }\n }\n}\n\nconst getPlaneLength = (type: VideoBufferType, width: number, height: number): number => {\n const chromaWidth = Math.trunc((width + 1) / 2);\n const chromaHeight = Math.trunc((height + 1) / 2);\n switch (type) {\n case VideoBufferType.ARGB:\n case VideoBufferType.RGBA:\n case VideoBufferType.ABGR:\n case VideoBufferType.BGRA:\n return width * height * 4;\n case VideoBufferType.RGB24:\n case VideoBufferType.I444:\n return width * height * 3;\n case VideoBufferType.I420:\n return width * height + chromaWidth * chromaHeight * 2;\n case VideoBufferType.I420A:\n return width * height * 2 + chromaWidth * chromaWidth * 2;\n case VideoBufferType.I422:\n return width * height + chromaWidth * height * 2;\n case VideoBufferType.I010:\n return width * height * 2 + chromaWidth * chromaHeight * 4;\n case VideoBufferType.NV12:\n return width * height + chromaWidth * chromaWidth * 2;\n }\n};\n\nconst getPlaneInfos = (\n dataPtr: bigint,\n type: VideoBufferType,\n width: number,\n height: number,\n): VideoBufferInfo_ComponentInfo[] => {\n const chromaWidth = Math.trunc((width + 1) / 2);\n const chromaHeight = Math.trunc((height + 1) / 2);\n switch (type) {\n case VideoBufferType.I420: {\n const y = new VideoBufferInfo_ComponentInfo({ dataPtr, stride: width, size: width * height });\n const u = new VideoBufferInfo_ComponentInfo({\n dataPtr: y.dataPtr! + BigInt(y.size!),\n stride: chromaWidth,\n size: chromaWidth * chromaHeight,\n });\n const v = new VideoBufferInfo_ComponentInfo({\n dataPtr: u.dataPtr! + BigInt(u.size!),\n stride: chromaWidth,\n size: chromaWidth * chromaHeight,\n });\n return [y, u, v];\n }\n case VideoBufferType.I420A: {\n const y = new VideoBufferInfo_ComponentInfo({ dataPtr, stride: width, size: width * height });\n const u = new VideoBufferInfo_ComponentInfo({\n dataPtr: y.dataPtr! + BigInt(y.size!),\n stride: chromaWidth,\n size: chromaWidth * chromaHeight,\n });\n const v = new VideoBufferInfo_ComponentInfo({\n dataPtr: u.dataPtr! + BigInt(u.size!),\n stride: chromaWidth,\n size: chromaWidth * chromaHeight,\n });\n const a = new VideoBufferInfo_ComponentInfo({\n dataPtr: v.dataPtr! + BigInt(v.size!),\n stride: width,\n size: width * height,\n });\n return [y, u, v, a];\n }\n case VideoBufferType.I422: {\n const y = new VideoBufferInfo_ComponentInfo({ dataPtr, stride: width, size: width * height });\n const u = new VideoBufferInfo_ComponentInfo({\n dataPtr: y.dataPtr! + BigInt(y.size!),\n stride: chromaWidth,\n size: chromaWidth * height,\n });\n const v = new VideoBufferInfo_ComponentInfo({\n dataPtr: u.dataPtr! + BigInt(u.size!),\n stride: chromaWidth,\n size: chromaWidth * height,\n });\n return [y, u, v];\n }\n case VideoBufferType.I444: {\n const y = new VideoBufferInfo_ComponentInfo({ dataPtr, stride: width, size: width * height });\n const u = new VideoBufferInfo_ComponentInfo({\n dataPtr: y.dataPtr! + BigInt(y.size!),\n stride: width,\n size: width * height,\n });\n const v = new VideoBufferInfo_ComponentInfo({\n dataPtr: u.dataPtr! + BigInt(u.size!),\n stride: width,\n size: width * height,\n });\n return [y, u, v];\n }\n case VideoBufferType.I010: {\n const y = new VideoBufferInfo_ComponentInfo({\n dataPtr,\n stride: width * 2,\n size: width * height * 2,\n });\n const u = new VideoBufferInfo_ComponentInfo({\n dataPtr: y.dataPtr! + BigInt(y.size!),\n stride: chromaWidth * 2,\n size: chromaWidth * chromaHeight * 2,\n });\n const v = new VideoBufferInfo_ComponentInfo({\n dataPtr: u.dataPtr! + BigInt(u.size!),\n stride: chromaWidth * 2,\n size: chromaWidth * chromaHeight * 2,\n });\n return [y, u, v];\n }\n case VideoBufferType.NV12: {\n const y = new VideoBufferInfo_ComponentInfo({ dataPtr, stride: width, size: width * height });\n const uv = new VideoBufferInfo_ComponentInfo({\n dataPtr: y.dataPtr! + BigInt(y.size!),\n stride: chromaWidth * 2,\n size: chromaWidth * chromaHeight * 2,\n });\n return [y, uv];\n }\n default:\n return [];\n }\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/video_frame.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { OwnedVideoBuffer, VideoConvertResponse } from '@livekit/rtc-ffi-bindings';\nimport {\n VideoBufferInfo,\n VideoBufferInfo_ComponentInfo,\n VideoBufferType,\n} from '@livekit/rtc-ffi-bindings';\nimport { FfiClient, FfiHandle, FfiRequest } from './ffi_client.js';\n\nexport class VideoFrame {\n data: Uint8Array;\n width: number;\n height: number;\n type: VideoBufferType;\n\n constructor(data: Uint8Array, width: number, height: number, type: VideoBufferType) {\n this.data = data;\n this.width = width;\n this.height = height;\n this.type = type;\n }\n\n /** @internal */\n get dataPtr(): bigint {\n return FfiClient.instance.retrievePtr(new Uint8Array(this.data.buffer));\n }\n\n /** @internal */\n protoInfo(): VideoBufferInfo {\n const info = new VideoBufferInfo({\n width: this.width,\n height: this.height,\n type: this.type,\n dataPtr: this.dataPtr,\n });\n\n switch (this.type) {\n case VideoBufferType.ARGB:\n case VideoBufferType.RGBA:\n case VideoBufferType.ABGR:\n case VideoBufferType.BGRA:\n info.stride = this.width * 4;\n break;\n case VideoBufferType.RGB24:\n info.stride = this.width * 3;\n break;\n default:\n info.stride = 0;\n }\n\n info.components.push(...getPlaneInfos(this.dataPtr, this.type, this.width, this.height));\n\n return info;\n }\n\n /** @internal */\n static fromOwnedInfo(owned: OwnedVideoBuffer): VideoFrame {\n const info = owned.info!;\n const frame = new VideoFrame(\n FfiClient.instance.copyBuffer(\n info.dataPtr!,\n getPlaneLength(info.type!, info.width!, info.height!),\n ),\n info.width!,\n info.height!,\n info.type!,\n );\n // Dispose of the handle to prevent memory leaks\n new FfiHandle(owned.handle!.id!).dispose();\n return frame;\n }\n\n getPlane(planeNth: number): Uint8Array | void {\n const planeInfos = getPlaneInfos(this.dataPtr, this.type, this.width, this.height);\n if (planeNth >= planeInfos.length) return;\n\n const planeInfo = planeInfos[planeNth]!;\n return FfiClient.instance.copyBuffer(planeInfo.dataPtr!, planeInfo.size!);\n }\n\n convert(dstType: VideoBufferType, flipY = false): VideoFrame {\n const req = new FfiRequest({\n message: {\n case: 'videoConvert',\n value: {\n flipY,\n dstType,\n buffer: this.protoInfo(),\n },\n },\n });\n const resp = FfiClient.instance.request<VideoConvertResponse>(req);\n\n switch (resp.message.case) {\n case 'buffer':\n return VideoFrame.fromOwnedInfo(resp.message.value);\n case 'error':\n default:\n throw resp.message.value;\n }\n }\n}\n\nconst getPlaneLength = (type: VideoBufferType, width: number, height: number): number => {\n const chromaWidth = Math.trunc((width + 1) / 2);\n const chromaHeight = Math.trunc((height + 1) / 2);\n switch (type) {\n case VideoBufferType.ARGB:\n case VideoBufferType.RGBA:\n case VideoBufferType.ABGR:\n case VideoBufferType.BGRA:\n return width * height * 4;\n case VideoBufferType.RGB24:\n case VideoBufferType.I444:\n return width * height * 3;\n case VideoBufferType.I420:\n return width * height + chromaWidth * chromaHeight * 2;\n case VideoBufferType.I420A:\n return width * height * 2 + chromaWidth * chromaWidth * 2;\n case VideoBufferType.I422:\n return width * height + chromaWidth * height * 2;\n case VideoBufferType.I010:\n return width * height * 2 + chromaWidth * chromaHeight * 4;\n case VideoBufferType.NV12:\n return width * height + chromaWidth * chromaWidth * 2;\n }\n};\n\nconst getPlaneInfos = (\n dataPtr: bigint,\n type: VideoBufferType,\n width: number,\n height: number,\n): VideoBufferInfo_ComponentInfo[] => {\n const chromaWidth = Math.trunc((width + 1) / 2);\n const chromaHeight = Math.trunc((height + 1) / 2);\n switch (type) {\n case VideoBufferType.I420: {\n const y = new VideoBufferInfo_ComponentInfo({ dataPtr, stride: width, size: width * height });\n const u = new VideoBufferInfo_ComponentInfo({\n dataPtr: y.dataPtr! + BigInt(y.size!),\n stride: chromaWidth,\n size: chromaWidth * chromaHeight,\n });\n const v = new VideoBufferInfo_ComponentInfo({\n dataPtr: u.dataPtr! + BigInt(u.size!),\n stride: chromaWidth,\n size: chromaWidth * chromaHeight,\n });\n return [y, u, v];\n }\n case VideoBufferType.I420A: {\n const y = new VideoBufferInfo_ComponentInfo({ dataPtr, stride: width, size: width * height });\n const u = new VideoBufferInfo_ComponentInfo({\n dataPtr: y.dataPtr! + BigInt(y.size!),\n stride: chromaWidth,\n size: chromaWidth * chromaHeight,\n });\n const v = new VideoBufferInfo_ComponentInfo({\n dataPtr: u.dataPtr! + BigInt(u.size!),\n stride: chromaWidth,\n size: chromaWidth * chromaHeight,\n });\n const a = new VideoBufferInfo_ComponentInfo({\n dataPtr: v.dataPtr! + BigInt(v.size!),\n stride: width,\n size: width * height,\n });\n return [y, u, v, a];\n }\n case VideoBufferType.I422: {\n const y = new VideoBufferInfo_ComponentInfo({ dataPtr, stride: width, size: width * height });\n const u = new VideoBufferInfo_ComponentInfo({\n dataPtr: y.dataPtr! + BigInt(y.size!),\n stride: chromaWidth,\n size: chromaWidth * height,\n });\n const v = new VideoBufferInfo_ComponentInfo({\n dataPtr: u.dataPtr! + BigInt(u.size!),\n stride: chromaWidth,\n size: chromaWidth * height,\n });\n return [y, u, v];\n }\n case VideoBufferType.I444: {\n const y = new VideoBufferInfo_ComponentInfo({ dataPtr, stride: width, size: width * height });\n const u = new VideoBufferInfo_ComponentInfo({\n dataPtr: y.dataPtr! + BigInt(y.size!),\n stride: width,\n size: width * height,\n });\n const v = new VideoBufferInfo_ComponentInfo({\n dataPtr: u.dataPtr! + BigInt(u.size!),\n stride: width,\n size: width * height,\n });\n return [y, u, v];\n }\n case VideoBufferType.I010: {\n const y = new VideoBufferInfo_ComponentInfo({\n dataPtr,\n stride: width * 2,\n size: width * height * 2,\n });\n const u = new VideoBufferInfo_ComponentInfo({\n dataPtr: y.dataPtr! + BigInt(y.size!),\n stride: chromaWidth * 2,\n size: chromaWidth * chromaHeight * 2,\n });\n const v = new VideoBufferInfo_ComponentInfo({\n dataPtr: u.dataPtr! + BigInt(u.size!),\n stride: chromaWidth * 2,\n size: chromaWidth * chromaHeight * 2,\n });\n return [y, u, v];\n }\n case VideoBufferType.NV12: {\n const y = new VideoBufferInfo_ComponentInfo({ dataPtr, stride: width, size: width * height });\n const uv = new VideoBufferInfo_ComponentInfo({\n dataPtr: y.dataPtr! + BigInt(y.size!),\n stride: chromaWidth * 2,\n size: chromaWidth * chromaHeight * 2,\n });\n return [y, uv];\n }\n default:\n return [];\n }\n};\n"],"mappings":"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","names":[]}
@@ -21,8 +21,8 @@ __export(video_source_exports, {
21
21
  VideoSource: () => VideoSource
22
22
  });
23
23
  module.exports = __toCommonJS(video_source_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
  class VideoSource {
27
27
  constructor(width, height) {
28
28
  /** @internal */
@@ -30,8 +30,8 @@ class VideoSource {
30
30
  var _a;
31
31
  this.width = width;
32
32
  this.height = height;
33
- const req = new import_video_frame_pb.NewVideoSourceRequest({
34
- type: import_video_frame_pb.VideoSourceType.VIDEO_SOURCE_NATIVE,
33
+ const req = new import_rtc_ffi_bindings.NewVideoSourceRequest({
34
+ type: import_rtc_ffi_bindings.VideoSourceType.VIDEO_SOURCE_NATIVE,
35
35
  resolution: {
36
36
  width,
37
37
  height
@@ -46,11 +46,11 @@ class VideoSource {
46
46
  this.info = (_a = res.source) == null ? void 0 : _a.info;
47
47
  this.ffiHandle = new import_ffi_client.FfiHandle(res.source.handle.id);
48
48
  }
49
- captureFrame(frame, timestampUs = BigInt(0), rotation = import_video_frame_pb.VideoRotation.VIDEO_ROTATION_0) {
49
+ captureFrame(frame, timestampUs = BigInt(0), rotation = import_rtc_ffi_bindings.VideoRotation.VIDEO_ROTATION_0) {
50
50
  if (this.closed) {
51
51
  throw new Error("VideoSource is closed");
52
52
  }
53
- const req = new import_video_frame_pb.CaptureVideoFrameRequest({
53
+ const req = new import_rtc_ffi_bindings.CaptureVideoFrameRequest({
54
54
  sourceHandle: this.ffiHandle.handle,
55
55
  buffer: frame.protoInfo(),
56
56
  rotation,
@@ -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":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,wBAAqC;AAMrC,4BAKO;AAGA,MAAM,YAAY;AAAA,EAWvB,YAAY,OAAe,QAAgB;AAL3C;AAAA,kBAAS;AAvBX;AA6BI,SAAK,QAAQ;AACb,SAAK,SAAS;AAEd,UAAM,MAAM,IAAI,4CAAsB;AAAA,MACpC,MAAM,sCAAgB;AAAA,MACtB,YAAY;AAAA,QACV;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,MAAM,4BAAU,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,4BAAU,IAAI,OAAQ,OAAQ,EAAG;AAAA,EACxD;AAAA,EAEA,aACE,OACA,cAAc,OAAO,CAAC,GACtB,WAAW,oCAAc,kBACzB;AACA,QAAI,KAAK,QAAQ;AACf,YAAM,IAAI,MAAM,uBAAuB;AAAA,IACzC;AACA,UAAM,MAAM,IAAI,+CAAyB;AAAA,MACvC,cAAc,KAAK,UAAU;AAAA,MAC7B,QAAQ,MAAM,UAAU;AAAA,MACxB;AAAA,MACA;AAAA,IACF,CAAC;AAED,gCAAU,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":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,8BAKO;AACP,wBAAqC;AAG9B,MAAM,YAAY;AAAA,EAWvB,YAAY,OAAe,QAAgB;AAL3C;AAAA,kBAAS;AAvBX;AA6BI,SAAK,QAAQ;AACb,SAAK,SAAS;AAEd,UAAM,MAAM,IAAI,8CAAsB;AAAA,MACpC,MAAM,wCAAgB;AAAA,MACtB,YAAY;AAAA,QACV;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,MAAM,4BAAU,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,4BAAU,IAAI,OAAQ,OAAQ,EAAG;AAAA,EACxD;AAAA,EAEA,aACE,OACA,cAAc,OAAO,CAAC,GACtB,WAAW,sCAAc,kBACzB;AACA,QAAI,KAAK,QAAQ;AACf,YAAM,IAAI,MAAM,uBAAuB;AAAA,IACzC;AACA,UAAM,MAAM,IAAI,iDAAyB;AAAA,MACvC,cAAc,KAAK,UAAU;AAAA,MAC7B,QAAQ,MAAM,UAAU;AAAA,MACxB;AAAA,MACA;AAAA,IACF,CAAC;AAED,gCAAU,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,20 +1,7 @@
1
+ import { VideoSourceInfo, FfiHandle, VideoRotation } from '@livekit/rtc-ffi-bindings';
1
2
  import './ffi_client.cjs';
2
- import { VideoSourceInfo, VideoRotation } from './proto/video_frame_pb.cjs';
3
3
  import { VideoFrame } from './video_frame.cjs';
4
- import { FfiHandle } from './napi/native.d.cjs';
5
- import '@bufbuild/protobuf';
6
4
  import '@livekit/typed-emitter';
7
- import './proto/ffi_pb.cjs';
8
- import './proto/room_pb.cjs';
9
- import './proto/participant_pb.cjs';
10
- import './proto/handle_pb.cjs';
11
- import './proto/track_pb.cjs';
12
- import './proto/stats_pb.cjs';
13
- import './proto/e2ee_pb.cjs';
14
- import './proto/data_stream_pb.cjs';
15
- import './proto/audio_frame_pb.cjs';
16
- import './proto/rpc_pb.cjs';
17
- import './proto/track_publication_pb.cjs';
18
5
 
19
6
  declare class VideoSource {
20
7
  /** @internal */
@@ -1,20 +1,7 @@
1
+ import { VideoSourceInfo, FfiHandle, VideoRotation } from '@livekit/rtc-ffi-bindings';
1
2
  import './ffi_client.js';
2
- import { VideoSourceInfo, VideoRotation } from './proto/video_frame_pb.js';
3
3
  import { VideoFrame } from './video_frame.js';
4
- import { FfiHandle } from './napi/native.d.js';
5
- import '@bufbuild/protobuf';
6
4
  import '@livekit/typed-emitter';
7
- import './proto/ffi_pb.js';
8
- import './proto/room_pb.js';
9
- import './proto/participant_pb.js';
10
- import './proto/handle_pb.js';
11
- import './proto/track_pb.js';
12
- import './proto/stats_pb.js';
13
- import './proto/e2ee_pb.js';
14
- import './proto/data_stream_pb.js';
15
- import './proto/audio_frame_pb.js';
16
- import './proto/rpc_pb.js';
17
- import './proto/track_publication_pb.js';
18
5
 
19
6
  declare class VideoSource {
20
7
  /** @internal */
@@ -1 +1 @@
1
- {"version":3,"file":"video_source.d.ts","sourceRoot":"","sources":["../src/video_source.ts"],"names":[],"mappings":"AAGA,OAAO,EAAa,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,KAAK,EAGV,eAAe,EAChB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAGL,aAAa,EAEd,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,qBAAa,WAAW;IACtB,gBAAgB;IAChB,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,gBAAgB;IAChB,SAAS,EAAE,SAAS,CAAC;IACrB,gBAAgB;IAChB,MAAM,UAAS;IAEf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;gBAEH,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAuBzC,YAAY,CACV,KAAK,EAAE,UAAU,EACjB,WAAW,SAAY,EACvB,QAAQ,gBAAiC;IAiBrC,KAAK;CAIZ"}
1
+ {"version":3,"file":"video_source.d.ts","sourceRoot":"","sources":["../src/video_source.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAGV,eAAe,EAChB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAGL,aAAa,EAEd,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAa,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,qBAAa,WAAW;IACtB,gBAAgB;IAChB,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,gBAAgB;IAChB,SAAS,EAAE,SAAS,CAAC;IACrB,gBAAgB;IAChB,MAAM,UAAS;IAEf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;gBAEH,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAuBzC,YAAY,CACV,KAAK,EAAE,UAAU,EACjB,WAAW,SAAY,EACvB,QAAQ,gBAAiC;IAiBrC,KAAK;CAIZ"}
@@ -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.26",
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.2"
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
  };
@@ -164,4 +164,106 @@ describe('AudioMixer', () => {
164
164
  // Should get at least 2 frames (stream exhausts after 2)
165
165
  expect(frames.length).toBeGreaterThanOrEqual(2);
166
166
  });
167
+
168
+ it('completes mixing without lingering timers when iterator is fast', async () => {
169
+ const sampleRate = 48000;
170
+ const numChannels = 1;
171
+ const samplesPerChannel = 480;
172
+ const mixer = new AudioMixer(sampleRate, numChannels, {
173
+ blocksize: samplesPerChannel,
174
+ // Long timeout so the iterator always wins the race.
175
+ // Before the fix, each iteration leaked a 5s timer; with the fix,
176
+ // cancel() clears it immediately so the mixer shuts down without delay.
177
+ streamTimeoutMs: 5000,
178
+ });
179
+
180
+ const stream = createMockAudioStream(3, sampleRate, numChannels, samplesPerChannel, 42);
181
+ mixer.addStream(stream);
182
+
183
+ const frames: AudioFrame[] = [];
184
+ for await (const frame of mixer) {
185
+ frames.push(frame);
186
+ if (frames.length >= 2) break;
187
+ }
188
+
189
+ await mixer.aclose();
190
+
191
+ expect(frames.length).toBe(2);
192
+ // Verify the frames contain the expected mixed value
193
+ for (const frame of frames) {
194
+ expect(frame.data[0]).toBe(42);
195
+ }
196
+ });
197
+
198
+ it('produces frames even with many race iterations', async () => {
199
+ const sampleRate = 48000;
200
+ const numChannels = 1;
201
+ const samplesPerChannel = 480;
202
+ const mixer = new AudioMixer(sampleRate, numChannels, {
203
+ blocksize: samplesPerChannel,
204
+ streamTimeoutMs: 5000,
205
+ });
206
+
207
+ // Use more frames to stress multiple race iterations
208
+ const stream = createMockAudioStream(6, sampleRate, numChannels, samplesPerChannel, 10);
209
+ mixer.addStream(stream);
210
+
211
+ const frames: AudioFrame[] = [];
212
+ for await (const frame of mixer) {
213
+ frames.push(frame);
214
+ if (frames.length >= 4) break;
215
+ }
216
+
217
+ await mixer.aclose();
218
+
219
+ expect(frames.length).toBe(4);
220
+ // All frames should contain the expected value
221
+ for (const frame of frames) {
222
+ expect(frame.data[0]).toBe(10);
223
+ }
224
+ });
225
+
226
+ it('handles slow streams via timeout path', async () => {
227
+ const sampleRate = 48000;
228
+ const numChannels = 1;
229
+ const samplesPerChannel = 480;
230
+ const mixer = new AudioMixer(sampleRate, numChannels, {
231
+ blocksize: samplesPerChannel,
232
+ // Very short timeout to trigger the timeout path
233
+ streamTimeoutMs: 1,
234
+ });
235
+
236
+ // Create a stream that is slower than the timeout
237
+ async function* slowStream(): AsyncGenerator<AudioFrame> {
238
+ await new Promise((resolve) => setTimeout(resolve, 200));
239
+ const data = new Int16Array(numChannels * samplesPerChannel).fill(500);
240
+ yield new AudioFrame(data, sampleRate, numChannels, samplesPerChannel);
241
+ }
242
+
243
+ // Suppress the expected console.warn from the timeout path
244
+ const originalWarn = console.warn;
245
+ const warnings: string[] = [];
246
+ console.warn = (...args: unknown[]) => {
247
+ warnings.push(args.map(String).join(' '));
248
+ };
249
+
250
+ try {
251
+ mixer.addStream(slowStream());
252
+
253
+ // The mixer should produce a frame (zero-padded due to timeout)
254
+ // and auto-close when the stream exhausts.
255
+ const frames: AudioFrame[] = [];
256
+ for await (const frame of mixer) {
257
+ frames.push(frame);
258
+ if (frames.length >= 1) break;
259
+ }
260
+
261
+ await mixer.aclose();
262
+
263
+ // The timeout warning should have been logged
264
+ expect(warnings.some((w) => w.includes('stream timeout after'))).toBe(true);
265
+ } finally {
266
+ console.warn = originalWarn;
267
+ }
268
+ });
167
269
  });