@livekit/agents-plugin-silero 0.4.6 → 0.5.0
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.
- package/README.md +17 -0
- package/dist/index.cjs +31 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/onnx_model.cjs +95 -0
- package/dist/onnx_model.cjs.map +1 -0
- package/dist/onnx_model.d.ts.map +1 -1
- package/dist/onnx_model.js +64 -65
- package/dist/onnx_model.js.map +1 -1
- package/dist/onnxruntime.d.cjs +2 -0
- package/dist/onnxruntime.d.cjs.map +1 -0
- package/dist/onnxruntime.d.js +1 -0
- package/dist/onnxruntime.d.js.map +1 -0
- package/dist/vad.cjs +285 -0
- package/dist/vad.cjs.map +1 -0
- package/dist/vad.d.ts +1 -1
- package/dist/vad.d.ts.map +1 -1
- package/dist/vad.js +261 -244
- package/dist/vad.js.map +1 -1
- package/package.json +18 -8
- package/src/onnx_model.ts +2 -1
- package/src/vad.ts +4 -3
package/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
|
3
|
+
|
|
4
|
+
SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
-->
|
|
6
|
+
# Silero plugin for LiveKit Agents
|
|
7
|
+
|
|
8
|
+
The Agents Framework is designed for building realtime, programmable
|
|
9
|
+
participants that run on servers. Use it to create conversational, multi-modal
|
|
10
|
+
voice agents that can see, hear, and understand.
|
|
11
|
+
|
|
12
|
+
This package contains the Silero plugin, providing voice activity detection.
|
|
13
|
+
Refer to the [documentation](https://docs.livekit.io/agents/overview/) for
|
|
14
|
+
information on how to use it, or browse the [API
|
|
15
|
+
reference](https://docs.livekit.io/agents-js/modules/plugins_agents_plugin_silero.html).
|
|
16
|
+
See the [repository](https://github.com/livekit/agents-js) for more information
|
|
17
|
+
about the framework as a whole.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
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 src_exports = {};
|
|
20
|
+
__export(src_exports, {
|
|
21
|
+
VAD: () => import_vad.VAD,
|
|
22
|
+
VADStream: () => import_vad.VADStream
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(src_exports);
|
|
25
|
+
var import_vad = require("./vad.cjs");
|
|
26
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
27
|
+
0 && (module.exports = {
|
|
28
|
+
VAD,
|
|
29
|
+
VADStream
|
|
30
|
+
});
|
|
31
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport { VAD, VADStream } from './vad.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,iBAA+B;","names":[]}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport { VAD, VADStream } from './vad.js';\n"],"mappings":"AAGA,SAAS,KAAK,iBAAiB;","names":[]}
|
|
@@ -0,0 +1,95 @@
|
|
|
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 onnx_model_exports = {};
|
|
20
|
+
__export(onnx_model_exports, {
|
|
21
|
+
OnnxModel: () => OnnxModel,
|
|
22
|
+
newInferenceSession: () => newInferenceSession
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(onnx_model_exports);
|
|
25
|
+
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.src || new URL("main.js", document.baseURI).href;
|
|
26
|
+
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
27
|
+
var import_node_url = require("node:url");
|
|
28
|
+
var import_onnxruntime_node = require("onnxruntime-node");
|
|
29
|
+
const newInferenceSession = (forceCPU) => {
|
|
30
|
+
return import_onnxruntime_node.InferenceSession.create((0, import_node_url.fileURLToPath)(new URL("silero_vad.onnx", importMetaUrl).href), {
|
|
31
|
+
interOpNumThreads: 1,
|
|
32
|
+
intraOpNumThreads: 1,
|
|
33
|
+
executionMode: "sequential",
|
|
34
|
+
executionProviders: forceCPU ? [{ name: "cpu" }] : void 0
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
class OnnxModel {
|
|
38
|
+
#session;
|
|
39
|
+
#sampleRate;
|
|
40
|
+
#windowSizeSamples;
|
|
41
|
+
#contextSize;
|
|
42
|
+
#sampleRateNd;
|
|
43
|
+
#context;
|
|
44
|
+
// #state: Float32Array;
|
|
45
|
+
#rnnState;
|
|
46
|
+
#inputBuffer;
|
|
47
|
+
constructor(session, sampleRate) {
|
|
48
|
+
this.#session = session;
|
|
49
|
+
this.#sampleRate = sampleRate;
|
|
50
|
+
switch (sampleRate) {
|
|
51
|
+
case 8e3:
|
|
52
|
+
this.#windowSizeSamples = 256;
|
|
53
|
+
this.#contextSize = 32;
|
|
54
|
+
break;
|
|
55
|
+
case 16e3:
|
|
56
|
+
this.#windowSizeSamples = 512;
|
|
57
|
+
this.#contextSize = 64;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
this.#sampleRateNd = BigInt64Array.from([BigInt(sampleRate)]);
|
|
61
|
+
this.#context = new Float32Array(this.#contextSize);
|
|
62
|
+
this.#rnnState = new Float32Array(2 * 1 * 128);
|
|
63
|
+
this.#inputBuffer = new Float32Array(this.#contextSize + this.#windowSizeSamples);
|
|
64
|
+
}
|
|
65
|
+
get sampleRate() {
|
|
66
|
+
return this.#sampleRate;
|
|
67
|
+
}
|
|
68
|
+
get windowSizeSamples() {
|
|
69
|
+
return this.#windowSizeSamples;
|
|
70
|
+
}
|
|
71
|
+
get contextSize() {
|
|
72
|
+
return this.#contextSize;
|
|
73
|
+
}
|
|
74
|
+
async run(x) {
|
|
75
|
+
this.#inputBuffer.set(this.#context, 0);
|
|
76
|
+
this.#inputBuffer.set(x, this.#contextSize);
|
|
77
|
+
return await this.#session.run({
|
|
78
|
+
input: new import_onnxruntime_node.Tensor("float32", this.#inputBuffer, [
|
|
79
|
+
1,
|
|
80
|
+
this.#contextSize + this.#windowSizeSamples
|
|
81
|
+
]),
|
|
82
|
+
state: new import_onnxruntime_node.Tensor("float32", this.#rnnState, [2, 1, 128]),
|
|
83
|
+
sr: new import_onnxruntime_node.Tensor("int64", this.#sampleRateNd)
|
|
84
|
+
}).then((result) => {
|
|
85
|
+
this.#context = this.#inputBuffer.subarray(0, this.#contextSize);
|
|
86
|
+
return result.output.data.at(0);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
91
|
+
0 && (module.exports = {
|
|
92
|
+
OnnxModel,
|
|
93
|
+
newInferenceSession
|
|
94
|
+
});
|
|
95
|
+
//# sourceMappingURL=onnx_model.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/onnx_model.ts","../../../node_modules/.pnpm/tsup@8.3.5_@microsoft+api-extractor@7.43.7_@types+node@22.5.5__postcss@8.4.38_tsx@4.19.2_typescript@5.4.5/node_modules/tsup/assets/cjs_shims.js"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { fileURLToPath } from 'node:url';\nimport { InferenceSession, Tensor } from 'onnxruntime-node';\n\nexport type SampleRate = 8000 | 16000;\n\nexport const newInferenceSession = (forceCPU: boolean) => {\n return InferenceSession.create(fileURLToPath(new URL('silero_vad.onnx', import.meta.url).href), {\n interOpNumThreads: 1,\n intraOpNumThreads: 1,\n executionMode: 'sequential',\n executionProviders: forceCPU ? [{ name: 'cpu' }] : undefined,\n });\n};\n\nexport class OnnxModel {\n #session: InferenceSession;\n #sampleRate: number;\n #windowSizeSamples: number;\n #contextSize: number;\n #sampleRateNd: BigInt64Array;\n #context: Float32Array;\n // #state: Float32Array;\n #rnnState: Float32Array;\n #inputBuffer: Float32Array;\n\n constructor(session: InferenceSession, sampleRate: SampleRate) {\n this.#session = session;\n this.#sampleRate = sampleRate;\n\n switch (sampleRate) {\n case 8000:\n this.#windowSizeSamples = 256;\n this.#contextSize = 32;\n break;\n case 16000:\n this.#windowSizeSamples = 512;\n this.#contextSize = 64;\n break;\n }\n\n this.#sampleRateNd = BigInt64Array.from([BigInt(sampleRate)]);\n this.#context = new Float32Array(this.#contextSize);\n this.#rnnState = new Float32Array(2 * 1 * 128);\n this.#inputBuffer = new Float32Array(this.#contextSize + this.#windowSizeSamples);\n }\n\n get sampleRate(): number {\n return this.#sampleRate;\n }\n\n get windowSizeSamples(): number {\n return this.#windowSizeSamples;\n }\n\n get contextSize(): number {\n return this.#contextSize;\n }\n\n async run(x: Float32Array): Promise<number> {\n this.#inputBuffer.set(this.#context, 0);\n this.#inputBuffer.set(x, this.#contextSize);\n\n return await this.#session\n .run({\n input: new Tensor('float32', this.#inputBuffer, [\n 1,\n this.#contextSize + this.#windowSizeSamples,\n ]),\n state: new Tensor('float32', this.#rnnState, [2, 1, 128]),\n sr: new Tensor('int64', this.#sampleRateNd),\n })\n .then((result) => {\n // this.#state = result.output.data as Float32Array,\n this.#context = this.#inputBuffer.subarray(0, this.#contextSize);\n return (result.output!.data as Float32Array).at(0)!;\n });\n }\n}\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () =>\n typeof document === 'undefined'\n ? new URL(`file:${__filename}`).href\n : (document.currentScript && document.currentScript.src) ||\n new URL('main.js', document.baseURI).href\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACKA,IAAM,mBAAmB,MACvB,OAAO,aAAa,cAChB,IAAI,IAAI,QAAQ,UAAU,EAAE,EAAE,OAC7B,SAAS,iBAAiB,SAAS,cAAc,OAClD,IAAI,IAAI,WAAW,SAAS,OAAO,EAAE;AAEpC,IAAM,gBAAgC,iCAAiB;ADR9D,sBAA8B;AAC9B,8BAAyC;AAIlC,MAAM,sBAAsB,CAAC,aAAsB;AACxD,SAAO,yCAAiB,WAAO,+BAAc,IAAI,IAAI,mBAAmB,aAAe,EAAE,IAAI,GAAG;AAAA,IAC9F,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,eAAe;AAAA,IACf,oBAAoB,WAAW,CAAC,EAAE,MAAM,MAAM,CAAC,IAAI;AAAA,EACrD,CAAC;AACH;AAEO,MAAM,UAAU;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EAEA,YAAY,SAA2B,YAAwB;AAC7D,SAAK,WAAW;AAChB,SAAK,cAAc;AAEnB,YAAQ,YAAY;AAAA,MAClB,KAAK;AACH,aAAK,qBAAqB;AAC1B,aAAK,eAAe;AACpB;AAAA,MACF,KAAK;AACH,aAAK,qBAAqB;AAC1B,aAAK,eAAe;AACpB;AAAA,IACJ;AAEA,SAAK,gBAAgB,cAAc,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAC5D,SAAK,WAAW,IAAI,aAAa,KAAK,YAAY;AAClD,SAAK,YAAY,IAAI,aAAa,IAAI,IAAI,GAAG;AAC7C,SAAK,eAAe,IAAI,aAAa,KAAK,eAAe,KAAK,kBAAkB;AAAA,EAClF;AAAA,EAEA,IAAI,aAAqB;AACvB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,oBAA4B;AAC9B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,cAAsB;AACxB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,IAAI,GAAkC;AAC1C,SAAK,aAAa,IAAI,KAAK,UAAU,CAAC;AACtC,SAAK,aAAa,IAAI,GAAG,KAAK,YAAY;AAE1C,WAAO,MAAM,KAAK,SACf,IAAI;AAAA,MACH,OAAO,IAAI,+BAAO,WAAW,KAAK,cAAc;AAAA,QAC9C;AAAA,QACA,KAAK,eAAe,KAAK;AAAA,MAC3B,CAAC;AAAA,MACD,OAAO,IAAI,+BAAO,WAAW,KAAK,WAAW,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA,MACxD,IAAI,IAAI,+BAAO,SAAS,KAAK,aAAa;AAAA,IAC5C,CAAC,EACA,KAAK,CAAC,WAAW;AAEhB,WAAK,WAAW,KAAK,aAAa,SAAS,GAAG,KAAK,YAAY;AAC/D,aAAQ,OAAO,OAAQ,KAAsB,GAAG,CAAC;AAAA,IACnD,CAAC;AAAA,EACL;AACF;","names":[]}
|
package/dist/onnx_model.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"onnx_model.d.ts","sourceRoot":"","sources":["../src/onnx_model.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"onnx_model.d.ts","sourceRoot":"","sources":["../src/onnx_model.ts"],"names":[],"mappings":";AAIA,OAAO,EAAE,gBAAgB,EAAU,MAAM,kBAAkB,CAAC;AAE5D,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,KAAK,CAAC;AAEtC,eAAO,MAAM,mBAAmB,aAAc,OAAO,8BAOpD,CAAC;AAEF,qBAAa,SAAS;;gBAWR,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,UAAU;IAqB7D,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,IAAI,iBAAiB,IAAI,MAAM,CAE9B;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAEK,GAAG,CAAC,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;CAmB5C"}
|
package/dist/onnx_model.js
CHANGED
|
@@ -1,69 +1,68 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
executionProviders: forceCPU ? [{ name: 'cpu' }] : undefined,
|
|
11
|
-
});
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { InferenceSession, Tensor } from "onnxruntime-node";
|
|
3
|
+
const newInferenceSession = (forceCPU) => {
|
|
4
|
+
return InferenceSession.create(fileURLToPath(new URL("silero_vad.onnx", import.meta.url).href), {
|
|
5
|
+
interOpNumThreads: 1,
|
|
6
|
+
intraOpNumThreads: 1,
|
|
7
|
+
executionMode: "sequential",
|
|
8
|
+
executionProviders: forceCPU ? [{ name: "cpu" }] : void 0
|
|
9
|
+
});
|
|
12
10
|
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
this.#sampleRateNd = BigInt64Array.from([BigInt(sampleRate)]);
|
|
37
|
-
this.#context = new Float32Array(this.#contextSize);
|
|
38
|
-
this.#rnnState = new Float32Array(2 * 1 * 128);
|
|
39
|
-
this.#inputBuffer = new Float32Array(this.#contextSize + this.#windowSizeSamples);
|
|
40
|
-
}
|
|
41
|
-
get sampleRate() {
|
|
42
|
-
return this.#sampleRate;
|
|
43
|
-
}
|
|
44
|
-
get windowSizeSamples() {
|
|
45
|
-
return this.#windowSizeSamples;
|
|
46
|
-
}
|
|
47
|
-
get contextSize() {
|
|
48
|
-
return this.#contextSize;
|
|
49
|
-
}
|
|
50
|
-
async run(x) {
|
|
51
|
-
this.#inputBuffer.set(this.#context, 0);
|
|
52
|
-
this.#inputBuffer.set(x, this.#contextSize);
|
|
53
|
-
return await this.#session
|
|
54
|
-
.run({
|
|
55
|
-
input: new Tensor('float32', this.#inputBuffer, [
|
|
56
|
-
1,
|
|
57
|
-
this.#contextSize + this.#windowSizeSamples,
|
|
58
|
-
]),
|
|
59
|
-
state: new Tensor('float32', this.#rnnState, [2, 1, 128]),
|
|
60
|
-
sr: new Tensor('int64', this.#sampleRateNd),
|
|
61
|
-
})
|
|
62
|
-
.then((result) => {
|
|
63
|
-
// this.#state = result.output.data as Float32Array,
|
|
64
|
-
this.#context = this.#inputBuffer.subarray(0, this.#contextSize);
|
|
65
|
-
return result.output.data.at(0);
|
|
66
|
-
});
|
|
11
|
+
class OnnxModel {
|
|
12
|
+
#session;
|
|
13
|
+
#sampleRate;
|
|
14
|
+
#windowSizeSamples;
|
|
15
|
+
#contextSize;
|
|
16
|
+
#sampleRateNd;
|
|
17
|
+
#context;
|
|
18
|
+
// #state: Float32Array;
|
|
19
|
+
#rnnState;
|
|
20
|
+
#inputBuffer;
|
|
21
|
+
constructor(session, sampleRate) {
|
|
22
|
+
this.#session = session;
|
|
23
|
+
this.#sampleRate = sampleRate;
|
|
24
|
+
switch (sampleRate) {
|
|
25
|
+
case 8e3:
|
|
26
|
+
this.#windowSizeSamples = 256;
|
|
27
|
+
this.#contextSize = 32;
|
|
28
|
+
break;
|
|
29
|
+
case 16e3:
|
|
30
|
+
this.#windowSizeSamples = 512;
|
|
31
|
+
this.#contextSize = 64;
|
|
32
|
+
break;
|
|
67
33
|
}
|
|
34
|
+
this.#sampleRateNd = BigInt64Array.from([BigInt(sampleRate)]);
|
|
35
|
+
this.#context = new Float32Array(this.#contextSize);
|
|
36
|
+
this.#rnnState = new Float32Array(2 * 1 * 128);
|
|
37
|
+
this.#inputBuffer = new Float32Array(this.#contextSize + this.#windowSizeSamples);
|
|
38
|
+
}
|
|
39
|
+
get sampleRate() {
|
|
40
|
+
return this.#sampleRate;
|
|
41
|
+
}
|
|
42
|
+
get windowSizeSamples() {
|
|
43
|
+
return this.#windowSizeSamples;
|
|
44
|
+
}
|
|
45
|
+
get contextSize() {
|
|
46
|
+
return this.#contextSize;
|
|
47
|
+
}
|
|
48
|
+
async run(x) {
|
|
49
|
+
this.#inputBuffer.set(this.#context, 0);
|
|
50
|
+
this.#inputBuffer.set(x, this.#contextSize);
|
|
51
|
+
return await this.#session.run({
|
|
52
|
+
input: new Tensor("float32", this.#inputBuffer, [
|
|
53
|
+
1,
|
|
54
|
+
this.#contextSize + this.#windowSizeSamples
|
|
55
|
+
]),
|
|
56
|
+
state: new Tensor("float32", this.#rnnState, [2, 1, 128]),
|
|
57
|
+
sr: new Tensor("int64", this.#sampleRateNd)
|
|
58
|
+
}).then((result) => {
|
|
59
|
+
this.#context = this.#inputBuffer.subarray(0, this.#contextSize);
|
|
60
|
+
return result.output.data.at(0);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
68
63
|
}
|
|
64
|
+
export {
|
|
65
|
+
OnnxModel,
|
|
66
|
+
newInferenceSession
|
|
67
|
+
};
|
|
69
68
|
//# sourceMappingURL=onnx_model.js.map
|
package/dist/onnx_model.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"sources":["../src/onnx_model.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { fileURLToPath } from 'node:url';\nimport { InferenceSession, Tensor } from 'onnxruntime-node';\n\nexport type SampleRate = 8000 | 16000;\n\nexport const newInferenceSession = (forceCPU: boolean) => {\n return InferenceSession.create(fileURLToPath(new URL('silero_vad.onnx', import.meta.url).href), {\n interOpNumThreads: 1,\n intraOpNumThreads: 1,\n executionMode: 'sequential',\n executionProviders: forceCPU ? [{ name: 'cpu' }] : undefined,\n });\n};\n\nexport class OnnxModel {\n #session: InferenceSession;\n #sampleRate: number;\n #windowSizeSamples: number;\n #contextSize: number;\n #sampleRateNd: BigInt64Array;\n #context: Float32Array;\n // #state: Float32Array;\n #rnnState: Float32Array;\n #inputBuffer: Float32Array;\n\n constructor(session: InferenceSession, sampleRate: SampleRate) {\n this.#session = session;\n this.#sampleRate = sampleRate;\n\n switch (sampleRate) {\n case 8000:\n this.#windowSizeSamples = 256;\n this.#contextSize = 32;\n break;\n case 16000:\n this.#windowSizeSamples = 512;\n this.#contextSize = 64;\n break;\n }\n\n this.#sampleRateNd = BigInt64Array.from([BigInt(sampleRate)]);\n this.#context = new Float32Array(this.#contextSize);\n this.#rnnState = new Float32Array(2 * 1 * 128);\n this.#inputBuffer = new Float32Array(this.#contextSize + this.#windowSizeSamples);\n }\n\n get sampleRate(): number {\n return this.#sampleRate;\n }\n\n get windowSizeSamples(): number {\n return this.#windowSizeSamples;\n }\n\n get contextSize(): number {\n return this.#contextSize;\n }\n\n async run(x: Float32Array): Promise<number> {\n this.#inputBuffer.set(this.#context, 0);\n this.#inputBuffer.set(x, this.#contextSize);\n\n return await this.#session\n .run({\n input: new Tensor('float32', this.#inputBuffer, [\n 1,\n this.#contextSize + this.#windowSizeSamples,\n ]),\n state: new Tensor('float32', this.#rnnState, [2, 1, 128]),\n sr: new Tensor('int64', this.#sampleRateNd),\n })\n .then((result) => {\n // this.#state = result.output.data as Float32Array,\n this.#context = this.#inputBuffer.subarray(0, this.#contextSize);\n return (result.output!.data as Float32Array).at(0)!;\n });\n }\n}\n"],"mappings":"AAGA,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB,cAAc;AAIlC,MAAM,sBAAsB,CAAC,aAAsB;AACxD,SAAO,iBAAiB,OAAO,cAAc,IAAI,IAAI,mBAAmB,YAAY,GAAG,EAAE,IAAI,GAAG;AAAA,IAC9F,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,eAAe;AAAA,IACf,oBAAoB,WAAW,CAAC,EAAE,MAAM,MAAM,CAAC,IAAI;AAAA,EACrD,CAAC;AACH;AAEO,MAAM,UAAU;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EAEA,YAAY,SAA2B,YAAwB;AAC7D,SAAK,WAAW;AAChB,SAAK,cAAc;AAEnB,YAAQ,YAAY;AAAA,MAClB,KAAK;AACH,aAAK,qBAAqB;AAC1B,aAAK,eAAe;AACpB;AAAA,MACF,KAAK;AACH,aAAK,qBAAqB;AAC1B,aAAK,eAAe;AACpB;AAAA,IACJ;AAEA,SAAK,gBAAgB,cAAc,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAC5D,SAAK,WAAW,IAAI,aAAa,KAAK,YAAY;AAClD,SAAK,YAAY,IAAI,aAAa,IAAI,IAAI,GAAG;AAC7C,SAAK,eAAe,IAAI,aAAa,KAAK,eAAe,KAAK,kBAAkB;AAAA,EAClF;AAAA,EAEA,IAAI,aAAqB;AACvB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,oBAA4B;AAC9B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,cAAsB;AACxB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,IAAI,GAAkC;AAC1C,SAAK,aAAa,IAAI,KAAK,UAAU,CAAC;AACtC,SAAK,aAAa,IAAI,GAAG,KAAK,YAAY;AAE1C,WAAO,MAAM,KAAK,SACf,IAAI;AAAA,MACH,OAAO,IAAI,OAAO,WAAW,KAAK,cAAc;AAAA,QAC9C;AAAA,QACA,KAAK,eAAe,KAAK;AAAA,MAC3B,CAAC;AAAA,MACD,OAAO,IAAI,OAAO,WAAW,KAAK,WAAW,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA,MACxD,IAAI,IAAI,OAAO,SAAS,KAAK,aAAa;AAAA,IAC5C,CAAC,EACA,KAAK,CAAC,WAAW;AAEhB,WAAK,WAAW,KAAK,aAAa,SAAS,GAAG,KAAK,YAAY;AAC/D,aAAQ,OAAO,OAAQ,KAAsB,GAAG,CAAC;AAAA,IACnD,CAAC;AAAA,EACL;AACF;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=onnxruntime.d.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/vad.cjs
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
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 vad_exports = {};
|
|
20
|
+
__export(vad_exports, {
|
|
21
|
+
VAD: () => VAD,
|
|
22
|
+
VADStream: () => VADStream
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(vad_exports);
|
|
25
|
+
var import_agents = require("@livekit/agents");
|
|
26
|
+
var import_rtc_node = require("@livekit/rtc-node");
|
|
27
|
+
var import_onnx_model = require("./onnx_model.cjs");
|
|
28
|
+
const SLOW_INFERENCE_THRESHOLD = 200;
|
|
29
|
+
const defaultVADOptions = {
|
|
30
|
+
minSpeechDuration: 50,
|
|
31
|
+
minSilenceDuration: 250,
|
|
32
|
+
prefixPaddingDuration: 500,
|
|
33
|
+
maxBufferedSpeech: 6e4,
|
|
34
|
+
activationThreshold: 0.5,
|
|
35
|
+
sampleRate: 16e3,
|
|
36
|
+
forceCPU: true
|
|
37
|
+
};
|
|
38
|
+
class VAD extends import_agents.VAD {
|
|
39
|
+
#session;
|
|
40
|
+
#opts;
|
|
41
|
+
constructor(session, opts) {
|
|
42
|
+
super({ updateInterval: 32 });
|
|
43
|
+
this.#session = session;
|
|
44
|
+
this.#opts = opts;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Load and initialize the Silero VAD model.
|
|
48
|
+
*
|
|
49
|
+
* This method loads the ONNX model and prepares it for inference. When options are not provided,
|
|
50
|
+
* sane defaults are used.
|
|
51
|
+
*
|
|
52
|
+
* @remarks
|
|
53
|
+
* This method may take time to load the model into memory.
|
|
54
|
+
* It is recommended to call this method inside your prewarm mechanism.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* export default defineAgent({
|
|
59
|
+
* prewarm: async (proc: JobProcess) => {
|
|
60
|
+
* proc.userData.vad = await VAD.load();
|
|
61
|
+
* },
|
|
62
|
+
* entry: async (ctx: JobContext) => {
|
|
63
|
+
* const vad = ctx.proc.userData.vad! as VAD;
|
|
64
|
+
* // the rest of your agent logic
|
|
65
|
+
* },
|
|
66
|
+
* });
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* @param options -
|
|
70
|
+
* @returns Promise\<{@link VAD}\>: An instance of the VAD class ready for streaming.
|
|
71
|
+
*/
|
|
72
|
+
static async load(opts = {}) {
|
|
73
|
+
const mergedOpts = { ...defaultVADOptions, ...opts };
|
|
74
|
+
const session = await (0, import_onnx_model.newInferenceSession)(mergedOpts.forceCPU);
|
|
75
|
+
return new VAD(session, mergedOpts);
|
|
76
|
+
}
|
|
77
|
+
stream() {
|
|
78
|
+
return new VADStream(this.#opts, new import_onnx_model.OnnxModel(this.#session, this.#opts.sampleRate));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
class VADStream extends import_agents.VADStream {
|
|
82
|
+
#opts;
|
|
83
|
+
#model;
|
|
84
|
+
#task;
|
|
85
|
+
#expFilter = new import_agents.ExpFilter(0.35);
|
|
86
|
+
#extraInferenceTime = 0;
|
|
87
|
+
#logger = (0, import_agents.log)();
|
|
88
|
+
constructor(opts, model) {
|
|
89
|
+
super();
|
|
90
|
+
this.#opts = opts;
|
|
91
|
+
this.#model = model;
|
|
92
|
+
this.#task = new Promise(async () => {
|
|
93
|
+
let inferenceData = new Float32Array(this.#model.windowSizeSamples);
|
|
94
|
+
let speechBuffer = null;
|
|
95
|
+
let speechBufferMaxReached = false;
|
|
96
|
+
let speechBufferIndex = 0;
|
|
97
|
+
let pubSpeaking = false;
|
|
98
|
+
let pubSpeechDuration = 0;
|
|
99
|
+
let pubSilenceDuration = 0;
|
|
100
|
+
let pubCurrentSample = 0;
|
|
101
|
+
let pubTimestamp = 0;
|
|
102
|
+
let pubSampleRate = 0;
|
|
103
|
+
let pubPrefixPaddingSamples = 0;
|
|
104
|
+
let speechThresholdDuration = 0;
|
|
105
|
+
let silenceThresholdDuration = 0;
|
|
106
|
+
let inputFrames = [];
|
|
107
|
+
let inferenceFrames = [];
|
|
108
|
+
let resampler = null;
|
|
109
|
+
let inputCopyRemainingFrac = 0;
|
|
110
|
+
for await (const frame of this.input) {
|
|
111
|
+
if (typeof frame === "symbol") {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (!pubSampleRate || !speechBuffer) {
|
|
115
|
+
pubSampleRate = frame.sampleRate;
|
|
116
|
+
pubPrefixPaddingSamples = Math.trunc(
|
|
117
|
+
this.#opts.prefixPaddingDuration * pubSampleRate / 1e3
|
|
118
|
+
);
|
|
119
|
+
speechBuffer = new Int16Array(
|
|
120
|
+
this.#opts.maxBufferedSpeech * pubSampleRate + pubPrefixPaddingSamples
|
|
121
|
+
);
|
|
122
|
+
if (this.#opts.sampleRate !== pubSampleRate) {
|
|
123
|
+
resampler = new import_rtc_node.AudioResampler(
|
|
124
|
+
pubSampleRate,
|
|
125
|
+
this.#opts.sampleRate,
|
|
126
|
+
1,
|
|
127
|
+
import_rtc_node.AudioResamplerQuality.QUICK
|
|
128
|
+
// VAD doesn't need high quality
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
} else if (frame.sampleRate !== pubSampleRate) {
|
|
132
|
+
this.#logger.error("a frame with a different sample rate was already published");
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
inputFrames.push(frame);
|
|
136
|
+
if (resampler) {
|
|
137
|
+
inferenceFrames.push(...resampler.push(frame));
|
|
138
|
+
} else {
|
|
139
|
+
inferenceFrames.push(frame);
|
|
140
|
+
}
|
|
141
|
+
while (true) {
|
|
142
|
+
const startTime = process.hrtime.bigint();
|
|
143
|
+
const availableInferenceSamples = inferenceFrames.map((x) => x.samplesPerChannel).reduce((acc, x) => acc + x, 0);
|
|
144
|
+
if (availableInferenceSamples < this.#model.windowSizeSamples) {
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
const inputFrame = (0, import_agents.mergeFrames)(inputFrames);
|
|
148
|
+
const inferenceFrame = (0, import_agents.mergeFrames)(inferenceFrames);
|
|
149
|
+
inferenceData = Float32Array.from(
|
|
150
|
+
inferenceFrame.data.subarray(0, this.#model.windowSizeSamples),
|
|
151
|
+
(x) => x / 32767
|
|
152
|
+
);
|
|
153
|
+
const p = await this.#model.run(inferenceData).then((data) => this.#expFilter.apply(1, data));
|
|
154
|
+
const windowDuration = this.#model.windowSizeSamples / this.#opts.sampleRate * 1e3;
|
|
155
|
+
pubCurrentSample += this.#model.windowSizeSamples;
|
|
156
|
+
pubTimestamp += windowDuration;
|
|
157
|
+
const resamplingRatio = pubSampleRate / this.#model.sampleRate;
|
|
158
|
+
const toCopy = this.#model.windowSizeSamples * resamplingRatio + inputCopyRemainingFrac;
|
|
159
|
+
const toCopyInt = Math.trunc(toCopy);
|
|
160
|
+
inputCopyRemainingFrac = toCopy - toCopyInt;
|
|
161
|
+
const availableSpace = speechBuffer.length - speechBufferIndex;
|
|
162
|
+
const toCopyBuffer = Math.min(this.#model.windowSizeSamples, availableSpace);
|
|
163
|
+
if (toCopyBuffer > 0) {
|
|
164
|
+
speechBuffer.set(inputFrame.data.subarray(0, toCopyBuffer), speechBufferIndex);
|
|
165
|
+
speechBufferIndex += toCopyBuffer;
|
|
166
|
+
} else if (!speechBufferMaxReached) {
|
|
167
|
+
speechBufferMaxReached = true;
|
|
168
|
+
this.#logger.warn(
|
|
169
|
+
"maxBufferedSpeech reached, ignoring further data for the current speech input"
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
const inferenceDuration = Number((process.hrtime.bigint() - startTime) / BigInt(1e6));
|
|
173
|
+
this.#extraInferenceTime = Math.max(
|
|
174
|
+
0,
|
|
175
|
+
this.#extraInferenceTime + inferenceDuration - windowDuration
|
|
176
|
+
);
|
|
177
|
+
if (this.#extraInferenceTime > SLOW_INFERENCE_THRESHOLD) {
|
|
178
|
+
this.#logger.child({ delay: this.#extraInferenceTime }).warn("inference is slower than realtime");
|
|
179
|
+
}
|
|
180
|
+
if (pubSpeaking) {
|
|
181
|
+
pubSpeechDuration += inferenceDuration;
|
|
182
|
+
} else {
|
|
183
|
+
pubSilenceDuration += inferenceDuration;
|
|
184
|
+
}
|
|
185
|
+
this.queue.put({
|
|
186
|
+
type: import_agents.VADEventType.INFERENCE_DONE,
|
|
187
|
+
samplesIndex: pubCurrentSample,
|
|
188
|
+
timestamp: pubTimestamp,
|
|
189
|
+
silenceDuration: pubSilenceDuration,
|
|
190
|
+
speechDuration: pubSpeechDuration,
|
|
191
|
+
probability: p,
|
|
192
|
+
inferenceDuration,
|
|
193
|
+
frames: [
|
|
194
|
+
new import_rtc_node.AudioFrame(inputFrame.data.subarray(0, toCopyInt), pubSampleRate, 1, toCopyInt)
|
|
195
|
+
],
|
|
196
|
+
speaking: pubSpeaking
|
|
197
|
+
});
|
|
198
|
+
const resetWriteCursor = () => {
|
|
199
|
+
if (!speechBuffer) throw new Error("speechBuffer is empty");
|
|
200
|
+
if (speechBufferIndex <= pubPrefixPaddingSamples) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const paddingData = speechBuffer.subarray(
|
|
204
|
+
speechBufferIndex - pubPrefixPaddingSamples,
|
|
205
|
+
speechBufferIndex
|
|
206
|
+
);
|
|
207
|
+
speechBuffer.set(paddingData, 0);
|
|
208
|
+
speechBufferIndex = pubPrefixPaddingSamples;
|
|
209
|
+
speechBufferMaxReached = false;
|
|
210
|
+
};
|
|
211
|
+
const copySpeechBuffer = () => {
|
|
212
|
+
if (!speechBuffer) throw new Error("speechBuffer is empty");
|
|
213
|
+
return new import_rtc_node.AudioFrame(
|
|
214
|
+
speechBuffer.subarray(0, speechBufferIndex),
|
|
215
|
+
pubSampleRate,
|
|
216
|
+
1,
|
|
217
|
+
speechBufferIndex
|
|
218
|
+
);
|
|
219
|
+
};
|
|
220
|
+
if (p > this.#opts.activationThreshold) {
|
|
221
|
+
speechThresholdDuration += windowDuration;
|
|
222
|
+
silenceThresholdDuration = 0;
|
|
223
|
+
if (!pubSpeaking && speechThresholdDuration >= this.#opts.minSpeechDuration) {
|
|
224
|
+
pubSpeaking = true;
|
|
225
|
+
pubSilenceDuration = 0;
|
|
226
|
+
pubSpeechDuration = speechThresholdDuration;
|
|
227
|
+
this.queue.put({
|
|
228
|
+
type: import_agents.VADEventType.START_OF_SPEECH,
|
|
229
|
+
samplesIndex: pubCurrentSample,
|
|
230
|
+
timestamp: pubTimestamp,
|
|
231
|
+
silenceDuration: pubSilenceDuration,
|
|
232
|
+
speechDuration: pubSpeechDuration,
|
|
233
|
+
probability: p,
|
|
234
|
+
inferenceDuration,
|
|
235
|
+
frames: [copySpeechBuffer()],
|
|
236
|
+
speaking: pubSpeaking
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
} else {
|
|
240
|
+
silenceThresholdDuration += windowDuration;
|
|
241
|
+
speechThresholdDuration = 0;
|
|
242
|
+
if (!pubSpeaking) {
|
|
243
|
+
resetWriteCursor();
|
|
244
|
+
}
|
|
245
|
+
if (pubSpeaking && silenceThresholdDuration > this.#opts.minSilenceDuration) {
|
|
246
|
+
pubSpeaking = false;
|
|
247
|
+
pubSpeechDuration = 0;
|
|
248
|
+
pubSilenceDuration = silenceThresholdDuration;
|
|
249
|
+
this.queue.put({
|
|
250
|
+
type: import_agents.VADEventType.END_OF_SPEECH,
|
|
251
|
+
samplesIndex: pubCurrentSample,
|
|
252
|
+
timestamp: pubTimestamp,
|
|
253
|
+
silenceDuration: pubSilenceDuration,
|
|
254
|
+
speechDuration: pubSpeechDuration,
|
|
255
|
+
probability: p,
|
|
256
|
+
inferenceDuration,
|
|
257
|
+
frames: [copySpeechBuffer()],
|
|
258
|
+
speaking: pubSpeaking
|
|
259
|
+
});
|
|
260
|
+
resetWriteCursor();
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
inputFrames = [];
|
|
264
|
+
inferenceFrames = [];
|
|
265
|
+
if (inputFrame.data.length > toCopyInt) {
|
|
266
|
+
const data = inputFrame.data.subarray(toCopyInt);
|
|
267
|
+
inputFrames.push(new import_rtc_node.AudioFrame(data, pubSampleRate, 1, Math.trunc(data.length / 2)));
|
|
268
|
+
}
|
|
269
|
+
if (inferenceFrame.data.length > this.#model.windowSizeSamples) {
|
|
270
|
+
const data = inferenceFrame.data.subarray(this.#model.windowSizeSamples);
|
|
271
|
+
inferenceFrames.push(
|
|
272
|
+
new import_rtc_node.AudioFrame(data, this.#opts.sampleRate, 1, Math.trunc(data.length / 2))
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
281
|
+
0 && (module.exports = {
|
|
282
|
+
VAD,
|
|
283
|
+
VADStream
|
|
284
|
+
});
|
|
285
|
+
//# sourceMappingURL=vad.cjs.map
|