javascriptgoogle-chromehtml5-audiomediastreamcreateobjecturl

Play audio from ajax call using audio.srcObject and a MediaStream


I've implemented an HTTPS endpoint in php that returns mp3 data. Then, after an ajax call in javascript, I play it via the following:

let blob = new Blob([response.value], { type: 'audio/mp3' });

 cleanup = () => {
   // Not 100% sure this is needed:
   audio.src = '';
   // But this is:
   URL.revokeObjectURL(url);
 };

 let url = URL.createObjectURL(blob)
 let audio = new Audio();

 audio.addEventListener('ended', cleanup);

 audio.src = url;

 audio.play();

This seems to be working somewhat, but I'm hitting some browser issues in Fx playback bugs and some Chrome devtools crashes. I assume that maybe these issues are based on my use of URL.createObject(). It sounds like in the future the way to do this will be to set audio.srcObject instead, but it's not ready in Chrome yet, at least not for Blobs. MediaStreams are supported, but I can't find a way to create a MediaStream from the response body of my request.

So, my question: is there a way to play my mp3 using audio.srcObject = someMediaStream? Or do I need to stick with URL.createObjectURL until audio.srcObject = new Blob() is supported? This will only be running in Chrome.


Solution

  • You could create a MediaStream from an AudioElement playing the media from the blob:// URI using the MediaElement.captureStream() method, but that would defeat the purpose since you would still have to play that media on the source <audio> element.

    You could also read your Blob as an ArrayBuffer, then decode this media's audio data using an AudioContext and its decodeAudioData() method, then passing the resulting AudioBuffer to an AudioBufferSourceNode and finally connecting this latter to a MediaStreamSourceNode.

    But... the bugs you describe are most probably not caused by your use of the blob:// URI, which is currently indeed the best way to play an audio media.

    Hopefully someday browsers will implement the specs entirely and we will be able to pass other objects as srcObject, and maybe even see it spread to other elements, but I stopped holding my breath a few years ago...

    So yes, continue to use the blob:// URI, and file reports to chromium's team about their bugs.



    Ps: if you can, setting the src directly to the URL you do fetch using AJAX is actually the best option.