Воспроизвести аудио из частичного ответа и сохранить буфер после завершения - PullRequest
0 голосов
/ 05 октября 2018

Справочная информация

Я пишу сервис для обслуживания статических аудиофайлов в блоках, чтобы обеспечить свободный доступ для пользователей с более низкой пропускной способностью.Как только файл будет полностью передан (последовательность блоков является линейной, пользователи не смогут «перепрыгнуть» диапазон), я хочу сохранить файл в локальном кэше (используя localforage, но это не является частью этого вопроса), чтобыпозже загрузите кэшированные файлы оттуда и сохраните пропускную способность.

Проблема

С моим текущим уровнем знаний / кода / инструментов возможно только одно из следующих действий:

A) Потоковое аудио с помощью HTMLAudioElement

const audio = new Audio()
audio.src = url
audio.preload = 'auto'
audio.load()

Аудио HTML5 внутренне заботится о частичном ответе, работает нормально, ноЯ не могу получить доступ к базовому буферу, чтобы сохранить файл после полной загрузки.Таким образом, я не смогу кешировать файл локально, не загрузив его отдельно (в другом запросе).

B) Скачать / извлечь файл в целом, затемиграть в нее

fetch(url, options) // set content header to array buffer
  .then((response) => {
    var blob = new Blob([response.value], { type: 'audio/mp3' })
    var url = window.URL.createObjectURL(blob)
    const audio = new Audio()
    audio.src = url
    audio.play()
  })

Это дает мне доступ к данным, чтобы я мог кэшировать их для повторного использования в автономном режиме.Но я теряю опцию потоковой передачи, которая делает практически невозможным воспроизведение больших файлов без ожидания.

C) Использование пользовательского загрузчика и воспроизведение каждого фрагмента с использованием API WebAudio

Поскольку A и B было недостаточно, я написал пользовательский загрузчик , который загружает чанки (что работает нормально) и отправляет событие с текущим чанком (как ArrayBuffer) в качестве данных.Он также отправляет другое событие подряд, которое возвращает все фрагменты, поэтому я могу создать из него большой двоичный объект:

const chunkSize = 2048
const audioContext = new AudioContext()
const loader = new StreamLoader(url,  {step: chunkSize})

loader.on(StreamLoader.event.response, (data) => {
  // data.response is of type ArrayBuffer
  const floats = new Float32Array(data.response)
  const audioBuffer = audioContext.createBuffer(1, chunkSize, 4410)
  audioBuffer.getChannelData(0).set(floats)
  const sourceNode = new AudioBufferSourceNode(audioContext, {buffer: audioBuffer})
  sourceNode.connect(audioContext.destination)
  sourceNode.start(0)
})

loader.once(StreamLoader.event.complete, (data) => {
  const blob = new Blob(Object.values(data), {type: fileType})
  const objectURL = URL.createObjectURL(blob)
  const audio = new Audio();
  audio.src = url;
  audio.play();
})

loader.load()

Проблема здесь в том, что он производит только странный громкий шум.Тем не менее, воспроизведение с большого двоичного объекта после его завершения работает нормально.

Мне известно о проблеме, что для правильного декодирования аудио должен присутствовать заголовок, поэтому мне любопытно, как HTMLAudioElement или MediaStreamна самом деле внутренне решить эту проблему.

D) Использование MediaStream или MediaRecorder с пользовательским загрузчиком

Поскольку я не записываю излокальное устройство, я не получил ни одного из них для работы с потоковыми чанками, которые я загрузил с помощью xhr.Они ограничены для использования с локальными источниками мультимедиа?

E) Использование таких инструментов, как Howler, SoundManager, SoundJS.

Я нашел вышеупомянутые инструменты, но, к сожалению, пришелвернуться к выпуску A или B. используя их.

Ожидаемое решение

Я ожидаю найти решение, которое позволяет мне воспроизводить звук из потока (частичный ответ) и для доступа к буферизованным данным для их кэширования.

Связанные ресурсы SO:

Как воспроизвести фрагменты аудиопотока, записанные с помощью WebRTC?

HTML5 запись звука в файл

HTML Источник аудиоэлемента из кэша

...