2

I've searched related questions but wasn't able to find any relevant info.

I'm trying to get the Web Audio API to play an mp3 file which is encoded in another file container, so what I'm doing so far is parsing said container, and feeding the result binary data (arraybuffer) to the audioContext.decodeAudioData method, which supposedly accepts any kind of arraybuffer containing audio data. However, it always throws the error callback.

I only have a faint grasp of what I'm doing so probably the whole approach is wrong. Or maybe it's just not possible.

Has any of you tried something like this before? Any help is appreciated!

Here's some of the code to try to illustrate this better. The following just stores the arraybuffer:

newFile: function(filename){
    var that=this;
    var oReq = new XMLHttpRequest();
    oReq.open("GET", filename, true);
    oReq.responseType = "arraybuffer";
    oReq.onload = function (oEvent) {
      var arrayBuffer = oReq.response; // 
      if (arrayBuffer) {
        that.arrayBuffer=arrayBuffer;
        that.parsed=true;
      }
    };
    oReq.send(null);

And this is what I'm doing in the decoding part:

newTrack: function(tracknumber){
    var that=this;
    var arraybuffer=Parser.arrayBuffer;
    that.audioContext.decodeAudioData(arraybuffer,function(buffer){
        var track={};
        track.trackBuffer=buffer;
        track.isLoaded=true;
        track.trackSource=null;
        track.gainNode=that.audioContext.createGainNode(); 
        that.tracklist.push(track);

        },alert('error'));

Where Parser is an object literal that I've used to parse and store the arraybuffer (which has the newFile function)

So, to sum up, I don't know if I'm doing something wrong or it simply cannot be done.

Stephane Rolland
  • 38,876
  • 35
  • 121
  • 169
poeschl
  • 25
  • 1
  • 4
  • You `error callback` isn't a function your just calling a alert, try wrapping that in an anonymous function. – Musa Jul 30 '13 at 17:19
  • Yes I know, it's there just to check if decodeAudioData works :) – poeschl Jul 30 '13 at 18:16
  • 2
    As you have it the alert will fire regardless of decodeAudioData success or failure. – Musa Jul 30 '13 at 18:19
  • Oh my god, are you kidding? Is that the problem? I don't quite understand why though, shouldn't it fire whatever is on the third parameter if the decoding is not successful? Thanks! i'll try that later – poeschl Jul 30 '13 at 18:30
  • 1
    Nope. You're not passing a function as a callback, you're *invoking* the function immediately, and what's being passed is the return value of the alert, which is undefined. – Kevin Ennis Jul 30 '13 at 18:47
  • Thanks! The problem however is not really solved, since it still doesn't work trying to decode as mp3. Do any of you know if with this approach something like what I explained would be feasible? – poeschl Jul 31 '13 at 17:01

1 Answers1

1

Without the container, I'm not sure how decodeAudioData would know that it's an MP3. Or what the bitrate is. Or how many channels it has. Or a lot of other pretty important information. Basically, you need to tell decodeAudioData how to interpret that ArrayBuffer.

The only thing I could think of on the client side is trying to use a Blob. You'd basically have to write the header yourself, and then readAsArrayBuffer before passing it in to decodeAudioData.

If you're interested in trying that out, here's a spec: http://www.mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm

And here's RecorderJS, which would show you how to create the Blob (although it writes RIFF/WAV headers instead of MP3):

https://github.com/mattdiamond/Recorderjs/blob/master/recorderWorker.js

You'd want to look at the encodeWAV method.

Anyway, I would strongly recommend getting this sorted out on the server instead, if you can.

Kevin Ennis
  • 14,226
  • 2
  • 43
  • 44
  • I sorted this out, in the end the issue was totally unrelated to what I posted, but oddly enough, decodeAudioData doesn't need any kind of indication as to what type of buffer you're passing, so long it's a valid accepted audio element format. I know it should be better done in the server, but this was just an experiment. Anyway, thanks for the input, I'm accepting your answer since it's the only one right now. – poeschl Aug 01 '13 at 18:21