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
-
cd frameworks/av/services/audioflinger
- Editar
Configuration.h
. -
#define TEE_SINK
. - Vuelva a compilar
libaudioflinger.so
. -
adb root
-
adb remount
- Empuje o sincronice el nuevo
libaudioflinger.so
con el/system/lib
del dispositivo.
Configuración en tiempo de ejecución
-
adb shell getprop | grep ro.debuggable
Confirme que la salida es:[ro.debuggable]: [1]
-
adb shell
-
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
-
echo af.tee=# > /data/local.prop
Donde el valoraf.tee
es un número descrito 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 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
- Ejecute su prueba de audio.
-
adb shell dumpsys media.audio_flinger
- 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. - 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 dedumpsys
, pero aún se guardan en/data/misc/audioserver
al cerrar la pista. - 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:
- Revierta los cambios del código fuente a
Configuration.h
. - Vuelva a compilar
libaudioflinger.so
. - Empuje o sincronice 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 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
yFastCapture
. - 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
:
Puntos notables:
-
init
bifurca ymediaserver
. -
init
detecta la muerte demediaserver
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:
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 shellEl 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