@livekit/rtc-node 0.11.1 → 0.12.1

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 (135) hide show
  1. package/dist/audio_frame.cjs +94 -0
  2. package/dist/audio_frame.cjs.map +1 -0
  3. package/dist/audio_frame.js +64 -67
  4. package/dist/audio_frame.js.map +1 -1
  5. package/dist/audio_resampler.cjs +153 -0
  6. package/dist/audio_resampler.cjs.map +1 -0
  7. package/dist/audio_resampler.js +129 -134
  8. package/dist/audio_resampler.js.map +1 -1
  9. package/dist/audio_source.cjs +116 -0
  10. package/dist/audio_source.cjs.map +1 -0
  11. package/dist/audio_source.js +92 -85
  12. package/dist/audio_source.js.map +1 -1
  13. package/dist/audio_stream.cjs +104 -0
  14. package/dist/audio_stream.cjs.map +1 -0
  15. package/dist/audio_stream.js +77 -78
  16. package/dist/audio_stream.js.map +1 -1
  17. package/dist/e2ee.cjs +268 -0
  18. package/dist/e2ee.cjs.map +1 -0
  19. package/dist/e2ee.d.ts.map +1 -1
  20. package/dist/e2ee.js +244 -221
  21. package/dist/e2ee.js.map +1 -1
  22. package/dist/ffi_client.cjs +95 -0
  23. package/dist/ffi_client.cjs.map +1 -0
  24. package/dist/ffi_client.d.ts +2 -2
  25. package/dist/ffi_client.d.ts.map +1 -1
  26. package/dist/ffi_client.js +67 -48
  27. package/dist/ffi_client.js.map +1 -1
  28. package/dist/index.cjs +166 -0
  29. package/dist/index.cjs.map +1 -0
  30. package/dist/index.d.ts +5 -5
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +119 -48
  33. package/dist/index.js.map +1 -1
  34. package/dist/napi/native.d.cjs +17 -0
  35. package/dist/napi/native.d.cjs.map +1 -0
  36. package/dist/napi/native.d.js +1 -0
  37. package/dist/napi/native.d.js.map +1 -0
  38. package/dist/native.cjs +301 -0
  39. package/dist/native.d.ts +19 -0
  40. package/dist/native.js +15 -0
  41. package/dist/participant.cjs +388 -0
  42. package/dist/participant.cjs.map +1 -0
  43. package/dist/participant.js +363 -339
  44. package/dist/participant.js.map +1 -1
  45. package/dist/proto/audio_frame_pb.cjs +193 -0
  46. package/dist/proto/audio_frame_pb.cjs.map +1 -0
  47. package/dist/proto/audio_frame_pb.js +120 -320
  48. package/dist/proto/audio_frame_pb.js.map +1 -1
  49. package/dist/proto/e2ee_pb.cjs +131 -0
  50. package/dist/proto/e2ee_pb.cjs.map +1 -0
  51. package/dist/proto/e2ee_pb.js +76 -202
  52. package/dist/proto/e2ee_pb.js.map +1 -1
  53. package/dist/proto/ffi_pb.cjs +76 -0
  54. package/dist/proto/ffi_pb.cjs.map +1 -0
  55. package/dist/proto/ffi_pb.js +33 -92
  56. package/dist/proto/ffi_pb.js.map +1 -1
  57. package/dist/proto/handle_pb.cjs +33 -0
  58. package/dist/proto/handle_pb.cjs.map +1 -0
  59. package/dist/proto/handle_pb.js +6 -22
  60. package/dist/proto/handle_pb.js.map +1 -1
  61. package/dist/proto/participant_pb.cjs +50 -0
  62. package/dist/proto/participant_pb.cjs.map +1 -0
  63. package/dist/proto/participant_pb.js +19 -57
  64. package/dist/proto/participant_pb.js.map +1 -1
  65. package/dist/proto/room_pb.cjs +370 -0
  66. package/dist/proto/room_pb.cjs.map +1 -0
  67. package/dist/proto/room_pb.js +239 -632
  68. package/dist/proto/room_pb.js.map +1 -1
  69. package/dist/proto/rpc_pb.cjs +63 -0
  70. package/dist/proto/rpc_pb.cjs.map +1 -0
  71. package/dist/proto/rpc_pb.js +26 -72
  72. package/dist/proto/rpc_pb.js.map +1 -1
  73. package/dist/proto/stats_pb.cjs +256 -0
  74. package/dist/proto/stats_pb.cjs.map +1 -0
  75. package/dist/proto/stats_pb.js +175 -456
  76. package/dist/proto/stats_pb.js.map +1 -1
  77. package/dist/proto/track_pb.cjs +116 -0
  78. package/dist/proto/track_pb.cjs.map +1 -0
  79. package/dist/proto/track_pb.js +65 -171
  80. package/dist/proto/track_pb.js.map +1 -1
  81. package/dist/proto/video_frame_pb.cjs +161 -0
  82. package/dist/proto/video_frame_pb.cjs.map +1 -0
  83. package/dist/proto/video_frame_pb.js +101 -269
  84. package/dist/proto/video_frame_pb.js.map +1 -1
  85. package/dist/room.cjs +440 -0
  86. package/dist/room.cjs.map +1 -0
  87. package/dist/room.js +384 -373
  88. package/dist/room.js.map +1 -1
  89. package/dist/rpc.cjs +89 -0
  90. package/dist/rpc.cjs.map +1 -0
  91. package/dist/rpc.js +59 -63
  92. package/dist/rpc.js.map +1 -1
  93. package/dist/track.cjs +100 -0
  94. package/dist/track.cjs.map +1 -0
  95. package/dist/track.js +66 -62
  96. package/dist/track.js.map +1 -1
  97. package/dist/track_publication.cjs +106 -0
  98. package/dist/track_publication.cjs.map +1 -0
  99. package/dist/track_publication.js +76 -74
  100. package/dist/track_publication.js.map +1 -1
  101. package/dist/transcription.cjs +17 -0
  102. package/dist/transcription.cjs.map +1 -0
  103. package/dist/transcription.js +0 -1
  104. package/dist/transcription.js.map +1 -1
  105. package/dist/types.cjs +17 -0
  106. package/dist/types.cjs.map +1 -0
  107. package/dist/types.js +0 -1
  108. package/dist/types.js.map +1 -1
  109. package/dist/version.cjs +29 -0
  110. package/dist/version.cjs.map +1 -0
  111. package/dist/version.d.ts +1 -1
  112. package/dist/version.js +4 -1
  113. package/dist/version.js.map +1 -1
  114. package/dist/video_frame.cjs +242 -0
  115. package/dist/video_frame.cjs.map +1 -0
  116. package/dist/video_frame.js +212 -201
  117. package/dist/video_frame.js.map +1 -1
  118. package/dist/video_source.cjs +63 -0
  119. package/dist/video_source.cjs.map +1 -0
  120. package/dist/video_source.d.ts.map +1 -1
  121. package/dist/video_source.js +42 -37
  122. package/dist/video_source.js.map +1 -1
  123. package/dist/video_stream.cjs +103 -0
  124. package/dist/video_stream.cjs.map +1 -0
  125. package/dist/video_stream.js +76 -77
  126. package/dist/video_stream.js.map +1 -1
  127. package/package.json +18 -9
  128. package/src/audio_frame.ts +2 -2
  129. package/src/audio_source.ts +2 -2
  130. package/src/e2ee.ts +2 -2
  131. package/src/ffi_client.ts +4 -4
  132. package/src/index.ts +14 -8
  133. package/src/version.ts +1 -1
  134. package/src/video_frame.ts +1 -1
  135. package/src/video_source.ts +5 -1
@@ -1,139 +1,134 @@
1
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
- if (kind === "m") throw new TypeError("Private method is not writable");
3
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
- };
7
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
- };
12
- var _AudioResampler_inputRate, _AudioResampler_outputRate, _AudioResampler_channels, _AudioResampler_ffiHandle;
13
- // SPDX-FileCopyrightText: 2024 LiveKit, Inc.
14
- //
15
- // SPDX-License-Identifier: Apache-2.0
16
- import { create } from '@bufbuild/protobuf';
17
- import { AudioFrame } from './audio_frame.js';
18
- import { FfiClient, FfiHandle } from './ffi_client.js';
19
- import { FlushSoxResamplerRequestSchema, NewSoxResamplerRequestSchema, PushSoxResamplerRequestSchema, SoxResamplerDataType, } from './proto/audio_frame_pb.js';
20
- /**
21
- * Resampler quality. Higher quality settings result in better audio quality but require more
22
- * processing power.
23
- */
24
- export var AudioResamplerQuality;
25
- (function (AudioResamplerQuality) {
26
- AudioResamplerQuality[AudioResamplerQuality["QUICK"] = 0] = "QUICK";
27
- AudioResamplerQuality[AudioResamplerQuality["LOW"] = 1] = "LOW";
28
- AudioResamplerQuality[AudioResamplerQuality["MEDIUM"] = 2] = "MEDIUM";
29
- AudioResamplerQuality[AudioResamplerQuality["HIGH"] = 3] = "HIGH";
30
- AudioResamplerQuality[AudioResamplerQuality["VERY_HIGH"] = 4] = "VERY_HIGH";
31
- })(AudioResamplerQuality || (AudioResamplerQuality = {}));
32
- /**
33
- * AudioResampler provides functionality to resample audio data from an input sample rate to
34
- * an output sample rate using the Sox resampling library. It supports multiple channels and
35
- * configurable resampling quality.
36
- */
37
- export class AudioResampler {
38
- /**
39
- * Initializes a new AudioResampler.
40
- *
41
- * @param inputRate - The sample rate of the input audio data (in Hz).
42
- * @param outputRate - The desired sample rate of the output audio data (in Hz).
43
- * @param channels - The number of audio channels (e.g., 1 for mono, 2 for stereo). Defaults to 1.
44
- * @param quality - The quality setting for the resampler. Defaults to
45
- * `AudioResamplerQuality.MEDIUM`.
46
- */
47
- constructor(inputRate, outputRate, channels = 1, quality = AudioResamplerQuality.MEDIUM) {
48
- _AudioResampler_inputRate.set(this, void 0);
49
- _AudioResampler_outputRate.set(this, void 0);
50
- _AudioResampler_channels.set(this, void 0);
51
- _AudioResampler_ffiHandle.set(this, void 0);
52
- __classPrivateFieldSet(this, _AudioResampler_inputRate, inputRate, "f");
53
- __classPrivateFieldSet(this, _AudioResampler_outputRate, outputRate, "f");
54
- __classPrivateFieldSet(this, _AudioResampler_channels, channels, "f");
55
- const req = create(NewSoxResamplerRequestSchema, {
56
- inputRate,
57
- outputRate,
58
- numChannels: channels,
59
- qualityRecipe: quality,
60
- inputDataType: SoxResamplerDataType.SOXR_DATATYPE_INT16I,
61
- outputDataType: SoxResamplerDataType.SOXR_DATATYPE_INT16I,
62
- flags: 0,
63
- });
64
- const res = FfiClient.instance.request({
65
- message: {
66
- case: 'newSoxResampler',
67
- value: req,
68
- },
69
- });
70
- if (res.message.case !== 'resampler') {
71
- throw new Error(res.message.value ?? 'Unknown Error');
72
- }
73
- __classPrivateFieldSet(this, _AudioResampler_ffiHandle, new FfiHandle(res.message.value.handle.id), "f");
1
+ import { create } from "@bufbuild/protobuf";
2
+ import { AudioFrame } from "./audio_frame.js";
3
+ import { FfiClient, FfiHandle } from "./ffi_client.js";
4
+ import {
5
+ FlushSoxResamplerRequestSchema,
6
+ NewSoxResamplerRequestSchema,
7
+ PushSoxResamplerRequestSchema,
8
+ SoxQualityRecipe,
9
+ SoxResamplerDataType
10
+ } from "./proto/audio_frame_pb.js";
11
+ var AudioResamplerQuality = ((AudioResamplerQuality2) => {
12
+ AudioResamplerQuality2[AudioResamplerQuality2["QUICK"] = SoxQualityRecipe.SOXR_QUALITY_QUICK] = "QUICK";
13
+ AudioResamplerQuality2[AudioResamplerQuality2["LOW"] = SoxQualityRecipe.SOXR_QUALITY_LOW] = "LOW";
14
+ AudioResamplerQuality2[AudioResamplerQuality2["MEDIUM"] = SoxQualityRecipe.SOXR_QUALITY_MEDIUM] = "MEDIUM";
15
+ AudioResamplerQuality2[AudioResamplerQuality2["HIGH"] = SoxQualityRecipe.SOXR_QUALITY_HIGH] = "HIGH";
16
+ AudioResamplerQuality2[AudioResamplerQuality2["VERY_HIGH"] = SoxQualityRecipe.SOXR_QUALITY_VERYHIGH] = "VERY_HIGH";
17
+ return AudioResamplerQuality2;
18
+ })(AudioResamplerQuality || {});
19
+ class AudioResampler {
20
+ #inputRate;
21
+ #outputRate;
22
+ #channels;
23
+ #ffiHandle;
24
+ /**
25
+ * Initializes a new AudioResampler.
26
+ *
27
+ * @param inputRate - The sample rate of the input audio data (in Hz).
28
+ * @param outputRate - The desired sample rate of the output audio data (in Hz).
29
+ * @param channels - The number of audio channels (e.g., 1 for mono, 2 for stereo). Defaults to 1.
30
+ * @param quality - The quality setting for the resampler. Defaults to
31
+ * `AudioResamplerQuality.MEDIUM`.
32
+ */
33
+ constructor(inputRate, outputRate, channels = 1, quality = AudioResamplerQuality.MEDIUM) {
34
+ this.#inputRate = inputRate;
35
+ this.#outputRate = outputRate;
36
+ this.#channels = channels;
37
+ const req = create(NewSoxResamplerRequestSchema, {
38
+ inputRate,
39
+ outputRate,
40
+ numChannels: channels,
41
+ qualityRecipe: quality,
42
+ inputDataType: SoxResamplerDataType.SOXR_DATATYPE_INT16I,
43
+ outputDataType: SoxResamplerDataType.SOXR_DATATYPE_INT16I,
44
+ flags: 0
45
+ });
46
+ const res = FfiClient.instance.request({
47
+ message: {
48
+ case: "newSoxResampler",
49
+ value: req
50
+ }
51
+ });
52
+ if (res.message.case !== "resampler") {
53
+ throw new Error(res.message.value ?? "Unknown Error");
54
+ }
55
+ this.#ffiHandle = new FfiHandle(res.message.value.handle.id);
56
+ }
57
+ /**
58
+ * Push audio data into the resampler and retrieve any available resampled data.
59
+ *
60
+ * This method accepts audio data, resamples it according to the configured input and output rates,
61
+ * and returns any resampled data that is available after processing the input.
62
+ *
63
+ * @param data - The audio frame to resample
64
+ *
65
+ * @returns A list of {@link AudioFrame} objects containing the resampled audio data. The list may
66
+ * be empty if no output data is available yet.
67
+ */
68
+ push(data) {
69
+ const req = create(PushSoxResamplerRequestSchema, {
70
+ resamplerHandle: this.#ffiHandle.handle,
71
+ dataPtr: data.protoInfo().dataPtr,
72
+ size: data.data.byteLength
73
+ });
74
+ const res = FfiClient.instance.request({
75
+ message: {
76
+ case: "pushSoxResampler",
77
+ value: req
78
+ }
79
+ });
80
+ if (res.error) {
81
+ throw new Error(res.error);
74
82
  }
75
- /**
76
- * Push audio data into the resampler and retrieve any available resampled data.
77
- *
78
- * This method accepts audio data, resamples it according to the configured input and output rates,
79
- * and returns any resampled data that is available after processing the input.
80
- *
81
- * @param data - The audio frame to resample
82
- *
83
- * @returns A list of {@link AudioFrame} objects containing the resampled audio data. The list may
84
- * be empty if no output data is available yet.
85
- */
86
- push(data) {
87
- const req = create(PushSoxResamplerRequestSchema, {
88
- resamplerHandle: __classPrivateFieldGet(this, _AudioResampler_ffiHandle, "f").handle,
89
- dataPtr: data.protoInfo().dataPtr,
90
- size: data.data.byteLength,
91
- });
92
- const res = FfiClient.instance.request({
93
- message: {
94
- case: 'pushSoxResampler',
95
- value: req,
96
- },
97
- });
98
- if (res.error) {
99
- throw new Error(res.error);
100
- }
101
- if (!res.outputPtr) {
102
- return [];
103
- }
104
- const outputData = FfiClient.instance.copyBuffer(res.outputPtr, res.size);
105
- return [
106
- new AudioFrame(new Int16Array(outputData.buffer), __classPrivateFieldGet(this, _AudioResampler_outputRate, "f"), __classPrivateFieldGet(this, _AudioResampler_channels, "f"), Math.trunc(outputData.length / __classPrivateFieldGet(this, _AudioResampler_channels, "f") / 2)),
107
- ];
83
+ if (!res.outputPtr) {
84
+ return [];
108
85
  }
109
- /**
110
- * Flush any remaining audio data through the resampler and retrieve the resampled data.
111
- *
112
- * @remarks
113
- * This method should be called when no more input data will be provided to ensure that all
114
- * internal buffers are processed and all resampled data is output.
115
- */
116
- flush() {
117
- const req = create(FlushSoxResamplerRequestSchema, {
118
- resamplerHandle: __classPrivateFieldGet(this, _AudioResampler_ffiHandle, "f").handle,
119
- });
120
- const res = FfiClient.instance.request({
121
- message: {
122
- case: 'flushSoxResampler',
123
- value: req,
124
- },
125
- });
126
- if (res.error) {
127
- throw new Error(res.error);
128
- }
129
- if (!res.outputPtr) {
130
- return [];
131
- }
132
- const outputData = FfiClient.instance.copyBuffer(res.outputPtr, res.size);
133
- return [
134
- new AudioFrame(new Int16Array(outputData.buffer), __classPrivateFieldGet(this, _AudioResampler_outputRate, "f"), __classPrivateFieldGet(this, _AudioResampler_channels, "f"), Math.trunc(outputData.length / __classPrivateFieldGet(this, _AudioResampler_channels, "f") / 2)),
135
- ];
86
+ const outputData = FfiClient.instance.copyBuffer(res.outputPtr, res.size);
87
+ return [
88
+ new AudioFrame(
89
+ new Int16Array(outputData.buffer),
90
+ this.#outputRate,
91
+ this.#channels,
92
+ Math.trunc(outputData.length / this.#channels / 2)
93
+ )
94
+ ];
95
+ }
96
+ /**
97
+ * Flush any remaining audio data through the resampler and retrieve the resampled data.
98
+ *
99
+ * @remarks
100
+ * This method should be called when no more input data will be provided to ensure that all
101
+ * internal buffers are processed and all resampled data is output.
102
+ */
103
+ flush() {
104
+ const req = create(FlushSoxResamplerRequestSchema, {
105
+ resamplerHandle: this.#ffiHandle.handle
106
+ });
107
+ const res = FfiClient.instance.request({
108
+ message: {
109
+ case: "flushSoxResampler",
110
+ value: req
111
+ }
112
+ });
113
+ if (res.error) {
114
+ throw new Error(res.error);
136
115
  }
116
+ if (!res.outputPtr) {
117
+ return [];
118
+ }
119
+ const outputData = FfiClient.instance.copyBuffer(res.outputPtr, res.size);
120
+ return [
121
+ new AudioFrame(
122
+ new Int16Array(outputData.buffer),
123
+ this.#outputRate,
124
+ this.#channels,
125
+ Math.trunc(outputData.length / this.#channels / 2)
126
+ )
127
+ ];
128
+ }
137
129
  }
138
- _AudioResampler_inputRate = new WeakMap(), _AudioResampler_outputRate = new WeakMap(), _AudioResampler_channels = new WeakMap(), _AudioResampler_ffiHandle = new WeakMap();
130
+ export {
131
+ AudioResampler,
132
+ AudioResamplerQuality
133
+ };
139
134
  //# sourceMappingURL=audio_resampler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"audio_resampler.js","sourceRoot":"","sources":["../src/audio_resampler.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6CAA6C;AAC7C,EAAE;AACF,sCAAsC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAMvD,OAAO,EACL,8BAA8B,EAC9B,4BAA4B,EAC5B,6BAA6B,EAE7B,oBAAoB,GACrB,MAAM,2BAA2B,CAAC;AAEnC;;;GAGG;AACH,MAAM,CAAN,IAAY,qBAMX;AAND,WAAY,qBAAqB;IAC/B,mEAA2C,CAAA;IAC3C,+DAAuC,CAAA;IACvC,qEAA6C,CAAA;IAC7C,iEAAyC,CAAA;IACzC,2EAAkD,CAAA;AACpD,CAAC,EANW,qBAAqB,KAArB,qBAAqB,QAMhC;AAED;;;;GAIG;AACH,MAAM,OAAO,cAAc;IAMzB;;;;;;;;OAQG;IACH,YACE,SAAiB,EACjB,UAAkB,EAClB,QAAQ,GAAG,CAAC,EACZ,OAAO,GAAG,qBAAqB,CAAC,MAAM;QAlBxC,4CAAmB;QACnB,6CAAoB;QACpB,2CAAkB;QAClB,4CAAsB;QAiBpB,uBAAA,IAAI,6BAAc,SAAS,MAAA,CAAC;QAC5B,uBAAA,IAAI,8BAAe,UAAU,MAAA,CAAC;QAC9B,uBAAA,IAAI,4BAAa,QAAQ,MAAA,CAAC;QAE1B,MAAM,GAAG,GAAG,MAAM,CAAC,4BAA4B,EAAE;YAC/C,SAAS;YACT,UAAU;YACV,WAAW,EAAE,QAAQ;YACrB,aAAa,EAAE,OAAqC;YACpD,aAAa,EAAE,oBAAoB,CAAC,oBAAoB;YACxD,cAAc,EAAE,oBAAoB,CAAC,oBAAoB;YACzD,KAAK,EAAE,CAAC;SACT,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC,OAAO,CAA0B;YAC9D,OAAO,EAAE;gBACP,IAAI,EAAE,iBAAiB;gBACvB,KAAK,EAAE,GAAG;aACX;SACF,CAAC,CAAC;QAEH,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,eAAe,CAAC,CAAC;QACxD,CAAC;QAED,uBAAA,IAAI,6BAAc,IAAI,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,MAAO,CAAC,EAAE,CAAC,MAAA,CAAC;IAChE,CAAC;IAED;;;;;;;;;;OAUG;IACH,IAAI,CAAC,IAAgB;QACnB,MAAM,GAAG,GAAG,MAAM,CAAC,6BAA6B,EAAE;YAChD,eAAe,EAAE,uBAAA,IAAI,iCAAW,CAAC,MAAM;YACvC,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,OAAO;YACjC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU;SAC3B,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC,OAAO,CAA2B;YAC/D,OAAO,EAAE;gBACP,IAAI,EAAE,kBAAkB;gBACxB,KAAK,EAAE,GAAG;aACX;SACF,CAAC,CAAC;QAEH,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YACnB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,UAAU,GAAG,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1E,OAAO;YACL,IAAI,UAAU,CACZ,IAAI,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,EACjC,uBAAA,IAAI,kCAAY,EAChB,uBAAA,IAAI,gCAAU,EACd,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,uBAAA,IAAI,gCAAU,GAAG,CAAC,CAAC,CACnD;SACF,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,KAAK;QACH,MAAM,GAAG,GAAG,MAAM,CAAC,8BAA8B,EAAE;YACjD,eAAe,EAAE,uBAAA,IAAI,iCAAW,CAAC,MAAM;SACxC,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC,OAAO,CAA4B;YAChE,OAAO,EAAE;gBACP,IAAI,EAAE,mBAAmB;gBACzB,KAAK,EAAE,GAAG;aACX;SACF,CAAC,CAAC;QAEH,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YACnB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,UAAU,GAAG,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1E,OAAO;YACL,IAAI,UAAU,CACZ,IAAI,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,EACjC,uBAAA,IAAI,kCAAY,EAChB,uBAAA,IAAI,gCAAU,EACd,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,uBAAA,IAAI,gCAAU,GAAG,CAAC,CAAC,CACnD;SACF,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"sources":["../src/audio_resampler.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { create } from '@bufbuild/protobuf';\nimport { AudioFrame } from './audio_frame.js';\nimport { FfiClient, FfiHandle } from './ffi_client.js';\nimport type {\n FlushSoxResamplerResponse,\n NewSoxResamplerResponse,\n PushSoxResamplerResponse,\n} from './proto/audio_frame_pb.js';\nimport {\n FlushSoxResamplerRequestSchema,\n NewSoxResamplerRequestSchema,\n PushSoxResamplerRequestSchema,\n SoxQualityRecipe,\n SoxResamplerDataType,\n} from './proto/audio_frame_pb.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 = create(NewSoxResamplerRequestSchema, {\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 if (res.message.case !== 'resampler') {\n throw new Error(res.message.value ?? 'Unknown Error');\n }\n\n this.#ffiHandle = new FfiHandle(res.message.value.handle!.id);\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 = create(PushSoxResamplerRequestSchema, {\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 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 /**\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 = create(FlushSoxResamplerRequestSchema, {\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"]}
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var audio_source_exports = {};
20
+ __export(audio_source_exports, {
21
+ AudioSource: () => AudioSource
22
+ });
23
+ module.exports = __toCommonJS(audio_source_exports);
24
+ var import_protobuf = require("@bufbuild/protobuf");
25
+ var import_ffi_client = require("./ffi_client.cjs");
26
+ var import_native = require("./napi/native.cjs");
27
+ var import_audio_frame_pb = require("./proto/audio_frame_pb.cjs");
28
+ class AudioSource {
29
+ constructor(sampleRate, numChannels, queueSize = 1e3) {
30
+ /** @internal */
31
+ this.release = () => {
32
+ };
33
+ this.promise = this.newPromise();
34
+ /** @internal */
35
+ this.timeout = void 0;
36
+ this.sampleRate = sampleRate;
37
+ this.numChannels = numChannels;
38
+ this.queueSize = queueSize;
39
+ this.lastCapture = 0;
40
+ this.currentQueueSize = 0;
41
+ const req = (0, import_protobuf.create)(import_audio_frame_pb.NewAudioSourceRequestSchema, {
42
+ type: import_audio_frame_pb.AudioSourceType.AUDIO_SOURCE_NATIVE,
43
+ sampleRate,
44
+ numChannels,
45
+ queueSizeMs: queueSize
46
+ });
47
+ const res = import_ffi_client.FfiClient.instance.request({
48
+ message: {
49
+ case: "newAudioSource",
50
+ value: req
51
+ }
52
+ });
53
+ this.info = res.source.info;
54
+ this.ffiHandle = new import_native.FfiHandle(res.source.handle.id);
55
+ }
56
+ get queuedDuration() {
57
+ return Math.max(
58
+ this.currentQueueSize - Number(process.hrtime.bigint() / BigInt(1e6)) + this.lastCapture,
59
+ 0
60
+ );
61
+ }
62
+ clearQueue() {
63
+ const req = (0, import_protobuf.create)(import_audio_frame_pb.ClearAudioBufferRequestSchema, {
64
+ sourceHandle: this.ffiHandle.handle
65
+ });
66
+ import_ffi_client.FfiClient.instance.request({
67
+ message: {
68
+ case: "clearAudioBuffer",
69
+ value: req
70
+ }
71
+ });
72
+ this.release();
73
+ }
74
+ /** @internal */
75
+ async newPromise() {
76
+ return new Promise((resolve) => {
77
+ this.release = resolve;
78
+ });
79
+ }
80
+ async waitForPlayout() {
81
+ return this.promise.then(() => {
82
+ this.lastCapture = 0;
83
+ this.currentQueueSize = 0;
84
+ this.promise = this.newPromise();
85
+ });
86
+ }
87
+ async captureFrame(frame) {
88
+ const now = Number(process.hrtime.bigint() / BigInt(1e6));
89
+ const elapsed = this.lastCapture === 0 ? 0 : now - this.lastCapture;
90
+ const frameDurationMs = frame.samplesPerChannel / frame.sampleRate * 1e3;
91
+ this.currentQueueSize += frameDurationMs - elapsed;
92
+ this.lastCapture = now;
93
+ if (this.timeout) {
94
+ clearTimeout(this.timeout);
95
+ }
96
+ this.timeout = setTimeout(this.release, this.currentQueueSize - 50);
97
+ const req = (0, import_protobuf.create)(import_audio_frame_pb.CaptureAudioFrameRequestSchema, {
98
+ sourceHandle: this.ffiHandle.handle,
99
+ buffer: frame.protoInfo()
100
+ });
101
+ const res = import_ffi_client.FfiClient.instance.request({
102
+ message: { case: "captureAudioFrame", value: req }
103
+ });
104
+ const cb = await import_ffi_client.FfiClient.instance.waitFor((ev) => {
105
+ return ev.message.case == "captureAudioFrame" && ev.message.value.asyncId == res.asyncId;
106
+ });
107
+ if (cb.error) {
108
+ throw new Error(cb.error);
109
+ }
110
+ }
111
+ }
112
+ // Annotate the CommonJS export names for ESM import in node:
113
+ 0 && (module.exports = {
114
+ AudioSource
115
+ });
116
+ //# sourceMappingURL=audio_source.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/audio_source.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { create } from '@bufbuild/protobuf';\nimport type { AudioFrame } from './audio_frame.js';\nimport { FfiClient } from './ffi_client.js';\nimport { FfiHandle } from './napi/native.js';\nimport type {\n AudioSourceInfo,\n CaptureAudioFrameCallback,\n CaptureAudioFrameResponse,\n ClearAudioBufferResponse,\n NewAudioSourceResponse,\n} from './proto/audio_frame_pb.js';\nimport {\n AudioSourceType,\n CaptureAudioFrameRequestSchema,\n ClearAudioBufferRequestSchema,\n NewAudioSourceRequestSchema,\n} from './proto/audio_frame_pb.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 release = () => {};\n promise = this.newPromise();\n /** @internal */\n timeout?: ReturnType<typeof setTimeout> = undefined;\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 = create(NewAudioSourceRequestSchema, {\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 = create(ClearAudioBufferRequestSchema, {\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.release();\n }\n\n /** @internal */\n async newPromise() {\n return new Promise<void>((resolve) => {\n this.release = resolve;\n });\n }\n\n async waitForPlayout() {\n return this.promise.then(() => {\n this.lastCapture = 0;\n this.currentQueueSize = 0;\n this.promise = this.newPromise();\n });\n }\n\n async captureFrame(frame: AudioFrame) {\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 += frameDurationMs - elapsed;\n\n this.lastCapture = now;\n\n if (this.timeout) {\n clearTimeout(this.timeout);\n }\n\n // remove 50ms to account for processing time\n // (e.g. using wait_for_playout for very small chunks)\n this.timeout = setTimeout(this.release, this.currentQueueSize - 50);\n\n const req = create(CaptureAudioFrameRequestSchema, {\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"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,sBAAuB;AAEvB,wBAA0B;AAC1B,oBAA0B;AAQ1B,4BAKO;AAEA,MAAM,YAAY;AAAA,EAmBvB,YAAY,YAAoB,aAAqB,YAAY,KAAM;AATvE;AAAA,mBAAU,MAAM;AAAA,IAAC;AACjB,mBAAU,KAAK,WAAW;AAE1B;AAAA,mBAA0C;AAOxC,SAAK,aAAa;AAClB,SAAK,cAAc;AACnB,SAAK,YAAY;AAEjB,SAAK,cAAc;AACnB,SAAK,mBAAmB;AAExB,UAAM,UAAM,wBAAO,mDAA6B;AAAA,MAC9C,MAAM,sCAAgB;AAAA,MACtB;AAAA,MACA;AAAA,MACA,aAAa;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,OAAO,IAAI,OAAQ;AACxB,SAAK,YAAY,IAAI,wBAAU,IAAI,OAAQ,OAAQ,EAAE;AAAA,EACvD;AAAA,EAEA,IAAI,iBAAyB;AAC3B,WAAO,KAAK;AAAA,MACV,KAAK,mBAAmB,OAAO,QAAQ,OAAO,OAAO,IAAI,OAAO,GAAO,CAAC,IAAI,KAAK;AAAA,MACjF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,aAAa;AACX,UAAM,UAAM,wBAAO,qDAA+B;AAAA,MAChD,cAAc,KAAK,UAAU;AAAA,IAC/B,CAAC;AAED,gCAAU,SAAS,QAAkC;AAAA,MACnD,SAAS;AAAA,QACP,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,IACF,CAAC;AAED,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA,EAGA,MAAM,aAAa;AACjB,WAAO,IAAI,QAAc,CAAC,YAAY;AACpC,WAAK,UAAU;AAAA,IACjB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,iBAAiB;AACrB,WAAO,KAAK,QAAQ,KAAK,MAAM;AAC7B,WAAK,cAAc;AACnB,WAAK,mBAAmB;AACxB,WAAK,UAAU,KAAK,WAAW;AAAA,IACjC,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,aAAa,OAAmB;AACpC,UAAM,MAAM,OAAO,QAAQ,OAAO,OAAO,IAAI,OAAO,GAAO,CAAC;AAC5D,UAAM,UAAU,KAAK,gBAAgB,IAAI,IAAI,MAAM,KAAK;AACxD,UAAM,kBAAmB,MAAM,oBAAoB,MAAM,aAAc;AACvE,SAAK,oBAAoB,kBAAkB;AAE3C,SAAK,cAAc;AAEnB,QAAI,KAAK,SAAS;AAChB,mBAAa,KAAK,OAAO;AAAA,IAC3B;AAIA,SAAK,UAAU,WAAW,KAAK,SAAS,KAAK,mBAAmB,EAAE;AAElE,UAAM,UAAM,wBAAO,sDAAgC;AAAA,MACjD,cAAc,KAAK,UAAU;AAAA,MAC7B,QAAQ,MAAM,UAAU;AAAA,IAC1B,CAAC;AAED,UAAM,MAAM,4BAAU,SAAS,QAAmC;AAAA,MAChE,SAAS,EAAE,MAAM,qBAAqB,OAAO,IAAI;AAAA,IACnD,CAAC;AAED,UAAM,KAAK,MAAM,4BAAU,SAAS,QAAmC,CAAC,OAAO;AAC7E,aAAO,GAAG,QAAQ,QAAQ,uBAAuB,GAAG,QAAQ,MAAM,WAAW,IAAI;AAAA,IACnF,CAAC;AAED,QAAI,GAAG,OAAO;AACZ,YAAM,IAAI,MAAM,GAAG,KAAK;AAAA,IAC1B;AAAA,EACF;AACF;","names":[]}
@@ -1,90 +1,97 @@
1
- // SPDX-FileCopyrightText: 2024 LiveKit, Inc.
2
- //
3
- // SPDX-License-Identifier: Apache-2.0
4
- import { create } from '@bufbuild/protobuf';
5
- import { FfiClient } from './ffi_client.js';
6
- import { FfiHandle } from './napi/native.js';
7
- import { AudioSourceType, CaptureAudioFrameRequestSchema, ClearAudioBufferRequestSchema, NewAudioSourceRequestSchema, } from './proto/audio_frame_pb.js';
8
- export class AudioSource {
9
- constructor(sampleRate, numChannels, queueSize = 1000) {
10
- /** @internal */
11
- this.release = () => { };
12
- this.promise = this.newPromise();
13
- /** @internal */
14
- this.timeout = undefined;
15
- this.sampleRate = sampleRate;
16
- this.numChannels = numChannels;
17
- this.queueSize = queueSize;
18
- this.lastCapture = 0;
19
- this.currentQueueSize = 0;
20
- const req = create(NewAudioSourceRequestSchema, {
21
- type: AudioSourceType.AUDIO_SOURCE_NATIVE,
22
- sampleRate: sampleRate,
23
- numChannels: numChannels,
24
- queueSizeMs: queueSize,
25
- });
26
- const res = FfiClient.instance.request({
27
- message: {
28
- case: 'newAudioSource',
29
- value: req,
30
- },
31
- });
32
- this.info = res.source.info;
33
- this.ffiHandle = new FfiHandle(res.source.handle.id);
34
- }
35
- get queuedDuration() {
36
- return Math.max(this.currentQueueSize - Number(process.hrtime.bigint() / 1000000n) + this.lastCapture, 0);
37
- }
38
- clearQueue() {
39
- const req = create(ClearAudioBufferRequestSchema, {
40
- sourceHandle: this.ffiHandle.handle,
41
- });
42
- FfiClient.instance.request({
43
- message: {
44
- case: 'clearAudioBuffer',
45
- value: req,
46
- },
47
- });
48
- this.release();
49
- }
1
+ import { create } from "@bufbuild/protobuf";
2
+ import { FfiClient } from "./ffi_client.js";
3
+ import { FfiHandle } from "./napi/native.js";
4
+ import {
5
+ AudioSourceType,
6
+ CaptureAudioFrameRequestSchema,
7
+ ClearAudioBufferRequestSchema,
8
+ NewAudioSourceRequestSchema
9
+ } from "./proto/audio_frame_pb.js";
10
+ class AudioSource {
11
+ constructor(sampleRate, numChannels, queueSize = 1e3) {
50
12
  /** @internal */
51
- async newPromise() {
52
- return new Promise((resolve) => {
53
- this.release = resolve;
54
- });
55
- }
56
- async waitForPlayout() {
57
- return this.promise.then(() => {
58
- this.lastCapture = 0;
59
- this.currentQueueSize = 0;
60
- this.promise = this.newPromise();
61
- });
13
+ this.release = () => {
14
+ };
15
+ this.promise = this.newPromise();
16
+ /** @internal */
17
+ this.timeout = void 0;
18
+ this.sampleRate = sampleRate;
19
+ this.numChannels = numChannels;
20
+ this.queueSize = queueSize;
21
+ this.lastCapture = 0;
22
+ this.currentQueueSize = 0;
23
+ const req = create(NewAudioSourceRequestSchema, {
24
+ type: AudioSourceType.AUDIO_SOURCE_NATIVE,
25
+ sampleRate,
26
+ numChannels,
27
+ queueSizeMs: queueSize
28
+ });
29
+ const res = FfiClient.instance.request({
30
+ message: {
31
+ case: "newAudioSource",
32
+ value: req
33
+ }
34
+ });
35
+ this.info = res.source.info;
36
+ this.ffiHandle = new FfiHandle(res.source.handle.id);
37
+ }
38
+ get queuedDuration() {
39
+ return Math.max(
40
+ this.currentQueueSize - Number(process.hrtime.bigint() / BigInt(1e6)) + this.lastCapture,
41
+ 0
42
+ );
43
+ }
44
+ clearQueue() {
45
+ const req = create(ClearAudioBufferRequestSchema, {
46
+ sourceHandle: this.ffiHandle.handle
47
+ });
48
+ FfiClient.instance.request({
49
+ message: {
50
+ case: "clearAudioBuffer",
51
+ value: req
52
+ }
53
+ });
54
+ this.release();
55
+ }
56
+ /** @internal */
57
+ async newPromise() {
58
+ return new Promise((resolve) => {
59
+ this.release = resolve;
60
+ });
61
+ }
62
+ async waitForPlayout() {
63
+ return this.promise.then(() => {
64
+ this.lastCapture = 0;
65
+ this.currentQueueSize = 0;
66
+ this.promise = this.newPromise();
67
+ });
68
+ }
69
+ async captureFrame(frame) {
70
+ const now = Number(process.hrtime.bigint() / BigInt(1e6));
71
+ const elapsed = this.lastCapture === 0 ? 0 : now - this.lastCapture;
72
+ const frameDurationMs = frame.samplesPerChannel / frame.sampleRate * 1e3;
73
+ this.currentQueueSize += frameDurationMs - elapsed;
74
+ this.lastCapture = now;
75
+ if (this.timeout) {
76
+ clearTimeout(this.timeout);
62
77
  }
63
- async captureFrame(frame) {
64
- const now = Number(process.hrtime.bigint() / 1000000n);
65
- const elapsed = this.lastCapture === 0 ? 0 : now - this.lastCapture;
66
- const frameDurationMs = (frame.samplesPerChannel / frame.sampleRate) * 1000;
67
- this.currentQueueSize += frameDurationMs - elapsed;
68
- this.lastCapture = now;
69
- if (this.timeout) {
70
- clearTimeout(this.timeout);
71
- }
72
- // remove 50ms to account for processing time
73
- // (e.g. using wait_for_playout for very small chunks)
74
- this.timeout = setTimeout(this.release, this.currentQueueSize - 50);
75
- const req = create(CaptureAudioFrameRequestSchema, {
76
- sourceHandle: this.ffiHandle.handle,
77
- buffer: frame.protoInfo(),
78
- });
79
- const res = FfiClient.instance.request({
80
- message: { case: 'captureAudioFrame', value: req },
81
- });
82
- const cb = await FfiClient.instance.waitFor((ev) => {
83
- return ev.message.case == 'captureAudioFrame' && ev.message.value.asyncId == res.asyncId;
84
- });
85
- if (cb.error) {
86
- throw new Error(cb.error);
87
- }
78
+ this.timeout = setTimeout(this.release, this.currentQueueSize - 50);
79
+ const req = create(CaptureAudioFrameRequestSchema, {
80
+ sourceHandle: this.ffiHandle.handle,
81
+ buffer: frame.protoInfo()
82
+ });
83
+ const res = FfiClient.instance.request({
84
+ message: { case: "captureAudioFrame", value: req }
85
+ });
86
+ const cb = await FfiClient.instance.waitFor((ev) => {
87
+ return ev.message.case == "captureAudioFrame" && ev.message.value.asyncId == res.asyncId;
88
+ });
89
+ if (cb.error) {
90
+ throw new Error(cb.error);
88
91
  }
92
+ }
89
93
  }
94
+ export {
95
+ AudioSource
96
+ };
90
97
  //# sourceMappingURL=audio_source.js.map