Android Audio系统深度解析

Android Audio系统深度解析
从AudioFlinger到AudioPolicyService:音频数据流与路由机制完全指南

作者:Audio系统研究团队 | 更新时间:2026年4月

目录导航

  1. 一、Android Audio系统概述
  2. 二、Audio系统总体架构
  3. 三、AudioFlinger核心机制
  4. 四、AudioPolicyService策略管理
  5. 五、Audio Path数据流
  6. 六、Audio路由规则代码解析
  7. 七、总结

一、Android Audio系统概述

Android Audio系统是Android平台的核心子系统之一,负责音频数据的采集、播放、控制和管理。从技术实现角度来看,它是一个多层架构,涉及应用框架、Native服务层、硬件抽象层以及内核驱动。

核心设计哲学:策略与机制的分离

AudioPolicyService负责策略决策——决定音频从哪个设备输出、音量应该多大;而AudioFlinger负责机制执行——具体如何与音频硬件通信、如何进行音频混音。这种设计使系统具有良好的可扩展性。

二、Audio系统总体架构

2.1 分层架构

image.png

层级 组件 职责
应用层 MediaPlayer、AudioTrack Java API接口
框架层 AudioSystem、JNI 跨进程通信
服务层 AudioFlinger、PolicyService 混音处理、策略决策
HAL层 audio.primary.so等 硬件抽象
内核层 ALSA驱动 设备交互

2.2 Policy与Flinger协作

image.png

三、AudioFlinger核心机制

3.1 组件架构

image.png

3.2 数据传输机制

AudioFlinger使用共享内存实现高效数据传输。应用进程将PCM数据写入共享内存,AudioFlinger直接从共享内存读取进行混音,实现零拷贝。

代码:Track创建

// AudioFlinger.cpp
sp AudioFlinger::PlaybackThread::createTrack_l(...) {
    // 创建Track对象
    sp track = new Track(this, attr, sampleRate,
                         format, channelMask, bufferSize,
                         sharedBuffer, client, sessionId);

    // 注册到混音线程
    mTracks.add(track);
    return track;
}

四、AudioPolicyService策略管理

4.1 策略决策流程

image.png

4.2 策略到设备映射

策略 使用场景 设备优先级
STRATEGY_MEDIA 音乐、视频 耳机 > 蓝牙A2DP > 扬声器
STRATEGY_PHONE 语音通话 蓝牙SCO > 耳机 > 免提
STRATEGY_SONIFICATION 通知音 扬声器

五、Audio Path数据流分析

5.1 播放数据路径

image.png

5.2 播放时序图

图5-2 AudioTrack播放完整时序


image.png

5.3 录音数据路径


image.png

5.4 动态路由切换时序

image.png

六、Audio路由规则代码解析

6.1 audio_policy_configuration.xml配置

Android的音频路由规则通过XML配置文件定义,描述系统硬件能力、可用设备及路由规则。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Copyright (C) 2019 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
    <!-- version section contains a “version” tag in the form “major.minor” e.g version=”1.0” -->

    <!-- Global configuration Decalaration -->
    <globalConfiguration speaker_drc_enabled="true"/>


    <!-- Modules section:
        There is one section per audio HW module present on the platform.
        Each module section will contains two mandatory tags for audio HAL “halVersion” and “name”.
        The module names are the same as in current .conf file:
                “primary”, “A2DP”, “remote_submix”, “USB”
        Each module will contain the following sections:
        “devicePorts”: a list of device descriptors for all input and output devices accessible via this
        module.
        This contains both permanently attached devices and removable devices.
        “mixPorts”: listing all output and input streams exposed by the audio HAL
        “routes”: list of possible connections between input and output devices or between stream and
        devices.
            "route": is defined by an attribute:
                -"type": <mux|mix> means all sources are mutual exclusive (mux) or can be mixed (mix)
                -"sink": the sink involved in this route
                -"sources": all the sources than can be connected to the sink via vis route
        “attachedDevices”: permanently attached devices.
        The attachedDevices section is a list of devices names. The names correspond to device names
        defined in <devicePorts> section.
        “defaultOutputDevice”: device to be used by default when no policy rule applies
    -->
    <modules>
        <!-- Primary Audio HAL -->
        <module name="primary" halVersion="3.0">
            <attachedDevices>
                <item>Speaker</item>
                <item>Built-In Mic</item>
                <item>Built-In Back Mic</item>
            </attachedDevices>
            <defaultOutputDevice>Speaker</defaultOutputDevice>
            <mixPorts>
                <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
                <mixPort name="deep_buffer" role="source"
                        flags="AUDIO_OUTPUT_FLAG_DEEP_BUFFER">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
                <mixPort name="compressed_offload" role="source"
                         flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING">
                    <profile name="" format="AUDIO_FORMAT_MP3"
                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
                    <profile name="" format="AUDIO_FORMAT_AAC"
                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
                    <profile name="" format="AUDIO_FORMAT_AAC_LC"
                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
                </mixPort>
                <mixPort name="voice_tx" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                </mixPort>
                <mixPort name="primary input" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                             channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
                </mixPort>
                <mixPort name="voice_rx" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
                </mixPort>
            </mixPorts>
            <devicePorts>
                <!-- Output devices declaration, i.e. Sink DEVICE PORT -->
                <devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink">
                   <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                </devicePort>
                <devicePort tagName="Speaker" role="sink" type="AUDIO_DEVICE_OUT_SPEAKER" address="">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                    <gains>
                        <gain name="gain_1" mode="AUDIO_GAIN_MODE_JOINT"
                              minValueMB="-8400"
                              maxValueMB="4000"
                              defaultValueMB="0"
                              stepValueMB="100"/>
                    </gains>
                </devicePort>
                <devicePort tagName="Wired Headset" type="AUDIO_DEVICE_OUT_WIRED_HEADSET" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </devicePort>
                <devicePort tagName="Wired Headphones" type="AUDIO_DEVICE_OUT_WIRED_HEADPHONE" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </devicePort>
                <devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                </devicePort>
                <devicePort tagName="BT SCO Headset" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                </devicePort>
                <devicePort tagName="BT SCO Car Kit" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                </devicePort>
                <devicePort tagName="Telephony Tx" type="AUDIO_DEVICE_OUT_TELEPHONY_TX" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                </devicePort>

                <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                             channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
                </devicePort>
                <devicePort tagName="Built-In Back Mic" type="AUDIO_DEVICE_IN_BACK_MIC" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                             channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
                </devicePort>
                <devicePort tagName="Wired Headset Mic" type="AUDIO_DEVICE_IN_WIRED_HEADSET" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                             channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
                </devicePort>
                <devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
                </devicePort>
                <devicePort tagName="Telephony Rx" type="AUDIO_DEVICE_IN_TELEPHONY_RX" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
                </devicePort>
            </devicePorts>
            <!-- route declaration, i.e. list all available sources for a given sink -->
            <routes>
                <route type="mix" sink="Earpiece"
                       sources="primary output,deep_buffer,BT SCO Headset Mic"/>
                <route type="mix" sink="Speaker"
                       sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
                <route type="mix" sink="Wired Headset"
                       sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
                <route type="mix" sink="Wired Headphones"
                       sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
                <route type="mix" sink="primary input"
                       sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic"/>
                <route type="mix" sink="Telephony Tx"
                       sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic, voice_tx"/>
                <route type="mix" sink="voice_rx"
                       sources="Telephony Rx"/>
            </routes>

        </module>

        <!-- A2dp Input Audio HAL -->
        <xi:include href="a2dp_in_audio_policy_configuration.xml"/>

        <!-- Usb Audio HAL -->
        <xi:include href="usb_audio_policy_configuration.xml"/>

        <!-- Remote Submix Audio HAL -->
        <xi:include href="r_submix_audio_policy_configuration.xml"/>

        <!-- Bluetooth Audio HAL -->
        <xi:include href="bluetooth_audio_policy_configuration.xml"/>

        <!-- MSD Audio HAL (optional) -->
        <xi:include href="msd_audio_policy_configuration.xml"/>

    </modules>
    <!-- End of Modules section -->

    <!-- Volume section:
        IMPORTANT NOTE: Volume tables have been moved to engine configuration.
                        Keep it here for legacy.
                        Engine will fallback on these files if none are provided by engine.
     -->

    <xi:include href="audio_policy_volumes.xml"/>
    <xi:include href="default_volume_tables.xml"/>

    <!-- End of Volume section -->

    <!-- Surround Sound configuration -->

    <xi:include href="surround_sound_configuration_5_0.xml"/>

    <!-- End of Surround Sound configuration -->

</audioPolicyConfiguration>

6.2 路由决策核心函数

getDevicesForStrategyInt是AudioPolicyManager中核心的路由决策函数,根据策略和系统状态计算最佳输出设备。
getDevicesForStrategyInt 实现

void AudioPolicyManager::getDevicesForStrategyInt(
    strategy_type_t strategy,
    SortedVector>& devices) {

    devices.clear();

    for (size_t i = 0; i < mOutputs.size(); i++) {
        sp outputDesc = mOutputs.valueAt(i);

        if (outputDesc->supportedTries(strategy)) {
            audio_devices_t device = outputDesc->devices();

            switch (strategy) {
                case STRATEGY_MEDIA:
                    // 媒体播放: 优先耳机/蓝牙
                    if (device & (AUDIO_DEVICE_OUT_WIRED_HEADSET |
                                 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP)) {
                        devices.add(outputDesc->mDevice);
                    } else if (device & AUDIO_DEVICE_OUT_SPEAKER) {
                        devices.add(outputDesc->mDevice);
                    }
                    break;

                case STRATEGY_PHONE:
                    // 电话: 优先SCO/耳机
                    if (device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO) {
                        devices.add(outputDesc->mDevice);
                    } else if (device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
                        devices.add(outputDesc->mDevice);
                    }
                    break;

                case STRATEGY_SONIFICATION:
                    // 通知音: 使用扬声器
                    if (device & AUDIO_DEVICE_OUT_SPEAKER) {
                        devices.add(outputDesc->mDevice);
                    }
                    break;
            }
        }
    }
}

6.3 ForceUse强制配置

ForceUse用于处理特殊场景的强制路由,如勿扰模式下强制路由到耳机。

ForceUse配置处理

audio_devices_t AudioPolicyManager::getForceUse(
    audio_policy_force_use_t usage) const {

    switch (usage) {
        case FORCE_FOR_MEDIA:
            return mForceUse[usage];

        case FORCE_FOR_RECORD:
            if (mForceUse[usage] == FORCE_NONE) {
                return FORCE_WIRED_ACCESSORY;
            }
            return mForceUse[usage];

        case FORCE_FOR_BT_SCO:
            return mForceUse[usage];

        case FORCE_FOR_ENFORCED_AUDIBLE:
            return mForceUse[usage];

        default:
            return FORCE_NONE;
    }
}

6.4 动态路由切换代码

checkOutputsForDevice 实现

void AudioPolicyManager::checkOutputsForDevice(
    const sp& device,
    audio_policy_dev_state_t state) {

    for (size_t i = 0; i < mOutputs.size(); i++) {
        sp outputDesc = mOutputs.valueAt(i);

        if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
            // 询问Engine获取备选设备
            DeviceVector availableDevices =
                getAvailableDevicesForStrategy(
                    outputDesc->getStrategy());

            if (availableDevices.contains(device)) {
                // 创建新Patch
                sp patchRecord = createPatch(...);

                // 更新输出描述符
                outputDesc->mPatch = patchRecord;

                // 通知AudioFlinger
                mpClientInterface->setAudioPortConfig(...);
            }
        }
    }
}

七、总结

三个核心要点

  1. 策略与机制分离:Policy决策做什么,Flinger执行怎么做。
  2. 共享内存高效传输:零拷贝,保证低延迟。
  3. Patch统一路由:无论是播放还是录制,都通过Patch统一管理。

进阶学习路径

  • 深入阅读frameworks/av/services/audioflinger/源码
  • 了解Audio HAL厂商实现
  • 学习AudioEffect音效框架
  • 研究车载AudioZone等高级特性
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容