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 rootadb remount- Envie ou sincronize o novo
libaudioflinger.socom o/system/libdo dispositivo.
Configuração do tempo de execução
adb shell getprop | grep ro.debuggable
Confirme se a saída é:[ro.debuggable]: [1]adb shellls -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/audioserverchown media:media /data/misc/audioserverecho af.tee=# > /data/local.prop
Em que o valoraf.teeé um número descrito abaixo.chmod 644 /data/local.propreboot
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 pullqualquer arquivo/data/misc/audioserver/*.wavde 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/audioserverapó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
dumpsysimediatamente 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.sonovamente. - Envie ou sincronize o
libaudioflinger.sorestaurado para o/system/libdo dispositivo. adb shellrm /data/local.proprm /data/misc/audioserver/*.wavreboot
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
FastMixereFastCapture. - 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
mediaserverfalha 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:
initbifurca e executamediaserver.initdetecta a morte demediaservere faz uma nova bifurcação conforme necessário.- O registro de
ALOGxnã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
NBLOGpara criar entradas de registro e anexá-las a um buffer circular na memória compartilhada. -
MediaLogServicepode 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
MediaLogServicee 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 rootadb shellecho ro.test_harness=1 > /data/local.propchmod 644 /data/local.propreboot
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