预加载audio缓冲区 – 什么是合理可靠的?

我将audio信号处理应用程序从Win XP转换到Win 7(至less)。 你可以想象它是一个声纳应用程序 – 一个信号被生成并发出,并且一个相关的/被修改的信号被重新读入。应用程序希望独占使用audio硬件,并且不能承受小故障 – 我们不想读像“Windows哔声导致导弹发射”的头条新闻。

看看Windows SDKaudio样本,与我的情况最相关的是RenderExclusiveEventDriven示例。 在audio引擎之外,它准备10秒的audio播放,通过IAudioRenderClient对象的GetBuffer()ReleaseBuffer()以10ms的块提供给渲染引擎。 它首先使用这些函数预加载一个10ms的audio块,然后依靠常规的10ms事件加载后续的块。

希望这意味着总会有10-20ms的audio数据被缓冲。 我们应该如何可靠地(即无故障)在合理的现代硬件上(不到18个月大)?

以前,人们可以通过waveXXX() API预先加载至less半秒钟的audio,这样,如果Windows在其他地方忙碌,audio连续性就不太可能受到影响。 500毫秒似乎比10-20毫秒更安全的余量…但如果你想要事件驱动和独占模式, IAudioRenderClient文档并没有完全说清楚,如果是或不可能预加载超过一个IAudioRenderClient缓冲区值得。

任何人都可以确认,如果更广泛的预加载仍然是可能的? 是build议,劝阻还是两者都不?

如果你担心发射导弹,我不认为你应该使用Windows或任何其他非实时操作系统。

也就是说,我们正在研究另一个消耗更高带宽数据的应用程序(连续数小时或更长的时间,每秒400 MB)。 我们已经看到操作系统在5秒内无响应的故障,所以我们在数据采集硬件上有很大的缓冲区。

和其他所有的计算一样,你走得越宽:

  • 增加吞吐量
  • 增加延迟

我会说512个采样缓冲区是通常用于非苛刻的延迟智能应用程序的最小值。 我见过多达4k缓冲区。 内存使用明智的,对于当代设备来说还是几乎没有任何东西 – 对于16位音频,每个通道只有8千字节的内存。 你有更好的播放稳定性和更低的CPU周期浪费。 对于音频应用来说,这意味着您可以在音频开始跳过之前用更多的DSP处理更多的音轨。

另一方面,我只看到了一些专业的音频接口,可以处理32个样本缓冲区。 大多数能够达到128个样本,当然你仍然限制在较低的频道和效果计数,即使有专业的硬件,当你的项目变大时,你可以增加缓冲,当你需要“实时”捕捉时,降低它,禁用音轨或效果一场表演。 就可能的最低延迟而言,实际上同一个盒子可以在Linux和定制的实时内核上获得比在不允许做这种事情的Windows上更低的延迟。 请记住,64位采样缓冲区理论上听起来可能是8毫秒的延迟,但实际上它更像是两倍 – 因为您有输入和输出延迟以及处理延迟。

对于一个音乐播放器来说,延迟不是问题,你可以使用更大的缓冲区,对于像游戏这样的东西,为了在视觉上和声音之间仍然保持一定程度的同步,你需要保持较低的音量。不能让你的声音落后于动作的半秒,因为音乐表演与已录制的素材一起捕捉,所以你需要延迟低。 你不应该超出你的用例要求,因为一个小的缓冲区将不必要地增加到CPU的使用和音频丢失的可能性。 对于音频播放器来说,4k缓冲就好了,如果您能够在您播放的那一刻和您听到歌曲开始的那一刻之间生活了半秒钟的延迟

我在DAW项目中做了一种“混合”的解决方案 – 因为我想用GPGPU来处理CPU的巨大性能,所以我在内部用两条处理路径来分割工作 – 64个采样缓冲区,用于实时音频这是在CPU上处理的,另一个相当宽的缓冲区大小是由GPU处理的数据。 自然,它们都是通过“CPU缓冲区”出来的,以便完美同步,但GPU路径是“预先处理的”,因此可以为已经记录的数据提供更高的吞吐量,并且保持CPU使用率更低,因此实时音频更可靠。 我真的很惊讶,专业的DAW软件还没有走上这条道路,但不是太多,知道这个行业的大鱼在硬件上花了多少钱,这个硬件比现代中端GPU要小得多。 自从Cuda和OpenCL推出以来,他们一直声称“GPU的延迟太多了”,但是预缓冲和预处理对于已经记录的数据来说确实不是问题,并且会增加DAW可以处理的项目巨大。

简短的答案是肯定的,你可以预先加载大量的数据。

本示例使用GetDevicePeriod调用返回设备的最小服务时间间隔(以纳秒为单位),然后将该值传递给Initialize 。 如果您愿意,您可以传递更大的价值。

增加期限的缺点是你正在增加延迟。 如果你只是在播放一个波形,并没有计划在飞行中做出改变,那么这不是问题。 但是如果你有一个正弦波发生器,那么等待时间的增加意味着听到频率或振幅的变化需要更长的时间。

你是否有退出取决于一些事情。 你是否适当地设置线程优先级? 缓冲区有多小? 你准备样品有多少CPU? 一般来说,现代CPU可以处理相当低的延迟。 为了进行比较,ASIO音频设备在96kHz的情况下以2048个采样缓冲器(20毫秒)运行,并且没有任何问题。 ASIO使用类似的双缓冲方案。

这太长了,不能作为评论,所以这也可能是一个答案(有资格)。

尽管它是从我提交的问题的最终形式编辑而来的,但是我所预期的“更广泛的预加载”不是所使用的缓冲区的大小,而是所使用的缓冲区的数量。 (有些意外的)结果都有助于扩大我的理解。

但我很好奇。 在旧的waveXXX()世界中,可以通过waveOutPrepareHeader()waveOutWrite()调用“预加载”多个缓冲区,其中的第一个waveOutWrite()将开始播放。 我的旧应用程序在一个突发中从一组64个缓冲区中“预加载”了60个缓冲区,每个缓冲区以48kHz的频率播放512个样本,在系统中创建超过600ms的缓冲区,周期为10.66ms。

在WASAPI世界中使用IAudioCient::Start()之前使用多个IAudioRenderClient::GetBuffer()IAudioRenderClient::ReleaseBuffer()调用,似乎仍然是可能的…至少在我的(非常普通的)硬件上,并没有广泛的测试(还)。 尽管文档强烈建议独家的,事件驱动的音频是严格的双缓冲系统。

我不知道任何人都应该着手开发这个设计,但是我想我会指出它可能会得到支持。