2017-04-12 13 views
2

我有一台服务器通过websocket发送原始音频块。我们的想法是检索并播放它们,以尽可能平滑播放。流式处理原始音频数据期间在webaudio播放中出现裂缝

这里是代码最重要的一块:

ws.onmessage = function (event) { 
    var view = new Int16Array(event.data); 
    var viewf = new Float32Array(view.length); 

    audioBuffer = audioCtx.createBuffer(1, viewf.length, 22050); 
    audioBuffer.getChannelData(0).set(viewf); 
    source = audioCtx.createBufferSource(); 
    source.buffer = audioBuffer; 
    source.connect(audioCtx.destination); 
    source.start(0); 
}; 

这工作体面的好,但也有在播放一些裂缝:网络延迟并不恒定,所以数据的最新块没有按”到达前一个正在播放的结尾,所以我可以结束两个缓冲区一起玩一会儿或者根本不玩。

我想:

  • source.onended玩下一个,但它不是无缝的:有每块的尾部裂纹,而每个接缝的整体累积使回放越说越比流更晚。
  • 将新数据追加到当前正在播放的缓冲区中,但这似乎是被禁止的:缓冲区的大小是固定的。

有没有适当的解决方案来解决这个问题?唯一的要求是播放来自websocket的未压缩音频。

编辑:解决方法:鉴于我知道我的缓冲区长度,我可以安排播放这样:

if(nextStartTime == 0) nextStartTime = audioCtx.currentTime + (audioBuffer.length/audioBuffer.sampleRate)/2; 
source.start(nextStartTime); 
nextStartTime += audioBuffer.length/audioBuffer.sampleRate; 

第一次,我安排播放的开始半个buffer-以后再允许最大的意外延迟。然后,我将下一个缓冲区开始时间存储在缓冲区末尾。

回答

2

您应该从https://www.html5rocks.com/en/tutorials/audio/scheduling/开始,它很好地解释了如何在WebAudio中安排时间。

对于您的使用案例,您还应该利用这一事实,即您知道PCM样本的采样率,并知道您已阅读了多少样本。这决定了播放缓冲区需要多长时间。用它来确定何时安排下一个缓冲区。

(但要注意的是,如果PCM采样速率是不一样的audioCtx.sampleRate,数据将被重新采样,这可能会弄乱你的时间。

+0

谢谢,这是我所做的,而不是简单的“现在玩”。我现在有一些听起来更好的东西! – Ploppe

0

有一个更好的方式来处理这个问题,这些天...考虑使用Media Source扩展

相反不得不安排缓冲区并自己做所有事情,你基本上会将接收到的数据转储到缓冲区中,并让浏览器担心缓冲播放,就好像它是通过HTTP的文件一样。

Chrome支持播放WAV文件。由于您的数据处于原始PCM中,因此您需要伪装WAV文件标头。幸运的是,这并不难:http://soundfile.sapp.org/doc/WaveFormat/

+0

不幸的是,媒体源扩展目前不支持WAV .. :(https://github.com/w3c/media-source/issues/55 – bertrandg

+0

嗨,布拉德,你有任何链接显示如何使用MediaSource解码MP3数据块来自套接字? –