0

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

enter image description here

and this file i can play on windows machine. Any help?

Sunil Garg
  • 14,608
  • 25
  • 132
  • 189

1 Answers1

-1

You should open that in any audio editor and see properties.

Asterisk do not accept

  1. anything which is not 8khz PCM mono

  2. anything which is compressed or another way not simple

arheops
  • 15,544
  • 1
  • 21
  • 27
  • its shows 16bit 8000HZ 1''58, is this correct? – Sunil Garg Mar 07 '23 at 06:47
  • Check if it is not compressed. But asterisk will work even with incorrect header, if all other body is okay. – arheops Mar 07 '23 at 17:10
  • Also check that file readable by asterisk user(permissions) – arheops Mar 07 '23 at 17:11
  • file is readable , i tried the command that asterisk uses to convert wav to gsm, it is not getting converted.. i updated my question as well , the file i created using streams is showing chunk length error – Sunil Garg Mar 09 '23 at 06:02
  • I think the simplest is to make some files which are without header. Like sln/raw PCM or ulaw. Asterisk can read it. Or you can read wav in some HEX editor, compare with what should be, check source code of your ffmpeg wraper. – arheops Mar 09 '23 at 19:12