speechflow 1.6.4 → 1.6.6
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/CHANGELOG.md +22 -0
- package/README.md +28 -3
- package/etc/speechflow.yaml +15 -13
- package/etc/stx.conf +5 -0
- package/package.json +5 -5
- package/speechflow-cli/dst/speechflow-main-api.js +3 -7
- package/speechflow-cli/dst/speechflow-main-api.js.map +1 -1
- package/speechflow-cli/dst/speechflow-main-graph.js +1 -1
- package/speechflow-cli/dst/speechflow-main.js +6 -0
- package/speechflow-cli/dst/speechflow-main.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-compressor-wt.js +1 -21
- package/speechflow-cli/dst/speechflow-node-a2a-compressor-wt.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-compressor.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-compressor.js +12 -11
- package/speechflow-cli/dst/speechflow-node-a2a-compressor.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-expander-wt.js +1 -21
- package/speechflow-cli/dst/speechflow-node-a2a-expander-wt.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-expander.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-expander.js +12 -11
- package/speechflow-cli/dst/speechflow-node-a2a-expander.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-ffmpeg.js +4 -10
- package/speechflow-cli/dst/speechflow-node-a2a-ffmpeg.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-filler.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-filler.js +18 -16
- package/speechflow-cli/dst/speechflow-node-a2a-filler.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-gain.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-gain.js +8 -8
- package/speechflow-cli/dst/speechflow-node-a2a-gain.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-gender.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-gender.js +70 -60
- package/speechflow-cli/dst/speechflow-node-a2a-gender.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-meter.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-meter.js +58 -42
- package/speechflow-cli/dst/speechflow-node-a2a-meter.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-mute.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-mute.js +44 -10
- package/speechflow-cli/dst/speechflow-node-a2a-mute.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-pitch.d.ts +13 -0
- package/speechflow-cli/dst/speechflow-node-a2a-pitch.js +213 -0
- package/speechflow-cli/dst/speechflow-node-a2a-pitch.js.map +1 -0
- package/speechflow-cli/dst/speechflow-node-a2a-pitch2-wt.js +149 -0
- package/speechflow-cli/dst/speechflow-node-a2a-pitch2-wt.js.map +1 -0
- package/speechflow-cli/dst/speechflow-node-a2a-pitch2.d.ts +13 -0
- package/speechflow-cli/dst/speechflow-node-a2a-pitch2.js +202 -0
- package/speechflow-cli/dst/speechflow-node-a2a-pitch2.js.map +1 -0
- package/speechflow-cli/dst/speechflow-node-a2a-rnnoise.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-rnnoise.js +13 -11
- package/speechflow-cli/dst/speechflow-node-a2a-rnnoise.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-speex.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-speex.js +13 -12
- package/speechflow-cli/dst/speechflow-node-a2a-speex.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-vad.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-vad.js +26 -25
- package/speechflow-cli/dst/speechflow-node-a2a-vad.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-wav.js +35 -7
- package/speechflow-cli/dst/speechflow-node-a2a-wav.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-amazon.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-amazon.js +16 -16
- package/speechflow-cli/dst/speechflow-node-a2t-amazon.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-deepgram.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-deepgram.js +16 -16
- package/speechflow-cli/dst/speechflow-node-a2t-deepgram.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-openai.d.ts +1 -2
- package/speechflow-cli/dst/speechflow-node-a2t-openai.js +15 -21
- package/speechflow-cli/dst/speechflow-node-a2t-openai.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-amazon.d.ts +1 -2
- package/speechflow-cli/dst/speechflow-node-t2a-amazon.js +9 -15
- package/speechflow-cli/dst/speechflow-node-t2a-amazon.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.d.ts +1 -2
- package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.js +13 -18
- package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-kokoro.d.ts +0 -1
- package/speechflow-cli/dst/speechflow-node-t2a-kokoro.js +4 -10
- package/speechflow-cli/dst/speechflow-node-t2a-kokoro.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-amazon.js +3 -3
- package/speechflow-cli/dst/speechflow-node-t2t-amazon.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-deepl.js +2 -2
- package/speechflow-cli/dst/speechflow-node-t2t-deepl.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-format.js +36 -2
- package/speechflow-cli/dst/speechflow-node-t2t-format.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-google.js +2 -2
- package/speechflow-cli/dst/speechflow-node-t2t-google.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-modify.js +5 -5
- package/speechflow-cli/dst/speechflow-node-t2t-modify.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-ollama.js +3 -3
- package/speechflow-cli/dst/speechflow-node-t2t-ollama.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-openai.js +2 -2
- package/speechflow-cli/dst/speechflow-node-t2t-openai.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-sentence.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-sentence.js +13 -13
- package/speechflow-cli/dst/speechflow-node-t2t-sentence.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-subtitle.js +8 -8
- package/speechflow-cli/dst/speechflow-node-t2t-subtitle.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-transformers.js +2 -2
- package/speechflow-cli/dst/speechflow-node-t2t-transformers.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-x2x-filter.js +2 -2
- package/speechflow-cli/dst/speechflow-node-x2x-filter.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-x2x-trace.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-x2x-trace.js +42 -8
- package/speechflow-cli/dst/speechflow-node-x2x-trace.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-device.js +6 -4
- package/speechflow-cli/dst/speechflow-node-xio-device.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-file.js +19 -18
- package/speechflow-cli/dst/speechflow-node-xio-file.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-mqtt.js +13 -13
- package/speechflow-cli/dst/speechflow-node-xio-mqtt.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-websocket.js +8 -8
- package/speechflow-cli/dst/speechflow-node-xio-websocket.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node.js +6 -6
- package/speechflow-cli/dst/speechflow-node.js.map +1 -1
- package/speechflow-cli/dst/speechflow-util-audio.d.ts +1 -0
- package/speechflow-cli/dst/speechflow-util-audio.js +22 -1
- package/speechflow-cli/dst/speechflow-util-audio.js.map +1 -1
- package/speechflow-cli/dst/speechflow-util-error.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-util-error.js +7 -1
- package/speechflow-cli/dst/speechflow-util-error.js.map +1 -1
- package/speechflow-cli/dst/speechflow-util-stream.d.ts +2 -1
- package/speechflow-cli/dst/speechflow-util-stream.js +23 -3
- package/speechflow-cli/dst/speechflow-util-stream.js.map +1 -1
- package/speechflow-cli/etc/oxlint.jsonc +2 -1
- package/speechflow-cli/etc/tsconfig.json +1 -0
- package/speechflow-cli/package.json +20 -20
- package/speechflow-cli/src/speechflow-main-api.ts +6 -13
- package/speechflow-cli/src/speechflow-main-graph.ts +1 -1
- package/speechflow-cli/src/speechflow-main.ts +4 -0
- package/speechflow-cli/src/speechflow-node-a2a-compressor-wt.ts +1 -29
- package/speechflow-cli/src/speechflow-node-a2a-compressor.ts +13 -12
- package/speechflow-cli/src/speechflow-node-a2a-expander-wt.ts +1 -29
- package/speechflow-cli/src/speechflow-node-a2a-expander.ts +13 -12
- package/speechflow-cli/src/speechflow-node-a2a-ffmpeg.ts +4 -10
- package/speechflow-cli/src/speechflow-node-a2a-filler.ts +19 -17
- package/speechflow-cli/src/speechflow-node-a2a-gain.ts +8 -8
- package/speechflow-cli/src/speechflow-node-a2a-gender.ts +83 -72
- package/speechflow-cli/src/speechflow-node-a2a-meter.ts +66 -46
- package/speechflow-cli/src/speechflow-node-a2a-mute.ts +11 -10
- package/speechflow-cli/src/speechflow-node-a2a-pitch.ts +221 -0
- package/speechflow-cli/src/speechflow-node-a2a-rnnoise.ts +14 -12
- package/speechflow-cli/src/speechflow-node-a2a-speex.ts +14 -13
- package/speechflow-cli/src/speechflow-node-a2a-vad.ts +26 -25
- package/speechflow-cli/src/speechflow-node-a2a-wav.ts +2 -7
- package/speechflow-cli/src/speechflow-node-a2t-amazon.ts +16 -16
- package/speechflow-cli/src/speechflow-node-a2t-deepgram.ts +16 -16
- package/speechflow-cli/src/speechflow-node-a2t-openai.ts +15 -21
- package/speechflow-cli/src/speechflow-node-t2a-amazon.ts +9 -15
- package/speechflow-cli/src/speechflow-node-t2a-elevenlabs.ts +13 -18
- package/speechflow-cli/src/speechflow-node-t2a-kokoro.ts +4 -10
- package/speechflow-cli/src/speechflow-node-t2t-amazon.ts +3 -3
- package/speechflow-cli/src/speechflow-node-t2t-deepl.ts +2 -2
- package/speechflow-cli/src/speechflow-node-t2t-format.ts +3 -2
- package/speechflow-cli/src/speechflow-node-t2t-google.ts +2 -2
- package/speechflow-cli/src/speechflow-node-t2t-modify.ts +6 -6
- package/speechflow-cli/src/speechflow-node-t2t-ollama.ts +3 -3
- package/speechflow-cli/src/speechflow-node-t2t-openai.ts +2 -2
- package/speechflow-cli/src/speechflow-node-t2t-sentence.ts +13 -13
- package/speechflow-cli/src/speechflow-node-t2t-subtitle.ts +12 -16
- package/speechflow-cli/src/speechflow-node-t2t-transformers.ts +2 -2
- package/speechflow-cli/src/speechflow-node-x2x-filter.ts +2 -2
- package/speechflow-cli/src/speechflow-node-x2x-trace.ts +10 -9
- package/speechflow-cli/src/speechflow-node-xio-device.ts +7 -5
- package/speechflow-cli/src/speechflow-node-xio-file.ts +20 -19
- package/speechflow-cli/src/speechflow-node-xio-mqtt.ts +14 -14
- package/speechflow-cli/src/speechflow-node-xio-websocket.ts +11 -11
- package/speechflow-cli/src/speechflow-node.ts +6 -6
- package/speechflow-cli/src/speechflow-util-audio.ts +31 -1
- package/speechflow-cli/src/speechflow-util-error.ts +9 -3
- package/speechflow-cli/src/speechflow-util-stream.ts +31 -6
- package/speechflow-ui-db/dst/index.js +25 -25
- package/speechflow-ui-db/package.json +11 -11
- package/speechflow-ui-db/src/app.vue +14 -5
- package/speechflow-ui-st/dst/index.js +460 -25
- package/speechflow-ui-st/package.json +13 -13
- package/speechflow-ui-st/src/app.vue +8 -3
- package/speechflow-cli/dst/speechflow-util-webaudio-wt.js +0 -124
- package/speechflow-cli/dst/speechflow-util-webaudio-wt.js.map +0 -1
- package/speechflow-cli/dst/speechflow-util-webaudio.d.ts +0 -13
- package/speechflow-cli/dst/speechflow-util-webaudio.js +0 -137
- package/speechflow-cli/dst/speechflow-util-webaudio.js.map +0 -1
- /package/speechflow-cli/dst/{speechflow-util-webaudio-wt.d.ts → speechflow-node-a2a-pitch2-wt.d.ts} +0 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
** SpeechFlow - Speech Processing Flow Graph
|
|
4
|
+
** Copyright (c) 2024-2025 Dr. Ralf S. Engelschall <rse@engelschall.com>
|
|
5
|
+
** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
41
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
42
|
+
};
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
/* standard dependencies */
|
|
45
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
46
|
+
const node_stream_1 = __importDefault(require("node:stream"));
|
|
47
|
+
/* external dependencies */
|
|
48
|
+
const node_web_audio_api_1 = require("node-web-audio-api");
|
|
49
|
+
/* internal dependencies */
|
|
50
|
+
const speechflow_node_1 = __importDefault(require("./speechflow-node"));
|
|
51
|
+
const util = __importStar(require("./speechflow-util"));
|
|
52
|
+
/* audio pitch shifter class using WebAudio */
|
|
53
|
+
class AudioPitchShifter extends util.WebAudio {
|
|
54
|
+
/* internal state */
|
|
55
|
+
pitchNode = null;
|
|
56
|
+
config;
|
|
57
|
+
/* construct object */
|
|
58
|
+
constructor(sampleRate, channels, config = {}) {
|
|
59
|
+
super(sampleRate, channels);
|
|
60
|
+
this.config = {
|
|
61
|
+
shift: config.shift ?? 1.0,
|
|
62
|
+
frameSize: config.frameSize ?? 2048,
|
|
63
|
+
overlap: config.overlap ?? 0.5
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/* setup object */
|
|
67
|
+
async setup() {
|
|
68
|
+
await super.setup();
|
|
69
|
+
/* add pitch shifter worklet module */
|
|
70
|
+
const url = node_path_1.default.resolve(__dirname, "speechflow-node-a2a-pitch2-wt.js");
|
|
71
|
+
await this.audioContext.audioWorklet.addModule(url);
|
|
72
|
+
/* create pitch shifter worklet node */
|
|
73
|
+
this.pitchNode = new node_web_audio_api_1.AudioWorkletNode(this.audioContext, "pitch-shifter", {
|
|
74
|
+
numberOfInputs: 1,
|
|
75
|
+
numberOfOutputs: 1,
|
|
76
|
+
outputChannelCount: [this.channels],
|
|
77
|
+
processorOptions: {
|
|
78
|
+
shift: this.config.shift,
|
|
79
|
+
frameSize: this.config.frameSize,
|
|
80
|
+
overlap: this.config.overlap
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
/* connect nodes: source -> pitch -> capture */
|
|
84
|
+
this.sourceNode.connect(this.pitchNode);
|
|
85
|
+
this.pitchNode.connect(this.captureNode);
|
|
86
|
+
/* configure initial pitch shift */
|
|
87
|
+
const currentTime = this.audioContext.currentTime;
|
|
88
|
+
const params = this.pitchNode.parameters;
|
|
89
|
+
params.get("shift")?.setValueAtTime(this.config.shift, currentTime);
|
|
90
|
+
}
|
|
91
|
+
/* update pitch shift value */
|
|
92
|
+
setShift(shift) {
|
|
93
|
+
if (this.pitchNode !== null) {
|
|
94
|
+
const currentTime = this.audioContext.currentTime;
|
|
95
|
+
const params = this.pitchNode.parameters;
|
|
96
|
+
params.get("shift")?.setTargetAtTime(shift, currentTime, 0.01);
|
|
97
|
+
}
|
|
98
|
+
this.config.shift = shift;
|
|
99
|
+
}
|
|
100
|
+
/* destroy the pitch shifter */
|
|
101
|
+
async destroy() {
|
|
102
|
+
/* disconnect pitch node */
|
|
103
|
+
if (this.pitchNode !== null) {
|
|
104
|
+
this.pitchNode.disconnect();
|
|
105
|
+
this.pitchNode = null;
|
|
106
|
+
}
|
|
107
|
+
/* destroy parent */
|
|
108
|
+
await super.destroy();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/* SpeechFlow node for pitch adjustment using WebAudio */
|
|
112
|
+
class SpeechFlowNodeA2APitch2 extends speechflow_node_1.default {
|
|
113
|
+
/* declare official node name */
|
|
114
|
+
static name = "a2a-pitch2";
|
|
115
|
+
/* internal state */
|
|
116
|
+
closing = false;
|
|
117
|
+
pitchShifter = null;
|
|
118
|
+
/* construct node */
|
|
119
|
+
constructor(id, cfg, opts, args) {
|
|
120
|
+
super(id, cfg, opts, args);
|
|
121
|
+
/* declare node configuration parameters */
|
|
122
|
+
this.configure({
|
|
123
|
+
shift: { type: "number", val: 1.0, match: (n) => n >= 0.25 && n <= 4.0 },
|
|
124
|
+
frameSize: { type: "number", val: 2048, match: (n) => n >= 256 && n <= 8192 && (n & (n - 1)) === 0 },
|
|
125
|
+
overlap: { type: "number", val: 0.5, match: (n) => n >= 0.0 && n <= 0.9 }
|
|
126
|
+
});
|
|
127
|
+
/* declare node input/output format */
|
|
128
|
+
this.input = "audio";
|
|
129
|
+
this.output = "audio";
|
|
130
|
+
}
|
|
131
|
+
/* open node */
|
|
132
|
+
async open() {
|
|
133
|
+
/* clear destruction flag */
|
|
134
|
+
this.closing = false;
|
|
135
|
+
/* setup pitch shifter */
|
|
136
|
+
this.pitchShifter = new AudioPitchShifter(this.config.audioSampleRate, this.config.audioChannels, {
|
|
137
|
+
shift: this.params.shift,
|
|
138
|
+
frameSize: this.params.frameSize,
|
|
139
|
+
overlap: this.params.overlap
|
|
140
|
+
});
|
|
141
|
+
await this.pitchShifter.setup();
|
|
142
|
+
/* establish a transform stream */
|
|
143
|
+
const self = this;
|
|
144
|
+
this.stream = new node_stream_1.default.Transform({
|
|
145
|
+
readableObjectMode: true,
|
|
146
|
+
writableObjectMode: true,
|
|
147
|
+
decodeStrings: false,
|
|
148
|
+
transform(chunk, encoding, callback) {
|
|
149
|
+
if (self.closing) {
|
|
150
|
+
callback(new Error("stream already destroyed"));
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (!Buffer.isBuffer(chunk.payload))
|
|
154
|
+
callback(new Error("invalid chunk payload type"));
|
|
155
|
+
else {
|
|
156
|
+
/* shift pitch of audio chunk */
|
|
157
|
+
const payload = util.convertBufToI16(chunk.payload, self.config.audioLittleEndian);
|
|
158
|
+
self.pitchShifter?.process(payload).then((result) => {
|
|
159
|
+
if (self.closing)
|
|
160
|
+
throw new Error("stream already destroyed");
|
|
161
|
+
/* take over pitch-shifted data */
|
|
162
|
+
const outputPayload = util.convertI16ToBuf(result, self.config.audioLittleEndian);
|
|
163
|
+
/* final check before pushing to avoid race condition */
|
|
164
|
+
if (self.closing)
|
|
165
|
+
throw new Error("stream already destroyed");
|
|
166
|
+
chunk.payload = outputPayload;
|
|
167
|
+
this.push(chunk);
|
|
168
|
+
callback();
|
|
169
|
+
}).catch((error) => {
|
|
170
|
+
if (!self.closing)
|
|
171
|
+
callback(util.ensureError(error, "pitch shifting failed"));
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
final(callback) {
|
|
176
|
+
if (self.closing) {
|
|
177
|
+
callback();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
this.push(null);
|
|
181
|
+
callback();
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
/* close node */
|
|
186
|
+
async close() {
|
|
187
|
+
/* indicate closing */
|
|
188
|
+
this.closing = true;
|
|
189
|
+
/* destroy pitch shifter */
|
|
190
|
+
if (this.pitchShifter !== null) {
|
|
191
|
+
await this.pitchShifter.destroy();
|
|
192
|
+
this.pitchShifter = null;
|
|
193
|
+
}
|
|
194
|
+
/* shutdown stream */
|
|
195
|
+
if (this.stream !== null) {
|
|
196
|
+
await util.destroyStream(this.stream);
|
|
197
|
+
this.stream = null;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
exports.default = SpeechFlowNodeA2APitch2;
|
|
202
|
+
//# sourceMappingURL=speechflow-node-a2a-pitch2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"speechflow-node-a2a-pitch2.js","sourceRoot":"","sources":["../src/speechflow-node-a2a-pitch2.ts"],"names":[],"mappings":"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"}
|
|
@@ -53,7 +53,7 @@ class SpeechFlowNodeA2ARNNoise extends speechflow_node_1.default {
|
|
|
53
53
|
/* declare official node name */
|
|
54
54
|
static name = "a2a-rnnoise";
|
|
55
55
|
/* internal state */
|
|
56
|
-
|
|
56
|
+
closing = false;
|
|
57
57
|
sampleSize = 480; /* = 10ms at 48KHz, as required by RNNoise! */
|
|
58
58
|
worker = null;
|
|
59
59
|
/* construct node */
|
|
@@ -68,11 +68,12 @@ class SpeechFlowNodeA2ARNNoise extends speechflow_node_1.default {
|
|
|
68
68
|
/* open node */
|
|
69
69
|
async open() {
|
|
70
70
|
/* clear destruction flag */
|
|
71
|
-
this.
|
|
71
|
+
this.closing = false;
|
|
72
72
|
/* initialize worker */
|
|
73
73
|
this.worker = new node_worker_threads_1.Worker((0, node_path_1.resolve)(__dirname, "speechflow-node-a2a-rnnoise-wt.js"));
|
|
74
74
|
this.worker.on("error", (err) => {
|
|
75
75
|
this.log("error", `RNNoise worker thread error: ${err}`);
|
|
76
|
+
this.stream?.emit("error", err);
|
|
76
77
|
});
|
|
77
78
|
this.worker.on("exit", (code) => {
|
|
78
79
|
if (code !== 0)
|
|
@@ -115,7 +116,7 @@ class SpeechFlowNodeA2ARNNoise extends speechflow_node_1.default {
|
|
|
115
116
|
/* send message to worker */
|
|
116
117
|
let seq = 0;
|
|
117
118
|
const workerProcessSegment = async (segment) => {
|
|
118
|
-
if (this.
|
|
119
|
+
if (this.closing)
|
|
119
120
|
return segment;
|
|
120
121
|
const id = `${seq++}`;
|
|
121
122
|
return new Promise((resolve) => {
|
|
@@ -130,7 +131,7 @@ class SpeechFlowNodeA2ARNNoise extends speechflow_node_1.default {
|
|
|
130
131
|
writableObjectMode: true,
|
|
131
132
|
decodeStrings: false,
|
|
132
133
|
transform(chunk, encoding, callback) {
|
|
133
|
-
if (self.
|
|
134
|
+
if (self.closing) {
|
|
134
135
|
callback(new Error("stream already destroyed"));
|
|
135
136
|
return;
|
|
136
137
|
}
|
|
@@ -149,13 +150,14 @@ class SpeechFlowNodeA2ARNNoise extends speechflow_node_1.default {
|
|
|
149
150
|
this.push(chunk);
|
|
150
151
|
callback();
|
|
151
152
|
}).catch((err) => {
|
|
152
|
-
|
|
153
|
-
|
|
153
|
+
const error = util.ensureError(err);
|
|
154
|
+
self.log("warning", `processing of chunk failed: ${error.message}`);
|
|
155
|
+
callback(error);
|
|
154
156
|
});
|
|
155
157
|
}
|
|
156
158
|
},
|
|
157
159
|
final(callback) {
|
|
158
|
-
if (self.
|
|
160
|
+
if (self.closing) {
|
|
159
161
|
callback();
|
|
160
162
|
return;
|
|
161
163
|
}
|
|
@@ -166,16 +168,16 @@ class SpeechFlowNodeA2ARNNoise extends speechflow_node_1.default {
|
|
|
166
168
|
}
|
|
167
169
|
/* close node */
|
|
168
170
|
async close() {
|
|
169
|
-
/* indicate
|
|
170
|
-
this.
|
|
171
|
+
/* indicate closing */
|
|
172
|
+
this.closing = true;
|
|
171
173
|
/* shutdown worker */
|
|
172
174
|
if (this.worker !== null) {
|
|
173
175
|
this.worker.terminate();
|
|
174
176
|
this.worker = null;
|
|
175
177
|
}
|
|
176
|
-
/*
|
|
178
|
+
/* shutdown stream */
|
|
177
179
|
if (this.stream !== null) {
|
|
178
|
-
this.stream
|
|
180
|
+
await util.destroyStream(this.stream);
|
|
179
181
|
this.stream = null;
|
|
180
182
|
}
|
|
181
183
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"speechflow-node-a2a-rnnoise.js","sourceRoot":"","sources":["../src/speechflow-node-a2a-rnnoise.ts"],"names":[],"mappings":";AAAA;;;;EAIE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEF,6BAA6B;AAC7B,8DAA8C;AAC9C,6DAAsD;AACtD,yCAA4C;AAE5C,6BAA6B;AAC7B,wEAAmE;AACnE,wDAAmE;AAEnE,qFAAqF;AACrF,MAAqB,wBAAyB,SAAQ,yBAAc;IAChE,kCAAkC;IAC3B,MAAM,CAAC,IAAI,GAAG,aAAa,CAAA;IAElC,sBAAsB;IACd,
|
|
1
|
+
{"version":3,"file":"speechflow-node-a2a-rnnoise.js","sourceRoot":"","sources":["../src/speechflow-node-a2a-rnnoise.ts"],"names":[],"mappings":"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"}
|
|
@@ -55,7 +55,7 @@ class SpeechFlowNodeA2ASpeex extends speechflow_node_1.default {
|
|
|
55
55
|
/* declare official node name */
|
|
56
56
|
static name = "a2a-speex";
|
|
57
57
|
/* internal state */
|
|
58
|
-
|
|
58
|
+
closing = false;
|
|
59
59
|
sampleSize = 480; /* = 10ms at 48KHz */
|
|
60
60
|
speexProcessor = null;
|
|
61
61
|
/* construct node */
|
|
@@ -72,7 +72,7 @@ class SpeechFlowNodeA2ASpeex extends speechflow_node_1.default {
|
|
|
72
72
|
/* open node */
|
|
73
73
|
async open() {
|
|
74
74
|
/* clear destruction flag */
|
|
75
|
-
this.
|
|
75
|
+
this.closing = false;
|
|
76
76
|
/* validate sample rate compatibility */
|
|
77
77
|
if (this.config.audioSampleRate !== 48000)
|
|
78
78
|
throw new Error(`Speex node requires 48KHz sample rate, got ${this.config.audioSampleRate}Hz`);
|
|
@@ -95,7 +95,7 @@ class SpeechFlowNodeA2ASpeex extends speechflow_node_1.default {
|
|
|
95
95
|
writableObjectMode: true,
|
|
96
96
|
decodeStrings: false,
|
|
97
97
|
transform(chunk, encoding, callback) {
|
|
98
|
-
if (self.
|
|
98
|
+
if (self.closing) {
|
|
99
99
|
callback(new Error("stream already destroyed"));
|
|
100
100
|
return;
|
|
101
101
|
}
|
|
@@ -106,12 +106,12 @@ class SpeechFlowNodeA2ASpeex extends speechflow_node_1.default {
|
|
|
106
106
|
const payload = util.convertBufToI16(chunk.payload);
|
|
107
107
|
/* process Int16Array in necessary fixed-size segments */
|
|
108
108
|
util.processInt16ArrayInSegments(payload, self.sampleSize, (segment) => {
|
|
109
|
-
if (self.
|
|
109
|
+
if (self.closing)
|
|
110
110
|
throw new Error("stream already destroyed");
|
|
111
111
|
self.speexProcessor?.processInt16(segment);
|
|
112
112
|
return Promise.resolve(segment);
|
|
113
113
|
}).then((payload) => {
|
|
114
|
-
if (self.
|
|
114
|
+
if (self.closing)
|
|
115
115
|
throw new Error("stream already destroyed");
|
|
116
116
|
/* convert Int16Array back into Buffer */
|
|
117
117
|
const buf = util.convertI16ToBuf(payload);
|
|
@@ -121,13 +121,14 @@ class SpeechFlowNodeA2ASpeex extends speechflow_node_1.default {
|
|
|
121
121
|
this.push(chunk);
|
|
122
122
|
callback();
|
|
123
123
|
}).catch((err) => {
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
const error = util.ensureError(err);
|
|
125
|
+
self.log("warning", `processing of chunk failed: ${error.message}`);
|
|
126
|
+
callback(error);
|
|
126
127
|
});
|
|
127
128
|
}
|
|
128
129
|
},
|
|
129
130
|
final(callback) {
|
|
130
|
-
if (self.
|
|
131
|
+
if (self.closing) {
|
|
131
132
|
callback();
|
|
132
133
|
return;
|
|
133
134
|
}
|
|
@@ -138,16 +139,16 @@ class SpeechFlowNodeA2ASpeex extends speechflow_node_1.default {
|
|
|
138
139
|
}
|
|
139
140
|
/* close node */
|
|
140
141
|
async close() {
|
|
141
|
-
/* indicate
|
|
142
|
-
this.
|
|
142
|
+
/* indicate closing */
|
|
143
|
+
this.closing = true;
|
|
143
144
|
/* destroy processor */
|
|
144
145
|
if (this.speexProcessor !== null) {
|
|
145
146
|
this.speexProcessor.destroy();
|
|
146
147
|
this.speexProcessor = null;
|
|
147
148
|
}
|
|
148
|
-
/*
|
|
149
|
+
/* shutdown stream */
|
|
149
150
|
if (this.stream !== null) {
|
|
150
|
-
this.stream
|
|
151
|
+
await util.destroyStream(this.stream);
|
|
151
152
|
this.stream = null;
|
|
152
153
|
}
|
|
153
154
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"speechflow-node-a2a-speex.js","sourceRoot":"","sources":["../src/speechflow-node-a2a-speex.ts"],"names":[],"mappings":";AAAA;;;;EAIE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEF,6BAA6B;AAC7B,0DAA4C;AAC5C,sDAA0C;AAC1C,8DAA8C;AAE9C,6BAA6B;AAC7B,6EAAsF;AAEtF,6BAA6B;AAC7B,wEAAmE;AACnE,wDAAmE;AAEnE,mFAAmF;AACnF,MAAqB,sBAAuB,SAAQ,yBAAc;IAC9D,kCAAkC;IAC3B,MAAM,CAAC,IAAI,GAAG,WAAW,CAAA;IAEhC,sBAAsB;IACd,
|
|
1
|
+
{"version":3,"file":"speechflow-node-a2a-speex.js","sourceRoot":"","sources":["../src/speechflow-node-a2a-speex.ts"],"names":[],"mappings":"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"}
|
|
@@ -58,7 +58,7 @@ class SpeechFlowNodeA2AVAD extends speechflow_node_1.default {
|
|
|
58
58
|
queueRecv = this.queue.pointerUse("recv");
|
|
59
59
|
queueVAD = this.queue.pointerUse("vad");
|
|
60
60
|
queueSend = this.queue.pointerUse("send");
|
|
61
|
-
|
|
61
|
+
closing = false;
|
|
62
62
|
tailTimer = null;
|
|
63
63
|
activeEventListeners = new Set();
|
|
64
64
|
/* construct node */
|
|
@@ -84,7 +84,7 @@ class SpeechFlowNodeA2AVAD extends speechflow_node_1.default {
|
|
|
84
84
|
if (this.config.audioBitDepth !== 16 || !this.config.audioLittleEndian)
|
|
85
85
|
throw new Error("VAD node currently supports PCM-S16LE audio only");
|
|
86
86
|
/* clear destruction flag */
|
|
87
|
-
this.
|
|
87
|
+
this.closing = false;
|
|
88
88
|
/* internal processing constants */
|
|
89
89
|
const vadSampleRateTarget = 16000; /* internal target of VAD */
|
|
90
90
|
const vadSamplesPerFrame = 512; /* required for VAD v5 */
|
|
@@ -108,7 +108,7 @@ class SpeechFlowNodeA2AVAD extends speechflow_node_1.default {
|
|
|
108
108
|
redemptionFrames: this.params.redemptionFrames,
|
|
109
109
|
preSpeechPadFrames: this.params.preSpeechPadFrames,
|
|
110
110
|
onSpeechStart: () => {
|
|
111
|
-
if (this.
|
|
111
|
+
if (this.closing)
|
|
112
112
|
return;
|
|
113
113
|
this.log("info", "VAD: speech start");
|
|
114
114
|
if (this.params.mode === "unplugged") {
|
|
@@ -117,7 +117,7 @@ class SpeechFlowNodeA2AVAD extends speechflow_node_1.default {
|
|
|
117
117
|
}
|
|
118
118
|
},
|
|
119
119
|
onSpeechEnd: (audio) => {
|
|
120
|
-
if (this.
|
|
120
|
+
if (this.closing)
|
|
121
121
|
return;
|
|
122
122
|
const duration = util.audioArrayDuration(audio, vadSampleRateTarget);
|
|
123
123
|
this.log("info", `VAD: speech end (duration: ${duration.toFixed(2)}s)`);
|
|
@@ -125,7 +125,7 @@ class SpeechFlowNodeA2AVAD extends speechflow_node_1.default {
|
|
|
125
125
|
tail = true;
|
|
126
126
|
clearTailTimer();
|
|
127
127
|
this.tailTimer = setTimeout(() => {
|
|
128
|
-
if (this.
|
|
128
|
+
if (this.closing || this.tailTimer === null)
|
|
129
129
|
return;
|
|
130
130
|
tail = false;
|
|
131
131
|
this.tailTimer = null;
|
|
@@ -133,14 +133,14 @@ class SpeechFlowNodeA2AVAD extends speechflow_node_1.default {
|
|
|
133
133
|
}
|
|
134
134
|
},
|
|
135
135
|
onVADMisfire: () => {
|
|
136
|
-
if (this.
|
|
136
|
+
if (this.closing)
|
|
137
137
|
return;
|
|
138
138
|
this.log("info", "VAD: speech end (segment too short)");
|
|
139
139
|
if (this.params.mode === "unplugged") {
|
|
140
140
|
tail = true;
|
|
141
141
|
clearTailTimer();
|
|
142
142
|
this.tailTimer = setTimeout(() => {
|
|
143
|
-
if (this.
|
|
143
|
+
if (this.closing || this.tailTimer === null)
|
|
144
144
|
return;
|
|
145
145
|
tail = false;
|
|
146
146
|
this.tailTimer = null;
|
|
@@ -148,7 +148,7 @@ class SpeechFlowNodeA2AVAD extends speechflow_node_1.default {
|
|
|
148
148
|
}
|
|
149
149
|
},
|
|
150
150
|
onFrameProcessed: (audio) => {
|
|
151
|
-
if (this.
|
|
151
|
+
if (this.closing)
|
|
152
152
|
return;
|
|
153
153
|
try {
|
|
154
154
|
/* annotate the current audio segment */
|
|
@@ -167,14 +167,14 @@ class SpeechFlowNodeA2AVAD extends speechflow_node_1.default {
|
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
169
|
catch (error) {
|
|
170
|
-
this.log("error", `VAD frame processing error: ${error}
|
|
170
|
+
this.log("error", `VAD frame processing error: ${error}`, { cause: error });
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
173
|
});
|
|
174
174
|
this.vad.start();
|
|
175
175
|
}
|
|
176
176
|
catch (error) {
|
|
177
|
-
throw new Error(`failed to initialize VAD: ${error}
|
|
177
|
+
throw new Error(`failed to initialize VAD: ${error}`, { cause: error });
|
|
178
178
|
}
|
|
179
179
|
/* provide Duplex stream and internally attach to VAD */
|
|
180
180
|
const self = this;
|
|
@@ -185,7 +185,7 @@ class SpeechFlowNodeA2AVAD extends speechflow_node_1.default {
|
|
|
185
185
|
highWaterMark: 1,
|
|
186
186
|
/* receive audio chunk (writable side of stream) */
|
|
187
187
|
write(chunk, encoding, callback) {
|
|
188
|
-
if (self.
|
|
188
|
+
if (self.closing) {
|
|
189
189
|
callback(new Error("stream already destroyed"));
|
|
190
190
|
return;
|
|
191
191
|
}
|
|
@@ -220,7 +220,7 @@ class SpeechFlowNodeA2AVAD extends speechflow_node_1.default {
|
|
|
220
220
|
segmentIdx: 0, segmentData
|
|
221
221
|
});
|
|
222
222
|
/* push segments through Voice Activity Detection (VAD) */
|
|
223
|
-
if (self.vad && !self.
|
|
223
|
+
if (self.vad && !self.closing) {
|
|
224
224
|
try {
|
|
225
225
|
for (const segment of segmentData)
|
|
226
226
|
self.vad.processAudio(segment.data);
|
|
@@ -232,13 +232,13 @@ class SpeechFlowNodeA2AVAD extends speechflow_node_1.default {
|
|
|
232
232
|
callback();
|
|
233
233
|
}
|
|
234
234
|
catch (error) {
|
|
235
|
-
callback(error
|
|
235
|
+
callback(util.ensureError(error, "VAD processing failed"));
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
238
|
},
|
|
239
239
|
/* receive no more audio chunks (writable side of stream) */
|
|
240
240
|
final(callback) {
|
|
241
|
-
if (self.
|
|
241
|
+
if (self.closing) {
|
|
242
242
|
callback();
|
|
243
243
|
return;
|
|
244
244
|
}
|
|
@@ -248,13 +248,13 @@ class SpeechFlowNodeA2AVAD extends speechflow_node_1.default {
|
|
|
248
248
|
},
|
|
249
249
|
/* send audio chunk(s) (readable side of stream) */
|
|
250
250
|
read(_size) {
|
|
251
|
-
if (self.
|
|
251
|
+
if (self.closing) {
|
|
252
252
|
this.push(null);
|
|
253
253
|
return;
|
|
254
254
|
}
|
|
255
255
|
/* try to perform read operation from scratch */
|
|
256
256
|
const tryToRead = () => {
|
|
257
|
-
if (self.
|
|
257
|
+
if (self.closing) {
|
|
258
258
|
this.push(null);
|
|
259
259
|
return;
|
|
260
260
|
}
|
|
@@ -262,7 +262,7 @@ class SpeechFlowNodeA2AVAD extends speechflow_node_1.default {
|
|
|
262
262
|
const flushPendingChunks = () => {
|
|
263
263
|
let pushed = 0;
|
|
264
264
|
while (true) {
|
|
265
|
-
if (self.
|
|
265
|
+
if (self.closing) {
|
|
266
266
|
this.push(null);
|
|
267
267
|
return;
|
|
268
268
|
}
|
|
@@ -294,7 +294,7 @@ class SpeechFlowNodeA2AVAD extends speechflow_node_1.default {
|
|
|
294
294
|
mode we else would be never called again until
|
|
295
295
|
we at least once push a new chunk as the result */
|
|
296
296
|
setTimeout(() => {
|
|
297
|
-
if (self.
|
|
297
|
+
if (self.closing || self.queue === null)
|
|
298
298
|
return;
|
|
299
299
|
tryToRead();
|
|
300
300
|
}, 0);
|
|
@@ -304,14 +304,15 @@ class SpeechFlowNodeA2AVAD extends speechflow_node_1.default {
|
|
|
304
304
|
};
|
|
305
305
|
/* await forthcoming audio chunks */
|
|
306
306
|
const awaitForthcomingChunks = () => {
|
|
307
|
-
|
|
307
|
+
self.activeEventListeners.delete(awaitForthcomingChunks);
|
|
308
|
+
if (self.closing)
|
|
308
309
|
return;
|
|
309
310
|
const element = self.queueSend.peek();
|
|
310
311
|
if (element !== undefined
|
|
311
312
|
&& element.type === "audio-frame"
|
|
312
313
|
&& element.isSpeech !== undefined)
|
|
313
314
|
flushPendingChunks();
|
|
314
|
-
else if (!self.
|
|
315
|
+
else if (!self.closing && !self.activeEventListeners.has(awaitForthcomingChunks)) {
|
|
315
316
|
self.queue.once("write", awaitForthcomingChunks);
|
|
316
317
|
self.activeEventListeners.add(awaitForthcomingChunks);
|
|
317
318
|
}
|
|
@@ -323,7 +324,7 @@ class SpeechFlowNodeA2AVAD extends speechflow_node_1.default {
|
|
|
323
324
|
&& element.type === "audio-frame"
|
|
324
325
|
&& element.isSpeech !== undefined)
|
|
325
326
|
flushPendingChunks();
|
|
326
|
-
else if (!self.
|
|
327
|
+
else if (!self.closing && !self.activeEventListeners.has(awaitForthcomingChunks)) {
|
|
327
328
|
self.queue.once("write", awaitForthcomingChunks);
|
|
328
329
|
self.activeEventListeners.add(awaitForthcomingChunks);
|
|
329
330
|
}
|
|
@@ -334,8 +335,8 @@ class SpeechFlowNodeA2AVAD extends speechflow_node_1.default {
|
|
|
334
335
|
}
|
|
335
336
|
/* close node */
|
|
336
337
|
async close() {
|
|
337
|
-
/* indicate
|
|
338
|
-
this.
|
|
338
|
+
/* indicate closing */
|
|
339
|
+
this.closing = true;
|
|
339
340
|
/* cleanup tail timer */
|
|
340
341
|
if (this.tailTimer !== null) {
|
|
341
342
|
clearTimeout(this.tailTimer);
|
|
@@ -346,9 +347,9 @@ class SpeechFlowNodeA2AVAD extends speechflow_node_1.default {
|
|
|
346
347
|
this.queue.removeListener("write", listener);
|
|
347
348
|
});
|
|
348
349
|
this.activeEventListeners.clear();
|
|
349
|
-
/*
|
|
350
|
+
/* shutdown stream */
|
|
350
351
|
if (this.stream !== null) {
|
|
351
|
-
this.stream
|
|
352
|
+
await util.destroyStream(this.stream);
|
|
352
353
|
this.stream = null;
|
|
353
354
|
}
|
|
354
355
|
/* cleanup queue pointers before closing VAD to prevent callback access */
|