7

I'm new to NodeJS, I'm trying to live stream from mic to MP3 file, the bytes are being written to the MP3 file in real-time and I would like the users to be able to play this MP3 streamed file in real-tile also.

What I did so far to read the stream (with the help of the great community of course) is:


var express     = require('express');
var app         = express();
var fs          = require('fs');

app.listen(3000, function() {
    console.log("[NodeJS] Application Listening on Port 3000");
});

app.get('/stream', function(req, res) {
    var key = req.params.key;

    var music = 'channels/stream-1.mp3';

    var stat = fs.statSync(music);
    range = req.headers.range;
    var readStream;

    if (range !== undefined) {
        var parts = range.replace(/bytes=/, "").split("-");

        var partial_start = parts[0];
        var partial_end = parts[1];

        if ((isNaN(partial_start) && partial_start.length > 1) || (isNaN(partial_end) && partial_end.length > 1)) {
            return res.sendStatus(500); //ERR_INCOMPLETE_CHUNKED_ENCODING
        }

        var start = parseInt(partial_start, 10);
        var end = partial_end ? parseInt(partial_end, 10) : stat.size - 1;
        var content_length = (end - start) + 1;

        res.status(206).header({
            'Content-Type': 'audio/mpeg',
            'Content-Length': content_length,
            'Content-Range': "bytes " + start + "-" + end + "/" + stat.size
        });

        readStream = fs.createReadStream(music, {start: start, end: end});
    } else {
        res.header({
            'Content-Type': 'audio/mpeg',
            'Content-Length': stat.size
        });
        readStream = fs.createReadStream(music);
    }


    readStream.pipe(res);
});

Starting "http://127.0.0.1:3000/stream" plays the stream correctly but only to the bytes that where recorded until the page finished loading, it plays the whole file correctly but then I will need to keep refreshing the page to get and read the new bytes.

What I'm looking for is to be able to play a live stream of that MP3 file where the browser/app detects and plays the new bytes automatically.

I appreciate directing me to what should I do.

tinyCoder
  • 350
  • 13
  • 37
  • 2
    You could do one of the following. Poll constantly using HTTP. Use WebSockets. Use [HLS](https://www.npmjs.com/package/hls-server). – Richard Dunn Nov 28 '19 at 00:13
  • I already made another project with WebSocket, also tried webRTC. But what I need is to read the file the way i mentioned. I will check HLS. – tinyCoder Nov 28 '19 at 08:31
  • Are you going to have some kind of front-end player. Relying on the browser's player might make your goal imposible. I also agree with @RichardDunn, The simplest way might be poling or an embed html5 player of some sort. The issue in your current code is probably du to the fact that the browser's player will read the `Content-length` once as it is downloading the file, not streaming it – Mathieu de Lorimier Nov 29 '19 at 21:07

3 Answers3

0

The reason this is happening is because you are specifying a content-length that is equivalent only to the current size of the mp3 file. So when it reaches that length, it stops sending data and closes the request. Thus, the audio stops playing.

You could try implementing your own streaming protocol, but I don't see much point. If you search the internet you can find all sorts of "live stream servers". Here's one I found that is done using nodejs. Perhaps it will be easy for you to integrate it into your own codebase.

https://www.npmjs.com/package/node-media-server

There's also Icecast, SHOUTcast, and surely a couple others that would work. Of course, those are not built using nodejs. But I don't see why you shouldn't be able to push your data into them as well.

flagoworld
  • 3,196
  • 2
  • 20
  • 16
  • node-media-server is for video streaming, and it doesn't seem to be supporting live broadcasting from mic/camera. – tinyCoder Dec 09 '19 at 19:03
  • Then try one of the non-node audio options, such as Icecast. – flagoworld Dec 10 '19 at 23:01
  • I made a lot of researches, there is nothing clear about how to setup a group audio call, shoutcast and icecast all arround streaming mp3 files. – tinyCoder Dec 11 '19 at 09:36
0

For watch real time changes in a specific folder or file I'm recommend to use: chokidar

Code example:

const watcher = chokidar.watch('file.mp3', {
  ...options
});

watcher.on('change', file => { console.log(`File ${path} has been changed`) })

Now you can listen to the changes and decide how return part of bytes to app/browser.

Fiodorov Andrei
  • 1,778
  • 1
  • 11
  • 26
0

Try removing the Content-Length header and adding Connection: Keep-Alive and Transfer-encoding: chunked.

Maybe this post could be helpful: Are HTTP keep-alive connections possible without content-length headers?

Javier Brea
  • 1,345
  • 12
  • 16
  • Thanks, i tried your solution but it didn't work, i still need to reload everytime to read the new bytes. – tinyCoder Dec 09 '19 at 19:00