ArtskydJ / node-sox-stream

:mega: A stream-friendly wrapper around SoX
53 stars 14 forks source link

Streams & Pipe resulting in ENOENT #23

Closed redvivi closed 3 years ago

redvivi commented 3 years ago

Hello

I am trying to implement on-the-fly transcoding using Sox in NodeJS, but the code is crashing with:

Error: spawn sox ENOENT at Process.ChildProcess._handle.onexit (internal/child_process.js:267:19) at onErrorNT (internal/child_process.js:469:16) at processTicksAndRejections (internal/process/task_queues.js:84:21) { errno: 'ENOENT', code: 'ENOENT', syscall: 'spawn sox', path: 'sox', spawnargs: [ '/tmp/981152e3-6091-4a32-a7e6-81f1b9157b90', '--type', 'flac', '-' ] }

The issue can be run directly from here : https://repl.it/@VianneyLejeune/Sox.

For your convenience, here is the code:

var sox = require('sox-stream'); // https://npm.io/package/sox-stream
var stream = require("stream");

function TranscodeAudioFromURL(url, callback) {
    var request = require('request');
    return new Promise((resolve, reject) => {
        request({
            url: url,
            encoding: null
        }, function(err, res, body) {
            if (!err && res.statusCode == 200) {
                const src = new stream.Readable(); // Stream for input
                const dest = new stream.Writable(); // Stream for output
                src.push(body); //push of the input audio file to the stream  
                src.push(null); // ending the stream
                src // Piping the output stream to the transcoder
                    .pipe(sox({
                        output: {
                            type: 'flac'
                        }
                    }))
                    .pipe(dest);               
                return resolve(dest); // return converted audio file as stream
            } else
                reject(err);
        });

    });
};

// Calling the transcoder
TranscodeAudioFromURL('https://s3.amazonaws.com/appforest_uf/f1611567418463x165993112458673100/ttsMP3.com_VoiceText_2021-1-25_10_25_1.mp3').then((outputStream) => {
    // "Success!"
    console.log("Transcoded binary"+JSON.stringify(outputStream))
}, reason => {
    // failure
    console.log(reason);
});

Am I missing something?

ArtskydJ commented 3 years ago

Hmmm... I'm not sure you're using the stream correctly.

To pipe in request, you do something like this:

const sox = require('sox-stream') // https://npm.io/package/sox-stream
const stream = require('stream')
const request = require('request')

function TranscodeAudioFromURL(url) {
    const transcode = sox({
       input: {
            type: 'mp3'
        },
        output: {
            type: 'flac'
        }
    })
    return request(url)
        .pipe(transcode)
}

const outputStream = TranscodeAudioFromURL('https://s3.amazonaws.com/appforest_uf/f1611567418463x165993112458673100/ttsMP3.com_VoiceText_2021-1-25_10_25_1.mp3')

const fileStream = require('fs').createWriteStream('./my_new_file.flac')

outputStream.pipe(fileStream)

Even though the request will be running in the background, you can return the stream right away. The stream won't pipe any data until the response comes.

And then you're not handling the stream response correctly either. Maybe the JSON.stringify code was just for debugging?


Sox might not handle mp3's by default. I think that requires some addon, or a recent version of sox.

redvivi commented 3 years ago

Thanks @ArtskydJ for your answer.

In my use-case, I do not output the file stream to a local file, but I need to get a base64 (or binary) stream. So I have refactored the code based on your suggested structure Replit here

const sox = require('sox-stream') // https://npm.io/package/sox-stream
const stream = require('stream')
const request = require('request')

function TranscodeAudioFromURL(url) {
    const transcode = sox({
       input: {
            type: 'mp3'
        },
        output: {
            type: 'flac'
        }
    })
    return request(url)
        .pipe(transcode)
}

const outputStream = TranscodeAudioFromURL('https://s3.amazonaws.com/appforest_uf/f1611567418463x165993112458673100/ttsMP3.com_VoiceText_2021-1-25_10_25_1.mp3')

const fileStream = new stream.Writable();
outputStream.pipe(fileStream);

But the error code is still the same

PS: Yes, the JSON.stringify code was just for debugging.

redvivi commented 3 years ago

Hey @ArtskydJ,

I hope this message finds you well. Had you the chance to have a look at my previous answer ?

Many thanks mate.

ArtskydJ commented 3 years ago

I think repl.it is having trouble finding a sox binary.

const sox = require('sox-stream') // https://npm.io/package/sox-stream
const stream = require('stream')
const request = require('request')
const soxPath = require('sox-bin') // <------------------------------------------------------ try adding this line

function TranscodeAudioFromURL(url) {
    const transcode = sox({
      soxPath, // <----------------------------------------------------------------- and also try adding this line
       input: {
            type: 'mp3'
// ...

Which this doesn't actually make repl.it work. It is having trouble finding libraries for the sox binary. You could install sox on your local machine and see if it works there.

redvivi commented 3 years ago

Correct. The binary couldn't be found and can't be installed in Repl.it.