低延迟音频

低延迟音频可让玩家感到游戏更逼真,响应更快速。

完成以下核对清单即可在您的 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,可以配置应用以缩短延迟时间。请参阅 实现最佳延迟时间

核对清单结果

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

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