Débogage audio

Cet article présente quelques conseils et astuces pour déboguer l'audio Android.

Lavabo en T

Le "tee sink" est une fonctionnalité de débogage AudioFlinger, disponible uniquement dans les builds personnalisés, qui permet de conserver un court fragment d'audio récent pour une analyse ultérieure. Cela permet de comparer ce qui a été réellement lu ou enregistré à ce qui était attendu.

Pour des raisons de confidentialité, le récepteur tee est désactivé par défaut, à la fois au moment de la compilation et au moment de l'exécution. Pour utiliser le récepteur tee, vous devez l'activer en le recompilant, et également en définissant une propriété. Veillez à désactiver cette fonctionnalité une fois le débogage terminé. Le tee sink ne doit pas être laissé activé dans les builds de production.

Les instructions de cette section s'appliquent à Android 7.x ou version ultérieure. Pour Android 5.x et 6.x, remplacez /data/misc/audioserver par /data/misc/media. De plus, vous devez utiliser un build userdebug ou eng. Si vous utilisez un build userdebug, désactivez la validation avec:

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

Configuration au moment de la compilation

  1. cd frameworks/av/services/audioflinger
  2. Modifier Configuration.h.
  3. Décommentez #define TEE_SINK.
  4. Recompilez libaudioflinger.so.
  5. adb root
  6. adb remount
  7. Transférez ou synchronisez le nouveau libaudioflinger.so avec le /system/lib de l'appareil.

Configuration d'exécution

  1. adb shell getprop | grep ro.debuggable
    Vérifiez que la sortie est la suivante: [ro.debuggable]: [1]
  2. adb shell
  3. ls -ld /data/misc/audioserver

    Vérifiez que la sortie est la suivante:

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

    Si le répertoire n'existe pas, créez-le comme suit:

    mkdir /data/misc/audioserver
    chown media:media /data/misc/audioserver
    
  4. echo af.tee=# > /data/local.prop
    où la valeur af.tee est un nombre décrit ci-dessous.
  5. chmod 644 /data/local.prop
  6. reboot

Valeurs de la propriété af.tee

La valeur de af.tee est un nombre compris entre 0 et 7, exprimant la somme de plusieurs bits, un par élément géographique. Consultez le code à AudioFlinger::AudioFlinger() dans AudioFlinger.cpp pour obtenir une explication de chaque bit, mais brièvement:

  • 1 = entrée
  • 2 = sortie FastMixer
  • 4 = AudioRecord et AudioTrack par piste

Il n'existe pas encore de bit pour le tampon profond ni pour le mixeur normal, mais vous pouvez obtenir des résultats similaires à l'aide de "4."

Tester et acquérir des données

  1. Exécutez votre test audio.
  2. adb shell dumpsys media.audio_flinger
  3. Recherchez une ligne dans la sortie dumpsys semblable à celle-ci:
    tee copied to /data/misc/audioserver/20131010101147_2.wav
    Il s'agit d'un fichier .wav PCM.
  4. adb pull ensuite tous les fichiers /data/misc/audioserver/*.wav qui vous intéressent. Notez que les noms de fichiers de dump spécifiques à la piste n'apparaissent pas dans la sortie dumpsys, mais sont toujours enregistrés dans /data/misc/audioserver lors de la fermeture de la piste.
  5. Examinez les fichiers de dump pour détecter les problèmes de confidentialité avant de les partager avec d'autres personnes.

Suggestions

Essayez ces idées pour obtenir des résultats plus utiles:

  • Désactivez les sons tactiles et les clics de touche pour réduire les interruptions dans la sortie du test.
  • Maximisez tous les volumes.
  • Désactivez les applications qui émettent du son ou enregistrent à partir du micro, si elles ne sont pas utiles pour votre test.
  • Les vidages spécifiques à un canal ne sont enregistrés que lorsque le canal est fermé. Vous devrez peut-être forcer la fermeture d'une application pour vider ses données spécifiques au canal.
  • Effectuez l'dumpsys immédiatement après le test. L'espace d'enregistrement disponible est limité.
  • Pour vous assurer de ne pas perdre vos fichiers de vidage, importez-les régulièrement sur votre hôte. Seul un nombre limité de fichiers de dump est conservé. Les fichiers de dump plus anciens sont supprimés une fois cette limite atteinte.

Restore

Comme indiqué ci-dessus, la fonctionnalité de récepteur en T ne doit pas être laissée activée. Restaurez votre build et votre appareil comme suit:

  1. Annulez les modifications apportées au code source pour revenir à Configuration.h.
  2. Recompilez libaudioflinger.so.
  3. Transférez ou synchronisez la libaudioflinger.so restaurée avec la /system/lib de l'appareil.
  4. adb shell
  5. rm /data/local.prop
  6. rm /data/misc/audioserver/*.wav
  7. reboot

media.log

Macros ALOGx

L'API de journalisation standard en langage Java du SDK Android est android.util.Log.

L'API de langage C correspondante dans le NDK Android est déclarée dans <android/log.h>.__android_log_print

Dans la partie native du framework Android, nous préférons les macros nommées ALOGE, ALOGW, ALOGI, ALOGV, etc. Elles sont déclarées dans <utils/Log.h>. Pour les besoins de cet article, nous les appellerons collectivement ALOGx.

Toutes ces API sont faciles à utiliser et bien connues. Elles sont donc omniprésentes sur la plate-forme Android. En particulier, le processus mediaserver, qui inclut le serveur audio AudioFlinger, utilise ALOGx de manière intensive.

Toutefois, ALOGx et les amis présentent certaines limites:

  • Ils sont susceptibles de générer du "spam de journal": le tampon de journal est une ressource partagée et peut donc facilement déborder en raison d'entrées de journal sans rapport, ce qui entraîne des informations manquantes. La variante ALOGV est désactivée au moment de la compilation par défaut. Toutefois, même si elle est activée, elle peut générer du spam dans les journaux.
  • Les appels système du kernel sous-jacents peuvent se bloquer, ce qui peut entraîner une inversion de priorité et, par conséquent, des perturbations et des inexactitudes de mesure. Cela est particulièrement important pour les threads critiques dans le temps, tels que FastMixer et FastCapture.
  • Si un journal particulier est désactivé pour réduire le spam, toutes les informations qui auraient été capturées par ce journal sont perdues. Il n'est pas possible d'activer un journal spécifique rétroactivement, une fois qu'il est clair que le journal aurait été intéressant.

NBLOG, media.log et MediaLogService

Les API NBLOG, le processus media.log et le service MediaLogService associés forment ensemble un système de journalisation plus récent pour les contenus multimédias. Ils sont spécifiquement conçus pour résoudre les problèmes ci-dessus. Nous utiliserons le terme "media.log" de manière approximative pour désigner les trois, mais à strictement parler, NBLOG est l'API de journalisation C++, media.log est un nom de processus Linux et MediaLogService est un service de liaison Android permettant d'examiner les journaux.

Une "timeline" media.log est une série d'entrées de journal dont l'ordre relatif est conservé. Par convention, chaque thread doit utiliser sa propre chronologie.

Avantages

Le système media.log présente les avantages suivants:

  • Ne bombarde pas le journal principal de messages indésirables, sauf si cela est nécessaire.
  • Peut être examiné même lorsque mediaserver plante ou se bloque.
  • Il n'est pas bloquant par chronologie.
  • Elle offre moins de perturbations sur les performances. (Bien entendu, aucune forme de journalisation n'est totalement non intrusive.)

Architecture

Le schéma ci-dessous montre la relation entre le processus mediaserver et le processus init, avant l'introduction de media.log:

Architecture avant media.log

Figure 1 : Architecture avant media.log

Points importants:

  • init forks et execs mediaserver.
  • init détecte la fin de mediaserver et crée un nouveau fork si nécessaire.
  • La journalisation ALOGx n'est pas affichée.

Le schéma ci-dessous montre la nouvelle relation entre les composants après l'ajout de media.log à l'architecture:

Architecture après media.log

Figure 2. Architecture après media.log

Modifications importantes

  • Les clients utilisent l'API NBLOG pour créer des entrées de journal et les ajouter à un tampon circulaire dans la mémoire partagée.
  • MediaLogService peut vider le contenu du tampon circulaire à tout moment.
  • Le tampon circulaire est conçu de manière à ce que toute corruption de la mémoire partagée ne provoque pas de plantage de MediaLogService. Il pourra toujours vider autant de tampon que possible qui n'est pas affecté par la corruption.
  • Le tampon circulaire est non bloquant et sans verrouillage pour l'écriture de nouvelles entrées et la lecture d'entrées existantes.
  • Aucun appel système du noyau n'est requis pour écrire dans le tampon circulaire ou le lire (à l'exception des codes temporels facultatifs).

Pays dans lesquels Android Auto peut être utilisé

Depuis Android 4.4, seuls quelques points de journalisation dans AudioFlinger utilisent le système media.log. Bien que les nouvelles API ne soient pas aussi faciles à utiliser que ALOGx, elles ne sont pas non plus extrêmement difficiles. Nous vous encourageons à vous familiariser avec le nouveau système de journalisation pour les cas où il est indispensable. En particulier, il est recommandé pour les threads AudioFlinger qui doivent s'exécuter fréquemment, périodiquement et sans blocage, tels que les threads FastMixer et FastCapture.

Fonctionnement

Ajouter des journaux

Tout d'abord, vous devez ajouter des journaux à votre code.

Dans les threads FastMixer et FastCapture, utilisez un code tel que celui-ci:

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

Étant donné que cette chronologie NBLog n'est utilisée que par les threads FastMixer et FastCapture, aucune exclusion mutuelle n'est nécessaire.

Dans d'autres threads AudioFlinger, utilisez mNBLogWriter:

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

Pour les threads autres que FastMixer et FastCapture, la chronologie NBLog du thread peut être utilisée à la fois par le thread lui-même et par les opérations de liaison. NBLog::Writer ne fournit aucune exclusion mutuelle implicite par chronologie. Assurez-vous donc que tous les journaux se produisent dans un contexte où le mutex mLock du thread est détenu.

Après avoir ajouté les journaux, reconstruisez AudioFlinger.

Attention:Une chronologie NBLog::Writer distincte est requise par thread pour assurer la sécurité des threads, car les chronologies omettent les mutex par conception. Si vous souhaitez que plusieurs threads utilisent la même chronologie, vous pouvez la protéger avec un mutex existant (comme décrit ci-dessus pour mLock). Vous pouvez également utiliser le wrapper NBLog::LockedWriter au lieu de NBLog::Writer. Toutefois, cela annule l'un des principaux avantages de cette API: son comportement non bloquant.

L'API NBLog complète est disponible sur frameworks/av/include/media/nbaio/NBLog.h.

Activer media.log

media.log est désactivé par défaut. Il n'est actif que lorsque la propriété ro.test_harness est 1. Pour l'activer, procédez comme suit:

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

La connexion est perdue lors du redémarrage. Par conséquent:

adb shell
La commande ps media affiche désormais deux processus :
  • media.log
  • mediaserver

Notez l'ID de processus de mediaserver pour plus tard.

Afficher les chronologies

Vous pouvez demander manuellement un vidage de journaux à tout moment. Cette commande affiche les journaux de toutes les chronologies actives et récentes, puis les efface:

dumpsys media.log

Notez que par conception, les chronologies sont indépendantes et qu'il n'existe aucun moyen de les fusionner.

Récupérer les journaux après l'arrêt de MediaServer

Essayez maintenant d'arrêter le processus mediaserver: kill -9 #, où # correspond à l'ID de processus que vous avez noté précédemment. Vous devriez voir un vidage de media.log dans le logcat principal, affichant tous les journaux menant à l'erreur.

dumpsys media.log