El audio de baja latencia hace que los juegos se sientan más realistas y responsivos.
Completa la siguiente lista de tareas para habilitar el audio de baja latencia en tu juego para Android:
- Usa Oboe.
- Solicita el modo de rendimiento de "latencia baja".
- Solicita el modo de uso compartido "exclusivo".
- Usa el convertidor de tasa de muestreo de Oboe o de 48,000 Hz.
- Establece el uso en AAUDIO_USAGE_GAME.
- Usa devoluciones de llamada de datos.
- Evita bloquear operaciones en la devolución de llamada.
- Ajusta el tamaño del búfer a "búfer doble".
1. Usa la API de Oboe
La API de Oboe es un wrapper de C++ que llama a AAudio en Android 8.1 (nivel de API 27) o versiones posteriores. En versiones anteriores, Oboe usa OpenSL ES.
Oboe está disponible en GitHub o como objeto binario precompilado. Oboe también tiene un QuirksManager que corrige problemas en dispositivos específicos, lo que hace que tu app sea compatible con más dispositivos. Si no puedes usar Oboe, usa AAudio directamente.
2. Solicita el modo de baja latencia
Con Oboe o AAudio, solicita el modo de baja latencia. De lo contrario, obtendrás un modo de latencia más alta de forma predeterminada.
Oboe
builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);
AAudio
AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
3. Solicita el modo exclusivo
También puedes solicitar acceso exclusivo al búfer MMAP. Es posible que tu app no obtenga acceso exclusivo; pero, si lo hace, escribirá directamente en un búfer que lee la DSP, lo que le brinda la latencia más baja posible.
Oboe
builder.setSharingMode(oboe::SharingMode::Exclusive);
AAudio
AAudioStreamBuilder_setSharingMode(builder, AAUDIO_SHARING_MODE_EXCLUSIVE);
4. Evita la conversión de la tasa de muestreo
Usa la tasa de muestreo natural del dispositivo. Para hacerlo, no especifiques una tasa de muestreo, y lo más probable es que obtengas 48,000 Hz. Si especificas una tasa de muestreo, el framework de audio enviará tus datos a una ruta diferente que puede tener una latencia mucho mayor.
Si necesitas usar una tasa de muestreo diferente, utiliza Oboe para realizar la conversión de tasa de muestreo:
builder->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::Medium);
5. Declara correctamente tu caso de uso
Especificar el motivo por el que tu app reproduce audio es fundamental para que el sistema aplique la configuración correcta de enrutamiento, volumen y rendimiento. Por ejemplo, los juegos deben indicar el uso AAUDIO_USAGE_GAME
para aprovechar al máximo las optimizaciones de latencia, en especial cuando se conectan auriculares Bluetooth.
Oboe
builder.setUsage(oboe::Usage::Game);
AAudio
AAudioStreamBuilder_setUsage(builder, AAUDIO_USAGE_GAME);
6. Usa una función de devolución de llamada
Usa una devolución de llamada para la transmisión de salida. Si usas un dispositivo que no admite el modo MMAP de AAudio y usas un dispositivo que bloquea las operaciones de escritura, es posible que la latencia sea mucho mayor.
Oboe
builder.setDataCallback(&myCallbackObject);
AAudio
AAudioStreamBuilder_setDataCallback(builder, &my_callback_proc);
7. Evita bloqueos en la devolución de llamada
Cuando usas una transmisión de latencia baja, el tiempo entre devoluciones de llamada puede ser muy corto, de solo unos milisegundos. Por lo tanto, es muy importante que no hagas nada en la devolución de llamada que pueda causar un bloqueo muy largo. Si se bloquea la devolución de llamada, se producen fallas y desbordamientos del búfer en el audio.
Evita hacer lo siguiente en una devolución de llamada:
- Asignar o liberar memoria
- Archivar o conectar E/S
- Esperar una exclusión mutua o un bloqueo
- Suspender
- Realizar cálculos complejos de CPU de única vez
Las devoluciones de llamada deben realizar cálculos matemáticos a un ritmo uniforme para lograr una reproducción fluida sin fallas.
8. Ajusta el tamaño del búfer
Una vez que la app abra la transmisión de audio, deberás ajustar el tamaño del búfer utilizable para lograr una latencia óptima. Oboe establece automáticamente el tamaño del búfer en dos aumentos de actividad. Sin embargo, con AAudio, la configuración predeterminada es mucho más alta. Usa el almacenamiento en búfer doble estableciendo el tamaño del búfer en el doble del tamaño del aumento. El tamaño del aumento es el tamaño máximo de la devolución de llamada.
AAudio:
int32_t frames = AAudioStream_getFramesPerBurst() * 2;
AAudioStream_setBufferSizeInFrames(stream, frames);
Si el tamaño del búfer es demasiado pequeño, es posible que experimentes fallas ocasionadas por subdesbordamiento. Para obtener un recuento de los errores, llama a AAudioStream_getXRunCount(stream)
. Aumenta el tamaño del búfer según sea necesario.
Consulta la Documentos de Oboe de GitHub para obtener una explicación de la terminología relacionada con los búferes.
OpenSL ES
Si admites versiones de Android anteriores a la 8.1, debes usar OpenSL ES. Si usas Oboe, puedes configurar tu app para mejorar la latencia. Consulta Cómo obtener una latencia óptima en los documentos de GitHub.
Resultados de la lista de tareas
La siguiente tabla contiene las mediciones de OboeTester para latencia de ida y vuelta (entrada a salida).
Configuración | Latencia (ms) |
---|---|
Sigue todas las recomendaciones. | 20 |
Modo de rendimiento con latencia baja | 205 |
No EXCLUSIVO (COMPARTIDO) | 26 |
44,100 Hz (AAudio) | 160 |
44,100 Hz (Oboe SRC) | 23 |
No se está usando una devolución de llamada de salida (MMAP) | 21 |
No se está usando una devolución de llamada de salida (no MMAP) | 62 |
Tamaño del búfer establecido al máximo | 53 |