I am using aws polly for text to speech and generating mp3 out of it, to get the certain wav as asterisk needs wav with specific paramters, I am using fluent-ffmpeg
npm package.
I generated the file by providing the destination path, and returned from the api using sendFile
method on response
. Here is the code
_convertMp3ToWav(mp3Buffer, destPath) {
const { options } = this;
return new Promise((resolve, reject) => {
ffmpeg(mp3Buffer)
.audioFilter(`highpass=f=300, lowpass=f=3400`)
.outputOptions([`-ar 8000`, `-ac 1`]
.output(destPath)
.on('error', (err) => {
log.error(`An error occured: ${err?.message || err?.stack}`);
reject({ err: 'Failed to convert from mp3 to wav' });
})
.on('end', async () => {
log.info(`successfully converted mp3 to wav at ${destPath}`);
resolve({ msg: "voice file generated" });
}).run();
});
}
res.status(200).sendFile(wavFilePath)
file is playable on local machine as well as working on asterisk server.
But i tried to avoid intermediate file generation, generated the stream and returned that stream using res.send(buffer)
Here is the code
_convertMp3ToWav(mp3Buffer) {
return new Promise((resolve, reject) => {
// create a writable output stream to store wav stream
const outputStream = new Stream.Writable();
const buffer = [];
// redefining _write function to write wav stream
outputStream._write = function (chunk, encoding, done) {
buffer.push(chunk);
done();
};
// convert mp3 buffer to wav buffer
ffmpeg(mp3Buffer)
.audioFilter(`highpass=f=300, lowpass=f=3400`)
.outputOptions([`-ar 8000`, `-ac 1`])
.output(outputStream)
.format('wav')
.on('error', (err) => {
log.error(`An error occured: ${err?.message || err?.stack}`);
reject({ err: 'Failed to convert from mp3 to wav' });
})
.on('end', async () => {
try {
// create wav buffer
const wavBuffer = Buffer.concat(buffer);
log.info(`successfully converted mp3 to wav buffer`);
resolve({ wavBuffer });
}
catch (err) {
log.error(`failed to create wav buffer : ${err?.message || err?.stack}`);
reject({ err: 'Failed to create wav buffer' });
}
}).run();
});
}
const buffer = await this._convertMp3ToWav(bufferStream);
res.send(buffer.wavBuffer);
I tried using as well
// set content type to audio/wav
res.set('Content-Type', 'audio/wav');
the file is playable on local but not working on asterisk.
Is there any problem with sending or encoding issues?
Update1
tried writing directly to the res like this
_convertMp3ToWav(mp3Buffer, res) {
return new Promise((resolve, reject) => {
// create a writable output stream to send wav stream in response
const outputStream = new Stream.Writable();
outputStream._write = function (chunk, encoding, done) {
res.write(chunk, encoding);
done();
};
// convert mp3 buffer to wav buffer
ffmpeg(mp3Buffer)
.audioFilter(`highpass=f=300, lowpass=f=3400`)
.outputOptions([`-ar 8000`, `-ac 1`])
.output(outputStream)
.format('wav')
.on('error', (err) => {
reject({ err: 'Failed to convert from mp3 to wav' });
})
.on('end', async () => {
try {
// end the response stream
res.end();
resolve();
}
catch (err) {
reject({ err: 'Failed to send wav buffer in response' });
}
}).run();
});
}
files generated from both functions mentioned in questions are not playable on asterisk, I checked the properties of these files using this website
and both files are showing
at least one of the list chunks has an incorrect length
other properties that asterisk understands are the same
and this file i can play on windows machine. Any help?