低延迟音频

低延迟音频使游戏感觉更逼真和更灵敏。

完成以下清单以在您的 Android 游戏中启用低延迟音频

  1. 使用 Oboe
  2. 请求性能模式“低延迟”
  3. 请求共享模式“独占”
  4. 使用 48000 Hz 或 Oboe 采样率转换器
  5. 将使用情况设置为 AAUDIO_USAGE_GAME
  6. 使用数据回调
  7. 避免在回调中阻塞操作
  8. 将缓冲区大小调整为“双缓冲”

1. 使用 Oboe API

Oboe API 是一个 C++ 包装器,它在 Android 8.1(API 级别 27)或更高版本上调用 AAudio。在早期 Android 版本上,Oboe 使用 OpenSL ES。

Oboe 可在 GitHub 上获得,也可以作为 预构建二进制文件 获得。Oboe 还具有 QuirksManager,可纠正特定设备上的问题,从而使您的应用与更多设备兼容。如果您无法使用 Oboe,请直接使用 AAudio。

2. 请求低延迟模式

使用 Oboe 或 AAudio 时,请求低延迟模式。否则,您将默认获得更高的延迟模式。

Oboe

builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);

AAudio

AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);

3. 请求独占模式

您还可以请求对 MMAP 缓冲区的独占访问。您的应用可能无法获得独占访问权限,但如果获得了,您的应用将直接写入由 DSP 读取的缓冲区,这将为您的应用提供尽可能低的延迟。

Oboe

builder.setSharingMode(oboe::SharingMode::Exclusive);

AAudio

AAudioStreamBuilder_setSharingMode(builder, AAUDIO_SHARING_MODE_EXCLUSIVE);

4. 避免采样率转换

使用设备的自然采样率。您可以通过不指定采样率来实现这一点,并且您几乎肯定会得到 48000 Hz。如果您确实指定了采样率,则音频框架会通过不同的路径发送您的数据,这可能会产生更高的延迟。

如果您确实需要使用不同的采样率,请使用 Oboe 进行采样率转换

builder->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::Medium);

5. 正确声明您的用例

指定您的应用播放音频的原因对于系统应用正确的路由、音量和性能设置至关重要。例如,游戏应指示使用 AAUDIO_USAGE_GAME 以充分利用延迟优化,尤其是在连接到蓝牙耳机时。

Oboe

builder.setUsage(oboe::Usage::Game);

AAudio

AAudioStreamBuilder_setUsage(builder, AAUDIO_USAGE_GAME);

6. 使用回调函数

为输出流使用回调。如果您使用阻塞写入并且您使用的设备不支持 AAudio MMAP 模式,则延迟可能会高得多。

Oboe

builder.setDataCallback(&myCallbackObject);

AAudio

AAudioStreamBuilder_setDataCallback(builder, &my_callback_proc);

7. 避免在回调中阻塞

当您使用低延迟流时,回调之间的时间可能非常短,只有几毫秒。因此,在回调中不要执行任何可能长时间阻塞的操作非常重要。如果回调被阻塞,缓冲区就会下溢,音频中就会出现故障。

避免在回调中执行以下操作

  • 分配或释放内存
  • 文件或网络 I/O
  • 等待互斥锁或锁
  • 休眠
  • 繁重的单次 CPU 计算

回调应以均匀的速度进行数学运算,以实现流畅的播放而不会出现故障。

8. 调整缓冲区大小

您的应用打开音频流后,需要调整可用缓冲区大小以获得最佳延迟。Oboe 会自动将缓冲区大小设置为两个突发。但是对于 AAudio,默认值要高得多。通过将缓冲区大小设置为突发大小的两倍来使用双缓冲。突发大小是最大回调大小。

AAudio

int32_t frames = AAudioStream_getFramesPerBurst() * 2;
AAudioStream_setBufferSizeInFrames(stream, frames);

如果缓冲区大小太小,则可能会出现由缓冲区下溢引起的故障。您可以通过调用 AAudioStream_getXRunCount(stream) 来获取故障计数。根据需要增加缓冲区大小。

有关缓冲区相关术语的解释,请参见 GitHub Oboe 文档

OpenSL ES

如果您支持 Android 8.1 之前的版本,则必须使用 OpenSL ES。如果您使用的是 Oboe,您可以配置您的应用以提高延迟。请参阅 GitHub 文档中的 获取最佳延迟

清单结果

下表包含 OboeTester 对往返(输入到输出)延迟的测量结果。

配置 延迟 (ms)
遵循所有建议 20
性能模式不是低延迟 205
不是独占 (共享) 26
44100 Hz (AAudio) 160
44100 Hz (Oboe SRC) 23
未使用输出回调 (MMAP) 21
未使用输出回调 (非 MMAP) 62
缓冲区大小设置为最大值 53