低延迟音频

低延迟音频使游戏感觉更加真实和响应迅速。

完成以下清单以在 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 对往返(输入到输出)延迟的测量结果。

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