Как я могу получить непрерывный поток сэмплов из JavaScript AudioAPI

#web-audio-api

#web-audio-api

Вопрос:

Я хотел бы получить непрерывный поток сэмплов в JavaScript из audio API. Единственный способ, который я нашел для получения сэмплов, — это объект MediaRecorder в JavaScript Audio API.

Я настроил свой рекордер следующим образом:

 var options = {
  mimeType: "audio/webm;codec=raw",
}
this.mediaRecorder = new MediaRecorder(stream, options);
this.mediaRecorder.ondataavailable = function (e) {
  this.decodeChunk(e.data);
}.bind(this);
this.mediaRecorder.start(/*timeslice=*/ 100 /*ms*/);
  

Это дает мне обратный вызов 10 раз в секунду с новыми данными. Пока все хорошо.

Данные закодированы, поэтому я использую audioCtx.decodeAudioData для их обработки:

 let fileReader = new FileReader();
fileReader.onloadend = () => {
  let encodedData = fileReader.resu<
  // console.log("Encoded length: "   encodedData.byteLength);
  this.audioCtx.decodeAudioData(encodedData,
    (decodedSamples) => {
      let newSamples = decodedSamples.getChannelData(0)
        .slice(this.firstChunkSize, decodedSamples.length);
      // The callback which handles the decodedSamples goes here.  All good.
      if (this.firstChunkSize == 0) {
        this.firstChunkSize = decodedSamples.length;
      }
    });
};
  

Все это тоже работает нормально.

Настройка данных для программы чтения файлов — вот где это становится странным:

 let blob;
if (!this.firstChunk) {
  this.firstChunk = chunk;
  blob = new Blob([chunk], { 'type': chunk.type });
} else {
  blob = new Blob([this.firstChunk, chunk], { 'type': chunk.type });
}
fileReader.readAsArrayBuffer(blob);
  

Первый фрагмент работает просто отлично, но второй и последующие фрагменты не декодируются, если я не объединю их с первым фрагментом. Я предполагаю, что здесь происходит то, что первый фрагмент имеет заголовок, который требуется для декодирования данных. Я удаляю сэмплы, декодированные из первого фрагмента, после их декодирования во второй раз. Смотрите this.firstChunkSize выше.

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

  1. У меня есть какая-то простая ошибка в моей логике «firstChunkSize» и «splice»

  2. Первый фрагмент имеет некоторый заголовок, из-за которого оставшиеся данные интерпретируются странным образом.

  3. При создании источника звука происходит какое-то странное взаимодействие с какой-либо опцией (шумоподавление?)

Комментарии:

1. Я обнаружил подсказку: это утверждение выполняется успешно после создания MediaRecorder, но не выполняется в ondataavailable обратном вызове: console.assert(this.MediaRecorder.mimeType == «audio / webm;codec= raw»). Кодек, похоже, меняется на «opus», но я не знаю почему. Я использую Chrome v86.

2. То же самое происходит, когда я пытаюсь использовать audio/webm;codecs=pcm, который является допустимым типом для: MediaRecorder.isTypeSupported(‘audio / webm;codecs=pcm’)

Ответ №1:

Вы хотите codecs= , а не codec= .

 var options = {
  mimeType: "audio/webm;codecs=pcm",
}
  

Хотя MediaRecorder.isSupported вернет true с codec= ним только потому, что этот параметр игнорируется. Например:

 MediaRecorder.isTypeSupported("audio/webm;codec=pcm")
true
MediaRecorder.isTypeSupported("audio/webm;codecs=pcm")
true
MediaRecorder.isTypeSupported("audio/webm;codecs=asdfasd")
false
MediaRecorder.isTypeSupported("audio/webm;codec=asdfasd")
true
  

Имя мусорного кодека asdfasd «поддерживается», если вы укажете codec вместо codecs .