Streaming audio from a Node.js server to HTML5 <audio> tag
Asked Answered
S

2

58

I've been experimenting with binary streams in Node.js, and much to my amazement do actually have a working demo of taking a Shoutcast stream using node-radio-stream and pushing it into a HTML5 element using chunked encoding. But it only works in Safari!

Here is my server code:

var radio = require("radio-stream");
var http = require('http');
var url = "http://67.205.85.183:7714";
var stream = radio.createReadStream(url);

var clients = [];

stream.on("connect", function() {
  console.error("Radio Stream connected!");
  console.error(stream.headers);
});


// When a chunk of data is received on the stream, push it to all connected clients
stream.on("data", function (chunk) {
    if (clients.length > 0){
        for (client in clients){
            clients[client].write(chunk);
        };
    }
});

// When a 'metadata' event happens, usually a new song is starting.
stream.on("metadata", function(title) {
  console.error(title);
});

// Listen on a web port and respond with a chunked response header. 
var server = http.createServer(function(req, res){ 
    res.writeHead(200,{
        "Content-Type": "audio/mpeg",
        'Transfer-Encoding': 'chunked'
    });
    // Add the response to the clients array to receive streaming
    clients.push(res);
    console.log('Client connected; streaming'); 
});
server.listen("8000", "127.0.0.1");

console.log('Server running at http://127.0.0.1:8000'); 

My client code is simply:

<audio controls src="http://localhost:8000/"></audio>

This works fine in Safari 5 on the Mac, but doesn't seem to do anything in Chrome or Firefox. Any ideas?

Possible candidates including encoding issues, or just partially-implemented HTML5 features...

Swadeshi answered 17/10, 2010 at 20:19 Comment(3)
Did you ever get this up & running?Vitalize
Yes, check out Nate's answer below for more information.Swadeshi
I'm not sure if this is a silly question, but where does the clients array come into play? I'm trying to replicate this and seem to be struggling.Anathematize
W
21

Here's a (slightly outdated) summary of the current status of HTML5 Audio and Icecast streams.

As you can see, a MP3 source only seems to work in Safari (and possibly IE9). You might need to experiment with some server-side transcoding (with ffmpeg or mencoder) to OGG Vorbis. I'm pretty sure I was able to get Chrome to behave properly when I was sending Vorbis data.

Firefox was still being a brat though, maybe it doesn't like the chunked encoding (all SHOUTcast servers respond with a HTTP/1.0 version response, which hadn't defined Transfer-Encoding: chunked yet). Try sending a Transfer-Encoding: identity response header with the OGG stream to disable chunked, and Firefox MIGHT work. I haven't tested this.

Let me know how it goes! Cheers!

Waldner answered 20/10, 2010 at 17:8 Comment(6)
Thanks! I'm checking out FFMpeg now to give it a try.Swadeshi
I was able to mess around with this a bit last night, and was actually able to get Chrome to play the transcoded OGG Vorbis data! It seemed that ffmpeg couldn't make a proper OGG file from the MP3 stream, but Chrome was still able to play it. I'm also experimenting with invoking lame and oggenc manually, and result seem promising (a nice compliant OGG file). I suspect that Firefox will work with this kind of stream as well. I'll try to make an updated example in the node-radio-stream repo soon!Waldner
Awesome! I just noticed the update on the node list - this is really nice!Swadeshi
For anybody stumbling upon these posts in the future, my node-radio-stream module has been renamed to node-icecast-stack: github.com/TooTallNate/node-icecast-stackWaldner
And once again, now node-icecast-stack has now been renamed to simply node-icecast: github.com/TooTallNate/node-icecastWaldner
@Waldner and now it's just node-icy, eh?Padegs
E
0

There are some solutions for H5 audio only live streaming:

  • HLS or LLHLS: The best compatibility, for Safari, Android, iOS. Now with MSE, Chrome is also able to play HLS by hls.js. Note that the latency is about 10s or larger for audio only stream.
  • HTTP-MP3: It's also widely supported solution, but because mp3 codec is used less and less, now aac and opus is much popular in H5. So, it is NOT recommend to use HTTP-MP3.
  • HTTP-AAC: It's supported by H5 browser, but generally not supported by CDN, so it's OK if you build your own server, but NOT if need a CDN.
  • HTTP-FLV or HTTP-TS: Use flv.js or mpegts.js by MSE. The latency is lower than HLS, and it's possible to use AAC codec, so it's a good solution also.
  • WebRTC: Yep, it's also possible to play the audio only stream by WebRTC.

Note: Opus is also available by HTTP-OGG, but ogg is not support by all browsers, and CDN does not support it, so it's NOT recommend.

Let's take a view for your stream source, however you didn't mention about it:

  • If use H5 to publish your stream, only WebRTC is available now.
  • If use IP camera, you must pull RTSP stream then covert to RTMP by FFmpeg, as such.
  • If use OBS, both RTMP or SRT is OK.

So the best solution maybe use a server(SRS) to convert your stream for player:

publisher(WebRTC, OBS, FFmpeg) 
    --RTMP/WebRTC--> Server(SRS) 
        --HLS/HTTP-FLV/WebRTC--> player(H5 audio)
Economically answered 18/12, 2021 at 3:51 Comment(9)
"but there is no stream like HTTP-AAC or HTTP-OPUS" This is wrong. AAC is encapsulated nicely in ADTS, which has been supported by all the common browsers for a decade or so. And, Opus drops in fine with Ogg or WebM.Jolyn
@Jolyn Thanks for your correction. AAC/ADTS is supported by browsers, by HLS, HTTP-FLV, HTTP-TS and HTTP-AAC. Ogg or WebM is not support by all H5 player, so I think it maybe not a good solution.Economically
@Jolyn For HTTP-AAC, I think H5 support it, but generally AAC/ADTS is carried by HLS/HTTP-FLV/HTTP-TS streaming, especially to use CDN to deliver it. So I think HTTP-AAC is not a good solution.Economically
Hundreds of thousands of internet radio stations streaming AAC with ADTS over HTTP would disagree with you. I assure you, it works fine. :-) And then, there's no overhead with segmented methods such as HLS. No unnecessary added latency. The only benefit is that you get to use file/blob-based CDNs. And nowadays we come full circle with "low latency" HLS, where we just push the packets straight on through to the client anyway. But, that last bit is a rant for another day...Jolyn
@Jolyn Thanks ^_^ Could you please show me a website using HTTP-AAC? Just to confirm how to use file/block-based CDN to deliver it, for live streaming.Economically
dir.xiph.org/codecs/AACJolyn
And, I meant in my comment above... the only benefit to these segmented protocols such as HLS/DASH is that you can use file/blob-based CDNs. For regular progressive HTTP streams, you need compatible CDNs, which are much more rare.Jolyn
@Jolyn Got it. Really thank you for your comment, HTTP-AAC is support by H5 browser, I will update my answer to identify that. And it make sense, the HLS/DASH is friendly for CDN, while HTTP live streaming is not. I think it's possible to use MSE to play HTTP-AAC, just like flv.js do.Economically
You could use MSE, sure, but there's no need to. Simply set the stream URL to the audio element's src attribute.Jolyn

© 2022 - 2025 — McMap. All rights reserved.