通过WebSockets将音频流式传输到Web音频播放器



我有一个

  1. 在服务器上将音频生成到1秒WAV文件中
  2. 读取WAV文件并通过websocket发送
  3. Websocket将二进制数据发送到AudioContext.decodeAudioData
  4. 解码后的音频缓冲到4个数据包(4秒(
  5. 缓冲区被处理并发送到AudioBufferSourceNode.start(时间(,其中时间=(clip_count*duration(

所以如果我有4个音频片段,通话看起来像

AudioBufferSourceNode.start(0);
AudioBufferSourceNode.start(1);
AudioBufferSourceNode.start(2);
AudioBufferSourceNode.start(3);

我原以为这会完美地安排4秒的音频,但我似乎面临着时钟问题,也许是因为我希望音频时钟是完美的。我已经使用了一个增益节点来消除每个声音片段之间的点击(1秒(,但我开始立即或在很长一段时间后出现时间问题。基本上,在最坏的情况下,我的音频播放方式是这样的

----------------------  -----------     -----------     -----------
| 1 second | 1 second |  |   950ms |     |  900ms  |    |   850ms  |
----------------------  -----------     -----------     -----------
gap          gap              gap

在该图中,"1秒"one_answers"#ms"是播放的音频量。它应该总是1秒。随着音频的发展,它似乎也出现了缺口。我想,即使我告诉音频上下文在0时播放一个文件,也没关系,但其他安排的音频片段可能准时,也可能不准时。

这是正确的吗,还是我的系统出现了其他问题?我是否可以100%可靠地安排音频剪辑在正确的时间播放,或者我是否需要添加一些计算来计算何时播放几毫秒的+/-?

看起来这个任务的目的是AudioWorkletNode

根据AudioBufferSourceNode文档:

AudioBufferSourceNode接口是一个AudioScheduledSourceNode,它表示由存储在AudioBuffer中的内存中音频数据组成的音频源。它特别适用于播放对计时精度要求特别严格的音频,例如必须与特定节奏匹配的声音,并且可以保存在内存中,而不是从磁盘或网络播放。要播放需要精确计时但必须从网络流式传输或从磁盘播放的声音,请使用AudioWorkletNode来实现其播放。

这种情况正好实现了来自网络的流式传输。AudioBufferSourceNode不是设计用于从网络动态更新。

什么会导致去同步

  1. 根据javascript调度程序的性质,不能保证在准确的时间执行代码。节点可能同时执行另一项作业,从而导致信息发送延迟
  2. 计时器在发送所有数据后运行下一个刻度,这可能需要一些时间
  3. 客户端调度程序比服务器端调度程序有更多的限制。通常,浏览器每秒可以执行大约250个定时器(每4ms一个(
  4. 所使用的API不是为该流程设计的

建议

  1. 始终保留缓冲区。如果由于某种原因,缓冲区中的帧已经播放,那么更快地请求新帧可能是合理的
  2. 在飞行中增加缓冲区。在收到两条消息后,可以开始播放,但将动态缓冲消息的数量增加到大约15秒可能是合理的
  3. 首选其他工具来处理连接和数据传输。Nginx将完美发球。在客户端将具有慢速连接的情况下;保持";节点,直到数据将被传输
  4. 在连接中断一秒钟的情况下(例如,在移动网络上(,应该有一些东西可以从正确的帧恢复状态,更新缓冲区,并在不中断的情况下完成所有这些操作

最新更新