Depuração de áudio

Este artigo descreve algumas dicas e truques para depurar o áudio do Android.

Pia de tee

A "pia da camiseta" é 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 comparar o que foi realmente reproduzido ou gravado em relação ao que era esperado.

Por questões de privacidade, o coletor de tee é desativado por padrão no tempo de compilação e no ambiente de execução. Para usar o coletor de tee, você precisará ativá-lo recompilando, e também definindo uma propriedade. Lembre-se de desativar esse recurso depuração concluída; o coletor de tee não deve ficar ativado em builds de produção.

As instruções nesta seção são para o Android 7.x e versões mais recentes. Para Android 5.x e 6.x, substitua /data/misc/audioserver por /data/misc/media. Além disso, é necessário usar um parâmetro userdebug eng. Se você usar um build userdebug, desative a verity com:

adb root && adb disable-verity && adb reboot

Configuração durante a compilação

  1. cd frameworks/av/services/audioflinger
  2. Edite Configuration.h.
  3. Remova a marca de comentário de #define TEE_SINK.
  4. Recrie libaudioflinger.so.
  5. adb root
  6. adb remount
  7. Envie ou sincronize o novo libaudioflinger.so com o /system/lib do dispositivo.

Configuração do ambiente de execução

  1. adb shell getprop | grep ro.debuggable
    Confirme se a saída é: [ro.debuggable]: [1]
  2. adb shell
  3. 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
    
  4. echo af.tee=# > /data/local.prop
    Em que o valor af.tee é um número descrito abaixo.
  5. chmod 644 /data/local.prop
  6. 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 atributo. Confira o código em AudioFlinger::AudioFlinger() no app AudioFlinger.cpp para uma explicação de cada bit, mas brevemente:

  • 1 = entrada
  • 2 = saída do FastMixer
  • 4 = registro de áudio e faixa de áudio por faixa

Ainda não há nada para buffer profundo ou mixer normal, mas você pode obter resultados semelhantes usando "4".

Testar e adquirir dados

  1. Execute o teste de áudio.
  2. adb shell dumpsys media.audio_flinger
  3. Procure uma linha no resultado de dumpsys como esta:
    tee copied to /data/misc/audioserver/20131010101147_2.wav
    É um arquivo PCM .wav.
  4. Em seguida, selecione adb pull todos os arquivos /data/misc/audioserver/*.wav de interesse. observe que os nomes de arquivo dump específicos da faixa não aparecem dumpsys saída, mas ainda serão salvos em /data/misc/audioserver após a interdição da faixa.
  5. Verifique os arquivos dump para verificar a privacidade antes de compartilhar com outras pessoas.

Sugestões

Use estas ideias para ter resultados mais úteis:

  • Desative os sons de toque e os cliques nas teclas para reduzir as interrupções no resultado do teste.
  • Maximize todos os volumes.
  • Desativar apps que emitem som ou gravam usando o microfone caso não sejam interessantes para o seu teste.
  • Os despejos específicos da faixa são salvos apenas quando a faixa é fechada. pode ser necessário forçar o fechamento do app para despejar os dados específicos da faixa.
  • Faça o dumpsys imediatamente após o teste. há uma quantidade limitada de espaço de gravação disponível.
  • Para não perder seus arquivos dump, fazer o upload deles para o host periodicamente. Apenas um número limitado de arquivos dump é preservado. os despejos antigos são removidos depois que esse limite é atingido.

Restaurar

Como mencionado acima, o recurso de coletor de tee não deve ficar ativado. Restaure o build e o dispositivo da seguinte maneira:

  1. Reverta as mudanças do código-fonte para Configuration.h.
  2. Recrie libaudioflinger.so.
  3. Enviar ou sincronizar o libaudioflinger.so restaurado ao /system/lib do dispositivo.
  4. adb shell
  5. rm /data/local.prop
  6. rm /data/misc/audioserver/*.wav
  7. reboot

media.log

Macros ALOGx

A API de geração de registros da linguagem Java padrão no SDK do Android é android.util.Log:

A API da linguagem C correspondente no Android NDK é __android_log_print declarado em <android/log.h>.

Dentro da parte nativa do framework do Android, preferem macros chamadas ALOGE, ALOGW, ALOGI, ALOGV etc. Elas são declaradas em <utils/Log.h>. Além disso, para os fins deste artigo, Vamos nos referir a eles coletivamente como ALOGx.

Todas essas APIs são fáceis de usar e bem compreendidas, por isso são abrangentes em toda a plataforma Android. Mais especificamente, mediaserver. que inclui o servidor de som AudioFlinger, usa ALOGx bastante.

No entanto, existem algumas limitações para ALOGx e amigos:

  • Eles são suscetíveis a "spam de registros": o buffer de registros é um recurso compartilhado para que ele possa transbordar facilmente devido a entradas de registro não relacionadas, resultando em informações que você perdeu. A variante ALOGV está desativada em o tempo de compilação por padrão. Mas, claro, isso pode resultar em spam de registro caso esteja ativada.
  • As chamadas subjacentes do sistema de kernel podem ser bloqueadas, possivelmente resultando em a inversão de prioridades e, consequentemente, as perturbações de medição e equívocos. Isso é de preocupação especial com linhas de execução urgentes, como FastMixer e FastCapture.
  • Se um registro específico estiver desativado para reduzir o spam de registros, então todas as informações que teriam sido capturadas por esse registro serão perdidas. Não é possível ativar um registro específico retroativamente, depois, fica claro que o registro seria interessante.

NBLOG, media.log e MediaLogService

As APIs NBLOG e o media.log associado processo e MediaLogService serviço juntos formam um novo sistema de geração de registros para mídia e são especificamente criada para resolver os problemas acima. Usaremos vagamente o termo “media.log” para se referir aos três, mas, falando estritamente, NBLOG é o API C++ Logging, media.log é um nome de processo do Linux e MediaLogService é um serviço de vinculação do Android para examinar registros.

Uma "linha do tempo" de media.log é uma série de entradas de registro cuja 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 envia spam ao registro principal, a menos e até que seja necessário.
  • Pode ser examinado mesmo quando o mediaserver falha ou trava.
  • Não bloqueia por linha do tempo.
  • Oferece menos interrupções ao desempenho. É claro que nenhuma forma de geração de registros é completamente não intrusiva.

Arquitetura

O diagrama abaixo mostra a relação do processo mediaserver e o processo init, antes da introdução de media.log:

Arquitetura antes de media.log

Figura 1. Arquitetura antes de media.log

Pontos importantes:

  • init bifurca e executa mediaserver.
  • O init detecta a morte de mediaserver e faz uma nova bifurcação conforme necessário.
  • A geração de registros ALOGx não é exibida.

O diagrama abaixo mostra a nova relação dos componentes, após a adição de media.log à arquitetura:

Arquitetura após media.log

Figura 2. Arquitetura após media.log

Mudanças importantes:

  • Os clientes usam a API NBLOG para criar entradas de registro e anexá-las ao um buffer circular na memória compartilhada.
  • O MediaLogService pode despejar o conteúdo do buffer circular a qualquer momento.
  • O buffer circular é projetado de modo que qualquer corrupção do a memória compartilhada não falhará MediaLogService, e ainda poderá para despejar o máximo do buffer não afetado pela corrupção.
  • O buffer circular não bloqueia nem bloqueia a gravação novas entradas e a leitura de entradas existentes.
  • Nenhuma chamada do sistema do kernel é necessária para gravar ou ler no buffer circular (exceto as marcações de tempo opcionais).

Onde usar

A partir do Android 4.4, 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 como ALOGx, mas também não são extremamente difíceis. Incentivamos você a conhecer o novo sistema de geração de registros em ocasiões em que é indispensável. Em particular, é recomendado para encadeamentos do AudioFlinger que precisam são executadas com frequência, periodicamente e sem bloqueios, como Linhas de execução FastMixer e FastCapture.

Como usar

Adicionar registros

Primeiro, você precisa adicionar registros ao seu 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 a linha do tempo NBLog é usada apenas pelas APIs FastMixer e FastCapture linhas de execução, não há necessidade de 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. NBLog::Writer não fornece nenhum exclusão mútua implícita por cronograma. 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: É necessário ter uma linha do tempo NBLog::Writer separada por linha de execução, para garantir a segurança da linha de execução, uma vez que as linhas do tempo omitem exclusões múltiplas por design. Se você quiser que mais de uma linha de execução use a mesma linha do tempo, é possível proteger com uma exclusões múltiplas existentes (conforme descrito acima para mLock). Ou pode use o wrapper NBLog::LockedWriter em vez de NBLog::Writer. No entanto, isso invalida um dos principais benefícios da API: a função não bloqueadora do seu modelo.

A API NBLog completa está em frameworks/av/include/media/nbaio/NBLog.h.

Ativar media.log

media.log está desativado por padrão. Ele só fica ativo quando a propriedade ro.test_harness é 1. Para ativar, 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
O comando ps media agora vai mostrar dois processos:
  • media.log
  • servidor de mídia

Anote o ID do processo mediaserver para mais tarde.

Mostrar as linhas do tempo

É possível solicitar um despejo de registros manualmente a qualquer momento. Este comando mostra os registros de todas as linhas do tempo ativas e recentes e os limpa:

dumpsys media.log

Por design, os cronogramas são independentes, e não é fácil mesclar linhas de tempo.

Recuperar registros após a interrupção do mediaserver

Agora tente encerrar o processo mediaserver: kill -9 #, em que # é o ID do processo que você anotou anteriormente. Um despejo de media.log vai aparecer. na logcat principal, mostrando todos os registros que levaram à falha.

dumpsys media.log