Android 的音频策略配置文件j即APS的配置文件(audio_policy_configuration.xml)是系统音频策略的基石,决定者音频数据的流向。其解析过程直接影响设备行为采用模块化 XML 设计,解析过程涉及多个关键步骤。以下是完整解析流程与技术要点:

1. 配置文件层级结构

文件通常位于/vendor/etc或/system/etc(开发板目录),内容如下:

<audioPolicyConfiguration>
  <globalConfiguration key="attached_input_devices" value="..."/>
  <modules>
    <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>                              <!-- I/O端口定义 -->
        <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
          <profile format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
        </mixPort>
      </mixPorts>
      <devicePorts>                           <!-- 物理/逻辑设备 -->
        <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
          <profile.../>
        </devicePort>
      </devicePorts>
      <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
            <profile.../>
         </devicePort>
      </devicePorts>
      <routes>                                 <!-- 路由规则 -->
        <route type="mix" sink="Speaker" sources="primary output"/>
      </routes>
    </module>
    <!-- 其他模块(蓝牙/USB等) -->
  </modules>
  <routingStrategies>                         <!-- 策略规则 -->
    <strategy name="STRATEGY_MEDIA" deviceCategory="DEVICE_CATEGORY_SPEAKER">
      <attributes usage="USAGE_MEDIA"/>
    </strategy>
  </routingStrategies>
</audioPolicyConfiguration>

在上一章提到,在创建AudioPolicyManager对象时,通过loadConfig加载配置文件,解析完成后,xml文件中的元素终究会转化AudioPolicyConfig中的成员。AudioPolicyConfig定义如下:

class AudioPolicyConfig{
...
    HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
    DeviceVector &mOutputDevices;
    DeviceVector &mInputDevices;
    sp<DeviceDescriptor> &mDefaultOutputDevice;
}

同时,这四个变量也在AudioPolicyManager中有定义。

mHwModules:保存了配置文件中所有的所有module标签集合,每个module标签对应一个HwModule类。

mAvailableOutputDevices:attchedDevices标签中,设备名称名字和devicePort标签的tagName相同,且type中有OUT字眼的DeviceDescriptor实体类集合,如示例文件中的Speaker设备。

mAvailableInputDevices:同mAvailableOutputDevices类似,换成type中有IN的DeviceDescriptor实体类集合,如上Built-In Mic。

mDefaultOutputDevice:保存defaultOutputDevice标签内名字和devicePort标签的tagName相同,如Speaker。

1.1module标签

每个module标签对应有自己的hal,也就是hal的源码实现都不一样,如primary、usb、a2dp等

    <modules>
        <!-- Primary Audio HAL -->
        <module name="primary" halVersion="3.0">
            <mixPorts>
                <mixPort name="primary output" role="source" ...>
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT".../>
                    <profile name="" format="AUDIO_FORMAT_MP3".../>
                    ...
                </mixPort>
            </mixPorts>
            <devicePorts>
                <devicePort>... </devicePort>
            ...
            </devicePorts>
            <routes>
                <route>...</route>
            </routes>
        </module>
    </modules>

对应到实体类:

class HwModule : public RefBase
{
    ...
    const String8 mName; // base name of the audio HW module (primary, a2dp ...)
    audio_module_handle_t mHandle;
    OutputProfileCollection mOutputProfiles; // output profiles exposed by this module
    InputProfileCollection mInputProfiles;  // input profiles exposed by this module
    uint32_t mHalVersion; // audio HAL API version
    DeviceVector mDeclaredDevices; // devices declared in audio_policy configuration file.
    DeviceVector mDynamicDevices; /**< devices that can be added/removed at runtime (e.g. rsbumix)*/
    AudioRouteVector mRoutes;
    PolicyAudioPortVector mPorts;
}

mOutputProfiles:mixport标签role为source类型,对应IOProfle实体类集合

 mInputProfiles:mixport标签role为sink的类型,对应IOProfle实体类集合

mDeclaredDevices:所有的deviceport标签,对应DeviceDescriptor实体类的集合

mRoutes:所有的route

mPorts:所有的mixport,deviceport标签对应的实体类,因为IOProfle和DeviceDescriptor都继承了AudioPort,所以相当于这是一个AudioPort集合

1.2MixPort标签

mixPort标签可以理解为stream流,流配置了自己的格式、采样率以及mask,分为输出流和输入流,一个mixport可以有很多个profile,表示支持多少种格式。

<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"/>
</mixPort>

每个mixport标签对应一个IOProfile实体类,IOProfile分别继承于AudioPort(frameworks/av/media/libaudiofoundation/include/media/AudioPort.h)和PolicyAudioPort

class IOProfile : public AudioPort, public PolicyAudioPort
{
    // Maximum number of input or output streams that can be simultaneously active for this profile.
    // By convention 0 means no limit. To respect legacy behavior, initialized to 0 for output
    // profiles and 1 for input profiles
    uint32_t     maxActiveCount;
private:
    DeviceVector mSupportedDevices; // supported devices: this input/output can be routed from/to
}

class AudioPort {
protected:
    std::string  mName;
    audio_port_type_t mType;
    audio_port_role_t mRole;
    AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
};

class PolicyAudioPort {
    uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
    sp<HwModule> mModule;     // audio HW module exposing this I/O stream
    AudioRouteVector mRoutes; // Routes involving this port
}

maxActiveCount:同时存活的流的最大数量,默认为1

标签中flag会影响该值,如果role为sink,且flag标记为AUDIO_INPUT_FLAG_MMAP_NOIRQ,则赋值为0,表示无穷大 

mSupportedDevices:当前流支持的设备集合

作为输出流source,mSupportedDevices保存此流可以输出到对应的device,stream -> device
作为输入流sink,mSupportedDevices保存了其他device能输出数据到此流,  device -> stream

根据route查找对应的source和sink,例如sink为输入流时对应规则如下:
(1)遍历其父类的成员mRoutes,因为是输入流,所以遍历mRoute集合中sink为自己的route,也就是找有哪些源source设备把数据传给自己。
(2)找到route后,根据route中source保存的对象,且对象type是AUDIO_PORT_TYPE_DEVICE类型(就是devicesPort标签对应的实体类DeviceDescriptor)
(3)把DeviceDescriptor保存在集合中,保存在以下mSupportedDevices中,作为其支持的设备;
MixPort的profile,会单独创建AudioProfile对象

class AudioProfile final : public RefBase, public Parcelable
{
...
private:
    std::string  mName;
    audio_format_t mFormat; // The format for an audio profile should only be set when initialized.
    ChannelMaskSet mChannelMasks;
    SampleRateSet mSamplingRates;

    bool mIsDynamicFormat = false;
    bool mIsDynamicChannels = false;
    bool mIsDynamicRate = false;
};

1.3Device标签

devicePort标签可以理解为一个device设备。

<devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink">
     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
</devicePort>
<devicePort tagName="Speaker" role="sink" type="AUDIO_DEVICE_OUT_SPEAKER" address="">
      <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000" hannelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</devicePort>

对应实体类DeviceDescriptor

class DeviceDescriptor : public DeviceDescriptorBase,
                         public PolicyAudioPort, public PolicyAudioPortConfig
{
...
private:
    std::string mTagName; // Unique human readable identifier for a device port found in conf file.
    FormatVector        mEncodedFormats;
    audio_format_t      mCurrentEncodedFormat;
}

class DeviceDescriptorBase : public AudioPort, public AudioPortConfig
{
}
class PolicyAudioPort {
    uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
    sp<HwModule> mModule;     // audio HW module exposing this I/O stream
    AudioRouteVector mRoutes; // Routes involving this port
}

class AudioPort {
protected:
    std::string  mName;
    audio_port_type_t mType;
    audio_port_role_t mRole;
    AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
}

class PolicyAudioPortConfig : public virtual RefBase
{
    union audio_io_flags mFlags = { AUDIO_INPUT_FLAG_NONE };
}

同上MixPort一样,也会在解析内部profile标签,创建新的AudioProfile。

1.4.route标签

route是把deviceport和mixport连接起来的路由,数据由一个stream输出到另一个device(output),或者从一个device输入到另一个stream(input);

<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>

对应的实体类为AudioRoute

class AudioRoute  : public virtual RefBase
{
...
private:
    PolicyAudioPortVector mSources;
    sp<PolicyAudioPort> mSink;
    audio_route_type_t mType;
}
XML 元素 内存对象 作用
<module> HwModule 抽象音频硬件模块
<mixPort> IOProfile 定义输入/输出端口能力
<devicePort> DeviceDescriptor 描述物理设备特性
<route> AudioRoute 建立端口与设备连接关系
<routingStrategies> Engine/ProductStrategy 音频策略到设备的映射规则

内容有点多,下篇文章中继续分析,这篇文章大多参考了@帅气好男人_Jack的讲解audio_policy_configuration.xml文件解析_audio policy config详解-CSDN博客,我是基于Android12代码分析的,有一些出入,请按照自己调试的代码对照分析。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐