Debug audio

Questo articolo descrive alcuni suggerimenti e trucchi per il debug dell'audio Android.

Lavandino a T

Il "tee sink" è una funzionalità di debug di AudioFlinger, disponibile solo nelle build personalizzate, per conservare un breve frammento di audio recente per un'analisi successiva. Ciò consente il confronto tra ciò che è stato effettivamente riprodotto o registrato e ciò che ci si aspettava.

Per motivi di privacy il tee sink è disabilitato per impostazione predefinita, sia in fase di compilazione che in fase di esecuzione. Per utilizzare il tee sink, dovrai abilitarlo ricompilando e anche impostando una proprietà. Assicurati di disabilitare questa funzione una volta terminato il debug; il lavandino a T non deve essere lasciato abilitato nelle build di produzione.

Le istruzioni in questa sezione si riferiscono ad Android 7.x e versioni successive. Per Android 5.x e 6.x, sostituire /data/misc/audioserver con /data/misc/media . Inoltre, è necessario utilizzare un userdebug o un build eng. Se usi una build userdebug, disabilita verity con:

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

Configurazione in fase di compilazione

  1. cd frameworks/av/services/audioflinger
  2. Modifica Configuration.h .
  3. Decommenta #define TEE_SINK .
  4. Ricostruire libaudioflinger.so .
  5. adb root
  6. adb remount
  7. Invia o sincronizza il nuovo libaudioflinger.so nel /system/lib del dispositivo.

Configurazione in fase di esecuzione

  1. adb shell getprop | grep ro.debuggable
    Confermare che l'output sia: [ro.debuggable]: [1]
  2. adb shell
  3. ls -ld /data/misc/audioserver

    Confermare che l'output sia:

    drwx------ media media ... media
    

    Se la directory non esiste, creala come segue:

    mkdir /data/misc/audioserver
    chown media:media /data/misc/audioserver
    
  4. echo af.tee=# > /data/local.prop
    Dove il valore af.tee è un numero descritto di seguito.
  5. chmod 644 /data/local.prop
  6. reboot

Valori per la proprietà af.tee

Il valore di af.tee è un numero compreso tra 0 e 7, che esprime la somma di più bit, uno per caratteristica. Vedi il codice in AudioFlinger::AudioFlinger() in AudioFlinger.cpp per una spiegazione di ogni bit, ma brevemente:

  • 1 = ingresso
  • 2 = uscita FastMixer
  • 4 = AudioRecord e AudioTrack per traccia

Non esiste ancora un bit per il buffer profondo o il mixer normale, ma puoi ottenere risultati simili usando "4".

Testare e acquisire dati

  1. Esegui il test audio.
  2. adb shell dumpsys media.audio_flinger
  3. Cerca una riga nell'output di dumpsys come questa:
    tee copied to /data/misc/audioserver/20131010101147_2.wav
    Questo è un file PCM .wav.
  4. Quindi adb pull tutti i file /data/misc/audioserver/*.wav di interesse; tieni presente che i nomi dei file dump specifici della traccia non appaiono nell'output dumpsys , ma vengono comunque salvati in /data/misc/audioserver alla chiusura della traccia.
  5. Esamina i file di dump per problemi di privacy prima di condividerli con altri.

Suggerimenti

Prova queste idee per risultati più utili:

  • Disattiva i suoni tattili e i clic dei tasti per ridurre le interruzioni nell'output del test.
  • Massimizza tutti i volumi.
  • Disattiva le app che emettono suoni o registrano dal microfono, se non interessano al tuo test.
  • I dump specifici della traccia vengono salvati solo quando la traccia è chiusa; potrebbe essere necessario forzare la chiusura di un'app per scaricare i dati specifici della traccia
  • Esegui i dumpsys immediatamente dopo il test; lo spazio di registrazione disponibile è limitato.
  • Per assicurarti di non perdere i file dump, caricali periodicamente sul tuo host. Viene conservato solo un numero limitato di file di dump; i dump più vecchi vengono rimossi una volta raggiunto tale limite.

Ristabilire

Come notato sopra, la funzionalità del tee sink non deve essere lasciata abilitata. Ripristina la build e il dispositivo come segue:

  1. Ripristina le modifiche del codice sorgente a Configuration.h .
  2. Ricostruire libaudioflinger.so .
  3. Invia o sincronizza il libaudioflinger.so ripristinato sul /system/lib del dispositivo.
  4. adb shell
  5. rm /data/local.prop
  6. rm /data/misc/audioserver/*.wav
  7. reboot

media.log

Macro ALOGx

L'API di registrazione del linguaggio Java standard nell'SDK di Android è android.util.Log .

L'API del linguaggio C corrispondente in Android NDK è __android_log_print dichiarata in <android/log.h> .

All'interno della porzione nativa del framework Android, preferiamo le macro denominate ALOGE , ALOGW , ALOGI , ALOGV , ecc. Sono dichiarate in <utils/Log.h> e per gli scopi di questo articolo ci riferiremo collettivamente a loro come ALOGx .

Tutte queste API sono facili da usare e ben comprensibili, quindi sono pervasive in tutta la piattaforma Android. In particolare il processo mediaserver , che include il server audio AudioFlinger, utilizza ampiamente ALOGx .

Tuttavia, ci sono alcune limitazioni per ALOGx e compagni:

  • Sono soggetti allo "spam dei log": il buffer dei log è una risorsa condivisa, quindi può facilmente traboccare a causa di voci di log non correlate, con conseguente perdita di informazioni. La variante ALOGV è disabilitata in fase di compilazione per impostazione predefinita. Ma ovviamente anche questo può provocare spam nei log se è abilitato.
  • Le chiamate di sistema del kernel sottostante potrebbero bloccarsi, con il rischio di inversione di priorità e di conseguenza disturbi e imprecisioni di misurazione. Ciò è di particolare interesse per i thread critici in termini di tempo come FastMixer e FastCapture .
  • Se un particolare registro viene disabilitato per ridurre lo spam nel registro, tutte le informazioni che sarebbero state acquisite da quel registro andranno perse. Non è possibile abilitare retroattivamente un registro specifico, dopo che risulta chiaro che il registro sarebbe stato interessante.

NBLOG, media.log e MediaLogService

Le API NBLOG , il processo media.log associato e il servizio MediaLogService insieme formano un nuovo sistema di registrazione per i media e sono progettati specificamente per risolvere i problemi di cui sopra. Utilizzeremo liberamente il termine "media.log" per fare riferimento a tutti e tre, ma in senso stretto NBLOG è l'API di registrazione C++, media.log è un nome di processo Linux e MediaLogService è un servizio di associazione Android per l'esame dei log.

Una "timeline" media.log è una serie di voci di log il cui ordinamento relativo viene preservato. Per convenzione, ogni thread dovrebbe utilizzare la propria sequenza temporale.

Benefici

I vantaggi del sistema media.log sono che:

  • Non invia spam al registro principale a meno che e finché non sia necessario.
  • Può essere esaminato anche quando mediaserver si blocca o si blocca.
  • Non è bloccante per sequenza temporale.
  • Offre meno disturbi alle prestazioni. (Ovviamente nessuna forma di registrazione è completamente non intrusiva.)

Architettura

Il diagramma seguente mostra la relazione tra il processo mediaserver e il processo init , prima che venga introdotto media.log :

Architettura prima di media.log

Figura 1. Architettura prima di media.log

Punti notevoli:

  • init fork ed execs mediaserver .
  • init rileva la morte di mediaserver e, se necessario, esegue nuovamente il fork.
  • La registrazione ALOGx non viene visualizzata.

Il diagramma seguente mostra la nuova relazione dei componenti, dopo che media.log è stato aggiunto all'architettura:

Architettura dopo media.log

Figura 2. Architettura dopo media.log

Cambiamenti importanti:

  • I client utilizzano l'API NBLOG per creare voci di registro e aggiungerle a un buffer circolare nella memoria condivisa.
  • MediaLogService può eseguire il dump del contenuto del buffer circolare in qualsiasi momento.
  • Il buffer circolare è progettato in modo tale che qualsiasi corruzione della memoria condivisa non provochi l'arresto anomalo MediaLogService e sarà comunque in grado di scaricare la maggior parte del buffer che non è interessata dalla corruzione.
  • Il buffer circolare non è bloccante ed è privo di blocchi sia per la scrittura di nuove voci che per la lettura delle voci esistenti.
  • Non sono necessarie chiamate di sistema del kernel per scrivere o leggere dal buffer circolare (a parte i timestamp opzionali).

Dove usarlo

A partire da Android 4.4, ci sono solo pochi punti di registro in AudioFlinger che utilizzano il sistema media.log . Sebbene le nuove API non siano facili da usare come ALOGx , non sono nemmeno estremamente difficili. Ti invitiamo a imparare il nuovo sistema di registrazione per quelle occasioni in cui è indispensabile. In particolare, è consigliato per i thread AudioFlinger che devono essere eseguiti frequentemente, periodicamente e senza blocchi come i thread FastMixer e FastCapture .

Come usare

Aggiungi log

Innanzitutto, devi aggiungere i log al tuo codice.

Nei thread FastMixer e FastCapture , utilizza codice come questo:

logWriter->log("string");
logWriter->logf("format", parameters);
logWriter->logTimestamp();

Poiché questa sequenza temporale NBLog viene utilizzata solo dai thread FastMixer e FastCapture , non è necessaria la mutua esclusione.

In altri thread AudioFlinger, utilizza mNBLogWriter :

mNBLogWriter->log("string");
mNBLogWriter->logf("format", parameters);
mNBLogWriter->logTimestamp();

Per thread diversi da FastMixer e FastCapture , la sequenza temporale NBLog del thread può essere utilizzata sia dal thread stesso sia dalle operazioni del raccoglitore. NBLog::Writer non fornisce alcuna esclusione reciproca implicita per sequenza temporale, quindi assicurati che tutti i log si verifichino all'interno di un contesto in cui viene mantenuto il mutex mLock del thread.

Dopo aver aggiunto i registri, ricostruisci AudioFlinger.

Attenzione: è necessaria una sequenza temporale NBLog::Writer separata per thread, per garantire la sicurezza del thread, poiché le sequenze temporali omettono mutex per impostazione predefinita. Se desideri che più di un thread utilizzi la stessa sequenza temporale, puoi proteggerla con un mutex esistente (come descritto sopra per mLock ). Oppure puoi utilizzare il wrapper NBLog::LockedWriter invece di NBLog::Writer . Tuttavia, ciò annulla uno dei vantaggi principali di questa API: il suo comportamento non bloccante.

L'API NBLog completa si trova in frameworks/av/include/media/nbaio/NBLog.h .

Abilita media.log

media.log è disabilitato per impostazione predefinita. È attivo solo quando la proprietà ro.test_harness è 1 . Puoi abilitarlo:

adb root
adb shell
echo ro.test_harness=1 > /data/local.prop
chmod 644 /data/local.prop
reboot

La connessione viene persa durante il riavvio, quindi:

adb shell
Il comando ps media ora mostrerà due processi:
  • media.log
  • mediaserver

Annotare l'ID del processo del mediaserver per dopo.

Visualizza le sequenze temporali

Puoi richiedere manualmente un dump del registro in qualsiasi momento. Questo comando mostra i registri di tutte le sequenze temporali attive e recenti, quindi li cancella:

dumpsys media.log

Tieni presente che, in base alla progettazione, le sequenze temporali sono indipendenti e non è possibile unirle.

Recupera i log dopo la morte del mediaserver

Ora prova a uccidere il processo mediaserver : kill -9 # , dove # è l'ID del processo che hai annotato in precedenza. Dovresti vedere un dump da media.log nel logcat principale, che mostra tutti i log che hanno portato all'arresto anomalo.

dumpsys media.log