我可以提供给 PCM 缓冲区的最少(可管理)样本量是多少?

What is the least amount of (managable) samples I can give to a PCM buffer?

一些 APIs,like this one,可以从样本数组(用数字表示)创建 PCM 缓冲区。

假设我想(近)实时生成和播放一些音频。我可以使用我神奇的 API 函数生成一个包含 100 个样本的 PCM 缓冲区并将它们从声卡发送出去。当播放这 100 个样本时,会生成另外 100 个样本,然后切换缓冲区。最后,我可以重复写入/播放/切换过程来创建源源不断的音频。

现在,请回答我的问题。我可以在写入/播放/切换方法中使用的最小样本大小是多少,而不会在音频流中发生可察觉的暂停?我知道这里的答案取决于采样率、处理器速度和到声卡的传输时间 - 所以如果更合适,请提供 "rule of thumb" 之类的答案!

(我对音频有点陌生,所以请随时指出我可能有的任何误解!)

TL;DR:如果小心的话,在桌面操作系统上很容易实现 1ms 缓冲区;从性能和能源使用的角度来看,这可能并不理想。

缓冲区大小的下限(以及此输出延迟)受限于操作系统的最坏情况调度延迟

事件的顺序是:

  1. 音频硬件逐渐从其缓冲区输出样本
  2. 在某个时候,它达到低水位线并生成中断,表明缓冲区需要补充更多样本
  3. 操作系统为中断服务,并将线程标记为准备好 运行
  4. 操作系统将线程调度到 运行 CPU
  5. 线程计算或以其他方式获取样本,并将它们写入输出缓冲区。

调度延迟是上述第 2 步和第 4 步之间的时间,主要由主机操作的设计决定。如果使用具有抢占式优先级调度的硬 RTOS,例如 VxWorks 或 eCos,最坏的情况可能是 uS 的几分之一。

通用桌面操作系统通常不那么灵活。 MacOSX 支持实时用户-space 调度,并且能够轻松处理 1ms 缓冲区。 Linux 内核可以配置为抢占式实时线程和由内核线程处理的 bottom-half 中断处理程序。您也应该能够在那里获得 1ms 的缓冲区大小。我无法评论最新版本的 NT 内核的功能。

也有可能在步骤 5 中发生(通常是严重的)延迟 - 当您的进程填满缓冲区时,如果它发生页面错误。通常的做法是获取所需的所有堆和堆栈内存,然后 mlock() 将其与程序代码和数据写入物理内存。

绝对忘记在解释或 JITed 语言中实现低延迟 运行 时间。您对语言 运行-time 正在做什么的控制太少,并且没有现实的前景来防止页面错误(例如内存分配)。我怀疑在这些情况下 10 毫秒会增加你的运气。

值得注意的是,由于中断和上下文切换的频率很高,呈现短缓冲区对系统性能(和能耗)有重大影响。这些破坏 L1 缓存局部性的方式与它们实际所做的工作不成比例。

虽然 1ms 音频缓冲区是可能的,但不一定是理想的。比如现代Windows的tick rate在10ms到30ms之间。这意味着,通常在音频驱动程序端,您需要保留一堆 1 ms 数据包的环形缓冲区来处理缓冲区不足的情况,以防 CPU 被其他人从您下面拉出来线程。

所有现代音频引擎都使用 2 的幂作为其音频缓冲区大小。从每帧 256 个样本开始,看看它如何为您工作。每个硬件都是不同的,您不能依赖于 Mac 或 PC 如何为您提供时间片。当您使用 运行 您的音频程序时,用户可能会在其他进程中计算圆周率。保持较大的缓冲区大小(例如每帧 2048 个样本)更安全,如果延迟困扰他们,让用户将其关闭。