Справочная информация
Я пишу сервис для обслуживания статических аудиофайлов в блоках, чтобы обеспечить свободный доступ для пользователей с более низкой пропускной способностью.Как только файл будет полностью передан (последовательность блоков является линейной, пользователи не смогут «перепрыгнуть» диапазон), я хочу сохранить файл в локальном кэше (используя 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 Источник аудиоэлемента из кэша