在IOS / Safari中音频Blob无法工作

9
我正在录制音频,将其作为 Blob 发送到 Node.js 服务器。随后,该服务器会将其发送给所有当前未进行录制的已连接用户。
将 Blob 发送出去:
mediaRecorder.onstop = function(e) {
  var blob = new Blob(this.chunks, { 'type' : 'audio/ogg; codecs=opus' });
  socket.emit('radio', blob);
};

接收Blob的服务器:

socket.on('radio', function(blob) {
  socket.broadcast.emit('voice', blob);
});

接收Blob的监听器:

socket.on('voice', function(arrayBuffer) {
  var blob = new Blob([arrayBuffer], { 'type' : 'audio/ogg; codecs=opus' });
  var audio = document.getElementById('audio');
  audio.src = window.URL.createObjectURL(blob);
  audio.play();
});

这在所有浏览器/设备上都有效,除了Safari和任何iOS设备。通过使用Safari的检查器进一步发现:

返回的第一个blob对象 返回的第二个blob对象 返回的第三个blob对象

Safari需要在其标头中添加其他内容才能正确解释blob对象吗?我已经研究了接受的音频类型,尝试了aac/mp3/ogg,但没有成功。继续阅读后,我听说在Safari和IOS中流式传输blob音频/视频数据存在错误,尽管我不太清楚具体细节。

指导将非常有帮助!

编辑:看起来这行代码 audio.src = window.URL.createObjectURL(blob); 在接收blob时导致了blob错误(我链接的图像)。

编辑2: 我尝试看看是否使用除blob之外的其他格式会起作用,选择使用base64编码字符串。看起来这在所有设备和浏览器上都有效,除了IOS和Safari。我得到的印象是它与IOS如何解释/加载数据有关...


1
你是否曾经找到了解决这个问题的方法? - scottmizo
现在应该可以了,参见类似问题的答案:https://dev59.com/XGYs5IYBdhLWcg3wAfAi#56330664 - lastmjs
3个回答

3
对我来说,解决方法是将一个源元素插入到音频元素中,并使用sourceElement.src属性引用blob。我甚至不需要将音频元素绑定到DOM。以下是示例,希望对某些人有所帮助。
var audioElement = document.createElement('audio')
var sourceElement = document.createElement('source')

audioElement.appendChild(sourceElement)

sourceElement.src = '<your blob url>'
sourceElement.type = 'audio/mp3' // or whatever

audioElement.load()

audioElement.play()

2

我没有找到使用音频元素的解决方案,但是Web Audio Api似乎可以解决这个问题:https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API

    var audioContext = new (window.AudioContext || window.webkitAudioContext);
    socket.on('voice', function(arrayBuffer) {
      audioContext.decodeAudioData(arrayBuffer, audioData => {
        var source = audioContext.createBufferSource();
        source.buffer = audioData;
        source.connect(audioContext.destination);
        source.start()
    });

在iOS上,您可能仍然会遇到问题,因为任何音频/视频都必须由用户操作触发。


1
我这周也遇到了类似的问题。我正在Safari上录制音频,音频blob生成得很好。但是当我尝试将blob发送到服务器时,没有数据传输到那里。下面的解决方案使用文件阅读器读取blob以将其转换为base64,然后将其发送到服务器。以下是对我有效的内容:
      const reader = new FileReader();
      reader.readAsDataURL(audioBlob);
      reader.onloadend = () => {
      const base64data = reader.result;

      const audioName = uuid.v4() + '.mp3';
      this.http.post(this.app.cloudStorageEndpoint + '/audios/local?audioName=' + audioName, base64data , header).subscribe(
        res => { resolve(audioName); },
        err => { reject(err); }
      );
  };

我已经在iPad和iPhone上测试了Safari 12,并且它运行良好。


这个问题有点不同。我能够将数据发送回服务器,但是在将其发送到其他连接的客户端时,在iOS和Safari上无法接收数据。 - jshbrmn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接