我有一个
- 在服务器上将音频生成到1秒WAV文件中
- 读取WAV文件并通过websocket发送
- Websocket将二进制数据发送到AudioContext.decodeAudioData
- 解码后的音频缓冲到4个数据包(4秒(
- 缓冲区被处理并发送到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不是设计用于从网络动态更新。
什么会导致去同步:
- 根据javascript调度程序的性质,不能保证在准确的时间执行代码。节点可能同时执行另一项作业,从而导致信息发送延迟
- 计时器在发送所有数据后运行下一个刻度,这可能需要一些时间
- 客户端调度程序比服务器端调度程序有更多的限制。通常,浏览器每秒可以执行大约250个定时器(每4ms一个(
- 所使用的API不是为该流程设计的
建议:
- 始终保留缓冲区。如果由于某种原因,缓冲区中的帧已经播放,那么更快地请求新帧可能是合理的
- 在飞行中增加缓冲区。在收到两条消息后,可以开始播放,但将动态缓冲消息的数量增加到大约15秒可能是合理的
- 首选其他工具来处理连接和数据传输。Nginx将完美发球。在客户端将具有慢速连接的情况下;保持";节点,直到数据将被传输
- 在连接中断一秒钟的情况下(例如,在移动网络上(,应该有一些东西可以从正确的帧恢复状态,更新缓冲区,并在不中断的情况下完成所有这些操作