低延迟音频使游戏感觉更加真实和响应迅速。
完成以下清单以在 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,则可以配置您的应用以提高延迟。请参阅 GitHub 文档中的 获取最佳延迟。
清单结果
下表包含 OboeTester 对往返(输入到输出)延迟的测量结果。
配置 | 延迟(毫秒) |
---|---|
遵循所有建议 | 20 |
性能模式不是低延迟 | 205 |
不是独占(共享) | 26 |
44100 Hz(AAudio) | 160 |
44100 Hz(Oboe SRC) | 23 |
不使用输出回调(MMAP) | 21 |
不使用输出回调(不是 MMAP) | 62 |
缓冲区大小设置为最大 | 53 |