Streaming .ogg file as it is created

I'm trying to make a bot play text-to-speech audio over voice chat using a speech synthesizer called RHVoice. When invoked from the command line using child_process.exec(), it takes an input file and converts it into speech, inserting into the audio file as it processes words. If I open this file with something like VLC while it's running it adapts to this "stream" behavior and increases the audio length as new information gets added. However, I don't know how to replicate this behavior with @discordjs/voice AudioResources. Originally I waited until RHVoice generated the entire message before streaming into VC:
fs.writeFileSync("./tts-message.txt", arguments[0]);
exec('RHVoice-test -i tts-message.txt -o tts-voice.ogg', (err) => {
if (err) {
throw new Error(err);
}

let resource = createAudioResource(fs.createReadStream('./tts-voice.ogg', {
inputType: StreamType.OggOpus
}));
ttsPlayer.play(resource);
});
fs.writeFileSync("./tts-message.txt", arguments[0]);
exec('RHVoice-test -i tts-message.txt -o tts-voice.ogg', (err) => {
if (err) {
throw new Error(err);
}

let resource = createAudioResource(fs.createReadStream('./tts-voice.ogg', {
inputType: StreamType.OggOpus
}));
ttsPlayer.play(resource);
});
This works, but for longer messages results in a large delay. If I create and play the AudioResource outside of the exec callback then it just plays the last sent TTS message. Any examples of this "play-as-created" behavior would be helpful. I believe bots which stream from music sites like YouTube do the same thing. Also, RHVoice tries to play using system audio if no output file is specified, so it's possible I could get a virtual audio cable and output that, but then it would be difficult to play speech in more than one server at a time discord.js version 14.15.2, node version 16.17.0
3 Replies
d.js toolkit
d.js toolkit6mo ago
- What's your exact discord.js npm list discord.js and node node -v version? - Not a discord.js issue? Check out #other-js-ts. - Consider reading #how-to-get-help to improve your question! - Explain what exactly your issue is. - Post the full error stack trace, not just the top part! - Show your code! - Issue solved? Press the button! - Marked as resolved by OP
chewie
chewie6mo ago
I have no solution to your problem, but you should update your NodeJS version, as you will at some point crash because of the version. v14.15.2 requires at least v18.0.0
murpyh
murpyhOP6mo ago
Thank you for the suggestion. Just realized my server is already on node v19 and I just updated to latest on my development computer. I ended up solving this using the NPM package tailing-stream, which allows you to create ReadableStreams on files that are still being created. I had to switch the output to mp3 for it to work, as the Opus formats error when the stream is first created. Webm gives this:
errored: Error: Did not find the EBML tag at the start of the stream
at WebmDemuxer._readTag (/home/murpyh/nestmind/node_modules/prism-media/src/core/WebmBase.js:113:18)
at WebmDemuxer._transform (/home/murpyh/nestmind/node_modules/prism-media/src/core/WebmBase.js:47:23)
errored: Error: Did not find the EBML tag at the start of the stream
at WebmDemuxer._readTag (/home/murpyh/nestmind/node_modules/prism-media/src/core/WebmBase.js:113:18)
at WebmDemuxer._transform (/home/murpyh/nestmind/node_modules/prism-media/src/core/WebmBase.js:47:23)
Ogg gives this:
errored: Error: capture_pattern is not OggS
at OggDemuxer._readPage (/home/murpyh/nestmind/node_modules/prism-media/src/opus/OggDemuxer.js:61:13)
at OggDemuxer._transform (/home/murpyh/nestmind/node_modules/prism-media/src/opus/OggDemuxer.js:37:29)
errored: Error: capture_pattern is not OggS
at OggDemuxer._readPage (/home/murpyh/nestmind/node_modules/prism-media/src/opus/OggDemuxer.js:61:13)
at OggDemuxer._transform (/home/murpyh/nestmind/node_modules/prism-media/src/opus/OggDemuxer.js:37:29)
I assume this is because header/footer information needed to identify the file isn't generated until the audio is finished, or maybe FFMPEG just handles this better than the @discordjs/voice demuxers. Not ideal but it works.
Want results from more Discord servers?
Add your server