第九板块:Android 多媒体体系 | 第二十三篇:AudioFlinger 与 AudioPolicyService 音频架构

第九板块:Android 多媒体体系 | 第二十三篇:AudioFlinger 与 AudioPolicyService 音频架构

所属板块:第九板块 --- Android 多媒体体系

前置知识:第二十二篇中的网络体系、Linux 内核驱动、Binder IPC、SELinux、Cgroup 资源隔离

本篇定位 :这是 Android 设备听觉体验的中央处理器 。如果说屏幕是输出视觉,那么音频系统就是输出声音的神经中枢 。本篇将彻底拆解 AudioFlinger 的混音(Mixing)引擎、AudioPolicyService 的策略决策逻辑、音频流(AudioTrack/AudioRecord) 的生命周期、音频焦点(Audio Focus) 的仲裁机制、低延迟音频(Fast Mixer) 的实现。我们将深入 HAL(Hardware Abstraction Layer)Kernel ALSA 驱动Framework Native 层,揭示 Android 如何在多应用同时发声时,既保证低延迟又保证互不干扰。全程无音频播放代码、无音效调优指南,仅保留 Android 音频架构的底层定义与系统级调度规范。


1. 核心结论先行(Thesis Statement)

Android 的音频系统是一个基于策略与合成的实时流水线

  • AudioFlinger 的本质音频合成工厂 。它运行在 System Server 之外的独立 Native 进程中,负责接收所有应用的音频数据(PCM),进行混音(Mixing)重采样(Resampling)格式转换,并最终写入 HAL 接口。
  • AudioPolicyService 的本质音频交通警。它运行在 System Server 中,负责制定规则:哪个设备(Speaker/Headset/BT)发声、音量多大、是否允许某个应用发声(音频焦点)。
  • 音频流的本质共享内存(Shared Memory)的搬运 。应用通过 AudioTrack 将 PCM 数据写入匿名共享内存(Ashmem),AudioFlinger 读取并混音。
  • 低延迟的本质绕过普通混音器 。通过 Fast Mixer 线程,建立从应用到底层驱动的直通路径(Passthrough),减少缓冲区拷贝。

2. 音频架构全景图

2.1 从应用播放到喇叭发声

#mermaid-svg-A47lCb6tN3bwTzkF{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-A47lCb6tN3bwTzkF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-A47lCb6tN3bwTzkF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-A47lCb6tN3bwTzkF .error-icon{fill:#552222;}#mermaid-svg-A47lCb6tN3bwTzkF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-A47lCb6tN3bwTzkF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-A47lCb6tN3bwTzkF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-A47lCb6tN3bwTzkF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-A47lCb6tN3bwTzkF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-A47lCb6tN3bwTzkF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-A47lCb6tN3bwTzkF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-A47lCb6tN3bwTzkF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-A47lCb6tN3bwTzkF .marker.cross{stroke:#333333;}#mermaid-svg-A47lCb6tN3bwTzkF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-A47lCb6tN3bwTzkF p{margin:0;}#mermaid-svg-A47lCb6tN3bwTzkF .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-A47lCb6tN3bwTzkF .cluster-label text{fill:#333;}#mermaid-svg-A47lCb6tN3bwTzkF .cluster-label span{color:#333;}#mermaid-svg-A47lCb6tN3bwTzkF .cluster-label span p{background-color:transparent;}#mermaid-svg-A47lCb6tN3bwTzkF .label text,#mermaid-svg-A47lCb6tN3bwTzkF span{fill:#333;color:#333;}#mermaid-svg-A47lCb6tN3bwTzkF .node rect,#mermaid-svg-A47lCb6tN3bwTzkF .node circle,#mermaid-svg-A47lCb6tN3bwTzkF .node ellipse,#mermaid-svg-A47lCb6tN3bwTzkF .node polygon,#mermaid-svg-A47lCb6tN3bwTzkF .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-A47lCb6tN3bwTzkF .rough-node .label text,#mermaid-svg-A47lCb6tN3bwTzkF .node .label text,#mermaid-svg-A47lCb6tN3bwTzkF .image-shape .label,#mermaid-svg-A47lCb6tN3bwTzkF .icon-shape .label{text-anchor:middle;}#mermaid-svg-A47lCb6tN3bwTzkF .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-A47lCb6tN3bwTzkF .rough-node .label,#mermaid-svg-A47lCb6tN3bwTzkF .node .label,#mermaid-svg-A47lCb6tN3bwTzkF .image-shape .label,#mermaid-svg-A47lCb6tN3bwTzkF .icon-shape .label{text-align:center;}#mermaid-svg-A47lCb6tN3bwTzkF .node.clickable{cursor:pointer;}#mermaid-svg-A47lCb6tN3bwTzkF .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-A47lCb6tN3bwTzkF .arrowheadPath{fill:#333333;}#mermaid-svg-A47lCb6tN3bwTzkF .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-A47lCb6tN3bwTzkF .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-A47lCb6tN3bwTzkF .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-A47lCb6tN3bwTzkF .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-A47lCb6tN3bwTzkF .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-A47lCb6tN3bwTzkF .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-A47lCb6tN3bwTzkF .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-A47lCb6tN3bwTzkF .cluster text{fill:#333;}#mermaid-svg-A47lCb6tN3bwTzkF .cluster span{color:#333;}#mermaid-svg-A47lCb6tN3bwTzkF div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-A47lCb6tN3bwTzkF .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-A47lCb6tN3bwTzkF rect.text{fill:none;stroke-width:0;}#mermaid-svg-A47lCb6tN3bwTzkF .icon-shape,#mermaid-svg-A47lCb6tN3bwTzkF .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-A47lCb6tN3bwTzkF .icon-shape p,#mermaid-svg-A47lCb6tN3bwTzkF .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-A47lCb6tN3bwTzkF .icon-shape .label rect,#mermaid-svg-A47lCb6tN3bwTzkF .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-A47lCb6tN3bwTzkF .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-A47lCb6tN3bwTzkF .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-A47lCb6tN3bwTzkF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 硬件
Linux 内核
硬件抽象层
System Server
应用进程

  1. 写入 PCM 数据
  2. 请求焦点
  3. 决策 (选设备/算音量)
  4. 混音/重采样
  5. pcm_write()
  6. DMA 传输
  7. I2S 信号
  8. 模拟信号
    AudioTrack (Java/Native)
    AudioManager (请求焦点)
    AudioPolicyService
    AudioFlinger
    audio.primary.so
    ALSA Driver (snd_pcm)
    /dev/snd/pcmC0D0p
    Audio Codec
    Speaker/Headset

2.2 核心组件职责表

组件 层级 职责 学术定义
AudioPolicyService Framework 决策者 管理音频路由、音量曲线、音频焦点、设备选择。
AudioFlinger Native 执行者 管理音频流、混音线程、重采样、与 HAL 交互。
PlaybackThread Native 工作线程 AudioFlinger 中的线程,负责特定输出设备的混音循环。
AudioTrack Framework 客户端接口 应用向音频系统输送数据的接口。
AudioHAL HAL 硬件接口 厂商实现的库,屏蔽不同硬件的差异。

3. AudioFlinger 的混音引擎

3.1 音频流(Track)的生命周期

AudioFlinger 为每个播放请求创建一个 Track
#mermaid-svg-JGb6gyKQEldgavi2{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JGb6gyKQEldgavi2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JGb6gyKQEldgavi2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JGb6gyKQEldgavi2 .error-icon{fill:#552222;}#mermaid-svg-JGb6gyKQEldgavi2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JGb6gyKQEldgavi2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JGb6gyKQEldgavi2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JGb6gyKQEldgavi2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JGb6gyKQEldgavi2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JGb6gyKQEldgavi2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JGb6gyKQEldgavi2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JGb6gyKQEldgavi2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JGb6gyKQEldgavi2 .marker.cross{stroke:#333333;}#mermaid-svg-JGb6gyKQEldgavi2 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JGb6gyKQEldgavi2 p{margin:0;}#mermaid-svg-JGb6gyKQEldgavi2 defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-JGb6gyKQEldgavi2 g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-JGb6gyKQEldgavi2 g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-JGb6gyKQEldgavi2 g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-JGb6gyKQEldgavi2 g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-JGb6gyKQEldgavi2 g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-JGb6gyKQEldgavi2 .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-JGb6gyKQEldgavi2 .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-JGb6gyKQEldgavi2 .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-JGb6gyKQEldgavi2 .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-JGb6gyKQEldgavi2 .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-JGb6gyKQEldgavi2 .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-JGb6gyKQEldgavi2 .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-JGb6gyKQEldgavi2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JGb6gyKQEldgavi2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-JGb6gyKQEldgavi2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JGb6gyKQEldgavi2 .edgeLabel .label text{fill:#333;}#mermaid-svg-JGb6gyKQEldgavi2 .label div .edgeLabel{color:#333;}#mermaid-svg-JGb6gyKQEldgavi2 .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-JGb6gyKQEldgavi2 .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-JGb6gyKQEldgavi2 .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-JGb6gyKQEldgavi2 .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-JGb6gyKQEldgavi2 .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-JGb6gyKQEldgavi2 .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JGb6gyKQEldgavi2 .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JGb6gyKQEldgavi2 #statediagram-barbEnd{fill:#333333;}#mermaid-svg-JGb6gyKQEldgavi2 .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JGb6gyKQEldgavi2 .cluster-label,#mermaid-svg-JGb6gyKQEldgavi2 .nodeLabel{color:#131300;}#mermaid-svg-JGb6gyKQEldgavi2 .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-JGb6gyKQEldgavi2 .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-JGb6gyKQEldgavi2 .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-JGb6gyKQEldgavi2 .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-JGb6gyKQEldgavi2 .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-JGb6gyKQEldgavi2 .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-JGb6gyKQEldgavi2 .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-JGb6gyKQEldgavi2 .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-JGb6gyKQEldgavi2 .note-edge{stroke-dasharray:5;}#mermaid-svg-JGb6gyKQEldgavi2 .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-JGb6gyKQEldgavi2 .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-JGb6gyKQEldgavi2 .statediagram-note text{fill:black;}#mermaid-svg-JGb6gyKQEldgavi2 .statediagram-note .nodeLabel{color:black;}#mermaid-svg-JGb6gyKQEldgavi2 .statediagram .edgeLabel{color:red;}#mermaid-svg-JGb6gyKQEldgavi2 #dependencyStart,#mermaid-svg-JGb6gyKQEldgavi2 #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-JGb6gyKQEldgavi2 .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-JGb6gyKQEldgavi2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 创建 AudioTrack
start()
flush()
pause()
start()
stop()
释放资源
Idle
Active
Flushing
Paused
Stopped

3.2 混音线程(PlaybackThread)

AudioFlinger 针对不同的输出设备创建不同的线程。

线程类型 特点 适用场景
MixerThread 最常用。支持多路混音,重采样。 音乐、游戏音效。
DirectOutputThread 直通。不经过混音器,直接写入 HAL。 HDMI 源码输出、USB 音频。
OffloadThread 硬解码。将压缩数据(MP3/AAC)直接送给 DSP 解码。 音乐播放(省电)。

3.3 混音算法(Mixing)

AudioFlinger 使用 Fixed-point Arithmetic(定点运算) 进行混音,以保证性能和精度。

学术定义

  • 混音公式 :Output=∑(Inputi×Volumei)Output = \sum (Input_i \times Volume_i)Output=∑(Inputi×Volumei)
  • 重采样(Resampling) :如果应用的采样率(如 44.1kHz)与硬件采样率(如 48kHz)不匹配,必须进行重采样。AudioFlinger 使用 SRC(Sample Rate Converter) 算法。
  • 溢出处理 :混音后的值可能超过 16-bit 范围(-32768 ~ 32767),需要进行 Clipping(削波) 处理。

4. AudioPolicyService 的策略决策

4.1 音频焦点(Audio Focus)仲裁

当多个应用同时请求播放时,APS 决定谁有权发声。

学术定义

  • 焦点类型
    • AUDIOFOCUS_GAIN:长时间播放(音乐)。
    • AUDIOFOCUS_GAIN_TRANSIENT:短暂播放(导航提示)。
    • AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:短暂播放,允许原声音量降低(通知音)。
  • 仲裁逻辑
    1. 新应用请求焦点。
    2. APS 检查当前焦点持有者。
    3. 根据焦点类型和优先级,决定是 抢占(Abandon) 还是 拒绝(Fail)

AudioPolicyService 音乐应用 导航应用 AudioPolicyService 音乐应用 导航应用 #mermaid-svg-dOTHWSENFxpR1N0Y{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-dOTHWSENFxpR1N0Y .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-dOTHWSENFxpR1N0Y .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-dOTHWSENFxpR1N0Y .error-icon{fill:#552222;}#mermaid-svg-dOTHWSENFxpR1N0Y .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dOTHWSENFxpR1N0Y .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-dOTHWSENFxpR1N0Y .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dOTHWSENFxpR1N0Y .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dOTHWSENFxpR1N0Y .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-dOTHWSENFxpR1N0Y .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dOTHWSENFxpR1N0Y .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dOTHWSENFxpR1N0Y .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dOTHWSENFxpR1N0Y .marker.cross{stroke:#333333;}#mermaid-svg-dOTHWSENFxpR1N0Y svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dOTHWSENFxpR1N0Y p{margin:0;}#mermaid-svg-dOTHWSENFxpR1N0Y .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-dOTHWSENFxpR1N0Y text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-dOTHWSENFxpR1N0Y .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-dOTHWSENFxpR1N0Y .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-dOTHWSENFxpR1N0Y .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-dOTHWSENFxpR1N0Y .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-dOTHWSENFxpR1N0Y #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-dOTHWSENFxpR1N0Y .sequenceNumber{fill:white;}#mermaid-svg-dOTHWSENFxpR1N0Y #sequencenumber{fill:#333;}#mermaid-svg-dOTHWSENFxpR1N0Y #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-dOTHWSENFxpR1N0Y .messageText{fill:#333;stroke:none;}#mermaid-svg-dOTHWSENFxpR1N0Y .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-dOTHWSENFxpR1N0Y .labelText,#mermaid-svg-dOTHWSENFxpR1N0Y .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-dOTHWSENFxpR1N0Y .loopText,#mermaid-svg-dOTHWSENFxpR1N0Y .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-dOTHWSENFxpR1N0Y .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-dOTHWSENFxpR1N0Y .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-dOTHWSENFxpR1N0Y .noteText,#mermaid-svg-dOTHWSENFxpR1N0Y .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-dOTHWSENFxpR1N0Y .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-dOTHWSENFxpR1N0Y .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-dOTHWSENFxpR1N0Y .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-dOTHWSENFxpR1N0Y .actorPopupMenu{position:absolute;}#mermaid-svg-dOTHWSENFxpR1N0Y .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-dOTHWSENFxpR1N0Y .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-dOTHWSENFxpR1N0Y .actor-man circle,#mermaid-svg-dOTHWSENFxpR1N0Y line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-dOTHWSENFxpR1N0Y :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} requestFocus(GAIN)授予焦点 (AUDIOFOCUS_REQUEST_GRANTED)开始播放requestFocus(GAIN_TRANSIENT_MAY_DUCK)通知降低音量 (onAudioFocusChange)授予焦点播放导航音 (音乐音量变小)

4.2 设备路由选择

APS 根据设备连接状态和策略选择输出设备。

设备状态 路由决策
仅扬声器 路由到 Speaker。
插入有线耳机 路由到 Headset(强制切换)。
连接蓝牙 A2DP 路由到 Bluetooth(如果未插耳机)。
HDMI 连接 路由到 HDMI(数字音频)。

5. 低延迟音频(Fast Mixer)

5.1 普通路径 vs 快速路径

特性 普通路径 (MixerThread) 快速路径 (Fast Mixer)
缓冲区大小 大 (20-100ms) 极小 (2-5ms)
线程优先级 普通 SCHED_FIFO (实时)
重采样 支持 不支持 (必须匹配硬件)
混音 多路混音 单路直通
适用场景 音乐、视频 游戏、VOIP、乐器

5.2 Fast Mixer 的实现

Fast Mixer 是一个独立的线程,绑定到特定的 CPU 核心,使用 FIFO 调度策略。

学术定义

  • SCHED_FIFO:实时调度策略。一旦线程运行,除非主动放弃或更高优先级抢占,否则不会被切换出去。
  • CPU Affinity:将线程绑定到特定的 CPU 核心,避免缓存失效和上下文切换延迟。

6. 关键源码深度解析

6.1 AudioFlinger 的混音循环

cpp 复制代码
// frameworks/av/services/audioflinger/Threads.cpp
void AudioFlinger::MixerThread::threadLoop() {
    while (!exitPending()) {
        // 1. 等待音频硬件就绪 (poll)
        waitForPcmSync();

        // 2. 准备混音缓冲区
        memset(mMixBuffer, 0, mMixBufferSize);

        // 3. 遍历所有活跃的 Track
        for (const sp<Track>& track : mActiveTracks) {
            // 读取 Track 数据
            track->getNextBuffer(&buffer);
            // 重采样
            resample(buffer);
            // 混音 (定点运算)
            mix(mMixBuffer, buffer, track->volume);
        }

        // 4. 写入 HAL
        mOutput->write(mMixBuffer, mMixBufferSize);
    }
}

6.2 AudioPolicyService 的焦点管理

cpp 复制代码
// frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
status_t AudioPolicyService::requestAudioFocus(...) {
    // 1. 检查是否已有焦点持有者
    sp<AudioFocusInfo> current = mFocusStack.top();

    // 2. 检查优先级
    if (newFocus.priority <= current.priority) {
        // 抢占当前焦点
        current->client->onAudioFocusChange(AUDIOFOCUS_LOSS);
        mFocusStack.pop();
    }

    // 3. 授予新焦点
    mFocusStack.push(newFocus);
    return NO_ERROR;
}

7. 音频系统的常见误区

误区 学术解释
音量越大,声音越响 音量是数字增益(Digital Gain),过大会导致 Clipping(削波失真)。
采样率越高,音质越好 如果源文件是 44.1kHz,强行升到 48kHz 会有损音质(SRC 误差)。
蓝牙音频是无损的 绝大多数蓝牙音频使用 SBC 编码(有损压缩),LDAC/aptX HD 才是接近无损。
应用可以直接控制硬件 不可以。所有音频必须经过 AudioFlinger 混音,应用只能控制自己的 Track 音量。

8. 本篇总结(Knowledge Closure)

关键点 纯学术定义
AudioFlinger 的本质 音频合成工厂,负责混音、重采样、格式转换。
AudioPolicyService 的本质 音频交通警,负责路由、音量、焦点仲裁。
音频流路径 应用 -> AudioTrack -> Shared Memory -> AudioFlinger -> HAL -> Kernel。
低延迟实现 Fast Mixer + SCHED_FIFO + CPU Affinity + 小缓冲区。
音频焦点 基于优先级的抢占式仲裁机制。

9. 第九板块结语

至此,第九板块:Android 多媒体体系 已完成核心架构解析。

我们从 AudioFlinger 的混音引擎 出发,深入 AudioPolicyService 的策略决策 ,探索 音频焦点的仲裁逻辑 ,最终抵达 低延迟音频的实时实现

我们揭示了 Android 音频系统的设计哲学:用策略隔离应用,用混音共享硬件,用实时线程保障延迟。

下一篇预告第九板块:Android 多媒体体系 | 第二十四篇:Camera Service 与 HAL3 成像流水线

相关推荐
故渊at1 小时前
第八板块:Android 网络体系与连接管理 | 第二十二篇:ConnectivityService 与 Netd 网络架构
android·网络·架构·连接管理·connectivity
咖啡星人k1 小时前
MonkeyCode 后端架构全解析:Go微服务如何支撑万级并发AI任务
微服务·架构·golang·monkeycode
cjie2212 小时前
常用视频缩放架构
fpga开发·架构
大神15732 小时前
Cordova Android 签名三种方式详解:证书生成、命令行直接签名与配置文件自动签名
android·java
私人珍藏库2 小时前
【Android】压缩视频1.1.28-视频压缩-解放内存
android·app·工具·软件·多功能
踏雪羽翼2 小时前
android 实现文字打印机效果
android·前端·javascript
朱莉^_^JuneLee2 小时前
Flutter 模块化架构实战:用 Barrel Export 管控模块边界
flutter·架构
“码”力全开2 小时前
打通安防孤岛:基于 Docker 与 GB28181/RTSP 架构的 AI 视频管理平台,全源码交付解锁二次开发自主权
人工智能·docker·架构
纳祥科技2 小时前
NX699,内置精度±5%晶振的lightning苹果PD快充12W
单片机·手机·音视频