Este artigo descreve algumas dicas e truques para depurar áudio no Android.
Tee sink
O "tee sink" é um recurso de depuração do AudioFlinger, disponível apenas em builds personalizados, para reter um fragmento curto de áudio recente para análise posterior. Isso permite a comparação entre o que foi realmente tocado ou gravado e o que era esperado.
Para privacidade, o coletor de tee é desativado por padrão no tempo de compilação e de execução. Para usar o coletor de tee, você precisa ativá-lo recriando-o e definindo uma propriedade. Desative esse recurso depois de terminar a depuração. O sink de tee não pode ser deixado ativado em builds de produção.
As instruções desta seção são para o Android 7.x e versões mais recentes. Para o Android
5.x e 6.x, substitua /data/misc/audioserver
por
/data/misc/media
. Além disso, é necessário usar um build userdebug ou
eng. Se você usar um build userdebug, desative o verity com:
adb root && adb disable-verity && adb reboot
Configuração no tempo de compilação
cd frameworks/av/services/audioflinger
- Editar
Configuration.h
. - Remova o comentário de
#define TEE_SINK
. - Crie novamente o
libaudioflinger.so
. adb root
adb remount
- Envie ou sincronize o novo
libaudioflinger.so
com o/system/lib
do dispositivo.
Configuração do tempo de execução
adb shell getprop | grep ro.debuggable
Confirme se a saída é:[ro.debuggable]: [1]
adb shell
ls -ld /data/misc/audioserver
Confirme se a saída é:
drwx------ media media ... media
Se o diretório não existir, crie-o da seguinte maneira:
mkdir /data/misc/audioserver
chown media:media /data/misc/audioserver
echo af.tee=# > /data/local.prop
Em que o valoraf.tee
é um número descrito abaixo.chmod 644 /data/local.prop
reboot
Valores para a propriedade af.tee
O valor de af.tee
é um número entre 0 e 7, que expressa
a soma de vários bits, um por elemento.
Consulte o código em AudioFlinger::AudioFlinger()
em AudioFlinger.cpp
para uma explicação de cada bit, mas brevemente:
- 1 = entrada
- 2 = saída do FastMixer
- 4 = AudioRecord e AudioTrack por faixa
Ainda não há um bit para buffer profundo ou mixer normal, mas você pode conseguir resultados semelhantes usando "4".
Testar e adquirir dados
- Execute o teste de áudio.
adb shell dumpsys media.audio_flinger
- Procure uma linha na saída
dumpsys
, como esta:
tee copied to /data/misc/audioserver/20131010101147_2.wav
Este é um arquivo PCM .wav. - Em seguida,
adb pull
qualquer arquivo/data/misc/audioserver/*.wav
de interesse. Os nomes de arquivos de despejo específicos da faixa não aparecem na saídadumpsys
, mas ainda são salvos em/data/misc/audioserver
após o fechamento da faixa. - Analise os arquivos de despejo para verificar se há problemas de privacidade antes de compartilhar com outras pessoas.
Sugestões
Para resultados mais úteis, tente estas ideias:
- Desative os sons de toque e os cliques de tecla para reduzir interrupções na saída do teste.
- Maximizar todos os volumes.
- Desative os apps que emitem som ou gravam pelo microfone, se eles não forem de interesse para o teste.
- Os despejos específicos da faixa são salvos apenas quando a faixa é fechada. Talvez seja necessário forçar o fechamento de um app para despejar os dados específicos da faixa.
- Faça a
dumpsys
imediatamente após o teste. Há uma quantidade limitada de espaço de gravação disponível. - Para não perder seus arquivos de despejo, faça upload deles no host periodicamente. Apenas um número limitado de arquivos de despejo é preservado. Os despejo mais antigos são removidos quando esse limite é atingido.
Restaurar
Conforme observado acima, o recurso de coletor de tee não deve ser ativado. Restaure o build e o dispositivo da seguinte maneira:
- Reverta as mudanças no código-fonte para
Configuration.h
. - Crie o
libaudioflinger.so
novamente. - Envie ou sincronize o
libaudioflinger.so
restaurado para o/system/lib
do dispositivo. adb shell
rm /data/local.prop
rm /data/misc/audioserver/*.wav
reboot
media.log
Macros ALOGx
A API de registro de linguagem Java padrão no SDK do Android é android.util.Log.
A API da linguagem C correspondente no Android NDK é
__android_log_print
declarada em <android/log.h>
.
Na parte nativa do framework do Android, preferimos macros com os nomes ALOGE
, ALOGW
,
ALOGI
, ALOGV
etc. Elas são declaradas em
<utils/Log.h>
e, para os fins deste artigo, vamos nos referir a elas coletivamente como ALOGx
.
Todas essas APIs são fáceis de usar e bem compreendidas, por isso são usadas
em toda a Plataforma Android. Especificamente, o processo mediaserver
,
que inclui o servidor de som AudioFlinger, usa
ALOGx
extensivamente.
No entanto, há algumas limitações para ALOGx
e amigos:
-
Eles são suscetíveis a "spam de registro": o buffer de registro é um recurso compartilhado
que pode transbordar facilmente devido a entradas de registro não relacionadas, resultando em
perda de informações. A variante
ALOGV
é desativada no momento da compilação por padrão. No entanto, ele pode resultar em spam de registro se estiver ativado. -
As chamadas do sistema do kernel podem ser bloqueadas, o que pode resultar na
inversão de prioridade e, consequentemente, em interferências e
incorreções de medição. Isso é de
preocupação especial para linhas de execução críticas para o tempo, como
FastMixer
eFastCapture
. - Se um registro específico for desativado para reduzir o spam, todas as informações que seriam capturadas por ele serão perdidas. Não é possível ativar um registro específico retroativamente, depois de ficar claro que ele seria interessante.
NBLOG, media.log e MediaLogService
As APIs NBLOG
e o processo media.log
associado e o serviço MediaLogService
juntos formam um sistema de registro mais recente para mídia e foram criados
especificamente para resolver os problemas acima. Usaremos o termo
"media.log" de forma genérica para nos referirmos aos três, mas, estritamente falando, NBLOG
é a
API de geração de registros C++, media.log
é um nome de processo do Linux e MediaLogService
é um serviço de vinculação do Android para examinar os registros.
Uma "linha do tempo" media.log
é uma série
de entradas de registro com a ordem relativa preservada.
Por convenção, cada linha de execução precisa usar a própria linha do tempo.
Vantagens
Os benefícios do sistema media.log
são:
- Não gera spam no registro principal, a menos que seja necessário.
- Pode ser examinado mesmo quando
mediaserver
falha ou trava. - Não bloqueia por linha do tempo.
- Oferece menos interferência no desempenho. Obviamente, nenhuma forma de registro é completamente não intrusiva.
Arquitetura
O diagrama abaixo mostra a relação entre o processo mediaserver
e o processo init
, antes da introdução do media.log
:

Figura 1. Arquitetura antes do media.log
Pontos importantes:
init
bifurca e executamediaserver
.init
detecta a morte demediaserver
e faz uma nova bifurcação conforme necessário.- O registro de
ALOGx
não é mostrado.
O diagrama abaixo mostra a nova relação dos componentes,
depois que media.log
foi adicionado à arquitetura:

Figura 2. Arquitetura após o media.log
Mudanças importantes:
-
Os clientes usam a API
NBLOG
para criar entradas de registro e anexá-las a um buffer circular na memória compartilhada. -
MediaLogService
pode despejar o conteúdo do buffer circular a qualquer momento. -
O buffer circular é projetado de modo que qualquer corrupção da
memória compartilhada não cause uma falha no
MediaLogService
e ainda seja capaz de despejar o máximo do buffer que não é afetado pela corrupção. - O buffer circular não bloqueia e não tem bloqueio para gravar novas entradas e ler entradas existentes.
- Nenhuma chamada de sistema do kernel é necessária para gravar ou ler o buffer circular (exceto carimbos de data/hora opcionais).
Onde usar
No Android 4.4 e versões mais recentes, há apenas alguns pontos de registro no AudioFlinger
que usam o sistema media.log
. Embora as novas APIs não sejam tão
fáceis de usar quanto a ALOGx
, elas também não são extremamente difíceis.
Recomendamos que você aprenda a usar o novo sistema de registro para as
ocasiões em que ele é indispensável.
Em particular, é recomendável para linhas de execução do AudioFlinger que precisam
ser executadas com frequência, periodicamente e sem bloqueio, como as
linhas de execução FastMixer
e FastCapture
.
Como usar
Adicionar registros
Primeiro, você precisa adicionar registros ao código.
Nas linhas de execução FastMixer
e FastCapture
, use um código como este:
logWriter->log("string"); logWriter->logf("format", parameters); logWriter->logTimestamp();
Como essa linha do tempo NBLog
é usada apenas pelas linhas de execução FastMixer
e
FastCapture
,
não é necessário fazer a exclusão mútua.
Em outras linhas de execução do AudioFlinger, use mNBLogWriter
:
mNBLogWriter->log("string"); mNBLogWriter->logf("format", parameters); mNBLogWriter->logTimestamp();
Para linhas de execução diferentes de FastMixer
e FastCapture
,
a linha do tempo NBLog
da linha de execução pode ser usada pela própria linha de execução e
por operações de vinculação. O NBLog::Writer
não fornece nenhuma
exclusão mútua implícita por linha do tempo. Portanto, verifique se todos os registros ocorrem
em um contexto em que o mutex mLock
da linha de execução é mantido.
Depois de adicionar os registros, recrie o AudioFlinger.
Atenção:uma linha do tempo NBLog::Writer
separada é necessária por linha de execução
para garantir a segurança da linha de execução, já que as linhas do tempo omitem mutexes por design. Se
você quiser que mais de uma linha de execução use a mesma linha do tempo, proteja com um
mutex existente (conforme descrito acima para mLock
). Ou use
o wrapper NBLog::LockedWriter
em vez de NBLog::Writer
.
No entanto, isso anula um dos principais benefícios dessa API: o comportamento
não bloqueado.
A API NBLog
completa está em frameworks/av/include/media/nbaio/NBLog.h
.
Ativar o media.log
media.log
está desativado por padrão. Ela só fica ativa quando a propriedade
ro.test_harness
é 1
. Para ativar esse recurso, faça o seguinte:
adb root
adb shell
echo ro.test_harness=1 > /data/local.prop
chmod 644 /data/local.prop
reboot
A conexão é perdida durante a reinicialização. Portanto:
adb shell
ps media
agora vai mostrar dois processos:
- media.log
- mediaserver
Anote o ID do processo de mediaserver
para uso posterior.
Mostrar as linhas do tempo
É possível solicitar um despejo de registro manualmente a qualquer momento. Este comando mostra os registros de todas as linhas do tempo ativas e recentes e os limpa:
dumpsys media.log
As linhas do tempo de design são independentes, e não há uma opção para mesclar linhas do tempo.
Recuperar registros após a morte do mediaserver
Agora tente encerrar o processo mediaserver
: kill -9 #
, em que # é
o ID do processo que você anotou anteriormente. Você vai encontrar um despejo de media.log
no logcat
principal, mostrando todos os registros que levaram ao erro.
dumpsys media.log