Depuración de audio

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

fregadero en T

El "tee fregadero" 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 comparar lo que realmente se reprodujo o grabó con lo que se esperaba.

Por motivos de privacidad, el fregadero en T está deshabilitado de forma predeterminada, tanto en tiempo de compilación como en tiempo de ejecución. Para utilizar el fregadero en T, deberá habilitarlo volviendo a compilar y también estableciendo una propiedad. Asegúrese de desactivar esta función una vez que haya terminado de depurar; el fregadero en T no debe dejarse habilitado en las versiones 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 utilizar una compilación de usuario o eng. Si utiliza una compilación de depuración de usuario, desactive la verdad 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. Descomentar #define TEE_SINK .
  4. Reconstruya 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 que se describe a continuación.
  5. chmod 644 /data/local.prop
  6. reboot

Valores para una 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

Aún no existe un bit para búfer profundo o mezclador normal, pero puedes 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 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 archivos de volcado específicos de la pista no aparecen en la salida dumpsys , pero aún así se guardan en /data/misc/audioserver al cerrar la pista.
  5. Revise los archivos de volcado por cuestiones de privacidad antes de compartirlos con otras personas.

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 la prueba.
  • Maximiza todos los volúmenes.
  • Desactive 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 sólo se guardan cuando la pista está cerrada; Es posible que tengas que forzar el cierre de una aplicación para poder volcar sus datos específicos de la pista.
  • Haga los 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. Sólo se conserva una cantidad limitada de archivos de volcado; Los volcados más antiguos se eliminan una vez que se alcanza ese límite.

Restaurar

Como se señaló 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. Reconstruya 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

medios.log

Macros ALOGx

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

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

Dentro de la parte nativa del marco de trabajo de Android, preferimos 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 bien comprendidas, por lo que están omnipresentes en toda la plataforma Android. En particular, el proceso mediaserver , que incluye el servidor de sonido AudioFlinger, utiliza ALOGx ampliamente.

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

  • Son susceptibles al "spam de registros": el búfer de registros es un recurso compartido, por lo que puede desbordarse fácilmente debido a entradas de registros 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 esto puede generar registros de spam si está habilitado.
  • Las llamadas al sistema del kernel subyacente podrían bloquearse, lo que posiblemente provocaría una inversión de prioridad y, en consecuencia, perturbaciones e imprecisiones en las mediciones. Esto es de especial preocupación para subprocesos en los que el tiempo es crítico, como FastMixer y FastCapture .
  • Si se deshabilita un registro en particular 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 quede claro que el registro hubiera sido interesante.

NBLOG, media.log y MediaLogService

Las API NBLOG y el proceso media.log asociado y el servicio MediaLogService juntos forman un sistema de registro más nuevo para medios y están diseñados específicamente para abordar los problemas anteriores. Usaremos libremente 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 carpeta de Android para examinar los registros.

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

Beneficios

Los beneficios del sistema media.log son que:

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

Arquitectura

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

Arquitectura antes de media.log

Figura 1. Arquitectura anterior a media.log

Puntos notables:

  • init bifurca y ejecuta mediaserver .
  • init detecta la muerte de mediaserver y vuelve a bifurcarlo según sea necesario.
  • El registro ALOGx no se muestra.

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

Arquitectura después de media.log

Figura 2. Arquitectura después de media.log

Cambios importantes:

  • Los clientes utilizan la API NBLOG para crear 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 daño en 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 desde el 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 utilizan 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 las que sea indispensable. En particular, se recomienda para subprocesos AudioFlinger que deben ejecutarse con frecuencia, periódicamente y sin bloqueos, como los subprocesos FastMixer y FastCapture .

Cómo utilizar

Agregar registros

Primero, necesitas agregar registros a tu código.

En los subprocesos FastMixer y FastCapture , utilice código como este:

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

Como esta línea de tiempo NBLog solo la utilizan los subprocesos FastMixer y FastCapture , no hay necesidad de exclusión mutua.

En otros hilos de AudioFlinger, use mNBLogWriter :

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

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

Después de haber agregado los registros, reconstruya AudioFlinger.

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

La API NBLog completa 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 . Puedes habilitarlo mediante:

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, entonces:

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

Tenga en cuenta el ID del proceso del mediaserver para más adelante.

Mostrar 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 los borra:

dumpsys media.log

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

Recuperar 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 previos al bloqueo.

dumpsys media.log