mirror of
https://github.com/rhasspy/espeak-ng.git
synced 2026-11-07 23:31:26 +00:00
Update AudioStream.js
- Verify last bytes of input stream are written to audio output stream before disconnecting audio nodes - Start MediaRecorder before first AudioData is written to audio output stream - Include error handling in disconnect() and abortHandler for abort() called immediately following start() for case of close() called on a closed stream - Check if data set in recorder dataavailable event is defined before calling data.arrayBuffer()
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
|
||||
class AudioStream {
|
||||
constructor({ stdin, recorder = false }) {
|
||||
if (!/^espeak-ng/.test(stdin)) {
|
||||
@@ -73,7 +74,11 @@ class AudioStream {
|
||||
this.audioReadableSignal = audioReadableSignal;
|
||||
this.audioReadableSignal.onabort = (e) => console.log(e.type);
|
||||
this.abortHandler = async (e) => {
|
||||
await this.disconnect(true);
|
||||
try {
|
||||
await this.disconnect(true);
|
||||
} catch (err) {
|
||||
console.warn(err.message);
|
||||
}
|
||||
console.log(
|
||||
`readOffset:${this.readOffset}, duration:${this.duration}, ac.currentTime:${this.ac.currentTime}`,
|
||||
`generator.readyState:${this.generator.readyState}, audioWriter.desiredSize:${this.audioWriter.desiredSize}`,
|
||||
@@ -97,9 +102,13 @@ class AudioStream {
|
||||
this.osc.disconnect();
|
||||
this.outputSource.disconnect();
|
||||
this.track.stop();
|
||||
await this.audioWriter.close();
|
||||
await this.audioWriter.closed;
|
||||
await this.inputReader.cancel();
|
||||
try {
|
||||
await this.audioWriter.close();
|
||||
await this.audioWriter.closed;
|
||||
await this.inputReader.cancel();
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
this.generator.stop();
|
||||
if (this.recorder && this.recorder.state === 'recording') {
|
||||
this.recorder.stop();
|
||||
@@ -158,13 +167,13 @@ class AudioStream {
|
||||
this.init = true;
|
||||
i = 44;
|
||||
}
|
||||
for (;
|
||||
i < value.buffer.byteLength;
|
||||
i++, this.readOffset++
|
||||
) {
|
||||
for (; i < value.buffer.byteLength; i++, this.readOffset++) {
|
||||
if (channelData.length === this.channelDataLength) {
|
||||
this.inputController.enqueue(new Uint8Array(channelData));
|
||||
channelData.length = 0;
|
||||
this.inputController.enqueue(
|
||||
new Uint8Array(
|
||||
channelData.splice(0, this.channelDataLength)
|
||||
)
|
||||
);
|
||||
}
|
||||
channelData.push(value[i]);
|
||||
}
|
||||
@@ -175,7 +184,7 @@ class AudioStream {
|
||||
close: async () => {
|
||||
console.log('Done writing input stream.');
|
||||
if (channelData.length) {
|
||||
this.inputController.enqueue(channelData);
|
||||
this.inputController.enqueue(new Uint8Array(channelData));
|
||||
}
|
||||
this.inputController.close();
|
||||
this.source.postMessage('Done writing input stream.', '*');
|
||||
@@ -186,17 +195,6 @@ class AudioStream {
|
||||
this.audioReadable.pipeTo(
|
||||
new WritableStream({
|
||||
write: async ({ timestamp }) => {
|
||||
if (this.inputController.desiredSize === 0) {
|
||||
await this.disconnect();
|
||||
console.log(
|
||||
`readOffset:${this.readOffset}, duration:${this.duration}, ac.currentTime:${this.ac.currentTime}`,
|
||||
`generator.readyState:${this.generator.readyState}, audioWriter.desiredSize:${this.audioWriter.desiredSize}`
|
||||
);
|
||||
return await Promise.all([
|
||||
new Promise((resolve) => (this.stream.oninactive = resolve)),
|
||||
new Promise((resolve) => (this.ac.onstatechange = resolve)),
|
||||
]);
|
||||
}
|
||||
const { value, done } = await this.inputReader.read();
|
||||
if (done) {
|
||||
console.log({ done });
|
||||
@@ -219,17 +217,35 @@ class AudioStream {
|
||||
buffer.getChannelData(0).set(floats);
|
||||
this.duration += buffer.duration;
|
||||
const frame = new AudioData({
|
||||
format:'FLTP',
|
||||
format: 'FLTP',
|
||||
sampleRate: 22050,
|
||||
numberOfChannels: 1,
|
||||
numberOfFrames: 220,
|
||||
timestamp,
|
||||
data: buffer.getChannelData(0),
|
||||
});
|
||||
await this.audioWriter.write(frame);
|
||||
if (this.recorder && this.recorder.state === 'inactive') {
|
||||
this.recorder.start();
|
||||
}
|
||||
await this.audioWriter.write(frame);
|
||||
if (
|
||||
value.length < this.channelDataLength &&
|
||||
(await this.inputReader.read()).done
|
||||
) {
|
||||
try {
|
||||
await this.disconnect();
|
||||
} catch (err) {
|
||||
console.warn(err.message);
|
||||
}
|
||||
console.log(
|
||||
`readOffset:${this.readOffset}, duration:${this.duration}, ac.currentTime:${this.ac.currentTime}`,
|
||||
`generator.readyState:${this.generator.readyState}, audioWriter.desiredSize:${this.audioWriter.desiredSize}`
|
||||
);
|
||||
return await Promise.all([
|
||||
new Promise((resolve) => (this.stream.oninactive = resolve)),
|
||||
new Promise((resolve) => (this.ac.onstatechange = resolve)),
|
||||
]);
|
||||
}
|
||||
},
|
||||
abort(e) {
|
||||
console.error(e.message);
|
||||
@@ -242,7 +258,9 @@ class AudioStream {
|
||||
),
|
||||
]);
|
||||
this.resolve(
|
||||
this.recorder ? await this.data.arrayBuffer() : 'Done streaming.'
|
||||
this.recorder
|
||||
? this.data && (await this.data.arrayBuffer())
|
||||
: 'Done streaming.'
|
||||
);
|
||||
return this.promise;
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user