Android-lydstakken: Hvorfor din musik bliver resamplet
Et dybtgående kig på hvordan Android håndterer lyd -- fra app til højttaler. Lær hvorfor AudioFlinger resampler din musik og hvad du kan gøre ved det.
Hvordan Android afspiller lyd
Enhver lyd din Android-telefon laver — notifikationer, telefonopkald, spileffekter, musik — rejser gennem den samme lydpipeline før den når dine ører. At forstå denne pipeline er nøglen til at forstå hvorfor din omhyggeligt kuraterede tabsfrie musiksamling måske ikke lyder helt så ren som du ville forvente.
Den standard Android-lydsti ser sådan ud:
App -> AudioTrack API -> AudioFlinger -> HAL (Hardware Abstraction Layer) -> Hardware (højttaler, DAC, Bluetooth-radio)
Når en musikafspiller-app vil producere lyd, opretter den et AudioTrack (eller bruger den nyere AAudio API, som stadig ruter gennem det samme system). Appen skriver PCM-lydsamples til dette track — afkodede lyddata ved den samplingsfrekvens og bitdybde kildefilen indeholder.
Disse samples indtræder derefter i AudioFlinger, Androids centrale lydmixing- og rutningsservice. AudioFlinger er trafikstyringen af Android-lyd. Den tager lydstrømme fra enhver app på systemet, mixer dem sammen, anvender systemniveau-effekter (som systemlydstyrken) og ruter resultatet til den korrekte outputenhed. Den kører som en native systemservice med forhøjet prioritet, og hver eneste lydsample på din enhed passerer gennem den.
Under AudioFlinger sidder Hardware Abstraction Layer (HAL), et enhedsspecifikt oversættelseslag skrevet af telefonproducenten. HAL konverterer AudioFlingers output til det format den faktiske hardware forventer — hvad enten det er en I2S-strøm til den interne DAC, USB-lydpakker til en ekstern DAC, eller kodet Bluetooth-lyd til trådløse hovedtelefoner.
Denne arkitektur er elegant fra et systemdesignperspektiv. Enhver app kan afspille lyd uden at bekymre sig om hardwarespecifikke detaljer, flere lydstrømme mixes problemfrit, og systemet opretholder kontrol over rutning og lydstyrkepolitik. Men for musikafspilning introducerer det et problem.
AudioFlinger-problemet
AudioFlinger opererer ved en fast samplingsfrekvens. På de fleste Android-enheder er denne frekvens enten 44.100 Hz eller 48.000 Hz — enhedsproducenten bestemmer når de konfigurerer HAL’en, og den kan typisk ikke ændres mens systemet kører. Den mest almindelige standard på moderne telefoner er 48 kHz.
Denne faste frekvens eksisterer fordi AudioFlinger fundamentalt er en mixer. Den skal kombinere lyd fra flere kilder — din musik, en indkommende notifikation, navigationsvejledning, et telefonopkald — til en enkelt outputstrøm til hardwaren. Mixing af lyd kræver at alle strømme er ved samme samplingsfrekvens. I stedet for dynamisk at ændre mixerfrekvensen hver gang en ny strøm starter (hvilket ville forstyrre alle andre aktive strømme), vælger AudioFlinger én frekvens og resampler alt til at matche.
Så enhver lydstrøm på enheden bliver resamplet til mixerens faste frekvens:
- Din 96 kHz hi-res FLAC? Resamplet ned til 48 kHz.
- Din 44,1 kHz CD-rip der afspilles på en 48 kHz mixer? Resamplet op til 48 kHz.
- Din 48 kHz podcast på en 48 kHz enhed? Passerer igennem uændret — du var heldig.
- Din DSD64 konverteret til 176,4 kHz PCM? Resamplet ned til 48 kHz.
Google designede AudioFlinger til det generelle tilfælde, og ærligt talt er det en fornuftig ingeniørbeslutning for en forbrugertelefon. En enhed der afspiller notifikationslyde mens den streamer Spotify mens den navigerer har brug for en fælles mixfrekvens. Men den blev aldrig designet til audiofil afspilning, og resamplingkvaliteten er, selvom den er tilstrækkelig, ikke hvad du ville vælge hvis lydtrofasthed var det eneste mål.
Resampleren indbygget i AudioFlinger er blevet forbedret over årene. Tidlige Android-versioner brugte en lavkvalitets lineær interpolator. Moderne versioner (Android 5.0 og senere) bruger en polyfase sinc-resampler der producerer fornuftige resultater. Men “fornuftige” og “gennemsigtige” er ikke det samme — enhver resamplingoperation introducerer et vist niveau af kvantiseringsstøj og potentielle aliasingartefakter, uanset hvor små.
Forhandling af samplingsfrekvens
Situationen er ikke helt håbløs. Android tilbyder mekanismer for apps til at påvirke outputsamplingsfrekvensen, selvom resultaterne er… inkonsistente.
Når en app opretter en lydstrøm gennem AAudio API’en (Androids moderne native lydgrænseflade), kan den anmode om en specifik samplingsfrekvens. Android vil forsøge at opfylde denne anmodning, og appen kan derefter tjekke hvilken frekvens der faktisk blev tildelt. Hvis enhedens hardware og HAL understøtter den anmodede frekvens, kan du få native afspilning uden resampling.
Android 12 og senere forbedrede dette med bedre understøttelse af native samplingsfrekvens-skift. På kompatible enheder kan systemet ændre HAL-outputfrekvensen til at matche hvad appen anmoder om, specielt for USB-lydenheder. En veldesignet app kan potentielt opnå bitperfekt output ved nummerets native frekvens.
Men “korrekt understøtter” gør et stort stykke arbejde i den sætning. Oplevelsen er frustrerende inkonsistent:
- Samsung låser samplingsfrekvensen til en fast værdi i deres HAL-implementering. Uanset hvad appen anmoder om, kører hardwaren altid ved 48 kHz.
- Pixel-enheder har generelt været mere tilladende og lader dig forhandle. Men selv her varierer adfærden mellem hardwaregenerationer.
- OnePlus? Afhænger af firmwareversionen. Sådan er virkeligheden for Android-lydudvikling.
- Nogle OEM’er tillader dynamisk frekvensskift men kun for visse outputenheder (USB DAC’er ja, hovedtelefonstik nej).
- Udviklerindstillinger på nogle enheder eksponerer en “USB audio routing”-kontakt eller samplingsfrekvens-override, men disse er skjult fra typiske brugere og ikke standardiseret.
Det praktiske resultat er at en appudvikler ikke kan stole på at få nogen specifik samplingsfrekvens. Appen skal undersøge enheden, anmode om en frekvens, tjekke hvad den faktisk modtog og tilpasse sig derefter. Dette undersøg-anmod-verificer mønster er den eneste pålidelige tilgang.
USB DAC-omvejen
USB audio class 1 og class 2 enheder præsenterer den mest lovende vej til højkvalitets lydoutput på Android. Når du tilslutter en USB DAC, opretter Androids USB-lyddriver en ny lydoutputenhed som AudioFlinger kan målrette. Fordi USB DAC’er typisk understøtter flere samplingsfrekvenser og rapporterer deres kapabiliteter til værten, er der bedre chance for at opnå native frekvensafspilning.
Lydkæden med en USB DAC ser sådan ud:
App -> AAudio API -> AudioFlinger -> USB Audio HAL -> USB Audio Class Driver -> USB DAC
Bemærk at AudioFlinger stadig er i stien. I modsætning til desktopoperativsystemer — hvor WASAPI Exclusive-tilstand på Windows eller hog mode i macOS CoreAudio kan omgå systemmixeren helt — tilbyder Android ikke ægte eksklusiv adgang til lydhardware. AudioFlinger sidder altid mellem appen og enheden. Altid.
Dog kan AudioFlinger, når stjernerne står rigtigt, fungere som passthrough i stedet for resampler:
- Appen anmoder om nummerets native samplingsfrekvens via AAudio.
- AudioFlinger tjekker om USB audio HAL’en understøtter den frekvens.
- Hvis understøttet konfigurerer AudioFlinger sit output ved den frekvens.
- Fordi den eneste aktive lydstrøm matcher mixerfrekvensen, sker ingen resampling.
- Samples passerer igennem AudioFlinger uændret og når USB DAC’en ved den originale frekvens.
Dette er så tæt på bitperfekt som Android kommer. Samples er ikke matematisk ændret, selvom de teknisk passerer gennem mixeren. For at dette fungerer, må du heller ikke have systemlyde eller andre lydstrømme aktive på samme tid — alt andet der afspilles ville tvinge AudioFlinger tilbage til mixing og potentielt resampling.
Appen skal håndtere betydelig kompleksitet for at få dette til at fungere: undersøge USB-enhedens understøttede frekvenser, anmode om den korrekte frekvens, verificere den tildelte frekvens og elegant håndtere enheds-afbrydelse. Appen skal også håndtere sin egen lydbufferstørrelse, fordi USB DAC’er har forskellige latenskarakteristikker end telefonens indbyggede lyd.
Bluetooth: Endnu et lag af konvertering
Bluetooth-lyd tilføjer et helt separat konverteringstrin oven på AudioFlinger. Efter din lyd passerer gennem systemmixeren indtræder den i Bluetooth-lydstakken, hvor den kodes til en Bluetooth-lydcodec før trådløs transmission.
Kæden bliver:
App -> AudioFlinger -> Bluetooth Codec Encoder -> Trådløs transmission -> Hovedtelefoner/højttaler
Enhver Bluetooth-codec er tabsgivende. Ingen undtagelser. Den tilgængelige båndbredde på et Bluetooth-link er simpelthen ikke nok til ukomprimeret lyd ved høje samplingsfrekvenser. Codecs adskiller sig i hvor aggressivt de komprimerer og hvilken kvalitet de opnår inden for den tilgængelige båndbredde.
SBC (Sub-Band Codec) er den universelle baseline — enhver Bluetooth-lydenhed understøtter den. Den topper ved cirka 345 kbps og 48 kHz. Den er forbedret markant med bedre encoder-implementeringer, men den er stadig den laveste fællesnævner.
LDAC, udviklet af Sony og inkluderet i Android siden version 8.0, tilbyder den højeste kvalitet ved op til 990 kbps og 96 kHz. Ved sin bedste indstilling betragtes LDAC generelt som gennemsigtig for det meste indhold — hvilket betyder at trænede lyttere har svært ved at skelne den fra den kablede original i kontrollerede tests. Men det er stadig tabsgivende komprimering.
For en detaljeret sammenligning af alle Bluetooth-codecs — LDAC, aptX, aptX HD, aptX Adaptive, AAC, SBC og LC3 — se vores guide til Bluetooth-lydcodecs.
Det vigtige punkt: selv hvis du omgår AudioFlingers resampling (ved at opnå native frekvens-output), genkomprimerer Bluetooth-kodningen alt bagefter. Bitperfekt afspilning over Bluetooth er fysisk umulig. Det bedste du kan gøre er at føde Bluetooth-encoderen det højeste kvalitets kildesignal og lade den gøre den bedste komprimering den kan.
Sådan navigerer Echobox i Android-lydstakken
Vi designede Echobox fra bunden til at arbejde med (og udenom) begrænsningerne i Androids lydsystem. Vores tre-lags arkitektur — Flutter til brugerfladen, Rust til lydorkestrering og Zig til realtidsoutput — giver os usædvanlig kontrol over hvad der sker med din lyd på hvert trin af pipelinen.
Arkitekturen
Flutter-laget håndterer alt du ser og interagerer med — biblioteksbrowseren, nu-afspiller skærmen og indstillinger. Det rører aldrig lyddata direkte.
Rust-motoren sidder i midten og håndterer det tunge arbejde: filafkodning (via Symphonia-biblioteket til formater som FLAC, MP3, AAC og DSD), samplingsfrekvenskonvertering, formatnormalisering, lydanalyse og tilstandsstyring. Vi valgte Rust fordi lydbehandling skal være både korrekt og hurtig — dens kombination af hukommelsessikkerhed og zero-cost abstraktioner betyder at vi ikke behøver vælge mellem de to.
Zig-laget kører realtids-lydcallbacket — koden der fyrer hver ~10 millisekund når operativsystemet anmoder om den næste chunk af lydsamples. Denne kode skal svare øjeblikkeligt med nul allokeringer og nul blokerende operationer. Vi bruger Zig til callbacket fordi det garanterer ingen skjult kontrolflow og ingen skjult hukommelsesallokering — du kan læse koden og vide præcis hvad den vil gøre ved runtime. Zig-callbacket læser forafkodede samples fra en låsefri ringbuffer (fyldt af Rust-motoren) og anvender en syv-trins DSP-kæde: ReplayGain, preamp, parametrisk EQ, crossfeed, lydstyrke, grafisk EQ og limiter.
Intelligent håndtering af samplingsfrekvens
I stedet for blindt at sende lyd ved en vilkårlig frekvens og håbe på det bedste, forhandler vi aktivt med enheden:
- Undersøg enhedens native frekvens ved at åbne en midlertidig AAudio-strøm og lade Android rapportere den optimale frekvens for den aktuelle outputenhed.
- Anmod om den frekvens ved initialisering af den rigtige afspilningsstrøm.
- Verificer den tildelte frekvens ved at læse hvad Android faktisk leverede tilbage — fordi den tildelte frekvens kan afvige fra hvad der blev anmodet.
- Resample intelligent ved hjælp af en højkvalitets sinc-interpolation resampler når nummerets samplingsfrekvens afviger fra enhedsfrekvensen. Denne resampler bruger et 256-tap FIR-filter med et BlackmanHarris-vindue, som er markant bedre end AudioFlingers indbyggede resampler.
Den afgørende fordel her er at undgå dobbelt resampling. Hvis en naiv app afkoder en 44,1 kHz FLAC og outputter den ved 44,1 kHz på en 48 kHz enhed, vil AudioFlinger resample den til 48 kHz med sin egen algoritme. Vi undgår dette ved at detektere at enheden kører ved 48 kHz og udføre én ren, højkvalitets resampling til 48 kHz selv — så AudioFlinger ikke har noget tilbage at konvertere.
Bitperfekt tilstand
For USB DAC-brugere tilbyder Echobox en bitperfekt tilstand der presser Androids kapabiliteter så langt de rækker:
- Anmoder nummerets præcise native samplingsfrekvens fra DAC’en.
- Omgår hele DSP-kæden — ingen EQ, ingen lydstyrkejustering, ingen ReplayGain, ingen limiter. Afkodede samples passerer igennem uændret.
- Hvis DAC’en ikke kan understøtte den anmodede frekvens, fejler afspilningen med en klar fejlmeddelelse i stedet for lydløst at resample. Dette er bevidst — hvis du har bedt om bitperfekt, fortjener du at vide når du ikke får det.
Signalvejsgennemsigtighed
Måske vigtigst af alt viser Echobox dig præcis hvad der sker. Signalvejsdiagnostikvisningen afslører den komplette lydkæde i realtid: kildeformat og samplingsfrekvens, om resampling er aktiv og ved hvilken kvalitet, hvilke DSP-trin der er engageret, hvilken outputfrekvens enheden faktisk kører ved, og hvilken Bluetooth-codec der bruges hvis relevant.
Dette niveau af gennemsigtighed er sjældent i musikafspiller-apps. De fleste afspillere er en sort boks — du trykker play og stoler på at det rigtige sker. Echobox lader dig verificere. Hvis din 96 kHz FLAC bliver resamplet til 48 kHz fordi din telefons interne DAC ikke understøtter 96 kHz, vil du se det. Hvis din USB DAC accepterer 96 kHz og DSP-kæden er helt omgået, vil du også se det.
Rutebevidst adfærd
Echobox klassificerer hver outputenhed efter rutetype — lokal højttaler, USB DAC, Bluetooth eller netværksrenderer — og tilpasser sin adfærd derefter. Når Bluetooth detekteres, deaktiveres bitperfekt tilstand automatisk (fordi det er meningsløst over en tabsgivende trådløs codec) og DSP-behandling forbliver aktiv, så du kan bruge EQ og lydstyrkekontrol. Når en USB DAC tilsluttes, bliver det fulde udvalg af samplingsfrekvensforhandling og bitperfekte muligheder tilgængeligt.
Denne rutebevidste politik betyder at du ikke behøver manuelt at justere indstillinger hver gang du skifter mellem hovedtelefoner og højttalere. Appen registrerer ændringen og sætter intelligente standarder for hver outputtype. For UPnP/DLNA streaming til netværkshøjttalere tilføjer Echobox endnu et lag af intelligens — detektion af enhedskapabiliteter og transkodning når det er nødvendigt. Og hvis du evaluerer hvad der gør en musikafspiller genuint audiofil-grade ud over bare lydstakken, dækker vores guide til audiofile musikafspillere hele billedet. Du kan også tjekke roadmappen for platformtilgængelighed ud over Android.
Virkeligheden for Android-lyd
- AudioFlinger er flaskehalsen. Enhver lyd på Android passerer gennem denne systemmixer, der opererer ved en fast samplingsfrekvens (normalt 48 kHz). Al lyd bliver resamplet til denne frekvens før den når hardwaren.
- Google designede AudioFlinger til generel brug, ikke audiofil afspilning. At mixe notifikationer, opkald og musik til én strøm kræver en fælles samplingsfrekvens, og resampling er afvejningen. Det er en fornuftig designbeslutning — bare ikke en der blev truffet med os i tankerne.
- USB DAC’er tilbyder den bedste vej til kvalitet på Android. De understøtter flere samplingsfrekvenser, og når de adresseres korrekt, kan AudioFlinger sende lyd igennem uden resampling.
- Android tilbyder ikke ægte eksklusiv tilstand. I modsætning til WASAPI Exclusive på Windows eller hog mode på macOS er der ingen måde at fuldstændigt omgå AudioFlinger. Mixeren er altid i stien, selv hvis den fungerer som passthrough.
- Bluetooth tilføjer endnu en tabsgivende konvertering oven på alt andet. Ingen Bluetooth-codec er tabsfri, og bitperfekt afspilning er umulig over trådløs.
- Echobox håndterer kompleksiteten ved at undersøge enhedsfrekvenser, udføre højkvalitets-resampling når det er nødvendigt, tilbyde bitperfekt USB DAC-output og vise dig præcis hvad der sker via signalvejsdiagnostik. Vores Rust/Zig-arkitektur giver os kontrol over lydpipelinen som de fleste apps simpelthen ikke har.
- Den ærlige bundlinje: på Android kræver det enten en USB DAC med ordentlig driverunderstøttelse eller accept af at systemet vil resample, at få din musik fra app til ører uden uønsket behandling. Vi byggede Echobox til at give dig værktøjerne og gennemsigtigheden til at navigere den virkelighed — og hvis du er udvikler der bygger noget lignende, håber vi denne guide sparer dig for nogle af de måneder vi brugte på at finde ud af det.