低延迟音频可让玩家感到游戏更逼真,响应更快速。
完成以下核对清单即可在您的 Android 游戏中实现低延迟音频:
- 使用 Oboe
- 请求“低延迟”高性能模式
- 请求“独占”共享模式
- 使用 48000 Hz 或 Oboe 采样率转换器
- 将用途设为 AAUDIO_USAGE_GAME
- 使用数据回调
- 避免回调中有阻塞操作
- 将缓冲区空间调整为“双缓冲区”
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 |