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

4

我有一个基本能用的系统,

  1. 能在服务器上生成1秒的WAV文件音频
  2. 能读取该WAV文件并通过websocket发送
  3. websocket将二进制数据发送到AudioContext.decodeAudioData
  4. 解码后的音频数据被缓冲,直到收集了4个封包(即4秒)
  5. 缓冲区被处理并发送到AudioBufferSourceNode.start(time),其中time = (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秒”和“#ms”代表正在播放的音频时长。它应该始终为1秒。随着音频的播放,似乎也会出现间隙。我想即使我告诉音频上下文在0时刻精确播放文件,但其他计划的音频剪辑可能会或可能不会准时。这是正确的吗?还是我的系统出了什么问题?是否有100%的可靠性,我可以安排音频剪辑在完全正确的时间播放,还是我需要添加一些计算来确定何时播放的误差范围为几毫秒?

我很想看到一个使用最新的Web Audio API技巧的工作演示解决方案。 - Scott Stensland
1
@ScottStensland 你是否遇到了类似的问题? - terratermatwoa
@terratermatwoa 我认为进一步的研究需要一个完整的演示。 - Jafar Akhondali
我还需要从服务器流式传输音频到浏览器...过去我使用WebWorker、Web Audio API、WebSockets和Node.js创建了一个可行的解决方案...现在正在构建一个新项目,所以是的,我也面临同样的问题...联系我https://github.com/scottstensland/websockets-streaming-audio - Scott Stensland
1个回答

3

看起来,用于此任务的工具是AudioWorkletNode

根据AudioBufferSourceNode文档

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

该情况正是从网络流式传输。AudioBufferSourceNode不适合通过网络进行动态更新。

可能导致不同步的原因

  1. 由于JavaScript调度程序的本质,无法保证在精确时间执行代码。节点可能同时执行其他作业,导致发送信息的延迟。
  2. 计时器在发送所有数据后下一个时刻运行,这可能需要一些时间。
  3. 客户端调度程序比服务器端调度程序更受限制。通常,浏览器每秒可以执行约250个计时器(每4ms一个)。
  4. 所使用的API不适用于此流程。

建议

  1. 始终保留缓冲区。如果由于某种原因从缓冲区中播放了帧,则可能需要更快地请求新帧。
  2. 动态增加缓冲区。收到两个消息后开始播放是可以的,但是动态增加缓冲消息的数量可能会更合理,例如到15秒左右。
  3. 首选另一种工具来处理连接和数据传输。Nginx将非常有效。如果客户端连接速度较慢,它将“保持”节点直到数据传输完成。
  4. 在临时断开连接的情况下(例如在移动网络上),应该有一些方法从适当的帧恢复状态,更新缓冲区并在没有中断的情况下执行所有操作。

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