My goal is to read an HTTP MP3 audio stream from the browser and have access to the raw audio data.
HTML5 < audio > lets me easily play the stream, but, as far as I know, does not grant access to the raw audio data. It just plays it.
JS XMLHTTPRequest can download files through HTTP and process the raw audio data. It seems to be a good candidate, but it suffers from a limitation: it does not grant access to the binary data until the download is finished (readystate = 4). In my case, the stream is unlimited, so the readystate stays permanently at 3 and the XHR response is null (this behavior is detailed in the mozilla documentation). Note that the cross-origin policy of the server I am connecting to is Access-Control-Allow-Origin: *
Code sample that works for local regular files, but not for streams. I get a null pointer exception at request.response.length
request = new XMLHttpRequest();
//request.open('GET', 'test.mp3', true);
request.open('GET', 'http://domain.com/stream.mp3', true);
request.responseType = 'arraybuffer';
request.onload = function() {
console.log("request onload");
var audioData = request.response;
audioCtx.decodeAudioData(audioData,
function(buffer) { myBuffer = buffer; source.buffer = myBuffer; },
function(e){"Error with decoding audio data" + e.err}
);
}
request.onreadystatechange = function() {
console.log("ready state = " + request.readyState);
console.log(request.response.length);
}
request.send();
Does anybody know alternatives or workarounds to those options, so that the raw binary packets can be read while downloading the stream?
Note that I don't have control on the server. It's an icecast http stream. Also, on the browser side, I'd like to avoid using Flash. Thank you
Edit: to clarify possible cross-origin questions, the JS is run on a page hosted in a localhost server.
The following workaround worked:
As stated in MDN https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data, it is possible to override the MIME type of http request, setting it to custom, and call responseText.
function load_binary_resource(url) {
var req = new XMLHttpRequest();
req.open('GET', url, false);
//XHR binary charset opt by Marcus Granado 2006 [http://mgran.blogspot.com]
req.overrideMimeType('text\/plain; charset=x-user-defined');
req.send(null);
if (req.status != 200) return '';
return req.responseText;
}
The point is that req.responseText does not suffer from the same limitation of req.response. It is not null in the state readystate=3. Then, the binary responseText is accessed with
var filestream = load_binary_resource(url);
var abyte = filestream.charCodeAt(x) & 0xff; // throw away high-order byte (f7)
A significant drawback is that req.responseText keeps growing as the stream is downloaded. The request should be reset from time to time to avoid excessive RAM consumption.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With