Safari 调用 decodeAudioData 错误,其中 Chrome 有效

Safari call to decodeAudioData errors with null where Chrome works

我正在使用 getUserMedia()mediaRecorder 来录制音频,然后将其存储为服务器上的 base64 编码文本。稍后,它从服务器检索,存储在客户端,然后,当用户单击播放按钮时,它会被未编码并播放。在 Chrome 上播放正常,但在 Safari decodeAudioData 上会向 catch 函数抛出一个 null 错误。我对此进行了大量研究,但看不出是什么引发了异常。

录制代码为:

      navigator.getUserMedia = ( navigator.getUserMedia ||
                                 navigator.webkitGetUserMedia ||
                                 navigator.mozGetUserMedia ||
                                 navigator.msGetUserMedia);
      if (navigator.getUserMedia) {
        //console.log('getUserMedia supported.');
        navigator.getUserMedia (
          { // constraints - only audio needed for this app
            audio: true
          },
          // Success callback
          function(stream) {
            const mediaRecorder = new MediaRecorder(stream);
            mediaRecorder.ondataavailable = audio.saveRecordedAudio;
          });
       }

播放代码为:

      const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
      const source = audioCtx.createBufferSource();
      const binaryAudioBlob = audio.b64toBlob(b64String);
      const reader = new FileReader();
      reader.addEventListener("loadend", function() {
        const bufferArray = reader.result;
        audioCtx.decodeAudioData(bufferArray, (buffer) => {
          source.buffer = buffer;
          source.connect(audioCtx.destination);
          source.start(0);
          console.log('started audio from blob');
        }, function(e){ 
          console.log("Error with decoding audio data" + e);  // e is null
        });
      });
      reader.readAsArrayBuffer(binaryAudioBlob);

其中 b64toBlob 函数是:

    b64toBlob: (b64Data, contentType, sliceSize) => {
      contentType = contentType || '';
      sliceSize = sliceSize || 512;

      const byteCharacters = atob(b64Data);
      const byteArrays = [];

      for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
        const slice = byteCharacters.slice(offset, offset + sliceSize);

        const byteNumbers = new Array(slice.length);
        for (let i = 0; i < slice.length; i++) {
          byteNumbers[i] = slice.charCodeAt(i);
        }

        const byteArray = new Uint8Array(byteNumbers);

        byteArrays.push(byteArray);
      }

      const blob = new Blob(byteArrays, {type: contentType});
      return blob;
    }

音频是用 Chrome 录制的。 Chrome 是否可能以 Safari 无法播放的格式对音频进行编码?据我所知,默认设置是 WAV,所以我认为 Safari 可以播放该格式(相对于 Ogg)。

非常感谢任何提示。

Chrome 和 Firefox 浏览器使用 MediaRecorder 录制音频流的默认格式是 Opus

Safari 无法读取此格式,这就是为什么 AudioContext.decodeAudioData() 会因此类输入而失败。

Safari 11+ 使用 WebAssembly 播放 Opus 文件。您需要绕过 decodeAudioData() 并直接使用网络音频 API。请参阅以下示例:

https://fetch-stream-audio.anthum.com/