Обрезать или обрезать звук, записанный с помощью медиа-рекордера JS
Требуемые знания
Как укоротить (спереди) массив аудио-блобов и при этом иметь воспроизводимый звук.
Цель
В конечном итоге я пытаюсь записать непрерывный 45-секундный цикл аудио с использованием API JS MediaRecorder. Пользователь сможет нажать кнопку, и последние 45 секунд звука будут сохранены. Я могу записать, воспроизвести и загрузить одну запись просто отлично.
вопрос
Когда у меня есть массив с именем chunks
скажем 1000 BLOB-объектов из MediaRecorder и использовать chunks.slice(500, 1000)
Полученный массив BLOB-объектов нельзя использовать для воспроизведения или загрузки аудио.
Довольно странно chunks.slice(0,500)
все еще работает нормально.
Код
let chunks = [];
navigator.mediaDevices.getUserMedia({ audio: true })
.then((stream) => {
const mediaRecorder = new MediaRecorder(stream);
mediaRecorder.ondataavailable = (e) => chunks.push(e.data);
}
// At some later time, attempt to trim
const trimmedAudio = chunks.slice(500, 1000)
const blob = new Blob(chunks, { 'type' : 'audio/ogg; codecs=opus' });
const audioURL = URL.createObjectURL(blob);
// audio is an audio DOM element
audio.src = audioURL;
// At this point the audio won't play
Попытки решения
Поскольку срезы от начала до середины работают, я попытался повернуть назад, разрезать и повернуть назад в исходное направление. Не удалось.
Я попытался оставить 16 капель в начале и удалить некоторые из середины. Не удалось.
ломоть
Я догадываюсь, что BLOB- объекты не всегда содержат данные и требуют некоторого преобразования в ArrayBuffer или определенный TypedArray. Я попробовал несколько таких преобразований, но до сих пор не нашел решения. Буду очень признателен за любые рекомендации, так как я могу найти любую документацию для редактирования записанных массивов BLOB-объектов.
Обновление 2017-02-11
Основываясь на совете Кайидо, чтобы объединить фрагменты, преобразовать их в ArrayBuffer и затем передать его в веб-аудио API, я попробовал следующее.
const blob = new Blob(chunksFromMediaRecorder, { 'type' : 'audio/ogg codecs=opus' })
// blob is Blob size: 32714, type: "audio/ogg codecs=opus"}
function playFromBlob(blob) {
const aCtx = new (window.AudioContext || window.webkitAudioContext)()
const source = aCtx.createBufferSource()
const fileReader = new FileReader()
let arrayBuffer
fileReader.onload = function() {
arrayBuffer = this.result
console.log('arrayBuffer', arrayBuffer) // ArrayBuffer {} with byte length 32714
aCtx.decodeAudioData(arrayBuffer) // throws: Uncaught (in promise) DOMException: Unable to decode audio data
.then(decodedData => {
// use the decoded data here
source.buffer = decodedData
source.connect(audioCtx.destination)
})
}
fileReader.readAsArrayBuffer(blob);
}
Вышеприведенный пример успешен при создании ArrayBuffer того же размера, что и Blob, но когда я передаю его в decodeAudioData
функция, она бросает Unable to decode audio data
ошибка. Есть ли шаг, который мне не хватает в процессе конвертации?
Обновление 2017-02-18
Кайидо отметил, что существует известная ошибка с Chrome, которая помешала бы мне сместить массив аудиоданных. Насколько я могу судить, это делает невозможным любое обрезание или обрезку аудио в Chrome (Firefox обрезка аудио массива работает, см. Комментарий Кайидо).
Чтобы достигнуть моей конечной цели непрерывных 45-летних ретроактивных записей, я сейчас создаю два экземпляра MediaRecorders
смещение на 45 с и обмен их. Поэтому, когда один в 45-х, а другой в 90-х, я начинаю новую запись и избавляюсь от 90-х MediaRecorder
, Определенно неоптимальный, но лучшее решение, которое я могу найти в настоящее время.