XMLHttpRequest и потоковая передача http

Моя цель — прочитать аудиопоток HTTP MP3 из браузера и получить доступ к необработанным аудиоданным.

  • HTML5 ‹ audio > позволяет легко воспроизводить поток, но, насколько мне известно, не предоставляет доступ к необработанным аудиоданным. Просто играет.

  • JS XMLHTTPRequest может загружать файлы через HTTP и обрабатывать необработанные аудиоданные. Кажется, это хороший кандидат, но у него есть ограничение: он не предоставляет доступ к двоичным данным, пока загрузка не будет завершена (readystate = 4). В моем случае поток неограничен, поэтому состояние готовности постоянно остается равным 3, а ответ XHR равен нулю (это поведение подробно описано в документации Mozilla). Обратите внимание, что политика перекрестного происхождения сервера, к которому я подключаюсь, — Access-Control-Allow-Origin: *

Пример кода, который работает для локальных обычных файлов, но не для потоков. Я получаю исключение нулевого указателя в 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();

Кто-нибудь знает альтернативы или обходные пути для этих вариантов, чтобы необработанные двоичные пакеты можно было читать во время загрузки потока?

Обратите внимание, что у меня нет контроля над сервером. Это ледяной http-поток. Кроме того, со стороны браузера я бы хотел избежать использования Flash. Спасибо

Изменить: чтобы прояснить возможные вопросы о перекрестном происхождении, JS запускается на странице, размещенной на локальном сервере.


person astooooooo    schedule 09.10.2015    source источник
comment
Чтобы было ясно, вам нужны необработанные декодированные аудиоданные PCM, а не битовый поток с сервера, да? Если это так, Web Audio API — это то, что вам нужно.   -  person Brad    schedule 09.10.2015
comment
@Brad действительно я использую API веб-аудио (в качестве подсказки см., например, метод decodeAudioData выше, в моем частичном коде). У меня просто возникли проблемы с получением буфера из потока и помещением его в API. Я думаю, что нашел решение, см. мое решение ниже.   -  person astooooooo    schedule 09.10.2015


Ответы (1)


Сработало следующее обходное решение:

Как указано в MDN https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receive_Binary_Data можно переопределить MIME-тип http-запроса, установив для него значение custom, и вызвать 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;
} 

Дело в том, что req.responseText не имеет того же ограничения, что и req.response. Он не равен нулю в состоянии readystate=3. Затем доступ к бинарному responseText осуществляется с помощью

var filestream = load_binary_resource(url);
var abyte = filestream.charCodeAt(x) & 0xff; // throw away high-order byte (f7)

Существенным недостатком является то, что req.responseText продолжает расти по мере загрузки потока. Запрос следует время от времени сбрасывать, чтобы избежать чрезмерного потребления оперативной памяти.

person astooooooo    schedule 09.10.2015
comment
Синхронные запросы устарели - person RobotRock; 23.01.2021