Reproducción de audio de baja latencia en Android

Actualmente estoy intentando minimizar la latencia de audio para una aplicación simple:

Tengo un video en una PC y estoy transmitiendo el audio del video a través de RTP a un cliente móvil. Con un algoritmo de almacenamiento en búfer muy similar, puedo lograr 90 ms de latencia en iOS, pero un terrible ± 180 ms en Android.

Supongo que la diferencia se debe a los conocidos problemas de latencia en Android.

Sin embargo, después de leer un poco, me encontré con este artículo , que dice que:

  1. El audio de baja latencia está disponible desde Android 4.1 / 4.2 en ciertos dispositivos.

  2. El audio de baja latencia se puede lograr usando libpd, que es la biblioteca Pure Data para Android .

Tengo 2 preguntas, directamente relacionadas con esas 2 declaraciones:

  1. ¿Dónde puedo encontrar más información sobre el nuevo audio de baja latencia en Jellybean? Esto es todo lo que puedo encontrar, pero me falta información específica . ¿Deberían los cambios ser transparentes para mí, o hay algunas llamadas nuevas de clase / API que debería implementar para que noté cualquier cambio en mi aplicación? Estoy usando la API de AudioTrack, y ni siquiera estoy seguro de si debería aprovechar los beneficios de esta mejora o si debería buscar otro mecanismo para la reproducción de audio.

  2. ¿Debería buscar usar libpd? Me parece que es la única oportunidad que tengo de lograr latencias más bajas, pero como siempre he pensado en la PD como una herramienta de síntesis de audio, ¿es realmente adecuada para un proyecto que simplemente toma fotogtwigs de una transmisión en red y los reproduce? ? Realmente no estoy haciendo ninguna síntesis. ¿Estoy siguiendo el camino equivocado?

Como nota adicional, antes de que alguien mencione OpenSL ES, este artículo deja bastante claro que no se deben esperar mejoras en la latencia al usarlo :

“Como OpenSL ES es una API C nativa, los subprocesos que no son de Dalvik que llaman OpenSL ES no tienen sobrecarga relacionada con Dalvik, como las pausas de recolección de basura. Sin embargo, no hay ningún beneficio de rendimiento adicional para el uso de OpenSL ES aparte de esto. en particular, el uso de OpenSL ES no da como resultado una latencia de audio inferior, una mayor prioridad de progtwigción, etc. que lo que la plataforma generalmente proporciona “.

Para la latencia más baja en Android a partir de la versión 4.2.2, debe hacer lo siguiente, ordenado de menos a más obvio:

  1. Elija un dispositivo que admita FEATURE_AUDIO_PRO si es posible, o FEATURE_AUDIO_LOW_LATENCY de lo contrario. (“Baja latencia” es 50 ms en una dirección; Pro es <20 ms ida y vuelta).

  2. Use OpenSL. El GC Dalvik tiene un costo amortizado bajo, pero cuando se ejecuta, lleva más tiempo del que puede permitir un hilo de audio de baja latencia.

  3. Procesar audio en una callback en cola de buffer. El sistema ejecuta devoluciones de llamada en cola de búfer en un subproceso que tiene una progtwigción más favorable que los subprocesos de modo de usuario normales.

  4. Haga que su tamaño de búfer sea un múltiplo de AudioManager.getProperty (PROPERTY_OUTPUT_FRAMES_PER_BUFFER). De lo contrario, su callback ocasionalmente recibirá dos llamadas por segmento de tiempo en lugar de una. A menos que el uso de la CPU sea realmente ligero, es probable que esto termine por fallar. (En Android M, es muy importante usar EXACTAMENTE el tamaño del búfer del sistema, debido a un error en el código de manejo del búfer).

  5. Use la frecuencia de muestreo proporcionada por AudioManager.getProperty (PROPERTY_OUTPUT_SAMPLE_RATE). De lo contrario, sus búferes toman un desvío a través del remuestreador del sistema.

  6. Nunca haga un syscall o bloquee un objeto de sincronización dentro de la callback del buffer. Si debe sincronizar, use una estructura sin cerrojo. Para obtener mejores resultados, use una estructura completamente libre de esperas, como un buffer de anillo de un solo escritor de un solo lector. Muchos desarrolladores se equivocan y terminan con fallas impredecibles y difíciles de depurar.

  7. Use instrucciones vectoriales como NEON, SSE o el conjunto de instrucciones equivalente en su procesador de destino.

  8. Pruebe y mida su código. Haga un seguimiento de cuánto tiempo lleva correr, y recuerde que necesita conocer el peor de los casos, no el promedio, porque el peor caso es el que causa los fallos. Y sé conservador. Ya sabes que si lleva más tiempo procesar tu audio que tocarlo, nunca tendrás una baja latencia. Pero en Android esto es aún más importante, porque la frecuencia de la CPU fluctúa mucho. Puede usar entre un 60% y un 70% de la CPU para audio, pero tenga en cuenta que esto cambiará a medida que el dispositivo se caliente o enfríe, o cuando las radios WiFi o LTE se enciendan y se apaguen, y así sucesivamente.

El audio de baja latencia ya no es una característica nueva para Android, pero aún requiere cambios específicos del dispositivo en el hardware, los controladores, el kernel y el marco para lograrlo. Esto significa que hay mucha variación en la latencia que puede esperar de diferentes dispositivos, y dado el precio de venta de los teléfonos Android, probablemente siempre habrá diferencias. Busque FEATURE_AUDIO_PRO o FEATURE_AUDIO_LOW_LATENCY para identificar dispositivos que cumplan con los criterios de latencia que requiere su aplicación.

Al utilizar OpenSL ES, debe cumplir los siguientes requisitos para obtener un bajo rendimiento de latencia en Jellybean y versiones posteriores de Android:

  • El audio debe ser mono o estéreo, PCM lineal.

  • La frecuencia de muestreo de audio debe ser la misma frecuencia de muestreo que la velocidad nativa de la salida (esto puede no ser necesario en algunos dispositivos, porque FastMixer es capaz de remuestrear si el vendedor lo configura para hacerlo. Pero en mis pruebas obtuve muy artefactos notables cuando se sobremuestrea desde 44.1 a 48 kHz en el FastMixer ).

  • Su BufferQueue debe tener al menos 2 buffers. (Este requisito se ha relajado desde entonces. Ver este compromiso por Glenn Kasten. No estoy seguro de qué versión de Android apareció por primera vez, pero supongo que sería 4.4).

  • No puede usar ciertos efectos (p. Ej. Reverb, Bass Boost, Ecualización, Virtualización, …).

La clase SoundPool también intentará hacer uso interno de AudioTrack rápido cuando sea posible (se aplicarán los mismos criterios que los anteriores, excepto la parte BufferQueue ).

Desde el enlace en tu punto 1:

“Audio de baja latencia

Android 4.2 mejora la compatibilidad con la reproducción de audio de baja latencia, a partir de las mejoras realizadas en la versión Android 4.1 para la latencia de salida de audio utilizando OpenSL ES, Soundpool y API de generación de tonos. Estas mejoras dependen del soporte de hardware: los dispositivos que ofrecen estas características de audio de baja latencia pueden publicitar su compatibilidad con aplicaciones a través de una constante de características de hardware “.

Su cita en forma completa:

“Actuación

Como OpenSL ES es una C API nativa, los subprocesos de aplicación no Dalvik que llaman a OpenSL ES no tienen sobrecarga relacionada con Dalvik, como pausas de recolección de basura. Sin embargo, no hay ningún beneficio de rendimiento adicional para el uso de OpenSL ES aparte de esto. En particular, el uso de OpenSL ES no da como resultado una latencia de audio menor, una mayor prioridad de progtwigción, etc. que lo que la plataforma generalmente proporciona. Por otro lado, a medida que la plataforma Android y las implementaciones de dispositivos específicos continúan evolucionando, una aplicación OpenSL ES puede beneficiarse de cualquier mejora futura en el rendimiento del sistema “.

Entonces, la API para comunicarse con los controladores y luego hw es OpenSl (de la misma manera que Opengl lo hace con los gráficos). Sin embargo, las versiones anteriores de Android tienen un mal diseño en controladores y / o hw. Estos problemas fueron abordados y corregidos con las versiones 4.1 y 4.2, por lo que si el HD tiene la potencia, usted obtiene baja latencia usando OpenSL.

De nuevo, de esta nota del sitio web de la biblioteca puredata, es evidente que la biblioteca usa OpenSL para lograr baja latencia:

Compatibilidad con baja latencia para dispositivos compatibles La última versión de Pd para Android (a partir del 28/12/2012) admite audio de baja latencia para dispositivos Android compatibles. Al actualizar su copia, asegúrese de extraer la última versión de ambos, pd-for-android y el submódulo libpd de GitHub.

En el momento de escribir, Galaxy Nexus, Nexus 4 y Nexus 10 proporcionan una pista de baja latencia para la salida de audio. Para acceder a la pista de baja latencia, una aplicación debe usar OpenSL y debe funcionar con la frecuencia de muestreo correcta y el tamaño del búfer. Esos parámetros dependen del dispositivo (Galaxy Nexus y Nexus 10 operan a 44100Hz, mientras que Nexus 4 opera a 48000Hz, el tamaño del buffer es diferente para cada dispositivo).

Como es su costumbre, Pd para Android revisa todas las complejidades tanto como sea posible, brindando acceso a las nuevas características de baja latencia cuando están disponibles y al mismo tiempo es compatible con versiones anteriores de Android. Debajo del capó, los componentes de audio de Pd para Android usarán OpenSL en Android 2.3 y posterior, mientras recurren a la antigua API AudioTrack / AudioRecord en Java en Android 2.2 y versiones anteriores.

Aquellos de ustedes que estén más interesados ​​en el problema de 10 milisegundos de Android, es decir, audio de baja latencia en Android. En Superpowered creamos el explicador de latencia de la ruta de audio de Android. Por favor mira aquí:

http://superpowered.com/androidaudiopathlatency/#axzz3fDHsEe56

Otra base de datos de latencias de audio y tamaños de búfer utilizados:

http://superpowered.com/latency/#table

Código fuente:

https://github.com/superpoweredSDK/SuperpoweredLatency

Aplicación para medir sampleRate y bufferSize: https://code.google.com/p/high-performance-audio/source/checkout y http://audiobuffersize.appspot.com/ DB de resultados