Este artigo descreve algumas dicas e truques para depurar o áudio do Android.
Lavatório
O "tee sink" é um recurso de depuração do AudioFlinger, disponível apenas em compilações personalizadas, para reter um pequeno fragmento de áudio recente para análise posterior. Isso permite a comparação entre o que foi realmente tocado ou gravado versus o que era esperado.
Para privacidade, o tee sink é desabilitado por padrão, tanto em tempo de compilação quanto em tempo de execução. Para usar o tee sink, você precisará habilitá-lo recompilando e também definindo uma propriedade. Certifique-se de desabilitar esse recurso depois de terminar a depuração; o tee sink não deve ser deixado habilitado em builds de produção.
As instruções nesta seção são para Android 7.xe superior. Para Android 5.xe 6.x, substitua /data/misc/audioserver por /data/misc/media . Além disso, você deve usar um userdebug ou eng build. Se você usar uma compilação userdebug, desative a veracidade com:
adb root && adb disable-verity && adb reboot
Configuração em tempo de compilação
-
cd frameworks/av/services/audioflinger - Editar
Configuration.h. - Remova o comentário
#define TEE_SINK. -
libaudioflinger.so. -
adb root -
adb remount - Envie ou sincronize o novo
libaudioflinger.socom o/system/libdo dispositivo.
Configuração em tempo de execução
-
adb shell getprop | grep ro.debuggable
Confirme se a saída é:[ro.debuggable]: [1] -
adb shell -
ls -ld /data/misc/audioserverConfirme se a saída é:
drwx------ media media ... media
Se o diretório não existir, crie-o da seguinte forma:
mkdir /data/misc/audioserverchown media:media /data/misc/audioserver -
echo af.tee=# > /data/local.prop
Onde 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, expressando a soma de vários bits, um por recurso. Veja o código em AudioFlinger::AudioFlinger() em AudioFlinger.cpp para uma explicação de cada bit, mas brevemente:
- 1 = entrada
- 2 = saída FastMixer
- 4 = AudioRecord e AudioTrack por faixa
Ainda não há um pouco para buffer profundo ou mixer normal, mas você pode obter resultados semelhantes usando "4".
Testar e adquirir dados
- Execute seu teste de áudio.
-
adb shell dumpsys media.audio_flinger - Procure uma linha na saída
dumpsyscomo esta:
tee copied to /data/misc/audioserver/20131010101147_2.wav
Este é um arquivo .wav PCM. - Então
adb pullquaisquer arquivos/data/misc/audioserver/*.wavde interesse; observe que os nomes de arquivos dump específicos da faixa não aparecem na saídadumpsys, mas ainda são salvos em/data/misc/audioserverapós o fechamento da faixa. - Revise os arquivos de despejo quanto a questões de privacidade antes de compartilhar com outras pessoas.
Sugestões
Experimente estas ideias para obter resultados mais úteis:
- Desative os sons de toque e cliques de teclas para reduzir as interrupções na saída de teste.
- Maximize todos os volumes.
- Desative os aplicativos que emitem som ou gravam do microfone, caso não sejam do interesse do seu teste.
- Os dumps específicos da trilha são salvos apenas quando a trilha é fechada; pode ser necessário forçar o fechamento de um aplicativo para despejar seus dados específicos da faixa
- Faça o
dumpsysimediatamente após o teste; há uma quantidade limitada de espaço de gravação disponível. - Para garantir que você não perca seus arquivos de despejo, carregue-os em seu host periodicamente. Apenas um número limitado de arquivos de despejo é preservado; dumps mais antigos são removidos depois que esse limite é atingido.
Restaurar
Conforme observado acima, o recurso tee sink não deve ser deixado ativado. Restaure sua compilação e dispositivo da seguinte maneira:
- Reverta as alterações do código-fonte para
Configuration.h. -
libaudioflinger.so. - Envie ou sincronize o
libaudioflinger.sorestaurado para o/system/libdo 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 Android SDK é android.util.Log .
A API de linguagem C correspondente no Android NDK é __android_log_print declarada em <android/log.h> .
Dentro da parte nativa da estrutura do Android, preferimos macros chamadas ALOGE , ALOGW , ALOGI , ALOGV , etc. Elas são declaradas em <utils/Log.h> e, para os propósitos 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 difundidas em toda a plataforma Android. Em particular, o processo mediaserver , que inclui o servidor de som AudioFlinger, usa extensivamente o ALOGx .
No entanto, existem algumas limitações para ALOGx e amigos:
- Eles são suscetíveis a "log spam": o buffer de log é um recurso compartilhado para que possa transbordar facilmente devido a entradas de log não relacionadas, resultando em informações perdidas. A variante
ALOGVé desabilitada em tempo de compilação por padrão. Mas é claro que mesmo isso pode resultar em spam de log se estiver ativado. - As chamadas de sistema do kernel subjacentes podem ser bloqueadas, possivelmente resultando em inversão de prioridade e, consequentemente, em distúrbios e imprecisões de medição. Isso é uma preocupação especial para threads de tempo crítico, como
FastMixereFastCapture. - Se um log específico for desabilitado para reduzir o spam de log, todas as informações que seriam capturadas por esse log serão perdidas. Não é possível habilitar um log específico retroativamente, depois que fica claro que o log 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 log mais recente para mídia e são projetados especificamente para resolver os problemas acima. Usaremos vagamente o termo "media.log" para nos referirmos a todos os três, mas estritamente falando NBLOG é a API de log C++, media.log é um nome de processo Linux e MediaLogService é um serviço de ligação do Android para examinar os logs.
Uma "linha do tempo" do media.log é uma série de entradas de log cuja ordem relativa é preservada. Por convenção, cada thread deve usar sua própria linha do tempo.
Benefícios
Os benefícios do sistema media.log são:
- Não envia spam para o log principal, a menos e até que seja necessário.
- Pode ser examinado mesmo quando
mediaservertrava ou trava. - Não é bloqueante por linha do tempo.
- Oferece menos perturbação ao desempenho. (É claro que nenhuma forma de registro é completamente não intrusiva.)
Arquitetura
O diagrama abaixo mostra o relacionamento do processo mediaserver e o processo init , antes media.log seja introduzido:

Figura 1. Arquitetura antes do media.log
Pontos notáveis:
-
initforks e execsmediaserver. -
initdetecta a morte domediaservere re-forks conforme necessário. - O registro
ALOGxnão é mostrado.
O diagrama abaixo mostra o novo relacionamento dos componentes, após o media.log ser adicionado à arquitetura:

Figura 2. Arquitetura após media.log
Mudanças importantes:
- Os clientes usam a API
NBLOGpara construir entradas de log 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 tal forma que qualquer corrupção da memória compartilhada não
MediaLogServicee ainda poderá despejar o máximo do buffer que não for afetado pela corrupção. - O buffer circular é sem bloqueio e sem bloqueio tanto para escrever novas entradas quanto para ler entradas existentes.
- Nenhuma chamada de sistema do kernel é necessária para gravar ou ler do buffer circular (além de timestamps opcionais).
Onde usar
A partir do Android 4.4, existem apenas alguns pontos de log no AudioFlinger que usam o sistema media.log . Embora as novas APIs não sejam tão fáceis de usar quanto ALOGx , elas também não são extremamente difíceis. Nós encorajamos você a aprender o novo sistema de registro para aquelas ocasiões em que é indispensável. Em particular, é recomendado para encadeamentos AudioFlinger que devem ser executados com frequência, periodicamente e sem bloqueio, como os FastMixer e FastCapture .
Como usar
Adicionar registros
Primeiro, você precisa adicionar logs ao seu código.
Nos threads FastMixer e FastCapture , use um código como este:
logWriter->log("string");
logWriter->logf("format", parameters);
logWriter->logTimestamp();
Como essa linha do tempo do NBLog é usada apenas pelos threads FastMixer e FastCapture , não há necessidade de exclusão mútua.
Em outros threads AudioFlinger, use mNBLogWriter :
mNBLogWriter->log("string");
mNBLogWriter->logf("format", parameters);
mNBLogWriter->logTimestamp();
Para encadeamentos diferentes de FastMixer e FastCapture , a linha do tempo do NBLog do encadeamento pode ser usada pelo próprio encadeamento e pelas operações do binder. NBLog::Writer não fornece nenhuma exclusão mútua implícita por linha do tempo, portanto, certifique-se de que todos os logs ocorram em um contexto em que o mutex mLock do thread seja mantido.
Depois de adicionar os logs, reconstrua o AudioFlinger.
Cuidado: Uma linha de tempo NBLog::Writer separada é necessária por encadeamento, para garantir a segurança do encadeamento, pois as linhas de tempo omitem mutexes por design. Se você quiser que mais de um thread use a mesma linha do tempo, você pode proteger com um mutex existente (conforme descrito acima para mLock ). Ou você pode usar o wrapper NBLog::LockedWriter em vez de NBLog::Writer . No entanto, isso nega um benefício principal dessa API: seu comportamento sem bloqueio.
A API completa NBLog está em frameworks/av/include/media/nbaio/NBLog.h .
Ativar media.log
media.log está desabilitado por padrão. Está ativo somente quando a propriedade ro.test_harness é 1 . Você pode habilitá-lo por:
adb rootadb shellecho ro.test_harness=1 > /data/local.propchmod 644 /data/local.propreboot
A conexão é perdida durante a reinicialização, então:
adb shellO comando
ps media agora mostrará dois processos:- media.log
- servidor de mídia
Anote o ID do processo do mediaserver para mais tarde.
Exibindo as linhas do tempo
Você pode solicitar manualmente um dump de log a qualquer momento. Este comando mostra logs de todas as linhas do tempo ativas e recentes e as limpa:
dumpsys media.log
Observe que, por design, as linhas de tempo são independentes e não há recurso para mesclar linhas de tempo.
Recuperando logs após a morte do mediaserver
Agora tente matar o processo do mediaserver : kill -9 # , onde # é o ID do processo que você anotou anteriormente. Você deve ver um dump de media.log no logcat principal, mostrando todos os logs que levaram ao travamento.
dumpsys media.log