Depuración de audio

Este artículo describe algunos consejos y trucos para depurar el audio de Android.

Fregadero en T

El "receptor de tee" es una función de depuración de AudioFlinger, disponible solo en compilaciones personalizadas, para retener un breve fragmento de audio reciente para su posterior análisis. Esto permite la comparación entre lo que realmente se reprodujo o grabó y lo que se esperaba.

Por motivos de privacidad, el receptor del tee está deshabilitado de forma predeterminada, tanto en tiempo de compilación como en tiempo de ejecución. Para usar el fregadero en T, deberá habilitarlo recompilando y también configurando una propiedad. Asegúrese de deshabilitar esta función una vez que haya terminado de depurar; el fregadero en T no debe dejarse habilitado en las compilaciones de producción.

Las instrucciones de esta sección son para Android 7.x y versiones posteriores. Para Android 5.x y 6.x, reemplace /data/misc/audioserver con /data/misc/media . Además, debe usar una compilación de depuración de usuario o eng. Si usa una compilación de depuración de usuario, deshabilite la veracidad con:

adb root && adb disable-verity && adb reboot

Configuración en tiempo de compilación

  1. cd frameworks/av/services/audioflinger
  2. Editar Configuration.h .
  3. #define TEE_SINK .
  4. Vuelva a compilar libaudioflinger.so .
  5. adb root
  6. adb remount
  7. Empuje o sincronice el nuevo libaudioflinger.so con el /system/lib del dispositivo.

Configuración en tiempo de ejecución

  1. adb shell getprop | grep ro.debuggable
    Confirme que la salida es: [ro.debuggable]: [1]
  2. adb shell
  3. ls -ld /data/misc/audioserver

    Confirme que la salida es:

    drwx------ media media ... media
    

    Si el directorio no existe, créelo de la siguiente manera:

    mkdir /data/misc/audioserver
    chown media:media /data/misc/audioserver
    
  4. echo af.tee=# > /data/local.prop
    Donde el valor af.tee es un número descrito a continuación.
  5. chmod 644 /data/local.prop
  6. reboot

Valores de la propiedad af.tee

El valor de af.tee es un número entre 0 y 7, que expresa la suma de varios bits, uno por característica. Consulte el código en AudioFlinger::AudioFlinger() en AudioFlinger.cpp para obtener una explicación de cada bit, pero brevemente:

  • 1 = entrada
  • 2 = salida FastMixer
  • 4 = AudioRecord y AudioTrack por pista

Todavía no hay bit para el búfer profundo o el mezclador normal, pero puede obtener resultados similares usando "4".

Probar y adquirir datos

  1. Ejecute su prueba de audio.
  2. adb shell dumpsys media.audio_flinger
  3. Busque una línea en la salida de dumpsys como esta:
    tee copied to /data/misc/audioserver/20131010101147_2.wav
    Este es un archivo PCM .wav.
  4. Luego adb pull cualquier archivo /data/misc/audioserver/*.wav de interés; tenga en cuenta que los nombres de archivo de volcado específicos de la pista no aparecen en la salida de dumpsys , pero aún se guardan en /data/misc/audioserver al cerrar la pista.
  5. Revise los archivos de volcado por cuestiones de privacidad antes de compartirlos con otros.

Sugerencias

Pruebe estas ideas para obtener resultados más útiles:

  • Desactive los sonidos táctiles y los clics de las teclas para reducir las interrupciones en la salida de prueba.
  • Maximiza todos los volúmenes.
  • Deshabilite las aplicaciones que emiten sonido o graban desde el micrófono, si no son de interés para su prueba.
  • Los volcados específicos de la pista solo se guardan cuando la pista está cerrada; es posible que deba forzar el cierre de una aplicación para volcar sus datos específicos de la pista
  • Realice el dumpsys inmediatamente después de la prueba; hay una cantidad limitada de espacio de grabación disponible.
  • Para asegurarse de no perder sus archivos de volcado, cárguelos periódicamente en su host. Solo se conserva un número limitado de archivos de volcado; los volcados más antiguos se eliminan después de alcanzar ese límite.

Restaurar

Como se indicó anteriormente, la función de fregadero en T no debe dejarse habilitada. Restaure su compilación y dispositivo de la siguiente manera:

  1. Revierta los cambios del código fuente a Configuration.h .
  2. Vuelva a compilar libaudioflinger.so .
  3. Empuje o sincronice el libaudioflinger.so restaurado con el /system/lib del dispositivo.
  4. adb shell
  5. rm /data/local.prop
  6. rm /data/misc/audioserver/*.wav
  7. reboot

media.log

macros ALOGx

La API de registro de lenguaje Java estándar en Android SDK es android.util.Log .

La API de lenguaje C correspondiente en Android NDK es __android_log_print declarada en <android/log.h> .

Dentro de la parte nativa del marco de trabajo de Android, preferimos las macros denominadas ALOGE , ALOGW , ALOGI , ALOGV , etc. Se declaran en <utils/Log.h> y, para los fines de este artículo, nos referiremos a ellas colectivamente como ALOGx .

Todas estas API son fáciles de usar y fáciles de entender, por lo que están presentes en toda la plataforma Android. En particular, el proceso del servidor de medios, que incluye el servidor de sonido mediaserver , utiliza ampliamente ALOGx .

Sin embargo, existen algunas limitaciones para ALOGx y sus amigos:

  • Son susceptibles al "spam de registro": el búfer de registro es un recurso compartido, por lo que puede desbordarse fácilmente debido a entradas de registro no relacionadas, lo que resulta en información perdida. La variante ALOGV está deshabilitada en tiempo de compilación de forma predeterminada. Pero, por supuesto, incluso puede generar spam de registro si está habilitado.
  • Las llamadas al sistema del núcleo subyacente podrían bloquearse, lo que posiblemente resulte en una inversión de prioridad y, en consecuencia, perturbaciones e inexactitudes en las mediciones. Esto es de especial interés para subprocesos de tiempo crítico como FastMixer y FastCapture .
  • Si un registro en particular está deshabilitado para reducir el spam de registros, se perderá cualquier información que hubiera sido capturada por ese registro. No es posible habilitar un registro específico de forma retroactiva, después de que queda claro que el registro hubiera sido interesante.

NBLOG, media.log y MediaLogService

Las API de NBLOG y el proceso media.log asociado y el servicio MediaLogService juntos forman un sistema de registro más nuevo para los medios y están diseñados específicamente para abordar los problemas anteriores. Usaremos vagamente el término "media.log" para referirnos a los tres, pero estrictamente hablando, NBLOG es la API de registro de C++, media.log es un nombre de proceso de Linux y MediaLogService es un servicio de enlace de Android para examinar los registros.

Una "línea de tiempo" de media.log es una serie de entradas de registro cuyo orden relativo se conserva. Por convención, cada hilo debe usar su propia línea de tiempo.

Beneficios

Los beneficios del sistema media.log son que:

  • No envía spam al registro principal a menos y hasta que sea necesario.
  • Se puede examinar incluso cuando el servidor de mediaserver falla o se cuelga.
  • No es bloqueante por línea de tiempo.
  • Ofrece menos perturbaciones al rendimiento. (Por supuesto, ninguna forma de registro es completamente no intrusiva).

Arquitectura

El siguiente diagrama muestra la relación del proceso mediaserver y el proceso init , antes de que se introduzca media.log :

Arquitectura antes de media.log

Figura 1. Arquitectura antes de media.log

Puntos notables:

  • init bifurca y mediaserver .
  • init detecta la muerte de mediaserver y vuelve a bifurcar según sea necesario.
  • No se muestra el registro ALOGx .

El siguiente diagrama muestra la nueva relación de los componentes, después media.log a la arquitectura:

Arquitectura después de media.log

Figura 2. Arquitectura después de media.log

Cambios importantes:

  • Los clientes usan la API NBLOG para construir entradas de registro y agregarlas a un búfer circular en la memoria compartida.
  • MediaLogService puede volcar el contenido del búfer circular en cualquier momento.
  • El búfer circular está diseñado de tal manera que cualquier corrupción de la memoria compartida no bloqueará MediaLogService y aún podrá volcar la mayor parte del búfer que no se vea afectado por la corrupción.
  • El búfer circular no bloquea ni bloquea tanto para escribir nuevas entradas como para leer entradas existentes.
  • No se requieren llamadas al sistema del kernel para escribir o leer del búfer circular (aparte de las marcas de tiempo opcionales).

Dónde utilizar

A partir de Android 4.4, solo hay unos pocos puntos de registro en AudioFlinger que usan el sistema media.log . Aunque las nuevas API no son tan fáciles de usar como ALOGx , tampoco son extremadamente difíciles. Te animamos a conocer el nuevo sistema de registro para aquellas ocasiones en que sea indispensable. En particular, se recomienda para subprocesos AudioFlinger que deben ejecutarse con frecuencia, periódicamente y sin bloqueos, como los FastMixer y FastCapture .

Cómo utilizar

Agregar registros

Primero, debe agregar registros a su código.

En FastMixer y FastCapture , use un código como este:

logWriter->log("string");
logWriter->logf("format", parameters);
logWriter->logTimestamp();

Como esta línea de tiempo de NBLog solo la utilizan los FastMixer y FastCapture , no es necesario excluirse mutuamente.

En otros subprocesos de AudioFlinger, use mNBLogWriter :

mNBLogWriter->log("string");
mNBLogWriter->logf("format", parameters);
mNBLogWriter->logTimestamp();

Para subprocesos que no sean FastMixer y FastCapture , la línea de tiempo NBLog del subproceso puede ser utilizada tanto por el propio subproceso como por las operaciones de enlace. NBLog::Writer no proporciona ninguna exclusión mutua implícita por línea de tiempo, así que asegúrese de que todos los registros se produzcan dentro de un contexto en el que se mantenga el mLock mutex del subproceso.

Una vez que haya agregado los registros, vuelva a compilar AudioFlinger.

Precaución: Se requiere una línea de tiempo NBLog::Writer separada por subproceso, para garantizar la seguridad de los subprocesos, ya que las líneas de tiempo omiten los mutex por diseño. Si desea que más de un subproceso use la misma línea de tiempo, puede proteger con un mutex existente (como se describe anteriormente para mLock ). O puede usar el envoltorio NBLog::LockedWriter en lugar de NBLog::Writer . Sin embargo, esto niega un beneficio principal de esta API: su comportamiento sin bloqueo.

La API completa de NBLog se encuentra en frameworks/av/include/media/nbaio/NBLog.h .

Habilitar media.log

media.log está deshabilitado de forma predeterminada. Está activo solo cuando la propiedad ro.test_harness es 1 . Puede habilitarlo de la siguiente manera:

adb root
adb shell
echo ro.test_harness=1 > /data/local.prop
chmod 644 /data/local.prop
reboot

La conexión se pierde durante el reinicio, por lo que:

adb shell
El comando ps media ahora mostrará dos procesos:
  • media.log
  • servidor multimedia

Anote el ID de proceso de mediaserver para más adelante.

Visualización de las líneas de tiempo

Puede solicitar manualmente un volcado de registros en cualquier momento. Este comando muestra registros de todas las líneas de tiempo activas y recientes, y luego las borra:

dumpsys media.log

Tenga en cuenta que, por diseño, los cronogramas son independientes y no existe ninguna posibilidad de fusionar los cronogramas.

Recuperación de registros después de la muerte del servidor de medios

Ahora intente eliminar el proceso mediaserver : kill -9 # , donde # es el ID del proceso que anotó anteriormente. Debería ver un volcado de media.log en el logcat principal, que muestra todos los registros que conducen al bloqueo.

dumpsys media.log