@livekit/rtc-node 0.13.31 → 0.13.33

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 (120) hide show
  1. package/dist/async_queue.d.ts +2 -3
  2. package/dist/audio_filter.d.ts +2 -3
  3. package/dist/audio_frame.d.ts +5 -6
  4. package/dist/audio_mixer.d.ts +3 -6
  5. package/dist/audio_resampler.d.ts +3 -6
  6. package/dist/audio_source.d.ts +5 -6
  7. package/dist/{audio_stream-B4hGVcKz.d.cts → audio_stream-CnODFAmo.d.cts} +26 -0
  8. package/dist/audio_stream.cjs +31 -18
  9. package/dist/audio_stream.cjs.map +1 -1
  10. package/dist/audio_stream.d.cts +1 -1
  11. package/dist/audio_stream.d.ts +61 -18
  12. package/dist/audio_stream.d.ts.map +1 -1
  13. package/dist/data_streams/index.d.ts +4 -3
  14. package/dist/data_streams/stream_reader.d.ts +48 -2
  15. package/dist/data_streams/stream_writer.d.ts +5 -7
  16. package/dist/data_streams/types.d.ts +41 -2
  17. package/dist/e2ee.d.ts +8 -10
  18. package/dist/ffi_client.d.ts +8 -10
  19. package/dist/frame_processor.d.ts +8 -11
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +2 -2
  22. package/dist/index.d.ts +22 -17
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +1 -107
  25. package/dist/log.d.ts +5 -7
  26. package/dist/participant.cjs +7 -2
  27. package/dist/participant.cjs.map +1 -1
  28. package/dist/participant.d.cts +1 -1
  29. package/dist/participant.d.ts +152 -18
  30. package/dist/participant.d.ts.map +1 -1
  31. package/dist/room.cjs +7 -0
  32. package/dist/room.cjs.map +1 -1
  33. package/dist/room.d.cts +2 -2
  34. package/dist/room.d.ts +220 -18
  35. package/dist/room.d.ts.map +1 -1
  36. package/dist/rpc.d.ts +7 -9
  37. package/dist/track.cjs +16 -0
  38. package/dist/track.cjs.map +1 -1
  39. package/dist/track.d.cts +1 -1
  40. package/dist/track.d.ts +67 -18
  41. package/dist/track.d.ts.map +1 -1
  42. package/dist/track_publication.d.cts +1 -1
  43. package/dist/track_publication.d.ts +45 -18
  44. package/dist/transcription.d.ts +3 -4
  45. package/dist/types.d.ts +2 -3
  46. package/dist/utils.d.ts +4 -5
  47. package/dist/version.cjs +1 -1
  48. package/dist/version.cjs.map +1 -1
  49. package/dist/version.d.cts +1 -1
  50. package/dist/version.d.ts +2 -3
  51. package/dist/video_frame.d.ts +4 -5
  52. package/dist/video_source.d.ts +6 -8
  53. package/dist/video_stream.d.cts +1 -1
  54. package/dist/video_stream.d.ts +5 -22
  55. package/package.json +5 -6
  56. package/src/audio_stream.ts +37 -24
  57. package/src/audio_stream_room_lifecycle.test.ts +50 -3
  58. package/src/index.ts +8 -1
  59. package/src/participant.ts +7 -1
  60. package/src/room.ts +14 -0
  61. package/src/tests/e2e.test.ts +137 -16
  62. package/src/track.ts +17 -0
  63. package/src/version.ts +1 -1
  64. package/dist/async_queue.js +0 -56
  65. package/dist/async_queue.js.map +0 -1
  66. package/dist/audio_filter.js +0 -24
  67. package/dist/audio_filter.js.map +0 -1
  68. package/dist/audio_frame.js +0 -78
  69. package/dist/audio_frame.js.map +0 -1
  70. package/dist/audio_mixer.js +0 -269
  71. package/dist/audio_mixer.js.map +0 -1
  72. package/dist/audio_resampler.js +0 -154
  73. package/dist/audio_resampler.js.map +0 -1
  74. package/dist/audio_source.js +0 -134
  75. package/dist/audio_source.js.map +0 -1
  76. package/dist/audio_stream-DEG1JKge.d.ts +0 -498
  77. package/dist/audio_stream.js +0 -109
  78. package/dist/audio_stream.js.map +0 -1
  79. package/dist/data_streams/index.js +0 -3
  80. package/dist/data_streams/index.js.map +0 -1
  81. package/dist/data_streams/stream_reader.js +0 -124
  82. package/dist/data_streams/stream_reader.js.map +0 -1
  83. package/dist/data_streams/stream_writer.js +0 -26
  84. package/dist/data_streams/stream_writer.js.map +0 -1
  85. package/dist/data_streams/types.js +0 -1
  86. package/dist/data_streams/types.js.map +0 -1
  87. package/dist/e2ee.js +0 -251
  88. package/dist/e2ee.js.map +0 -1
  89. package/dist/ffi_client.js +0 -89
  90. package/dist/ffi_client.js.map +0 -1
  91. package/dist/frame_processor.js +0 -29
  92. package/dist/frame_processor.js.map +0 -1
  93. package/dist/index.js.map +0 -1
  94. package/dist/log.js +0 -9
  95. package/dist/log.js.map +0 -1
  96. package/dist/participant.js +0 -715
  97. package/dist/participant.js.map +0 -1
  98. package/dist/room.js +0 -899
  99. package/dist/room.js.map +0 -1
  100. package/dist/rpc.js +0 -65
  101. package/dist/rpc.js.map +0 -1
  102. package/dist/track.js +0 -218
  103. package/dist/track.js.map +0 -1
  104. package/dist/track_publication.js +0 -100
  105. package/dist/track_publication.js.map +0 -1
  106. package/dist/transcription.js +0 -1
  107. package/dist/transcription.js.map +0 -1
  108. package/dist/types-_PdPVish.d.ts +0 -87
  109. package/dist/types.js +0 -1
  110. package/dist/types.js.map +0 -1
  111. package/dist/utils.js +0 -35
  112. package/dist/utils.js.map +0 -1
  113. package/dist/version.js +0 -5
  114. package/dist/version.js.map +0 -1
  115. package/dist/video_frame.js +0 -207
  116. package/dist/video_frame.js.map +0 -1
  117. package/dist/video_source.js +0 -53
  118. package/dist/video_source.js.map +0 -1
  119. package/dist/video_stream.js +0 -70
  120. package/dist/video_stream.js.map +0 -1
@@ -1,154 +0,0 @@
1
- import {
2
- FlushSoxResamplerRequest,
3
- NewSoxResamplerRequest,
4
- PushSoxResamplerRequest,
5
- SoxQualityRecipe,
6
- SoxResamplerDataType
7
- } from "@livekit/rtc-ffi-bindings";
8
- import { AudioFrame } from "./audio_frame.js";
9
- import { FfiClient, FfiHandle } from "./ffi_client.js";
10
- var AudioResamplerQuality = ((AudioResamplerQuality2) => {
11
- AudioResamplerQuality2[AudioResamplerQuality2["QUICK"] = SoxQualityRecipe.SOXR_QUALITY_QUICK] = "QUICK";
12
- AudioResamplerQuality2[AudioResamplerQuality2["LOW"] = SoxQualityRecipe.SOXR_QUALITY_LOW] = "LOW";
13
- AudioResamplerQuality2[AudioResamplerQuality2["MEDIUM"] = SoxQualityRecipe.SOXR_QUALITY_MEDIUM] = "MEDIUM";
14
- AudioResamplerQuality2[AudioResamplerQuality2["HIGH"] = SoxQualityRecipe.SOXR_QUALITY_HIGH] = "HIGH";
15
- AudioResamplerQuality2[AudioResamplerQuality2["VERY_HIGH"] = SoxQualityRecipe.SOXR_QUALITY_VERYHIGH] = "VERY_HIGH";
16
- return AudioResamplerQuality2;
17
- })(AudioResamplerQuality || {});
18
- class AudioResampler {
19
- #inputRate;
20
- #outputRate;
21
- #channels;
22
- #ffiHandle;
23
- /**
24
- * Initializes a new AudioResampler.
25
- *
26
- * @param inputRate - The sample rate of the input audio data (in Hz).
27
- * @param outputRate - The desired sample rate of the output audio data (in Hz).
28
- * @param channels - The number of audio channels (e.g., 1 for mono, 2 for stereo). Defaults to 1.
29
- * @param quality - The quality setting for the resampler. Defaults to
30
- * `AudioResamplerQuality.MEDIUM`.
31
- */
32
- constructor(inputRate, outputRate, channels = 1, quality = AudioResamplerQuality.MEDIUM) {
33
- this.#inputRate = inputRate;
34
- this.#outputRate = outputRate;
35
- this.#channels = channels;
36
- const req = new NewSoxResamplerRequest({
37
- inputRate,
38
- outputRate,
39
- numChannels: channels,
40
- qualityRecipe: quality,
41
- inputDataType: SoxResamplerDataType.SOXR_DATATYPE_INT16I,
42
- outputDataType: SoxResamplerDataType.SOXR_DATATYPE_INT16I,
43
- flags: 0
44
- });
45
- const res = FfiClient.instance.request({
46
- message: {
47
- case: "newSoxResampler",
48
- value: req
49
- }
50
- });
51
- switch (res.message.case) {
52
- case "resampler":
53
- this.#ffiHandle = new FfiHandle(res.message.value.handle.id);
54
- break;
55
- case "error":
56
- default:
57
- throw new Error(res.message.value);
58
- }
59
- }
60
- get inputRate() {
61
- return this.#inputRate;
62
- }
63
- get outputRate() {
64
- return this.#outputRate;
65
- }
66
- get channels() {
67
- return this.#channels;
68
- }
69
- /**
70
- * Releases the underlying native resampler handle. Must be called when
71
- * the resampler is no longer needed to avoid leaking the FD.
72
- */
73
- close() {
74
- this.#ffiHandle.dispose();
75
- }
76
- /**
77
- * Push audio data into the resampler and retrieve any available resampled data.
78
- *
79
- * This method accepts audio data, resamples it according to the configured input and output rates,
80
- * and returns any resampled data that is available after processing the input.
81
- *
82
- * @param data - The audio frame to resample
83
- *
84
- * @returns A list of {@link AudioFrame} objects containing the resampled audio data. The list may
85
- * be empty if no output data is available yet.
86
- */
87
- push(data) {
88
- const req = new PushSoxResamplerRequest({
89
- resamplerHandle: this.#ffiHandle.handle,
90
- dataPtr: data.protoInfo().dataPtr,
91
- size: data.data.byteLength
92
- });
93
- const res = FfiClient.instance.request({
94
- message: {
95
- case: "pushSoxResampler",
96
- value: req
97
- }
98
- });
99
- if (res.error) {
100
- throw new Error(res.error);
101
- }
102
- if (!res.outputPtr) {
103
- return [];
104
- }
105
- const outputData = FfiClient.instance.copyBuffer(res.outputPtr, res.size);
106
- return [
107
- new AudioFrame(
108
- new Int16Array(outputData.buffer),
109
- this.#outputRate,
110
- this.#channels,
111
- Math.trunc(outputData.length / this.#channels / 2),
112
- data.userdata
113
- )
114
- ];
115
- }
116
- /**
117
- * Flush any remaining audio data through the resampler and retrieve the resampled data.
118
- *
119
- * @remarks
120
- * This method should be called when no more input data will be provided to ensure that all
121
- * internal buffers are processed and all resampled data is output.
122
- */
123
- flush() {
124
- const req = new FlushSoxResamplerRequest({
125
- resamplerHandle: this.#ffiHandle.handle
126
- });
127
- const res = FfiClient.instance.request({
128
- message: {
129
- case: "flushSoxResampler",
130
- value: req
131
- }
132
- });
133
- if (res.error) {
134
- throw new Error(res.error);
135
- }
136
- if (!res.outputPtr) {
137
- return [];
138
- }
139
- const outputData = FfiClient.instance.copyBuffer(res.outputPtr, res.size);
140
- return [
141
- new AudioFrame(
142
- new Int16Array(outputData.buffer),
143
- this.#outputRate,
144
- this.#channels,
145
- Math.trunc(outputData.length / this.#channels / 2)
146
- )
147
- ];
148
- }
149
- }
150
- export {
151
- AudioResampler,
152
- AudioResamplerQuality
153
- };
154
- //# sourceMappingURL=audio_resampler.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/audio_resampler.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type {\n FlushSoxResamplerResponse,\n NewSoxResamplerResponse,\n PushSoxResamplerResponse,\n} from '@livekit/rtc-ffi-bindings';\nimport {\n FlushSoxResamplerRequest,\n NewSoxResamplerRequest,\n PushSoxResamplerRequest,\n SoxQualityRecipe,\n SoxResamplerDataType,\n} from '@livekit/rtc-ffi-bindings';\nimport { AudioFrame } from './audio_frame.js';\nimport { FfiClient, FfiHandle } from './ffi_client.js';\n\n/**\n * Resampler quality. Higher quality settings result in better audio quality but require more\n * processing power.\n */\nexport enum AudioResamplerQuality {\n QUICK = SoxQualityRecipe.SOXR_QUALITY_QUICK,\n LOW = SoxQualityRecipe.SOXR_QUALITY_LOW,\n MEDIUM = SoxQualityRecipe.SOXR_QUALITY_MEDIUM,\n HIGH = SoxQualityRecipe.SOXR_QUALITY_HIGH,\n VERY_HIGH = SoxQualityRecipe.SOXR_QUALITY_VERYHIGH,\n}\n\n/**\n * AudioResampler provides functionality to resample audio data from an input sample rate to\n * an output sample rate using the Sox resampling library. It supports multiple channels and\n * configurable resampling quality.\n */\nexport class AudioResampler {\n #inputRate: number;\n #outputRate: number;\n #channels: number;\n #ffiHandle: FfiHandle;\n\n /**\n * Initializes a new AudioResampler.\n *\n * @param inputRate - The sample rate of the input audio data (in Hz).\n * @param outputRate - The desired sample rate of the output audio data (in Hz).\n * @param channels - The number of audio channels (e.g., 1 for mono, 2 for stereo). Defaults to 1.\n * @param quality - The quality setting for the resampler. Defaults to\n * `AudioResamplerQuality.MEDIUM`.\n */\n constructor(\n inputRate: number,\n outputRate: number,\n channels = 1,\n quality = AudioResamplerQuality.MEDIUM,\n ) {\n this.#inputRate = inputRate;\n this.#outputRate = outputRate;\n this.#channels = channels;\n\n const req = new NewSoxResamplerRequest({\n inputRate,\n outputRate,\n numChannels: channels,\n qualityRecipe: quality as number as SoxQualityRecipe,\n inputDataType: SoxResamplerDataType.SOXR_DATATYPE_INT16I,\n outputDataType: SoxResamplerDataType.SOXR_DATATYPE_INT16I,\n flags: 0,\n });\n\n const res = FfiClient.instance.request<NewSoxResamplerResponse>({\n message: {\n case: 'newSoxResampler',\n value: req,\n },\n });\n\n switch (res.message.case) {\n case 'resampler':\n this.#ffiHandle = new FfiHandle(res.message.value.handle!.id!);\n break;\n case 'error':\n default:\n throw new Error(res.message.value);\n }\n }\n\n get inputRate(): number {\n return this.#inputRate;\n }\n\n get outputRate(): number {\n return this.#outputRate;\n }\n\n get channels(): number {\n return this.#channels;\n }\n\n /**\n * Releases the underlying native resampler handle. Must be called when\n * the resampler is no longer needed to avoid leaking the FD.\n */\n close() {\n this.#ffiHandle.dispose();\n }\n\n /**\n * Push audio data into the resampler and retrieve any available resampled data.\n *\n * This method accepts audio data, resamples it according to the configured input and output rates,\n * and returns any resampled data that is available after processing the input.\n *\n * @param data - The audio frame to resample\n *\n * @returns A list of {@link AudioFrame} objects containing the resampled audio data. The list may\n * be empty if no output data is available yet.\n */\n push(data: AudioFrame): AudioFrame[] {\n const req = new PushSoxResamplerRequest({\n resamplerHandle: this.#ffiHandle.handle,\n dataPtr: data.protoInfo().dataPtr,\n size: data.data.byteLength,\n });\n\n const res = FfiClient.instance.request<PushSoxResamplerResponse>({\n message: {\n case: 'pushSoxResampler',\n value: req,\n },\n });\n\n if (res.error) {\n throw new Error(res.error);\n }\n\n if (!res.outputPtr) {\n return [];\n }\n\n const outputData = FfiClient.instance.copyBuffer(res.outputPtr, res.size!);\n\n return [\n new AudioFrame(\n new Int16Array(outputData.buffer),\n this.#outputRate,\n this.#channels,\n Math.trunc(outputData.length / this.#channels / 2),\n data.userdata,\n ),\n ];\n }\n\n /**\n * Flush any remaining audio data through the resampler and retrieve the resampled data.\n *\n * @remarks\n * This method should be called when no more input data will be provided to ensure that all\n * internal buffers are processed and all resampled data is output.\n */\n flush(): AudioFrame[] {\n const req = new FlushSoxResamplerRequest({\n resamplerHandle: this.#ffiHandle.handle,\n });\n\n const res = FfiClient.instance.request<FlushSoxResamplerResponse>({\n message: {\n case: 'flushSoxResampler',\n value: req,\n },\n });\n\n if (res.error) {\n throw new Error(res.error);\n }\n\n if (!res.outputPtr) {\n return [];\n }\n\n const outputData = FfiClient.instance.copyBuffer(res.outputPtr, res.size!);\n return [\n new AudioFrame(\n new Int16Array(outputData.buffer),\n this.#outputRate,\n this.#channels,\n Math.trunc(outputData.length / this.#channels / 2),\n ),\n ];\n }\n}\n"],"mappings":"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","names":["AudioResamplerQuality"]}
@@ -1,134 +0,0 @@
1
- import {
2
- AudioSourceType,
3
- CaptureAudioFrameRequest,
4
- ClearAudioBufferRequest,
5
- FfiHandle,
6
- NewAudioSourceRequest
7
- } from "@livekit/rtc-ffi-bindings";
8
- import { FfiClient } from "./ffi_client.js";
9
- class AudioSource {
10
- constructor(sampleRate, numChannels, queueSize = 1e3) {
11
- /** @internal */
12
- this.promise = void 0;
13
- /** @internal */
14
- this.resolvePromise = void 0;
15
- /** @internal */
16
- this.timeout = void 0;
17
- /** @internal */
18
- this.closed = false;
19
- /**
20
- * Resolve the pending waitForPlayout() promise (if any) and reset the queue
21
- * bookkeeping. Mirrors python-sdks' AudioSource._release_waiter: the promise is
22
- * discarded here and lazily re-created by the next captureFrame, so a later
23
- * waitForPlayout() can never consume a stale resolution and report playout
24
- * complete while audio is still queued.
25
- * @internal
26
- */
27
- this.releaseWaiter = () => {
28
- var _a;
29
- if (!this.promise) {
30
- return;
31
- }
32
- (_a = this.resolvePromise) == null ? void 0 : _a.call(this);
33
- this.lastCapture = 0;
34
- this.currentQueueSize = 0;
35
- this.promise = void 0;
36
- this.resolvePromise = void 0;
37
- if (this.timeout) {
38
- clearTimeout(this.timeout);
39
- this.timeout = void 0;
40
- }
41
- };
42
- this.sampleRate = sampleRate;
43
- this.numChannels = numChannels;
44
- this.queueSize = queueSize;
45
- this.lastCapture = 0;
46
- this.currentQueueSize = 0;
47
- const req = new NewAudioSourceRequest({
48
- type: AudioSourceType.AUDIO_SOURCE_NATIVE,
49
- sampleRate,
50
- numChannels,
51
- queueSizeMs: queueSize
52
- });
53
- const res = FfiClient.instance.request({
54
- message: {
55
- case: "newAudioSource",
56
- value: req
57
- }
58
- });
59
- this.info = res.source.info;
60
- this.ffiHandle = new FfiHandle(res.source.handle.id);
61
- }
62
- get queuedDuration() {
63
- return Math.max(
64
- this.currentQueueSize - Number(process.hrtime.bigint() / BigInt(1e6)) + this.lastCapture,
65
- 0
66
- );
67
- }
68
- clearQueue() {
69
- const req = new ClearAudioBufferRequest({
70
- sourceHandle: this.ffiHandle.handle
71
- });
72
- FfiClient.instance.request({
73
- message: {
74
- case: "clearAudioBuffer",
75
- value: req
76
- }
77
- });
78
- this.releaseWaiter();
79
- }
80
- async waitForPlayout() {
81
- if (!this.promise) {
82
- return;
83
- }
84
- await this.promise;
85
- }
86
- async captureFrame(frame) {
87
- if (this.closed) {
88
- throw new Error("AudioSource is closed");
89
- }
90
- if (frame.samplesPerChannel === 0) {
91
- return;
92
- }
93
- const now = Number(process.hrtime.bigint() / BigInt(1e6));
94
- const elapsed = this.lastCapture === 0 ? 0 : now - this.lastCapture;
95
- const frameDurationMs = frame.samplesPerChannel / frame.sampleRate * 1e3;
96
- this.currentQueueSize = Math.max(this.currentQueueSize - elapsed, 0) + frameDurationMs;
97
- this.lastCapture = now;
98
- if (this.timeout) {
99
- clearTimeout(this.timeout);
100
- }
101
- if (!this.promise) {
102
- this.promise = new Promise((resolve) => {
103
- this.resolvePromise = resolve;
104
- });
105
- }
106
- this.timeout = setTimeout(this.releaseWaiter, this.currentQueueSize);
107
- const req = new CaptureAudioFrameRequest({
108
- sourceHandle: this.ffiHandle.handle,
109
- buffer: frame.protoInfo()
110
- });
111
- const res = FfiClient.instance.request({
112
- message: { case: "captureAudioFrame", value: req }
113
- });
114
- const cb = await FfiClient.instance.waitFor((ev) => {
115
- return ev.message.case == "captureAudioFrame" && ev.message.value.asyncId == res.asyncId;
116
- });
117
- if (cb.error) {
118
- throw new Error(cb.error);
119
- }
120
- }
121
- async close() {
122
- if (this.timeout) {
123
- clearTimeout(this.timeout);
124
- this.timeout = void 0;
125
- }
126
- this.releaseWaiter();
127
- this.ffiHandle.dispose();
128
- this.closed = true;
129
- }
130
- }
131
- export {
132
- AudioSource
133
- };
134
- //# sourceMappingURL=audio_source.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/audio_source.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type {\n AudioSourceInfo,\n CaptureAudioFrameCallback,\n CaptureAudioFrameResponse,\n ClearAudioBufferResponse,\n NewAudioSourceResponse,\n} from '@livekit/rtc-ffi-bindings';\nimport {\n AudioSourceType,\n CaptureAudioFrameRequest,\n ClearAudioBufferRequest,\n FfiHandle,\n NewAudioSourceRequest,\n} from '@livekit/rtc-ffi-bindings';\nimport type { AudioFrame } from './audio_frame.js';\nimport { FfiClient } from './ffi_client.js';\n\nexport class AudioSource {\n /** @internal */\n info: AudioSourceInfo;\n /** @internal */\n ffiHandle: FfiHandle;\n /** @internal */\n lastCapture: number;\n /** @internal */\n currentQueueSize: number;\n /** @internal */\n promise?: Promise<void> = undefined;\n /** @internal */\n resolvePromise?: () => void = undefined;\n /** @internal */\n timeout?: ReturnType<typeof setTimeout> = undefined;\n /** @internal */\n closed = false;\n\n sampleRate: number;\n numChannels: number;\n queueSize: number;\n\n constructor(sampleRate: number, numChannels: number, queueSize = 1000) {\n this.sampleRate = sampleRate;\n this.numChannels = numChannels;\n this.queueSize = queueSize;\n\n this.lastCapture = 0;\n this.currentQueueSize = 0;\n\n const req = new NewAudioSourceRequest({\n type: AudioSourceType.AUDIO_SOURCE_NATIVE,\n sampleRate: sampleRate,\n numChannels: numChannels,\n queueSizeMs: queueSize,\n });\n\n const res = FfiClient.instance.request<NewAudioSourceResponse>({\n message: {\n case: 'newAudioSource',\n value: req,\n },\n });\n\n this.info = res.source!.info!;\n this.ffiHandle = new FfiHandle(res.source!.handle!.id!);\n }\n\n get queuedDuration(): number {\n return Math.max(\n this.currentQueueSize - Number(process.hrtime.bigint() / BigInt(1000000)) + this.lastCapture,\n 0,\n );\n }\n\n clearQueue() {\n const req = new ClearAudioBufferRequest({\n sourceHandle: this.ffiHandle.handle,\n });\n\n FfiClient.instance.request<ClearAudioBufferResponse>({\n message: {\n case: 'clearAudioBuffer',\n value: req,\n },\n });\n\n this.releaseWaiter();\n }\n\n /**\n * Resolve the pending waitForPlayout() promise (if any) and reset the queue\n * bookkeeping. Mirrors python-sdks' AudioSource._release_waiter: the promise is\n * discarded here and lazily re-created by the next captureFrame, so a later\n * waitForPlayout() can never consume a stale resolution and report playout\n * complete while audio is still queued.\n * @internal\n */\n releaseWaiter = () => {\n if (!this.promise) {\n return;\n }\n\n this.resolvePromise?.();\n this.lastCapture = 0;\n this.currentQueueSize = 0;\n this.promise = undefined;\n this.resolvePromise = undefined;\n // cancel the drain timer (e.g. when released early by clearQueue), otherwise\n // it would fire later and release the waiter of a subsequent segment\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = undefined;\n }\n };\n\n async waitForPlayout() {\n if (!this.promise) {\n return;\n }\n\n await this.promise;\n }\n\n async captureFrame(frame: AudioFrame) {\n if (this.closed) {\n throw new Error('AudioSource is closed');\n }\n\n if (frame.samplesPerChannel === 0) {\n return;\n }\n\n const now = Number(process.hrtime.bigint() / BigInt(1000000));\n const elapsed = this.lastCapture === 0 ? 0 : now - this.lastCapture;\n const frameDurationMs = (frame.samplesPerChannel / frame.sampleRate) * 1000;\n this.currentQueueSize = Math.max(this.currentQueueSize - elapsed, 0) + frameDurationMs;\n\n this.lastCapture = now;\n\n if (this.timeout) {\n clearTimeout(this.timeout);\n }\n\n if (!this.promise) {\n this.promise = new Promise<void>((resolve) => {\n this.resolvePromise = resolve;\n });\n }\n\n this.timeout = setTimeout(this.releaseWaiter, this.currentQueueSize);\n\n const req = new CaptureAudioFrameRequest({\n sourceHandle: this.ffiHandle.handle,\n buffer: frame.protoInfo(),\n });\n\n const res = FfiClient.instance.request<CaptureAudioFrameResponse>({\n message: { case: 'captureAudioFrame', value: req },\n });\n\n const cb = await FfiClient.instance.waitFor<CaptureAudioFrameCallback>((ev) => {\n return ev.message.case == 'captureAudioFrame' && ev.message.value.asyncId == res.asyncId;\n });\n\n if (cb.error) {\n throw new Error(cb.error);\n }\n }\n\n async close() {\n // Clear any pending playout timeout so its callback doesn't fire after\n // the handle is disposed, which would reference freed native state.\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = undefined;\n }\n // Resolve any pending waitForPlayout() promise so callers don't hang.\n this.releaseWaiter();\n this.ffiHandle.dispose();\n this.closed = true;\n }\n}\n"],"mappings":"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","names":[]}