architecture audio Android pile audio Android rééchantillonnage AudioFlinger

La pile audio Android : pourquoi votre musique est rééchantillonnée

Un plongeon en profondeur dans la façon dont Android gère l'audio -- de l'application au haut-parleur. Découvrez pourquoi AudioFlinger rééchantillonne votre musique et ce que vous pouvez y faire.

· 12 min de lecture

Comment Android lit l’audio

Chaque son que votre téléphone Android produit — notifications, appels, effets de jeux, musique — traverse le même pipeline audio avant d’atteindre vos oreilles. Comprendre ce pipeline est la clé pour comprendre pourquoi votre collection de musique sans perte soigneusement constituée peut ne pas sonner aussi immaculée que vous l’espériez.

Le chemin audio standard d’Android ressemble à ceci :

App -> API AudioTrack -> AudioFlinger -> HAL (Hardware Abstraction Layer) -> Matériel (haut-parleur, DAC, radio Bluetooth)

Quand une application de lecteur de musique veut produire du son, elle crée un AudioTrack (ou utilise l’API AAudio plus récente, qui passe quand même par le même système). L’application écrit des échantillons audio PCM dans ce track — des données audio décodées au taux d’échantillonnage et à la profondeur de bits que contient le fichier source.

Ces échantillons entrent ensuite dans AudioFlinger, le service central de mixage et routage audio d’Android. AudioFlinger est le contrôleur de trafic de l’audio Android. Il prend les flux audio de chaque application du système, les mixe ensemble, applique les effets système (comme le volume système) et route le résultat vers le bon appareil de sortie. Il tourne comme un service système natif avec une priorité élevée, et chaque échantillon audio de votre appareil le traverse.

Sous AudioFlinger se trouve le Hardware Abstraction Layer (HAL), une couche de traduction spécifique à l’appareil écrite par le fabricant du téléphone. Le HAL convertit la sortie d’AudioFlinger dans le format que le matériel attend — que ce soit un flux I2S pour le DAC interne, des paquets audio USB pour un DAC externe, ou de l’audio Bluetooth encodé pour des écouteurs sans fil.

Cette architecture est élégante d’un point de vue conception système. N’importe quelle app peut lire de l’audio sans se soucier des spécificités matérielles, les flux audio multiples se mélangent harmonieusement, et le système maintient le contrôle sur le routage et la politique de volume. Mais pour la lecture musicale, elle introduit un problème.

Le problème AudioFlinger

AudioFlinger opère à un taux d’échantillonnage fixe. Sur la plupart des appareils Android, ce taux est soit 44 100 Hz soit 48 000 Hz — le fabricant de l’appareil décide quand il configure le HAL, et il ne peut typiquement pas changer pendant que le système tourne. Le défaut le plus courant sur les téléphones modernes est 48 kHz.

Ce taux fixe existe parce qu’AudioFlinger est fondamentalement un mixeur. Il doit combiner l’audio de sources multiples — votre musique, une notification entrante, les directions de navigation, un appel téléphonique — en un seul flux de sortie. Mixer de l’audio nécessite que tous les flux soient au même taux d’échantillonnage. Plutôt que de changer dynamiquement le taux du mixeur chaque fois qu’un nouveau flux démarre (ce qui perturberait tous les autres flux actifs), AudioFlinger choisit un taux et rééchantillonne tout pour correspondre.

Donc chaque flux audio de l’appareil est rééchantillonné au taux fixe du mixeur :

  • Votre FLAC hi-res 96 kHz ? Sous-échantillonné à 48 kHz.
  • Votre rip CD 44,1 kHz sur un mixeur 48 kHz ? Sur-échantillonné à 48 kHz.
  • Votre podcast 48 kHz sur un appareil 48 kHz ? Passe sans modification — vous avez eu de la chance.
  • Votre DSD64 converti en PCM 176,4 kHz ? Sous-échantillonné à 48 kHz.

Google a conçu AudioFlinger pour le cas général, et honnêtement, c’est une décision d’ingénierie raisonnable pour un téléphone grand public. Un appareil qui joue des sons de notification tout en streamant Spotify tout en naviguant a besoin d’un taux de mixage commun. Mais il n’a jamais été conçu pour la lecture audiophile, et la qualité de rééchantillonnage, bien qu’adéquate, n’est pas ce que vous choisiriez si la fidélité était le seul objectif.

Le rééchantillonneur intégré à AudioFlinger s’est amélioré au fil des ans. Les premières versions d’Android utilisaient un interpolateur linéaire de basse qualité. Les versions modernes (Android 5.0 et ultérieures) utilisent un rééchantillonneur sinc polyphase qui produit des résultats raisonnables. Mais “raisonnable” et “transparent” ne sont pas la même chose — chaque opération de rééchantillonnage introduit un certain niveau de bruit de quantification et d’artefacts d’aliasing potentiels, aussi faibles soient-ils.

Négociation du taux d’échantillonnage

La situation n’est pas totalement désespérée. Android fournit des mécanismes pour que les apps influencent le taux d’échantillonnage de sortie, bien que les résultats soient… inconsistants.

Quand une app crée un flux audio via l’API AAudio (l’interface audio native moderne d’Android), elle peut demander un taux d’échantillonnage spécifique. Android tente d’honorer cette demande, et l’app peut ensuite vérifier quel taux a effectivement été accordé. Si le matériel et le HAL de l’appareil supportent le taux demandé, vous pouvez obtenir une lecture native sans rééchantillonnage.

Android 12 et ultérieurs ont amélioré cela avec un meilleur support du changement de taux natif. Sur les appareils compatibles, le système peut changer le taux de sortie du HAL pour correspondre à ce que l’app demande, particulièrement pour les appareils audio USB. Une app bien conçue peut potentiellement obtenir une sortie bit-perfect au taux natif du morceau.

Mais “supporte correctement” fait beaucoup de travail dans cette phrase. L’expérience est frustrante d’inconsistance :

  • Samsung verrouille le taux d’échantillonnage à une valeur fixe dans leur implémentation HAL. Peu importe ce que l’app demande, le matériel tourne toujours à 48 kHz.
  • Les appareils Pixel ont généralement été plus permissifs. Mais même là, le comportement varie entre les générations de matériel.
  • OnePlus ? Ça dépend de la version du firmware. C’est la réalité du développement audio Android.
  • Certains OEM permettent le changement de taux dynamique mais seulement pour certains appareils de sortie (USB DAC oui, prise casque non).
  • Les options développeur sur certains appareils exposent un toggle “routage audio USB” ou une surcharge de taux, mais ceux-ci sont cachés de l’utilisateur typique et non standardisés.

Le résultat pratique est qu’un développeur d’app ne peut pas compter sur obtenir un taux spécifique. L’app doit sonder l’appareil, demander un taux, vérifier ce qu’elle a reçu, et s’adapter. Ce schéma sonder-demander-vérifier est la seule approche fiable.

Le contournement USB DAC

Les appareils USB audio classe 1 et classe 2 présentent le chemin le plus prometteur vers une sortie audio de haute qualité sur Android. Quand vous connectez un USB DAC, le pilote audio USB d’Android crée un nouvel appareil de sortie audio qu’AudioFlinger peut cibler. Comme les USB DAC supportent typiquement plusieurs taux d’échantillonnage et rapportent leurs capacités à l’hôte, il y a une meilleure chance d’obtenir une lecture au taux natif.

La chaîne audio avec un USB DAC ressemble à ceci :

App -> API AAudio -> AudioFlinger -> HAL Audio USB -> Pilote de classe audio USB -> USB DAC

Notez qu’AudioFlinger est toujours dans le chemin. Contrairement aux systèmes d’exploitation de bureau — où le mode exclusif WASAPI sous Windows ou le hog mode sous macOS CoreAudio peuvent contourner entièrement le mixeur système — Android n’offre pas de vrai accès exclusif au matériel audio. AudioFlinger se trouve toujours entre l’app et l’appareil. Toujours.

Cependant, quand les étoiles s’alignent, AudioFlinger peut agir comme un passthrough plutôt qu’un rééchantillonneur :

  1. L’app demande le taux d’échantillonnage natif du morceau via AAudio.
  2. AudioFlinger vérifie si le HAL audio USB supporte ce taux.
  3. Si supporté, AudioFlinger configure sa sortie à ce taux.
  4. Comme le seul flux audio actif correspond au taux du mixeur, aucun rééchantillonnage ne se produit.
  5. Les échantillons passent à travers AudioFlinger inchangés et atteignent le USB DAC au taux original.

C’est aussi proche du bit-perfect qu’Android le permet. Les échantillons ne sont pas mathématiquement altérés, même s’ils passent techniquement par le mixeur. Pour que cela fonctionne, vous ne devez pas non plus avoir de sons système ou d’autres flux audio actifs en même temps — tout autre audio forcerait AudioFlinger à revenir au mixage et potentiellement au rééchantillonnage.

Bluetooth : une autre couche de conversion

L’audio Bluetooth ajoute une étape de conversion entièrement séparée par-dessus AudioFlinger. Après que votre audio passe par le mixeur système, il entre dans la pile audio Bluetooth, où il est encodé dans un codec audio Bluetooth avant la transmission sans fil.

La chaîne devient :

App -> AudioFlinger -> Encodeur codec Bluetooth -> Transmission sans fil -> Casque/Enceinte

Chaque codec Bluetooth est avec perte. Sans exception. La bande passante disponible sur une liaison Bluetooth n’est tout simplement pas suffisante pour l’audio non compressé à de hauts taux d’échantillonnage. Les codecs diffèrent dans l’agressivité de leur compression et la qualité qu’ils atteignent dans la bande passante disponible.

SBC (Sub-Band Codec) est la référence universelle — chaque appareil audio Bluetooth le supporte. Il plafonne à environ 345 kbps et 48 kHz. Il s’est considérablement amélioré avec de meilleures implémentations d’encodeur, mais il reste le plus petit dénominateur commun.

LDAC, développé par Sony et inclus dans Android depuis la version 8.0, offre la plus haute qualité à jusqu’à 990 kbps et 96 kHz. À son meilleur réglage, LDAC est généralement considéré comme transparent pour la plupart du contenu — des auditeurs entraînés ont du mal à le distinguer de l’original filaire dans des tests contrôlés. Mais c’est quand même de la compression avec perte.

Pour une comparaison détaillée de tous les codecs Bluetooth — LDAC, aptX, aptX HD, aptX Adaptive, AAC, SBC et LC3 — consultez notre guide des codecs audio Bluetooth.

Le point important : même si vous contournez le rééchantillonnage d’AudioFlinger (en obtenant une sortie au taux natif), l’encodage Bluetooth re-compresse tout après. La lecture bit-perfect via Bluetooth est physiquement impossible. Le mieux que vous puissiez faire est d’alimenter l’encodeur Bluetooth avec le signal source de la plus haute qualité et le laisser faire la meilleure compression possible.

Comment Echobox navigue la pile audio Android

Nous avons conçu Echobox de A à Z pour travailler avec (et autour de) les contraintes du système audio d’Android. Notre architecture à trois couches — Flutter pour l’interface, Rust pour l’orchestration audio, et Zig pour la sortie temps réel — nous donne un contrôle inhabituel sur ce qui arrive à votre audio à chaque étape du pipeline.

L’architecture

La couche Flutter gère tout ce que vous voyez et avec quoi vous interagissez — le navigateur de bibliothèque, l’écran de lecture en cours et les paramètres. Elle ne touche jamais directement les données audio.

Le moteur Rust est au milieu et gère le gros du travail : décodage de fichiers (via la bibliothèque Symphonia pour les formats comme FLAC, MP3, AAC et DSD), conversion de taux d’échantillonnage, normalisation de format, analyse audio et gestion d’état. Nous avons choisi Rust parce que le traitement audio doit être à la fois correct et rapide — sa combinaison de sécurité mémoire et d’abstractions à coût zéro signifie que nous n’avons pas à choisir entre les deux.

La couche Zig exécute le callback audio temps réel — le code qui se déclenche toutes les ~10 millisecondes quand le système d’exploitation demande le prochain bloc d’échantillons audio. Ce code doit répondre immédiatement avec zéro allocation et zéro opération bloquante. Nous utilisons Zig pour le callback car il garantit aucun flux de contrôle caché et aucune allocation mémoire cachée. Le callback Zig lit des échantillons pré-décodés depuis un tampon circulaire sans verrou (rempli par le moteur Rust) et applique une chaîne DSP à sept étages : ReplayGain, préampli, EQ paramétrique, crossfeed, volume, EQ graphique et limiteur.

Gestion intelligente du taux d’échantillonnage

Plutôt que d’envoyer aveuglément l’audio à n’importe quel taux en espérant que tout ira bien, nous négocions activement avec l’appareil :

  1. Sonder le taux natif de l’appareil en ouvrant un flux AAudio temporaire et en laissant Android rapporter le taux optimal pour l’appareil de sortie actuel.
  2. Demander ce taux lors de l’initialisation du vrai flux de lecture.
  3. Vérifier le taux accordé en relisant ce qu’Android a effectivement fourni — car le taux accordé peut différer de ce qui a été demandé.
  4. Rééchantillonner intelligemment avec un rééchantillonneur à interpolation sinc de haute qualité quand le taux du morceau diffère du taux de l’appareil. Ce rééchantillonneur utilise un filtre FIR à 256 points avec une fenêtre BlackmanHarris, nettement meilleur que le rééchantillonneur intégré d’AudioFlinger.

L’avantage critique ici est d’éviter le double rééchantillonnage. Si une app naïve décode un FLAC 44,1 kHz et le sort à 44,1 kHz sur un appareil 48 kHz, AudioFlinger le rééchantillonnera à 48 kHz avec son propre algorithme. Nous évitons cela en détectant que l’appareil tourne à 48 kHz et en effectuant un seul rééchantillonnage propre et de haute qualité à 48 kHz nous-mêmes — pour qu’AudioFlinger n’ait plus rien à convertir.

Mode bit-perfect

Pour les utilisateurs de USB DAC, Echobox offre un mode bit-perfect qui pousse les capacités d’Android aussi loin que possible :

  • Demande le taux d’échantillonnage natif exact du morceau au DAC.
  • Contourne toute la chaîne DSP — pas d’EQ, pas d’ajustement de volume, pas de ReplayGain, pas de limiteur. Les échantillons décodés passent sans modification.
  • Si le DAC ne peut pas supporter le taux demandé, la lecture échoue avec une erreur claire plutôt que de rééchantillonner silencieusement.

Transparence du chemin du signal

Peut-être le plus important, Echobox vous montre exactement ce qui se passe. Les diagnostics du chemin du signal révèlent la chaîne audio complète en temps réel : format source et taux d’échantillonnage, si un rééchantillonnage est actif et à quelle qualité, quels étages DSP sont engagés, à quel taux l’appareil tourne réellement, et quel codec Bluetooth est utilisé le cas échéant.

Comportement sensible au routage

Echobox classifie chaque appareil de sortie par type de route — haut-parleur local, USB DAC, Bluetooth ou rendu réseau — et adapte son comportement en conséquence. Quand le Bluetooth est détecté, le mode bit-perfect est automatiquement désactivé (car il est sans objet via un codec sans fil avec perte) et le traitement DSP reste actif. Quand un USB DAC est connecté, toute la gamme de négociation de taux et d’options bit-perfect devient disponible.

Cette politique sensible au routage signifie que vous n’avez pas besoin d’ajuster manuellement les paramètres à chaque changement entre casque et enceintes. L’app détecte le changement et applique des défauts intelligents pour chaque type de sortie. Pour le streaming UPnP/DLNA vers les enceintes réseau, Echobox ajoute une autre couche d’intelligence — détectant les capacités des appareils et transcodant au besoin. Et si vous évaluez ce qui fait d’un lecteur de musique un vrai lecteur audiophile au-delà de la pile audio, notre guide du lecteur audiophile couvre le tableau complet. Vous pouvez aussi consulter la feuille de route pour la disponibilité sur d’autres plateformes.

La réalité de l’audio Android

  • AudioFlinger est le goulot d’étranglement. Chaque son sur Android passe par ce mixeur système, qui opère à un taux fixe (généralement 48 kHz). Tout l’audio est rééchantillonné à ce taux avant d’atteindre le matériel.
  • Google a conçu AudioFlinger pour l’usage général, pas la lecture audiophile. Mixer notifications, appels et musique en un seul flux nécessite un taux commun, et le rééchantillonnage est le compromis. C’est une décision de conception raisonnable — juste pas une prise avec nous en tête.
  • Les USB DAC offrent le meilleur chemin vers la qualité sur Android. Ils supportent plusieurs taux, et quand correctement adressés, AudioFlinger peut laisser passer l’audio sans rééchantillonnage.
  • Android n’offre pas de vrai mode exclusif. Contrairement au WASAPI Exclusive sous Windows ou au hog mode sous macOS, il n’y a pas moyen de contourner complètement AudioFlinger. Le mixeur est toujours dans le chemin, même s’il agit comme un passthrough.
  • Le Bluetooth ajoute une autre conversion avec perte par-dessus tout le reste. Aucun codec Bluetooth n’est sans perte, et la lecture bit-perfect est impossible en sans fil.
  • Echobox gère la complexité en sondant les taux des appareils, en effectuant un rééchantillonnage de haute qualité quand nécessaire, en offrant une sortie USB DAC bit-perfect, et en vous montrant exactement ce qui se passe via les diagnostics du chemin du signal. Notre architecture Rust/Zig nous donne un contrôle sur le pipeline audio que la plupart des apps n’ont tout simplement pas.
  • Le bilan honnête : sur Android, amener votre musique de l’app à vos oreilles sans traitement indésirable nécessite soit un USB DAC avec un support de pilote correct, soit l’acceptation que le système rééchantillonnera. Nous avons construit Echobox pour vous donner les outils et la transparence pour naviguer cette réalité — et si vous êtes un développeur construisant quelque chose de similaire, nous espérons que ce guide vous épargnera certains des mois que nous avons passés à tout comprendre.

Guides associés


Essayez Echobox

Vivez ce que ces guides décrivent — une lecture de précision sur Android.

Un email par jalon. Pas de bruit.