11

I've been googling this and looking around stackoverflow for a while but haven't found a solution - hence the post.

I am playing around with Node.js and WebSockets out of curiosity. I am trying to stream some binary data (an mp3) to the client. My code so far is below but is obviously not working as intended.

I suspect that my problem is that I am not actually sending binary data from the server and would like some clarification/help.

Heres my server...

var fs = require('fs');
var WebSocketServer = require('ws').Server;

var wss = new WebSocketServer({port: 8080,host:"127.0.0.1"});
wss.on('connection', function(ws) {    
    var readStream = 
    fs.createReadStream("test.mp3", 
     {'flags': 'r',
      'encoding': 'binary', 
      'mode': 0666, 
      'bufferSize': 64 * 1024});

    readStream.on('data', function(data) {
        ws.send(data, {binary: true, mask: false});
    });
});

And my client...

context = new webkitAudioContext();
var ws = new WebSocket("ws://localhost:8080");
ws.binaryType = 'arraybuffer';

ws.onmessage = function (evt) {
    context.decodeAudioData(
    evt.data,
        function(buffer) {
            console.log("Success");
        }, 
        function(error) {
            console.log("Error");
        });
};

The call to decode always end up in the error callback. I am assuming this is because it is receiving bad data.

So my question is how to I correctly stream the file as binary?

Thanks

fatlog
  • 1,182
  • 2
  • 14
  • 28
  • can you please provide me full example or code for this as I am learning node.js and web sockets and my requirements are also same – Ravi_Parmar Feb 04 '14 at 06:30

2 Answers2

4

What your server is doing is that it is sending messages consisting of binary audio data in 64 KB chunks to your client. Your client should rebuild the audio file before calling decodeAudioData.

You are calling decodeAudioDataevery time your client is getting message on websocket. You have to create a separate buffer to add all the chunks to it. Then on completion of transfer, the buffer should be given input to decodeAudioData.

You have two options now:

  1. You load entire file (fs.read) without using stream events and send the whole file with ws.send (easy to do)
  2. You use stream events, modify your client to accept chunks of data and assemble them before calling decodeAudioData
user568109
  • 47,225
  • 17
  • 99
  • 123
  • Thanks for the feedback. I'll give this a go. I was previously looking at fs.read but don't want to read the file in in one go. – fatlog Mar 26 '13 at 17:03
  • Actually, just thinking about that solution. Does that not mean that its not really streaming the file? I'll be waiting to receive the entire file before I start playing it... – fatlog Mar 26 '13 at 17:59
  • Just an update. I think the issue may be related to... http://stackoverflow.com/questions/10470742/define-valid-mp3-chunk-for-decodeaudiodata-webaudio-api I've tried using readFile instead of createReadSTream and it works perfectly - as in the file is passed and starts playing. Its not streamed however... – fatlog Mar 26 '13 at 22:00
  • I'm still trying to figure out how to create valid chunks however! – fatlog Mar 26 '13 at 22:06
  • OK, I'm getting somewhere. If I just use... fs.createReadStream("test.mp3") (drop the options), the first chunk is received successfully and is played. However all subsequent chunks result in teh error callback being executed on the client... – fatlog Mar 26 '13 at 22:25
0

Problem solved.

I fixed this issue with a combination of removing the "'encoding': 'binary'" parameter from the options passed to "createReadStream()" and the solution at...

decodeAudioData returning a null error

As per some of my comments, when I updated the createReadStream options, the first chunk was playing but all other chunks were executing the onError callback from decodeAudioData(). The solution in the link above fixed this for me. It seems that decodeAudioData() is a bit picky as to how the chunks it receives should be formatted. They should be valid chunks apparently...

Define 'valid mp3 chunk' for decodeAudioData (WebAudio API)

Community
  • 1
  • 1
fatlog
  • 1,182
  • 2
  • 14
  • 28
  • 2
    can you please provide me full example or code for this as I am learning node.js and web sockets and my requirements are audo streaming in html – Ravi_Parmar Feb 04 '14 at 06:31