Android 原生音频架构不足与改进实践

本文梳理了 Android 原生音频架构的核心问题,并给出具体改进方案和实现代码。

一、Android 原生音频架构

1.1 整体架构一览

Android 音频系统从顶层 App 到硬件,大致分为四层:

┌─────────────────────────────────────────────────────────────┐
│                     应用层 (App Layer)                       │
│         AudioTrack / AudioRecord / MediaPlayer              │
└────────────────────────────┬────────────────────────────────┘
                             │ Java API (AudioTrack.write())
┌────────────────────────────▼────────────────────────────────┐
│                  框架层 (Framework Layer)                   │
│    ┌──────────────────┐      ┌───────────────────────────┐  │
│    │   AudioFlinger   │ ←→   │  AudioPolicyService       │  │
│    │  (播放/混音/调度) │      │  (路由/音频策略/设备管理) │  │
│    └──────────────────┘      └───────────────────────────┘  │
│              ↑                        ↑                       │
│    ┌─────────┴────────────────────────┴────────┐             │
│    │              Native Layer                │             │
│    │  AudioTrack / AudioRecord / AudioEffect   │             │
│    └─────────────────────┬─────────────────────┘             │
└────────────────────────────┼────────────────────────────────┘
                             │ Binder IPC
┌────────────────────────────▼────────────────────────────────┐
│                   Audio HAL Layer                            │
│    (IAudioFlinger.hal / IAudioPolicy.hal / IEffect.hal)    │
└────────────────────────────┬────────────────────────────────┘
                             │
┌────────────────────────────▼────────────────────────────────┐
│                      音频硬件                                │
│             DAC / DSP / I2S / 扬声器 / 蓝牙 A2DP           │
└─────────────────────────────────────────────────────────────┘

每一层都通过 HIDL/AIDL HAL 接口解耦,厂商只需实现 HAL,无需改动上层。

1.2 AudioFlinger vs AudioPolicyService

很多人搞不清楚这两个服务的关系:

AudioFlinger:负责"怎么播放"
  → 管理 PlaybackThread 和 RecordThread
  → 实际的混音、调度、共享内存管理
  → 把混音后的数据写入 HAL

AudioPolicyService:负责"能不能播放"和"播到哪里"
  → 设备选型(speaker/headset/bt)
  → 路由策略(插耳机切输出源)
  → Audio Focus 管理(谁打断谁)
  → 音量管理(不同 Zone 的音量曲线)

1.3 关键音频路径

媒体播放路径:
MediaPlayer.decode()
  → AudioTrack.write()     [44.1kHz PCM]
    → AudioFlinger
      → PlaybackThread
        → 重采样 → [48kHz]
        → 混音
        → Output Effects → [均衡器/低音增强]
          → HAL.open_output_stream()
            → DAC → 扬声器

导航播报路径:
NavigationApp
  → AudioTrack.write()     [低延迟,FLAG_AUDIBILITY_ENFORCED]
    → AudioFlinger
      → PlaybackThread (高优先级)
        → 高优先级 Track 抢占 Mixer
        → 直接输出 → [压低媒体音量]
          → HAL → 扬声器

1.4 原架构的核心问题

| 问题 | 描述 |
|——|——|
| 单点瓶颈 | 所有 Track 共用一个 MixerThread,高优先级抢占时低优先级被连带影响 |
| Focus 粒度粗 | 只有 4 种状态,无法精细控制 Duck Level 和恢复时间 |
| 无 Zone 支持 | 标准 Android 无多区域音频概念,车载需要 CarAudioService 在上层模拟 |
| HAL 碎片化 | 不同厂商 HAL 性能差异大,延迟不可预期 |
| Effects 局限 | 第三方 App 无法 attach Effect 到自己的 Track |

二、改进后的音频架构

2.1 新架构全景

┌─────────────────────────────────────────────────────────────────┐
│                     应用层 (App Layer)                          │
│         AudioTrack / AudioRecord / MediaPlayer                  │
└─────────────────────────────┬─────────────────────────────────┘
                               │ Java/Native API
┌─────────────────────────────▼─────────────────────────────────┐
│                  框架层 (Framework Layer)                      │
│    ┌──────────────────┐      ┌──────────────────────────────┐  │
│    │   AudioFlinger  │ ←→   │  AudioPolicyService          │  │
│    │  + PriorityGroup│      │  + ExtendedAudioFocus        │  │
│    │  + AudioZone     │      │  + ZoneManager               │  │
│    └────────┬─────────┘      └──────────────────────────────┘  │
│             │                                                      │
│    ┌────────┴──────────────────────────────────┐                │
│    │        PriorityPlaybackThread              │                │
│    │  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌────┐│                │
│    │  │CRITICAL │ │IMPORTANT│ │ NORMAL │ │BG  ││                │
│    │  │ Group   │ │ Group   │ │ Group   │ │Group││                │
│    │  │(ADAS)   │ │(Nav)    │ │(Media)  │ │(Notif)│             │
│    │  └────┬────┘ └────┬────┘ └────┬────┘ └────┘│                │
│    │       └───────────┼───────────┼─────────────┘                │
│    │                   ↓           ↓                                │
│    │             ┌────────────┐                                    │
│    │             │ FinalMixer │ ← 各 Group 汇总                    │
│    │             └─────┬──────┘                                    │
│    │                   ↓                                            │
│    │             ┌────────────┐     ┌─────────────┐                 │
│    │             │ZoneEffects │ ←→  │TrackEffects │                 │
│    │             └─────┬──────┘     └─────────────┘                 │
│    └───────────────────┼────────────────────────────────────────────┘
│                        ↓
┌─────────────────────────▼────────────────────────────────────────┐
│                   Audio HAL Layer                                 │
│    ┌──────────────────────┐  ┌──────────────────────────────┐      │
│    │ StreamOut + Performance │  │ IStreamOutPerformanceExt   │      │
│    │ (带 PerformanceClass)    │  │ (新增性能等级查询接口)     │      │
│    └──────────────────────┘  └──────────────────────────────┘      │
└──────────────────────────────┼─────────────────────────────────────┘
                              ↓
                      音频硬件 (带性能等级标注)

2.2 Priority Group 分组混音机制

原架构:所有 Track → [单 Mixer] → HAL
       ↓ 问题:高优先级抢占时低优先级被连带影响

改进后:Track → [PriorityGroup 分类] → [各自独立 Mixer] → [FinalMixer] → HAL
       ↓ 优势:高优先级独立混音,不影响低优先级调度
PriorityPlaybackThread 内部流程:

① 高优先级 Track 写数据
   ↓
② CRITICAL Group 独立混音(5ms buffer,无 Effects bypass)
   ↓
③ IMPORTANT Group 独立混音(10ms buffer)
   ↓
④ NORMAL Group 混音(20ms buffer)
   ↓
⑤ BACKGROUND Group 混音(50ms buffer,Duck 时降到 10%)
   ↓
⑥ FinalMixer 汇总所有 Group 输出
   ↓
⑦ Zone Effects 处理
   ↓
⑧ 写入 HAL

2.3 AudioZone 多区域原生支持

原架构:无 Zone 概念,所有输出共享单音量控制
改进后:AudioZone 原生支持,每个 Zone 独立运行

AudioZoneManager ──┬── Zone[DRIVER]    { PriorityGroups + Focus }
                    ├── Zone[FRONT_PASSENGER] { ... }
                    ├── Zone[REAR_LEFT]  { ... }
                    ├── Zone[REAR_RIGHT] { ... }
                    └── Zone[CENTER]     { 导航/ADAS 语音 }

Zone 间隔离:
- 驾驶座导航播报 → 只在 DRIVER Zone 内打断媒体
- 后排音乐 → 不受驾驶座 Focus 变化影响
- Center Zone 的 ADAS 警示音 → 可配置是否压低其他 Zone

2.4 改进后的 AudioFocus 流程

原流程:
App 请求 Focus → 返回 GAIN/LOSS → 固定行为

改进后流程:
App 请求 Focus → ExtendedAudioFocus → 返回精细化 FocusInfo
                                         ├── duckLevel: 0.0~1.0
                                         ├── resumeDelayMs: 0~5000
                                         ├── affectedUsages: [...]
                                         └── zoneId: 隔离 Zone

Focus 变化回调:
  GAIN → 正常播放
  LOSS_TRANSIENT → pause() 等 resumeDelayMs 后自动恢复
  LOSS_TRANSIENT_MAY_DUCK → volume = duckLevel (可配置 30%)
  LOSS → pause()

2.5 HAL Performance Class 选择路径

AudioFlinger 查询 HAL PerformanceClass:

┌─────────────────┐
│ PERFORMANCE_A   │ → FastMixer 直连(< 20ms)
│ (延迟 < 20ms)  │   适用于:ADAS 警示、卡拉OK、实时监听
└─────────────────┘

┌─────────────────┐
│ PERFORMANCE_B   │ → 标准路径 + 优化(< 50ms)
│ (延迟 < 50ms)   │   适用于:导航播报、游戏音效
└─────────────────┘

┌─────────────────┐
│ PERFORMANCE_C   │ → 大 Buffer 稳定(< 100ms)
│ (延迟 < 100ms)  │   适用于:后台音乐、通知音
└─────────────────┘

┌─────────────────┐
│ UNSPECIFIED     │ → 按最坏情况处理(加额外缓冲)
└─────────────────┘

三、改进方案与代码实现

1. Priority Group 分组混音

// PriorityGroup.h
enum audio_priority_group_t : int32_t {
    PRIORITY_GROUP_CRITICAL = 0,   // ADAS 警示音,FLAG_AUDIBILITY_ENFORCED
    PRIORITY_GROUP_IMPORTANT = 1,  // 导航播报、语音通话
    PRIORITY_GROUP_NORMAL = 2,     // 媒体播放、游戏音效
    PRIORITY_GROUP_BACKGROUND = 3, // 通知音、Touch Sound
};

struct PriorityGroupConfig {
    audio_priority_group_t groupId;
    size_t maxTracks;
    uint32_t bufferSizeMs;       // CRITICAL 用小 buffer 低延迟
    int32_t resamplerQuality;
    bool effectsBypass;           // CRITICAL 通常 bypass Effects
};

// 默认配置
PriorityGroupConfig::defaultConfigs[PRIORITY_GROUP_COUNT] = {
    { CRITICAL,   8,  5ms, HIGH,   true  },   // 5ms,无 Effects
    { IMPORTANT, 16, 10ms, MEDIUM, false },
    { NORMAL,    32, 20ms, MEDIUM, false },
    { BACKGROUND,16, 50ms, LOW,   true  },   // 大 buffer 稳定
};
// PriorityPlaybackThread.cpp — 核心混音逻辑
bool PriorityPlaybackThread::threadLoop() {
    // Phase 1: 按 Group 独立混音
    memset(mFinalMixBuffer.data(), 0, bufferBytes);
    
    for (int i = 0; i < PRIORITY_GROUP_COUNT; i++) {
        auto& group = mPriorityGroups[i];
        if (!group->hasActiveTracks()) continue;
        
        std::vector<float> groupBuffer(frameCount * channels);
        group->mixTracks(mSampleRate, mChannelMask, frameCount,
                        groupBuffer.data(), frameCount);
        
        for (size_t j = 0; j < frameCount * channels; j++) {
            mFinalMixBuffer[j] += groupBuffer[j];  // 汇总
        }
    }
    
    // Phase 2: Ducking — 高优先级 Group 活跃时降低低优先级音量
    if (mIsDucking) {
        mPriorityGroups[BACKGROUND]->setVolume(mDuckingLevel * 0.5f);  // 10%
        mPriorityGroups[NORMAL]->setVolume(mDuckingLevel);               // 20%
    }
    
    writeToHal(mFinalMixBuffer.data(), frameCount);
    return true;
}

2. AudioZone 原生支持

// AudioZone.h — 多区域音频核心定义
enum audio_zone_id_t : int32_t {
    AUDIO_ZONE_ID_DEFAULT = 0,
    AUDIO_ZONE_ID_DRIVER = 0,
    AUDIO_ZONE_ID_FRONT_PASSENGER = 1,
    AUDIO_ZONE_ID_REAR_LEFT = 2,
    AUDIO_ZONE_ID_REAR_RIGHT = 3,
    AUDIO_ZONE_ID_CENTER = 4,      // 中央通道,导航/ADAS
};

class AudioZone : public RefBase {
    audio_zone_id_t getZoneId() const { return mConfig.zoneId; }
    
    // Zone 内按 PriorityGroup 分组,各自独立混音
    std::vector<sp<PriorityGroup>> mPriorityGroups;
    
    // Zone 级音量 + Focus 隔离
    float mVolume;
    sp<AudioFocusManager> mFocusManager;
};

class AudioZoneManager : public RefBase {
    std::vector<sp<AudioZone>> mZones;  // 所有 Zone
    
    // 全局混音入口
    status_t mixAllZones(void* halOutput, uint32_t halFrames);
    
    // Zone 路由配置
    status_t setZoneRoute(audio_zone_id_t zoneId, audio_io_handle_t halOutput);
};

3. AudioFocus 精细化控制

// AudioFocusRequest.java — 扩展 Focus 请求
public static class Builder {
    /** Ducking Level(0.0 ~ 1.0),原来只能 0 或 0.2 */
    public @NonNull Builder setDuckingLevel(float level) {
        mDuckingLevel = level;  // 可设 0.3 即 30%
        return this;
    }
    
    /** 延迟恢复时间(ms)*/
    public @NonNull Builder setResumeDelayMs(int delayMs) {
        mResumeDelayMs = delayMs;  // 被打断后等2秒再恢复
        return this;
    }
    
    /** 受影响的 Usage(只影响指定的,不影响其他)*/
    public @NonNull Builder setAffectedUsages(@NonNull AudioUsage[] usages) {
        mAffectedUsages = Arrays.copyOf(usages, usages.length);
        return this;
    }
    
    /** Zone 隔离(驾驶座的 Focus 不打断后排音乐)*/
    public @NonNull Builder setZoneId(int zoneId) {
        mZoneId = zoneId;
        return this;
    }
}

// 使用示例
AudioFocusRequest request = new AudioFocusRequest.Builder(AUDIOFOCUS_GAIN)
    .setDuckingLevel(0.3f)              // duck 到 30%
    .setResumeDelayMs(2000)              // 2秒后恢复
    .setAffectedUsages(MEDIA, GAME)      // 只压低媒体和游戏
    .setZoneId(DRIVER_ZONE)              // 只在驾驶 Zone 生效
    .build();

4. HAL Performance Class 标准

// StreamOut.h — 定义 HAL 性能等级
enum audio_hal_performance_class_t : int32_t {
    PERFORMANCE_CLASS_A = 0,  // 延迟 < 20ms,必须 FastMixer
    PERFORMANCE_CLASS_B = 1,    // 延迟 < 50ms
    PERFORMANCE_CLASS_C = 2,    // 延迟 < 100ms
};

struct audio_hal_performance_info_t {
    audio_hal_performance_class_t performanceClass;
    uint32_t latencyMs;          // 实测端到端延迟
    uint32_t halBufferMs;         // HAL 内部缓冲
    bool supportsFastMixer;
    bool supportsLowLatency;
};

class IStreamOutPerformanceExtension {
    virtual int getPerformanceClass(audio_hal_performance_info_t* info) = 0;
    virtual bool supportsLatency(uint32_t targetLatencyMs) = 0;
};
// AudioFlinger 根据等级选择路径
if (performanceClass == PERFORMANCE_CLASS_A) {
    useFastMixerPath(streamOut);        // < 20ms
} else if (performanceClass == PERFORMANCE_CLASS_B) {
    useOptimizedMixerPath(streamOut);   // < 50ms
} else {
    useStabilizedPath(streamOut);        // < 100ms
}

5. Track Effects 开放 API

// AudioTrack.java — 扩展 Builder
public static class Builder extends AudioTrack.Builder {
    private ArrayList<Integer> mEffectIds = new ArrayList<>();
    
    public @NonNull Builder setAttachEffect(int effectId) {
        mEffectIds.add(effectId);  // 支持多个 Effect 串行
        return this;
    }
}

AudioTrack track = new AudioTrack.Builder()
    .setAudioAttributes(...)
    .setAttachEffect(effectId1)  // 附加 Effect 到 Track
    .setAttachEffect(effectId2)
    .build();

track.attachEffect(effectId3);   // 动态 attach
track.detachEffect(effectId1);    // 动态 detach

四、总结

| 不足 | 改进方案 | 核心变化 |
|------|----------|----------|
| 单点瓶颈 | Priority Group 分组混音 | 按优先级独立 Mixer,互不影响 |
| Focus 太粗 | 多级 Focus + ResumeDelay | 精细化 Duck Level + 延迟恢复 |
| 多 Zone 太弱 | AudioZone 原生支持 | Zone 间 Focus 隔离 |
| HAL 碎片化 | Performance Class | 按性能等级选择最优路径 |
| Effects 局限 | Track Effects 开放 | App 可 attach Effect |

五、后续工作

  1. 优先级分类规则和 AudioPolicyService 联动完善
  2. AudioZone 的 HAL 路由需要和 CarAudioHAL 对接
  3. Track Effects 的 native 层实现 binder 通信
  4. Performance Class 在 HAL CTS 测试中验证
  5. 完整的测试用例(CTS/VTS)

完整的实现代码已上传到 GitHub,可作为内部设计文档或概念验证的基础。


配套代码仓库:
GitHub: fryduck/android-audio-architecture-improvement

发表评论