Skip to content

Instantly share code, notes, and snippets.

@revolunet
Last active June 30, 2024 09:21
Show Gist options
  • Save revolunet/e620e2c532b7144c62768a36b8b96da2 to your computer and use it in GitHub Desktop.
Save revolunet/e620e2c532b7144c62768a36b8b96da2 to your computer and use it in GitHub Desktop.
Web Audio streaming with fetch API
//
// loads remote file using fetch() streams and "pipe" it to webaudio API
// remote file must have CORS enabled if on another domain
//
// mostly from http://stackoverflow.com/questions/20475982/choppy-inaudible-playback-with-chunked-audio-through-web-audio-api
//
function play(url) {
var context = new (window.AudioContext || window.webkitAudioContext)();
var audioStack = [];
var nextTime = 0;
fetch(url).then(function(response) {
var reader = response.body.getReader();
function read() {
return reader.read().then(({ value, done })=> {
context.decodeAudioData(value.buffer, function(buffer) {
audioStack.push(buffer);
if (audioStack.length) {
scheduleBuffers();
}
}, function(err) {
console.log("err(decodeAudioData): "+err);
});
if (done) {
console.log('done');
return;
}
read()
});
}
read();
})
function scheduleBuffers() {
while ( audioStack.length) {
var buffer = audioStack.shift();
var source = context.createBufferSource();
source.buffer = buffer;
source.connect(context.destination);
if (nextTime == 0)
nextTime = context.currentTime + 0.01; /// add 50ms latency to work well across systems - tune this if you like
source.start(nextTime);
nextTime += source.buffer.duration; // Make the next buffer wait the length of the last buffer before being played
};
}
}
var url = 'http://www.metadecks.org/software/sweep/audio/demos/beats1.wav?adazdaz'
play(url);
@revolunet
Copy link
Author

What do you mean doesn't work ?

Can you make à jsfiddle ?

Btw updates code at https://github.com/revolunet/webaudio-wav-stream-player

@quarryman
Copy link

Not to confuse everyone,
reader.read().then( { value, done } ) expects 'value' to be of type Uint8Array according to body.getReader() docs, so it's not meant to have 'buffer' key.
So check it's type before trying to access it's props.

@vitaly-zdanevich
Copy link

I am getting Unable to decode audio data.

@MT00x
Copy link

MT00x commented Oct 25, 2017

I'm getting Uncaught (in promise) DOMException: Unable to decode audio data using your code in Chrome console on http://www.metadecks.org/

@MT00x
Copy link

MT00x commented Oct 26, 2017

I think that decodeAudioData cannot be called without audio header. So the first chunk is decoded, because it has the wav header readed from file, next chunks ( raw pcm in this case ) fails to decode because of the missing header.

@sunYanxl
Copy link

sunYanxl commented May 9, 2018

I tried your example,I also found that "decodeAudioData" cannot be called without audio header,So your example is problematic.

@iamzhanghao
Copy link

iamzhanghao commented Jun 8, 2018

read() can be improved:

function read() {
        return reader.read().then(({ value, done })=> {
          if (done) {
            console.log('done');
            return;
          }else{
            console.log(value,done);
            context.decodeAudioData(value.buffer, function(buffer) {
              audioStack.push(buffer);
              if (audioStack.length) {
                  scheduleBuffers();
              }
            }, function(err) {
              console.log("err(decodeAudioData): "+err);
            });
          }
          read()
        });
      }

Otherwise I get a undefined error

@ttfreeman
Copy link

It works on Chrome but not Firefox. The error on firefox: TypeError: response.body is undefined.

Also, how do we pause this?

@shreyas-jadhav
Copy link

I'm getting Uncaught (in promise) DOMException: Unable to decode audio data using your code in Chrome console on http://www.metadecks.org/

were you able to solve this?

@akhileshpulsemusic
Copy link

any update i am also getting the same issue in firefox ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment