En este artículo, se describen algunos trucos y sugerencias para depurar el audio de Android.
Lavabo de tina
El "tee sink" es una función de depuración de AudioFlinger, disponible solo en compilaciones personalizadas, para retener un fragmento corto de audio reciente para un análisis posterior. Esto permite comparar lo que se reprodujo o grabó realmente con lo que se esperaba.
Por motivos de privacidad, el sumidero de Tee está inhabilitado de forma predeterminada, tanto en el tiempo de compilación como en el tiempo de ejecución. Para usar el sumidero de tee, deberás volver a compilarlo y habilitarlo, y también configurar una propiedad. Asegúrate de inhabilitar esta función después de terminar la depuración. El sumidero de Tee 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, reemplaza /data/misc/audioserver
por /data/misc/media
. Además, debes usar una compilación userdebug o de eng. Si usas una compilación de userdebug, inhabilita Verity con lo siguiente:
adb root && adb disable-verity && adb reboot
Configuración en tiempo de compilación
cd frameworks/av/services/audioflinger
- Editar
Configuration.h
. - Quita el comentario de
#define TEE_SINK
. - Vuelve a compilar
libaudioflinger.so
. adb root
adb remount
- Envía o sincroniza el nuevo
libaudioflinger.so
con el/system/lib
del dispositivo.
Configuración del tiempo de ejecución
adb shell getprop | grep ro.debuggable
Confirma que el resultado sea:[ro.debuggable]: [1]
adb shell
ls -ld /data/misc/audioserver
Confirma que el resultado sea el siguiente:
drwx------ media media ... media
Si el directorio no existe, créalo de la siguiente manera:
mkdir /data/misc/audioserver
chown media:media /data/misc/audioserver
echo af.tee=# > /data/local.prop
Donde el valoraf.tee
es un número que se describe a continuación.chmod 644 /data/local.prop
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 componente.
Consulta el código en AudioFlinger::AudioFlinger()
en AudioFlinger.cpp
para obtener una explicación de cada bit, pero de forma breve:
- 1 = entrada
- 2 = Salida de FastMixer
- 4 = AudioRecord y AudioTrack por pista
Aún no hay un bit para el búfer profundo ni el mezclador normal, pero puedes obtener resultados similares con "4".
Prueba y adquiere datos
- Ejecuta la prueba de audio.
adb shell dumpsys media.audio_flinger
- Busca una línea en el resultado de
dumpsys
como esta:
tee copied to /data/misc/audioserver/20131010101147_2.wav
Este es un archivo .wav PCM. - Luego,
adb pull
cualquier archivo/data/misc/audioserver/*.wav
que te interese. Ten en cuenta que los nombres de los archivos de volcado específicos de la pista no aparecen en el resultado dedumpsys
, pero se guardan en/data/misc/audioserver
cuando se cierra la pista. - Revisa los archivos de volcado para detectar problemas de privacidad antes de compartirlos con otras personas.
Sugerencias
Prueba estas ideas para obtener resultados más útiles:
- Inhabilita los sonidos táctiles y los clics de teclas para reducir las interrupciones en el resultado de la prueba.
- Maximizar todos los volúmenes
- Inhabilita las apps que emitan sonido o que graban desde el micrófono si no son de interés para tu prueba.
- Los volcados específicos de la pista solo se guardan cuando se cierra la pista. Es posible que debas forzar el cierre de una app para volcar sus datos específicos de la pista.
- Realiza el
dumpsys
inmediatamente después de la prueba. Hay una cantidad limitada de espacio de grabación disponible. - Para asegurarte de no perder tus archivos de volcado, cárgalos en tu host de forma periódica. Solo se conserva una cantidad limitada de archivos de volcado. Los volcados más antiguos se quitan después de alcanzar ese límite.
Restablecer
Como se indicó más arriba, no se debe dejar habilitada la función de sumidero en T. Restablece la compilación y el dispositivo de la siguiente manera:
- Revierte los cambios en el código fuente a
Configuration.h
. - Vuelve a compilar
libaudioflinger.so
. - Envía o sincroniza el
libaudioflinger.so
restaurado con el/system/lib
del dispositivo. adb shell
rm /data/local.prop
rm /data/misc/audioserver/*.wav
reboot
media.log
Macros ALOGx
La API de registro estándar del lenguaje Java en el SDK de Android es android.util.Log.
La API correspondiente del lenguaje C en el NDK de Android se __android_log_print
declara en <android/log.h>
.
Dentro de la parte nativa del framework de Android, preferimos macros con nombres como ALOGE
, ALOGW
, ALOGI
, ALOGV
, etcétera. Se declaran en <utils/Log.h>
y, a los efectos de este artículo, nos referiremos a ellas colectivamente como ALOGx
.
Todas estas APIs son fáciles de usar y están bien comprendidas, por lo que están muy difundidas en la plataforma de Android. En particular, el proceso mediaserver
, que incluye el servidor de sonido AudioFlinger, usa ALOGx
de forma extensa.
Sin embargo, ALOGx
y los amigos tienen algunas limitaciones:
-
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 genera información perdida. La variante
ALOGV
está inhabilitada de forma predeterminada en el tiempo de compilación. Sin embargo, por supuesto, incluso puede generar spam de registro si está habilitado. -
Las llamadas subyacentes del sistema del kernel podrían bloquearse, lo que podría generar una inversión de prioridad y, en consecuencia, perturbaciones y errores de medición. Esto es de especial importancia para los subprocesos urgentes, como
FastMixer
yFastCapture
. - Si se inhabilita un registro en particular para reducir el spam de registro, se pierde toda la información que ese registro habría capturado. No es posible habilitar un registro específico de forma retroactiva, después de que quede claro que el registro habría sido interesante.
NBLOG, media.log y MediaLogService
Las APIs de NBLOG
y el proceso media.log
y el servicio MediaLogService
asociados forman un sistema de registro más reciente para el contenido multimedia y están diseñados específicamente para abordar los problemas anteriores. Usaremos el término "media.log" de forma imprecisa 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 Binder 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 subproceso debe usar su propio cronograma.
Beneficios
Los beneficios del sistema media.log
son los siguientes:
- No genera spam en el registro principal, a menos que sea necesario.
- Se puede examinar incluso cuando
mediaserver
falla o se bloquea. - No genera bloqueos por cronograma.
- Ofrece menos interrupciones en el rendimiento. (Por supuesto, ninguna forma de registro es completamente no intrusiva).
Arquitectura
En el siguiente diagrama, se muestra la relación entre el proceso mediaserver
y el proceso init
, antes de que se presente media.log
:

Figura 1: Arquitectura anterior a media.log
Puntos destacados:
init
bifurcaciones y ejecucionesmediaserver
.init
detecta la muerte demediaserver
y vuelve a crear una bifurcación según sea necesario.- No se muestra el registro de
ALOGx
.
En el siguiente diagrama, se muestra la nueva relación de los componentes, después de agregar media.log
a la arquitectura:

Figura 2: Arquitectura después de media.log
Cambios importantes:
-
Los clientes usan la API de
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 manera tal que cualquier daño en la memoria compartida no haga fallar a
MediaLogService
y aún pueda volcar la mayor parte del búfer que no se vea afectado por el daño. - El búfer circular no bloquea y no tiene bloqueo para escribir entradas nuevas y leer entradas existentes.
- No se requieren llamadas al sistema del kernel para escribir en el búfer circular ni leerlo (excepto las marcas de tiempo opcionales).
Dónde puedes usarlo
A partir de Android 4.4, solo hay algunos puntos de registro en AudioFlinger que usan el sistema media.log
. Si bien las nuevas APIs no son tan fáciles de usar como ALOGx
, tampoco son muy difíciles.
Te recomendamos que aprendas a usar el nuevo sistema de registro para las ocasiones en las que sea indispensable.
En particular, se recomienda para los subprocesos de AudioFlinger que deben ejecutarse con frecuencia, de forma periódica y sin bloqueos, como los subprocesos FastMixer
y FastCapture
.
How to use
Cómo agregar registros
Primero, debes agregar registros a tu código.
En los subprocesos FastMixer
y FastCapture
, usa un código como este:
logWriter->log("string"); logWriter->logf("format", parameters); logWriter->logTimestamp();
Como solo los subprocesos FastMixer
y FastCapture
usan este cronograma de NBLog
, no es necesario realizar la exclusión mutua.
En otros subprocesos de AudioFlinger, usa mNBLogWriter
:
mNBLogWriter->log("string"); mNBLogWriter->logf("format", parameters); mNBLogWriter->logTimestamp();
En el caso de los subprocesos que no son FastMixer
ni FastCapture
, el subproceso en sí y las operaciones de Binder pueden usar el cronograma NBLog
del subproceso. NBLog::Writer
no proporciona ninguna exclusión mutua implícita por cronograma, por lo que debes asegurarte de que todos los registros se produzcan en un contexto en el que se mantenga el mutex mLock
del subproceso.
Después de agregar los registros, vuelve a compilar AudioFlinger.
Precaución: Se requiere un cronograma NBLog::Writer
independiente por subproceso para garantizar la seguridad de los subprocesos, ya que los cronogramas omiten los mutexes de forma predeterminada. Si quieres que más de un subproceso use el mismo cronograma, puedes protegerlo con un mutex existente (como se describió anteriormente para mLock
). También puedes usar el wrapper NBLog::LockedWriter
en lugar de NBLog::Writer
.
Sin embargo, esto anula un beneficio principal de esta API: su comportamiento no bloqueador.
La API completa de NBLog
se encuentra en frameworks/av/include/media/nbaio/NBLog.h
.
Habilita media.log
media.log
está inhabilitado de forma predeterminada. Solo está activo cuando la propiedad ro.test_harness
es 1
. Para habilitarla, haz lo siguiente:
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 sucede lo siguiente:
adb shell
ps media
ahora mostrará dos procesos:
- media.log
- mediaserver
Anota el ID de proceso de mediaserver
para más adelante.
Cómo mostrar las líneas de tiempo
Puedes solicitar un volcado de registro de forma manual en cualquier momento. Este comando muestra los registros de todos los cronogramas activos y recientes y, luego, los borra:
dumpsys media.log
Ten en cuenta que, por diseño, los cronogramas son independientes y no hay una función para combinarlos.
Cómo recuperar registros después de que se cierre MediaServer
Ahora, intenta finalizar el proceso mediaserver
: kill -9 #
, en el que # es el ID del proceso que anotaste antes. Deberías ver un volcado de media.log
en el logcat
principal, que muestra todos los registros previos a la falla.
dumpsys media.log