Android开发之音频配置文件audio_policy_configuration.xml解析全过程

本文基于android7.0分析

一、前言

audio_policy.conf解析

前面我们已经介绍了audio_policy.conf 的解析全过程,但是,.conf 是一种简单的专有格式,有较大的局限性,无法描述电视和汽车等应用的复杂拓扑。Android 7.0 弃用了audio_policy.conf,并增加了对使用 XML 文件格式来定义音频拓扑的支持,这种文件格式更通俗易懂,具有多种编辑和解析工具,并且足够灵活,可以描述复杂的音频拓扑。

注意Android 7.0 仍支持使用 audio_policy.conf;系统会默认使用这种旧版格式。要使用 XML 文件格式,需要在设备 Makefile 中添加构建选项 USE_XML_AUDIO_POLICY_CONF := 1


二、XML 格式的优势

与在 .conf 文件中一样,新的 XML 文件支持定义输出输入流配置文件、可用于播放和捕获的设备以及音频属性的数量和类型。此外,XML 格式还提供以下增强功能:

  • 音频配置文件目前的结构类似于 HDMI 简单音频描述符,支持每种音频格式使用一组不同的采样率/声道掩码。
  • 设备和流之间所有可能连接的显式定义。以前,借助隐式规则,可以使连接到同一 HAL 模块的所有设备互连,从而阻止音频政策控制使用音频补丁程序 API 请求的连接。现在,在 XML 格式中,拓扑描述定义了连接限制。
  • 对“包含”的支持可避免出现重复的标准 A2DP、USB 或重新导向提交定义。
  • 可自定义的音量曲线。以前,音量表采用硬编码格式。在 XML 格式中,音量表通过描述来定义,并且可自定义。

frameworks/av/services/audiopolicy/config/audio_policy_configuration.xml 中的模板展示了很多已在使用的上述功能。


三、文件格式和位置

新的音频政策配置文件是 audio_policy_configuration.xml,位于 /system/etc。要查看采用新的 XML 文件格式的简单音频政策配置,请查看以下示例。

显示音频政策示例

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
    <globalConfiguration speaker_drc_enabled="true"/>
    <modules>
        <module name="primary" halVersion="3.0">
            <attachedDevices>
                <item>Speaker</item>
                <item>Earpiece</item>
                <item>Built-In 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="primary input" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000,48000"
                             channelMasks="AUDIO_CHANNEL_IN_MONO"/>
                </mixPort>
            </mixPorts>
            <devicePorts>
                <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" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </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="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000,48000"
                             channelMasks="AUDIO_CHANNEL_IN_MONO"/>
                </devicePort>
                <devicePort tagName="Wired Headset Mic" type="AUDIO_DEVICE_IN_WIRED_HEADSET" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000,48000"
                             channelMasks="AUDIO_CHANNEL_IN_MONO"/>
                </devicePort>
            </devicePorts>
            <routes>
                <route type="mix" sink="Earpiece" sources="primary output"/>
                <route type="mix" sink="Speaker" sources="primary output"/>
                <route type="mix" sink="Wired Headset" sources="primary output"/>
                <route type="mix" sink="primary input" sources="Built-In Mic,Wired Headset Mic"/>
            </routes>
        </module>
        <xi:include href="a2dp_audio_policy_configuration.xml"/>
    </modules>    
     
	<xi:include href="audio_policy_volumes.xml"/>
    <xi:include href="default_volume_tables.xml"/>
</audioPolicyConfiguration>

顶层结构中包含与各个音频 HAL 硬件模块对应的模块,其中每个模块都有一系列混合端口、设备端口和导向:

  • 混合端口描述了可以在音频 HAL 处打开以供播放和捕获的流的可能配置文件。
  • 设备端口描述了可以附上其类型(以及(可选)地址和音频属性,如果相关)的设备。
  • 导向(新)现在已从混合端口描述符中分离出来,支持描述从设备到设备或从流到设备的导向。

显示音量表示例

<?xml version="1.0" encoding="UTF-8"?>
<volumes>
    <reference name="FULL_SCALE_VOLUME_CURVE">
        <point>0,0</point>
        <point>100,0</point>
    </reference>
    <reference name="SILENT_VOLUME_CURVE">
        <point>0,-9600</point>
        <point>100,-9600</point>
    </reference>
    <reference name="DEFAULT_VOLUME_CURVE">
        <point>1,-4950</point>
        <point>33,-3350</point>
        <point>66,-1700</point>
        <point>100,0</point>
    </reference>
</volumes>

显示音量示例

<?xml version="1.0" encoding="UTF-8"?>
<volumes>
    <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_VOLUME_CURVE"/>
 
    <volume stream="AUDIO_STREAM_SYSTEM" deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_SYSTEM" deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_SYSTEM" deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_SYSTEM" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_VOLUME_CURVE"/>
 
    <volume stream="AUDIO_STREAM_RING" deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_RING" deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_RING" deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_RING" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"ref="DEFAULT_VOLUME_CURVE"/>
 
    <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER">
        <point>1,-5500</point>
        <point>20,-4300</point>
        <point>86,-1200</point>
        <point>100,0</point>
    </volume>
    <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_VOLUME_CURVE"/>
 
    <volume stream="AUDIO_STREAM_ALARM" deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_ALARM" deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_ALARM" deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_ALARM" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_VOLUME_CURVE"/>
 
    <volume stream="AUDIO_STREAM_NOTIFICATION" deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_NOTIFICATION" deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_NOTIFICATION" deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_NOTIFICATION" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_VOLUME_CURVE"/>
 
    <volume stream="AUDIO_STREAM_BLUETOOTH_SCO" deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_BLUETOOTH_SCO" deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_BLUETOOTH_SCO" deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_BLUETOOTH_SCO" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_VOLUME_CURVE"/>
 
    <volume stream="AUDIO_STREAM_ENFORCED_AUDIBLE" deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_ENFORCED_AUDIBLE" deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_ENFORCED_AUDIBLE" deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_ENFORCED_AUDIBLE" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_VOLUME_CURVE"/>
 
    <volume stream="AUDIO_STREAM_DTMF" deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_DTMF" deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_DTMF" deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_DTMF" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_VOLUME_CURVE"/>
 
    <volume stream="AUDIO_STREAM_TTS" deviceCategory="DEVICE_CATEGORY_HEADSET" ref="SILENT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_TTS" deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_TTS" deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="SILENT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_TTS" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="SILENT_VOLUME_CURVE"/>
 
    <volume stream="AUDIO_STREAM_ACCESSIBILITY" deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_ACCESSIBILITY" deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_ACCESSIBILITY" deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_ACCESSIBILITY" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_VOLUME_CURVE"/>
 
    <volume stream="AUDIO_STREAM_REROUTING" deviceCategory="DEVICE_CATEGORY_HEADSET" ref="FULL_SCALE_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_REROUTING" deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_REROUTING" deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="FULL_SCALE_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_REROUTING" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="FULL_SCALE_VOLUME_CURVE"/>
 
    <volume stream="AUDIO_STREAM_PATCH" deviceCategory="DEVICE_CATEGORY_HEADSET" ref="FULL_SCALE_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_PATCH" deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_PATCH" deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="FULL_SCALE_VOLUME_CURVE"/>
    <volume stream="AUDIO_STREAM_PATCH" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="FULL_SCALE_VOLUME_CURVE"/>
</volumes>

XML 包含 (XInclude) 方法可用于包含位于其他 XML 文件中的音频政策配置信息。所有包含的文件必须遵循上述结构,同时满足以下限制条件:

  • 文件只能包含顶层元素。
  • 文件不能包含 Xinclude 元素。

使用“包含”可避免将标准 Android 开放源代码项目 (AOSP) 音频 HAL 模块配置信息复制到所有音频政策配置文件(这样做容易出错)google为以下音频 HAL 提供了标准音频政策配置 xml 文件:

  • A2DPa2dp_audio_policy_configuration.xml
  • 重新导向子混音rsubmix_audio_policy_configuration.xml
  • USBusb_audio_policy_configuration.xml

四、解析

以如下audio_policy_configuration.xml为例:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Copyright (c) 2016, The Linux Foundation. All rights reserved
     Not a Contribution.
-->
<!-- Copyright (C) 2015 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_IN_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="Telephony Tx"
                       sources="voice_tx"/>
                <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"/>
                <route type="mix" sink="voice_rx"
                       sources="Telephony Rx"/>
            </routes>
 
        </module>
 
        <!-- HDMI Audio HAL -->
        <module description="HDMI Audio HAL" name="hdmi" version="2.0">
            <mixPorts>
                <mixPort name="hdmi output" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000"/>
                </mixPort>
            </mixPorts>
            <devicePorts>
                <devicePort tagName="HDMI Out" type="AUDIO_DEVICE_OUT_AUX_DIGITAL" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </devicePort>
            </devicePorts>
            <routes>
                <route type="mix" sink="HDMI Out"
                       sources="hdmi output"/>
            </routes>
        </module>
 
        <!-- A2dp Audio HAL -->
        <xi:include href="a2dp_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"/>
 
    </modules>
    <!-- End of Modules section -->
 
    <!-- Volume section -->
 
    <xi:include href="audio_policy_volumes.xml"/>
    <xi:include href="default_volume_tables.xml"/>
 
    <!-- End of Volume section -->
 
</audioPolicyConfiguration>

在之前我们已经介绍了的 audio_policy.conf 文章中可以知道,解析音频配置策略文件所处的类文件为 AudioPolicyManager.cpp 构造函数
在这里插入图片描述
而本章第一小节说了自Android 7.0 开始出现了.xml 音频配置策略文件,并且兼容老的 .conf ,通过宏定义 USE_XML_AUDIO_POLICY_CONF 控制 ,代码位于 AudioPolicyManager.cpp 构造函数 如下:
AudioPolicyManager.cpp 位于 \frameworks\av\services\audiopolicy\managerdefault

#ifdef USE_XML_AUDIO_POLICY_CONF
    mVolumeCurves = new VolumeCurvesCollection();
    AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
                             mDefaultOutputDevice, speakerDrcEnabled,
                             static_cast<VolumeCurvesCollection *>(mVolumeCurves));
    PolicySerializer serializer;
    if (serializer.deserialize(AUDIO_POLICY_XML_CONFIG_FILE, config) != NO_ERROR) {
#else
    mVolumeCurves = new StreamDescriptorCollection();
    AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
                             mDefaultOutputDevice, speakerDrcEnabled);
    if ((ConfigParsingUtils::loadConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE, config) != NO_ERROR) &&
            (ConfigParsingUtils::loadConfig(AUDIO_POLICY_CONFIG_FILE, config) != NO_ERROR)) {
#endif
        ALOGE("could not load audio policy configuration file, setting defaults");
        config.setDefault();
    }

可以看到首先是定义了 PolicySerializer 对象,
.xml 通过 PolicySerializer 类实现解析,解析入口函数为 deserialize
PolicySerializer对象 定义于 \frameworks\av\services\audiopolicy\common\managerdefinitions\include\Serializer.h
实现位于\frameworks\av\services\audiopolicy\common\managerdefinitions\src\Serializer.cpp
PolicySerializer 构造函数如下:

PolicySerializer::PolicySerializer() : mRootElementName(rootName)
{
    std::ostringstream oss;
    oss << gMajor << "." << gMinor;
    mVersion = oss.str();
    ALOGV("%s: Version=%s Root=%s", __FUNCTION__, mVersion.c_str(), mRootElementName.c_str());
}

可以看到构造函数初始化 变量 mRootElementName = rootName
mVersion =oss.str()= oss << gMajor << "." << gMinor;
rootName、gMajor 、gMinor 定义如下:

const char *const PolicySerializer::rootName = "audioPolicyConfiguration";
const uint32_t PolicySerializer::gMajor = 1;
const uint32_t PolicySerializer::gMinor = 0;

audioPolicyConfiguration 我们可以知道是 .xml的根节点元素字段名,因此 mRootElementName 会用来后面判断.xml的根节点元素字段名是否正确,如果不正确,则解析失败。
mVersion =1.0、mRootElementName=“audioPolicyConfiguration”

Serializer.h 源码如下

/*
 * Copyright (C) 2015 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.
 */
 
#pragma once
 
#include "AudioPolicyConfig.h"
#include <utils/StrongPointer.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <string>
#include <sstream>
#include <fstream>
 
struct _xmlNode;
struct _xmlDoc;
 
namespace android {
 
struct AudioGainTraits
{
    static const char *const tag;
    static const char *const collectionTag;
 
    struct Attributes
    {
        static const char mode[]; /**< gain modes supported, e.g. AUDIO_GAIN_MODE_CHANNELS. */
        /** controlled channels, needed if mode AUDIO_GAIN_MODE_CHANNELS. */
        static const char channelMask[];
        static const char minValueMB[]; /**< min value in millibel. */
        static const char maxValueMB[]; /**< max value in millibel. */
        static const char defaultValueMB[]; /**< default value in millibel. */
        static const char stepValueMB[]; /**< step value in millibel. */
        static const char minRampMs[]; /**< needed if mode AUDIO_GAIN_MODE_RAMP. */
        static const char maxRampMs[]; /**< .needed if mode AUDIO_GAIN_MODE_RAMP */
    };
 
    typedef AudioGain Element;
    typedef sp<Element> PtrElement;
    typedef AudioGainCollection Collection;
    typedef void *PtrSerializingCtx;
 
    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
                                PtrSerializingCtx serializingContext);
 
    // Gain has no child
};
 
// A profile section contains a name,  one audio format and the list of supported sampling rates
// and channel masks for this format
struct AudioProfileTraits
{·
    static const char *const tag;
    static const char *const collectionTag;
 
    struct Attributes
    {
        static const char name[];
        static const char samplingRates[];
        static const char format[];
        static const char channelMasks[];
    };
 
    typedef AudioProfile Element;
    typedef sp<AudioProfile> PtrElement;
    typedef AudioProfileVector Collection;
    typedef void *PtrSerializingCtx;
 
    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
                                PtrSerializingCtx serializingContext);
};
 
struct MixPortTraits
{
    static const char *const tag;
    static const char *const collectionTag;
 
    struct Attributes
    {
        static const char name[];
        static const char role[];
        static const char flags[];
    };
 
    typedef IOProfile Element;
    typedef sp<Element> PtrElement;
    typedef IOProfileCollection Collection;
    typedef void *PtrSerializingCtx;
 
    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
                                PtrSerializingCtx serializingContext);
 
    // Children are: GainTraits
};
 
struct DevicePortTraits
{
    static const char *const tag;
    static const char *const collectionTag;
 
    struct Attributes
    {
        static const char tagName[]; /**<  <device tag name>: any string without space. */
        static const char type[]; /**< <device type>. */
        static const char role[]; /**< <device role: sink or source>. */
        static const char roleSource[]; /**< <attribute role source value>. */
        static const char address[]; /**< optional: device address, char string less than 64. */
    };
    typedef DeviceDescriptor Element;
    typedef sp<DeviceDescriptor> PtrElement;
    typedef DeviceVector Collection;
    typedef void *PtrSerializingCtx;
 
    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
                                PtrSerializingCtx serializingContext);
    // Children are: GainTraits (optionnal)
};
 
struct RouteTraits
{
    static const char *const tag;
    static const char *const collectionTag;
 
    struct Attributes
    {
        static const char type[]; /**< <route type>: mix or mux. */
        static const char typeMix[]; /**< type attribute mix value. */
        static const char sink[]; /**< <sink: involved in this route>. */
        static const char sources[]; /**< sources: all source that can be involved in this route. */
    };
    typedef AudioRoute Element;
    typedef sp<AudioRoute> PtrElement;
    typedef AudioRouteVector Collection;
    typedef HwModule *PtrSerializingCtx;
 
    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
                                PtrSerializingCtx ctx);
};
 
struct ModuleTraits
{
    static const char *const tag;
    static const char *const collectionTag;
 
    static const char *const childAttachedDevicesTag;
    static const char *const childAttachedDeviceTag;
    static const char *const childDefaultOutputDeviceTag;
 
    struct Attributes
    {
        static const char name[];
        static const char version[];
    };
 
    typedef HwModule Element;
    typedef sp<Element> PtrElement;
    typedef HwModuleCollection Collection;
    typedef AudioPolicyConfig *PtrSerializingCtx;
 
    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
                                PtrSerializingCtx serializingContext);
 
    // Children are: mixPortTraits, devicePortTraits and routeTraits
    // Need to call deserialize on each child
};
 
struct GlobalConfigTraits
{
    static const char *const tag;
 
    struct Attributes
    {
        static const char speakerDrcEnabled[];
    };
 
    static status_t deserialize(const _xmlNode *root, AudioPolicyConfig &config);
};
 
struct VolumeTraits
{
    static const char *const tag;
    static const char *const collectionTag;
    static const char *const volumePointTag;
 
    struct Attributes
    {
        static const char stream[];
        static const char deviceCategory[];
        static const char reference[];
    };
 
    typedef VolumeCurve Element;
    typedef sp<VolumeCurve> PtrElement;
    typedef VolumeCurvesCollection Collection;
    typedef void *PtrSerializingCtx;
 
    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
                                PtrSerializingCtx serializingContext);
 
    // No Child
};
 
class PolicySerializer
{
private:
    static const char *const rootName;
 
    static const char *const versionAttribute;
    static const uint32_t gMajor; /**< the major number of the policy xml format version. */
    static const uint32_t gMinor; /**< the minor number of the policy xml format version. */
 
public:
    PolicySerializer();
    status_t deserialize(const char *str, AudioPolicyConfig &config);
 
private:
    typedef AudioPolicyConfig Element;
 
    std::string mRootElementName;
    std::string mVersion;
 
    // Children are: ModulesTraits, VolumeTraits
};
 
}

定义了 我们待会解析数据时的对象,
其中有 struct AudioGainTraits、struct AudioProfileTraits、struct MixPortTraits、struct DevicePortTraits、struct RouteTraits、struct ModuleTraits、struct GlobalConfigTraits、struct VolumeTraits 和解析入口类 class PolicySerializer
和 声明了解析 xml 的对象 struct _xmlNode、struct _xmlDoc

紧接着我们继续看到 入口函数

status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig &config)
{
    xmlDocPtr doc;
    doc = xmlParseFile(configFile);//将文件内容转换为xml文档
    if (doc == NULL) {
        ALOGE("%s: Could not parse %s document.", __FUNCTION__, configFile);
        return BAD_VALUE;
    }
/**
     audioPolicyConfiguration{
        ......
     }
*/
xmlNodePtr cur = xmlDocGetRootElement(doc);//得到xml的根节点元素
if (cur == NULL) {
    ALOGE("%s: Could not parse %s document: empty.", __FUNCTION__, configFile);
    xmlFreeDoc(doc);
    return BAD_VALUE;
}
if (xmlXIncludeProcess(doc) &lt; 0) {
     ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __FUNCTION__, configFile);
}

//mRootElementName="audioPolicyConfiguration"
if (xmlStrcmp(cur-&gt;name, (const xmlChar *) mRootElementName.c_str()))  {
    ALOGE("%s: No %s root element found in xml data %s.", __FUNCTION__, mRootElementName.c_str(),
          (const char *)cur-&gt;name);
    xmlFreeDoc(doc);
    return BAD_VALUE;
}

//versionAttribute = “version”;
string version = getXmlAttribute(cur, versionAttribute);
if (version.empty()) {
ALOGE("%s: No version found in root node %s", FUNCTION, mRootElementName.c_str());
return BAD_VALUE;
}

//mVersion = 1.0
if (version != mVersion) {
    ALOGE("%s: Version does not match; expect %s got %s", __FUNCTION__, mVersion.c_str(),
          version.c_str());
    return BAD_VALUE;
}

// Lets deserialize children
// Modules
ModuleTraits::Collection modules;
deserializeCollection&lt;ModuleTraits&gt;(doc, cur, modules, &amp;config);
config.setHwModules(modules);

// deserialize volume section
VolumeTraits::Collection volumes;
deserializeCollection&lt;VolumeTraits&gt;(doc, cur, volumes, &amp;config);
config.setVolumes(volumes);

// Global Configuration
GlobalConfigTraits::deserialize(cur, config);

xmlFreeDoc(doc);
return android::OK;

}

deserialize 函数有两个参数

const char *configFile //文件路径
#define AUDIO_POLICY_XML_CONFIG_FILE "/system/etc/audio_policy_configuration.xml"

AudioPolicyConfig &config //用于封装的整个.xml数据结构的对象。

参数类型跟我们解析.conf是一样的,

AudioPolicyConfig.h 源码位于: \frameworks\av\services\audiopolicy\common\managerdefinitions\include
源码如下:

/*
 * Copyright (C) 2009 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.
 */
 
#pragma once
 
#include <AudioGain.h>
#include <VolumeCurve.h>
#include <AudioPort.h>
#include <AudioPatch.h>
#include <DeviceDescriptor.h>
#include <IOProfile.h>
#include <HwModule.h>
#include <AudioInputDescriptor.h>
#include <AudioOutputDescriptor.h>
#include <AudioPolicyMix.h>
#include <EffectDescriptor.h>
#include <SoundTriggerSession.h>
#include <SessionRoute.h>
 
namespace android {
 
class AudioPolicyConfig
{
public:
    AudioPolicyConfig(HwModuleCollection &hwModules,
                      DeviceVector &availableOutputDevices,
                      DeviceVector &availableInputDevices,
                      sp<DeviceDescriptor> &defaultOutputDevices,
                      bool &isSpeakerDrcEnabled,
                      VolumeCurvesCollection *volumes = nullptr)
        : mHwModules(hwModules),
          mAvailableOutputDevices(availableOutputDevices),
          mAvailableInputDevices(availableInputDevices),
          mDefaultOutputDevices(defaultOutputDevices),
          mVolumeCurves(volumes),
          mIsSpeakerDrcEnabled(isSpeakerDrcEnabled)
    {}
 
    void setVolumes(const VolumeCurvesCollection &volumes)
    {
        if (mVolumeCurves != nullptr) {
            *mVolumeCurves = volumes;
        }
    }
 
    void setHwModules(const HwModuleCollection &hwModules)
    {
        mHwModules = hwModules;
    }
 
    void addAvailableDevice(const sp<DeviceDescriptor> &availableDevice)
    {
        if (audio_is_output_device(availableDevice->type())) {
            mAvailableOutputDevices.add(availableDevice);
        } else if (audio_is_input_device(availableDevice->type())) {
            mAvailableInputDevices.add(availableDevice);
        }
    }
 
    void addAvailableInputDevices(const DeviceVector &availableInputDevices)
    {
        mAvailableInputDevices.add(availableInputDevices);
    }
 
    void addAvailableOutputDevices(const DeviceVector &availableOutputDevices)
    {
        mAvailableOutputDevices.add(availableOutputDevices);
    }
 
    void setSpeakerDrcEnabled(bool isSpeakerDrcEnabled)
    {
        mIsSpeakerDrcEnabled = isSpeakerDrcEnabled;
    }
 
    const HwModuleCollection getHwModules() const { return mHwModules; }
 
    const DeviceVector &getAvailableInputDevices() const
    {
        return mAvailableInputDevices;
    }
 
    const DeviceVector &getAvailableOutputDevices() const
    {
        return mAvailableOutputDevices;
    }
 
    void setDefaultOutputDevice(const sp<DeviceDescriptor> &defaultDevice)
    {
        mDefaultOutputDevices = defaultDevice;
    }
 
    const sp<DeviceDescriptor> &getDefaultOutputDevice() const { return mDefaultOutputDevices; }
 
    void setDefault(void)
    {
        mDefaultOutputDevices = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
        sp<HwModule> module;
        sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
        mAvailableOutputDevices.add(mDefaultOutputDevices);
        mAvailableInputDevices.add(defaultInputDevice);
 
        module = new HwModule("primary");
 
        sp<OutputProfile> outProfile;
        outProfile = new OutputProfile(String8("primary"));
        outProfile->attach(module);
        outProfile->addAudioProfile(
                new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
        outProfile->addSupportedDevice(mDefaultOutputDevices);
        outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
        module->mOutputProfiles.add(outProfile);
 
        sp<InputProfile> inProfile;
        inProfile = new InputProfile(String8("primary"));
        inProfile->attach(module);
        inProfile->addAudioProfile(
                new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000));
        inProfile->addSupportedDevice(defaultInputDevice);
        module->mInputProfiles.add(inProfile);
 
        mHwModules.add(module);
    }
 
private:
    HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
    DeviceVector &mAvailableOutputDevices;
    DeviceVector &mAvailableInputDevices;
    sp<DeviceDescriptor> &mDefaultOutputDevices;
    VolumeCurvesCollection *mVolumeCurves;
    bool &mIsSpeakerDrcEnabled;
};
 
}; // namespace android

之前解析audio_policy.conf中我们已经知道通过AudioPolicyConfig类来装载整个音频策略文件数据,这里也是一样,通过AudioPolicyConfig 来封装audio_policy_configuration.xml所包含的策略数据,包含如下属性变量

HwModuleCollection &mHwModules;
/**< Collection of Module, with
    Profiles, i.e. Mix Ports.*/
.xml中所有module模块的集合
DeviceVector &mAvailableOutputDevices; .xml中所有output devices模块的集合
DeviceVector &mAvailableInputDevices; .xml中所有input devices模块的集合
sp<DeviceDescriptor> &mDefaultOutputDevices; .xml中默认output device
VolumeCurvesCollection *mVolumeCurves; .xml中音量集合

接着通过
1、通过 xmlParseFile 函数将整个 .xml解析后转换成 数据类型为 xmlDocPtr doc;
2、通过 xmlDocGetRootElement 函数获取到 根节点所有的元素,以数据类型为 xmlNodePtr cur 接收,也就是 audioPolicyConfiguration 开始包含的所有的元素
3、通过 if (xmlStrcmp(cur->name, (const xmlChar *) mRootElementName.c_str())) {},判断上面获取所有元素cur->name是否是以mRootElementName 作为根元素名字,通过前面解析PolicySerializer 构造函数我们知道mRootElementName=“audioPolicyConfiguration”,如果cur->name!=audioPolicyConfiguratio的话,则return BAD_VALUE,否则继续解析
4、接着通过函数 string version = getXmlAttribute(cur, versionAttribute); 获取 versionAttribute 版本号,

const char *const PolicySerializer::versionAttribute = "version";
 
string getXmlAttribute(const xmlNode *cur, const char *attribute)
{
    xmlChar *xmlValue = xmlGetProp(cur, (const xmlChar*)attribute);
    if (xmlValue == NULL) {
        return "";
    }
    string value((const char*)xmlValue);
    xmlFree(xmlValue);
    return value;
}

如果version.empty()return BAD_VALUE
如果version != mVersionreturn BAD_VALUE,前面在PolicySerializer 构造函数我们已经初始化
mVersion =1.0、mRootElementName=“audioPolicyConfiguration”
否则继续解析
5、进过一些列校验进入了正式解析,通过函数

ModuleTraits::Collection modules;
deserializeCollection<ModuleTraits>(doc, cur, modules, &config);
config.setHwModules(modules);  

前面我们在介绍 Serializer.h 已经说明了它声明了一些列 ****Traits ,用来解析过程中作为数据类型封装数据,待会我们解析时一个一个再来看他们的实现,首先我们这里用到了ModuleTraits,在Serializer.cpp中找到它的实现,源码如下:

const char *const ModuleTraits::childAttachedDevicesTag = "attachedDevices";
const char *const ModuleTraits::childAttachedDeviceTag = "item";
const char *const ModuleTraits::childDefaultOutputDeviceTag = "defaultOutputDevice";
 
const char *const ModuleTraits::tag = "module";
const char *const ModuleTraits::collectionTag = "modules";
 
const char ModuleTraits::Attributes::name[] = "name";
const char ModuleTraits::Attributes::version[] = "halVersion";
 
 
/**
root = moudle {} /moudle
module = HwModule
ctx = AudioPolicyConfig*
*/
status_t ModuleTraits::deserialize(xmlDocPtr doc, const xmlNode *root, PtrElement &module,
                                   PtrSerializingCtx ctx)
{
 
    /**
            1. name= primary  Attributes::name = "name"
	*/
    string name = getXmlAttribute(root, Attributes::name);
    if (name.empty()) {
        ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
        return BAD_VALUE;
    }
    uint32_t version = AUDIO_DEVICE_API_VERSION_MIN;//AUDIO_DEVICE_API_VERSION_2_0
    /**
        1. versionLiteral = 3.0 Attributes::version = "halVersion"
	*/
    string versionLiteral = getXmlAttribute(root, Attributes::version);//3
    if (!versionLiteral.empty()) {
        uint32_t major, minor;
 
		/**
                 1.  major = 3  minor = 0
		 */
        sscanf(versionLiteral.c_str(), "%u.%u", &major, &minor);
        version = HARDWARE_DEVICE_API_VERSION(major, minor);
        ALOGV("%s: mHalVersion = %04x major %u minor %u",  __FUNCTION__,
              version, major, minor);
    }
 
    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());
 
      /**
          1. Element = HwModule
	  */
    module = new Element(name.c_str(), version);
 
    // Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
    MixPortTraits::Collection mixPorts;
    deserializeCollection<MixPortTraits>(doc, root, mixPorts, NULL);
    module->setProfiles(mixPorts);
 
    DevicePortTraits::Collection devicePorts;
    deserializeCollection<DevicePortTraits>(doc, root, devicePorts, NULL);
    module->setDeclaredDevices(devicePorts);
 
    RouteTraits::Collection routes;
    deserializeCollection<RouteTraits>(doc, root, routes, module.get());
    module->setRoutes(routes);
 
    const xmlNode *children = root->xmlChildrenNode;
    while (children != NULL) {
        if (!xmlStrcmp(children->name, (const xmlChar *)childAttachedDevicesTag)) {
            ALOGV("%s: %s %s found", __FUNCTION__, tag, childAttachedDevicesTag);
            const xmlNode *child = children->xmlChildrenNode;
            while (child != NULL) {
                if (!xmlStrcmp(child->name, (const xmlChar *)childAttachedDeviceTag)) {
                    xmlChar *attachedDevice = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
                    if (attachedDevice != NULL) {
                        ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childAttachedDeviceTag,
                              (const char*)attachedDevice);
                        sp<DeviceDescriptor> device =
                                module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice));
                        ctx->addAvailableDevice(device);
                        xmlFree(attachedDevice);
                    }
                }
                child = child->next;
            }
        }
        if (!xmlStrcmp(children->name, (const xmlChar *)childDefaultOutputDeviceTag)) {
            xmlChar *defaultOutputDevice = xmlNodeListGetString(doc, children->xmlChildrenNode, 1);;
            if (defaultOutputDevice != NULL) {
                ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childDefaultOutputDeviceTag,
                      (const char*)defaultOutputDevice);
                sp<DeviceDescriptor> device =
                        module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)defaultOutputDevice));
                if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
                    ctx->setDefaultOutputDevice(device);
                    ALOGV("%s: default is %08x", __FUNCTION__, ctx->getDefaultOutputDevice()->type());
                }
                xmlFree(defaultOutputDevice);
            }
        }
        children = children->next;
    }
    return NO_ERROR;
}

可以看到初始化了其内部所携带的属性,和实现了 deserialize 函数

我们接着继续看到 deserializeCollection<ModuleTraits>(doc, cur, modules, &config); 函数,源码如下:

/**
       1. Collection = HwModuleCollection PtrSerializingCtx = AudioPolicyConfig*
           cur = audioPolicyConfiguration {} /audioPolicyConfiguration
       2. Collection = IOProfileCollection PtrSerializingCtx = void *
           cur = moudle {} /moudle
       3. Collection = AudioProfileVector PtrSerializingCtx = void *
           cur = mixPort {} /mixPort
       4. Collection = AudioGainCollection PtrSerializingCtx = void *
           cur = mixPort {} /mixPort
       5. Collection = DeviceVector PtrSerializingCtx = void *
           cur = moudle {} /moudle
       6. Collection = AudioProfileVector PtrSerializingCtx = void *
           cur = devicePort {} /devicePort
       7. Collection = AudioGainCollection PtrSerializingCtx = void *
           cur = devicePort {} /devicePort
 
*/
template <class Trait>
static status_t deserializeCollection(_xmlDoc *doc, const _xmlNode *cur,
                                      typename Trait::Collection &collection,
                                      typename Trait::PtrSerializingCtx serializingContext)
{
/**
1. Trait == ModuleTraits
2. Trait == MixPortTraits
3. Trait == AudioProfileTraits
4. Trait == AudioGainTraits
5. Trait == DevicePortTraits
6. Trait == AudioProfileTraits
7. Trait == AudioGainTraits
*/
 
    /**
         1.cur->xmlChildrenNode == globalConfiguration {} /globalConfiguration
         2.cur->xmlChildrenNode == attachedDevices {} /attachedDevices
         3.cur->xmlChildrenNode == profile {} /profile
         4.cur->xmlChildrenNode == profile {} /profile
         5.cur->xmlChildrenNode == attachedDevices {} /attachedDevices
         6.cur->xmlChildrenNode == profile {} /profile
    */
 
    const xmlNode *root = cur->xmlChildrenNode;
    while (root != NULL) {
 
	 /**
           1. collectionTag = modules   tag = moudle
           2. collectionTag = mixPorts   tag = mixPort
           3. collectionTag = profiles  tag = profile
           4. collectionTag = gains tag = gain
           5. collectionTag = devicePorts tag = devicePort
           6. collectionTag = profiles  tag = profile
	*/
        if (xmlStrcmp(root->name, (const xmlChar *)Trait::collectionTag) &&
                xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
            /**
                 1.root->next = moudles {} /moudles
                 2.root->next = defaultOutputDevice {} /defaultOutputDevice
                 3.root->next = mixPorts {} /mixPorts
                 4.root->next = profile {} /profile
                 5.root->next = defaultOutputDevice {} /defaultOutputDevice
                 6.root->next = mixPorts {} /mixPorts
                 7.root->next = devicePorts {} /devicePorts
	      */
	 			
            root = root->next;
            continue;
        }
        const xmlNode *child = root;
 
	/**
           1. collectionTag = modules  child->name = modules
           2. collectionTag = mixPorts  child->name = mixPorts
           3. collectionTag = devicePorts  child->name = devicePorts
	*/
        if (!xmlStrcmp(child->name, (const xmlChar *)Trait::collectionTag)) {
 
	     /**
               1. child->xmlChildrenNode = moudle {} /moudle
               2. child->xmlChildrenNode = mixPort {} /mixPort
               3. child->xmlChildrenNode = devicePort {} /devicePort
		 */
            child = child->xmlChildrenNode;
        }
        while (child != NULL) {
		/**
                  1. tag = moudle
                  2. tag = mixPort
                  3. tag = profile
                  4. tag = devicePort
                  5. tag = profile
		*/
            if (!xmlStrcmp(child->name, (const xmlChar *)Trait::tag)) {
                /**
                     1. PtrElement = HwModule
                     2. PtrElement = IOProfile
                     3. PtrElement = sp<AudioProfile>
                     4. PtrElement = sp<DeviceDescriptor>
                     5. PtrElement = sp<AudioProfile>
		   */
                typename Trait::PtrElement element;
                status_t status = Trait::deserialize(doc, child, element, serializingContext);
                if (status != NO_ERROR) {
                    return status;
                }
 
		/**
                 1. element = sp<AudioProfile>
                 2. element = IOProfile
                 3. element = sp<AudioProfile>
		*/
                if (collection.add(element) < 0) {
                    ALOGE("%s: could not add element to %s collection", __FUNCTION__,
                          Trait::collectionTag);
                }
            }
            child = child->next;
        }
        if (!xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
            return NO_ERROR;
        }
        root = root->next;
    }
    return NO_ERROR;
}

首先可以看到 deserializeCollection 函数通过模板类定义的 Trait,因此以后每次解析 ***Trait 都会是通过这个函数去解析,

这个函数中
1、 const xmlNode *root = cur->xmlChildrenNode; 获取到cur的子节点 root ,对应.xml中的
root= <globalConfiguration {} /globalConfiguration>
2、通过root!=NULL建立一个while循环,遍历root 中所有child node
3、然后root->name跟当前的模板类 template <class Trait>collectionTagtag值比较,也就是目前传入的ModuleTraits定义的

const char *const ModuleTraits::tag = "module";
const char *const ModuleTraits::collectionTag = "modules";
 /**
           1. collectionTag = modules   tag = moudle
           2. collectionTag = mixPorts   tag = mixPort
           3. collectionTag = profiles  tag = profile
           4. collectionTag = gains tag = gain
           5. collectionTag = devicePorts tag = devicePort
           6. collectionTag = profiles  tag = profile
	*/
        if (xmlStrcmp(root->name, (const xmlChar *)Trait::collectionTag) &&
                xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
            /**
                 1.root->next = moudles {} /moudles
                 2.root->next = defaultOutputDevice {} /defaultOutputDevice
                 3.root->next = mixPorts {} /mixPorts
                 4.root->next = profile {} /profile
                 5.root->next = defaultOutputDevice {} /defaultOutputDevice
                 6.root->next = mixPorts {} /mixPorts
                 7.root->next = devicePorts {} /devicePorts
	      */
 		
            root = root->next;
            continue;
        }
           const xmlNode *child = root;

如果 root->name 跟两者都不同相等,则进入该判断 root = root->next;
直到 root->nextroot->nameTrait 中的collectionTag 或者tag相等,此时如果我们这里的ModuleTraits与我们解析的collectionTag 相等,所以解析到对应.xml 获取到 child=root->next = moudles {} /moudles 就结束这个判断
4、接着又比较 child->namecollectionTag ,这个时候相等,则
child = child->xmlChildrenNode;

/**
           1. collectionTag = modules  child->name = modules
           2. collectionTag = mixPorts  child->name = mixPorts
           3. collectionTag = devicePorts  child->name = devicePorts
	*/
        if (!xmlStrcmp(child->name, (const xmlChar *)Trait::collectionTag)) {
 
	     /**
               1. child->xmlChildrenNode = moudle {} /moudle
               2. child->xmlChildrenNode = mixPort {} /mixPort
               3. child->xmlChildrenNode = devicePort {} /devicePort
		 */
            child = child->xmlChildrenNode;
        }

因为这个时候 collectionTag = moudles = child->name,所以 这个时候又获取到其子节点进行解析,child = child->xmlChildrenNode = moudle {} /moudle
5、接着又 通过child != NULL建立一个while循环,进行解析 moudle {} /moudle其内部所有子节点
6、接着 child->nametag 比较,跟模板类的 Trait tag值比较,此时相等,则进入模板类的Traitdeserialize进行解析其子模块,
7、循环遍历 child 中所有的 child = child->next;child->nametag相等的模块,并且添加到 模板类的TraitCollection

现在我们总结下这个函数:

1. 首先循环遍历传入的 const _xmlNode * cur中找到 cur->name 与 传入的 模板类TraitcollectionTag 相同的模块,
2. 如果找到则循环遍历 child = cur->xmlChildrenNode; 中找到所有 child ->name 与 传入的
模板类Traittag 相同的模块
3. 如果找到,则将 child 通过 传入的 模板类Traitdeserialize 继续进行明确解析,将解析的数据存入
模板类TraitPtrElement
5. 将所有 找到的 child 添加到 模板类Trait 的集合 Collection

通过上面的分析,我们可以知道 ModuleTraits 用来解析 <module {} /moldule>模块,那现在我们接下看到解析ModuleTraitsdeserialize怎么解析 <module {} /moldule>模块,在回顾到 ModuleTraitsdeserialize源码

/**
root = moudle {} /moudle
module = HwModule
ctx = AudioPolicyConfig*
 
*/
status_t ModuleTraits::deserialize(xmlDocPtr doc, const xmlNode *root, PtrElement &module,
                                   PtrSerializingCtx ctx)
{
 
    /**
            1. name= primary  Attributes::name = "name"
	*/
    string name = getXmlAttribute(root, Attributes::name);
    if (name.empty()) {
        ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
        return BAD_VALUE;
    }
    uint32_t version = AUDIO_DEVICE_API_VERSION_MIN;//AUDIO_DEVICE_API_VERSION_2_0
    /**
        1. versionLiteral = 3.0 Attributes::version = "halVersion"
	*/
    string versionLiteral = getXmlAttribute(root, Attributes::version);//3
    if (!versionLiteral.empty()) {
        uint32_t major, minor;
		/**
                 1.  major = 3  minor = 0
		 */
        sscanf(versionLiteral.c_str(), "%u.%u", &major, &minor);
        version = HARDWARE_DEVICE_API_VERSION(major, minor);
        ALOGV("%s: mHalVersion = %04x major %u minor %u",  __FUNCTION__,
              version, major, minor);
    }
 
    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());
 
      /**
          1. Element = HwModule
	  */
    module = new Element(name.c_str(), version);
 
    // Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
    MixPortTraits::Collection mixPorts;
    deserializeCollection<MixPortTraits>(doc, root, mixPorts, NULL);
    module->setProfiles(mixPorts);
 
    DevicePortTraits::Collection devicePorts;
    deserializeCollection<DevicePortTraits>(doc, root, devicePorts, NULL);
    module->setDeclaredDevices(devicePorts);
 
    RouteTraits::Collection routes;
    deserializeCollection<RouteTraits>(doc, root, routes, module.get());
    module->setRoutes(routes);
 
    const xmlNode *children = root->xmlChildrenNode;
    while (children != NULL) {
        if (!xmlStrcmp(children->name, (const xmlChar *)childAttachedDevicesTag)) {
            ALOGV("%s: %s %s found", __FUNCTION__, tag, childAttachedDevicesTag);
            const xmlNode *child = children->xmlChildrenNode;
            while (child != NULL) {
                if (!xmlStrcmp(child->name, (const xmlChar *)childAttachedDeviceTag)) {
                    xmlChar *attachedDevice = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
                    if (attachedDevice != NULL) {
                        ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childAttachedDeviceTag,
                              (const char*)attachedDevice);
                        sp<DeviceDescriptor> device =
                                module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice));
                        ctx->addAvailableDevice(device);
                        xmlFree(attachedDevice);
                    }
                }
                child = child->next;
            }
        }
        if (!xmlStrcmp(children->name, (const xmlChar *)childDefaultOutputDeviceTag)) {
            xmlChar *defaultOutputDevice = xmlNodeListGetString(doc, children->xmlChildrenNode, 1);;
            if (defaultOutputDevice != NULL) {
                ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childDefaultOutputDeviceTag,
                      (const char*)defaultOutputDevice);
                sp<DeviceDescriptor> device =
                        module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)defaultOutputDevice));
                if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
                    ctx->setDefaultOutputDevice(device);
                    ALOGV("%s: default is %08x", __FUNCTION__, ctx->getDefaultOutputDevice()->type());
                }
                xmlFree(defaultOutputDevice);
            }
        }
        children = children->next;
    }
    return NO_ERROR;
}

1、首先判断了 <module>{}</module> 中的nameversion字段,有效的话继续解析,判断这里比较简单,就不仔细说了。
2、然后创建了 module 对象,用来封装每一个 <module>{}</module> 的数据,构造函数传入步骤1 的nameversion ,module 类型为 HwModule, 声明位于:
\frameworks\av\services\audiopolicy\common\managerdefinitions\include\HwModule.h
源码如下:

/*
 * Copyright (C) 2015 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.
 */
 
#pragma once
 
#include "DeviceDescriptor.h"
#include "AudioRoute.h"
#include <hardware/audio.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <utils/Errors.h>
#include <utils/Vector.h>
#include <system/audio.h>
#include <cutils/config_utils.h>
#include <string>
 
namespace android {
 
class IOProfile;
class InputProfile;
class OutputProfile;
 
typedef Vector<sp<IOProfile> > InputProfileCollection;
typedef Vector<sp<IOProfile> > OutputProfileCollection;
typedef Vector<sp<IOProfile> > IOProfileCollection;
 
class HwModule : public RefBase
{
public:
    HwModule(const char *name, uint32_t halVersion = AUDIO_DEVICE_API_VERSION_MIN);
    ~HwModule();
 
    const char *getName() const { return mName.string(); }
 
 
    const DeviceVector &getDeclaredDevices() const { return mDeclaredDevices; }
    void setDeclaredDevices(const DeviceVector &devices);
 
    const InputProfileCollection &getInputProfiles() const { return mInputProfiles; }
 
    const OutputProfileCollection &getOutputProfiles() const { return mOutputProfiles; }
 
    void setProfiles(const IOProfileCollection &profiles);
 
    void setHalVersion(uint32_t halVersion) { mHalVersion = halVersion; }
    uint32_t getHalVersion() const { return mHalVersion; }
 
    sp<DeviceDescriptor> getRouteSinkDevice(const sp<AudioRoute> &route) const;
    DeviceVector getRouteSourceDevices(const sp<AudioRoute> &route) const;
    void setRoutes(const AudioRouteVector &routes);
 
    status_t addOutputProfile(const sp<IOProfile> &profile);
    status_t addInputProfile(const sp<IOProfile> &profile);
    status_t addProfile(const sp<IOProfile> &profile);
 
    status_t addOutputProfile(String8 name, const audio_config_t *config,
            audio_devices_t device, String8 address);
    status_t removeOutputProfile(String8 name);
    status_t addInputProfile(String8 name, const audio_config_t *config,
            audio_devices_t device, String8 address);
    status_t removeInputProfile(String8 name);
 
    audio_module_handle_t getHandle() const { return mHandle; }
 
    sp<AudioPort> findPortByTagName(const String8 &tagName) const
    {
        return mPorts.findByTagName(tagName);
    }
 
    // TODO remove from here (split serialization)
    void dump(int fd);
 
    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
 
private:
    void refreshSupportedDevices();
 
    uint32_t mHalVersion; // audio HAL API version
    DeviceVector mDeclaredDevices; // devices declared in audio_policy configuration file.
    AudioRouteVector mRoutes;
    AudioPortVector mPorts;
};
 
class HwModuleCollection : public Vector<sp<HwModule> >
{
public:
    sp<HwModule> getModuleFromName(const char *name) const;
 
    sp<HwModule> getModuleForDevice(audio_devices_t device) const;
 
    sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t device,
                                             const char *device_address,
                                             const char *device_name,
                                             bool matchAdress = true) const;
 
    status_t dump(int fd) const;
};
 
}; // namespace android

现在我们知道 <module>{}</module> 通过HwModule对象去封装,
HwModule源码我们可以知道 <module>{}</module> 包含

OutputProfileCollection mOutputProfiles; // output profiles exposed by this module
InputProfileCollection mInputProfiles;  // input profiles exposed by this module
DeviceVector mDeclaredDevices; // devices declared in audio_policy configuration file.
AudioRouteVector mRoutes;

3、创建了HwModule 就可以开始解析 <module>{}</module> ,首先解析的是

  // Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
    MixPortTraits::Collection mixPorts;
    deserializeCollection<MixPortTraits>(doc, root, mixPorts, NULL);
    module->setProfiles(mixPorts);

也就是对应.xml
<module>
{
<mixPorts>
{
<mixPort>{}</mixPort>
}
</mixPorts>
}
</module>
,通过 MixPortTraits 去解析
MixPortTraits 实现源码如下:

const char *const MixPortTraits::collectionTag = "mixPorts";
const char *const MixPortTraits::tag = "mixPort";
 
const char MixPortTraits::Attributes::name[] = "name";
const char MixPortTraits::Attributes::role[] = "role";
const char MixPortTraits::Attributes::flags[] = "flags";
 
/**
child = mixPort {} /mixPort
mixPort = IOProfile
PtrSerializingCtx = void *
*/
status_t MixPortTraits::deserialize(_xmlDoc *doc, const _xmlNode *child, PtrElement &mixPort,
                                    PtrSerializingCtx /*serializingContext*/)
{
    /**
        Attributes::name = "name"; name = "primary output"
	*/
    string name = getXmlAttribute(child, Attributes::name);
    if (name.empty()) {
        ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
        return BAD_VALUE;
    }
    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());
 
	/**
          Attributes::role = "role"; role = "source"
	*/
    string role = getXmlAttribute(child, Attributes::role);
    if (role.empty()) {
        ALOGE("%s: No %s found", __FUNCTION__, Attributes::role);
        return BAD_VALUE;
    }
    ALOGV("%s: Role=%s", __FUNCTION__, role.c_str());
    audio_port_role_t portRole = role == "source" ? AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
 
    /**
        mixPort = IOProfile 
	*/
    mixPort = new Element(String8(name.c_str()), portRole);
 
    AudioProfileTraits::Collection profiles;
    deserializeCollection<AudioProfileTraits>(doc, child, profiles, NULL);
    if (profiles.isEmpty()) {
        sp <AudioProfile> dynamicProfile = new AudioProfile(gDynamicFormat,
                                                            ChannelsVector(), SampleRateVector());
        dynamicProfile->setDynamicFormat(true);
        dynamicProfile->setDynamicChannels(true);
        dynamicProfile->setDynamicRate(true);
        profiles.add(dynamicProfile);
    }
    mixPort->setAudioProfiles(profiles);
 
    /**
         Attributes::flags = "flags"; flags = "AUDIO_OUTPUT_FLAG_PRIMARY"      
	*/
    string flags = getXmlAttribute(child, Attributes::flags);
    if (!flags.empty()) {
        // Source role
        if (portRole == AUDIO_PORT_ROLE_SOURCE) {
            mixPort->setFlags(OutputFlagConverter::maskFromString(flags));
        } else {
            // Sink role
            mixPort->setFlags(InputFlagConverter::maskFromString(flags));
        }
    }
    // Deserialize children
    AudioGainTraits::Collection gains;
    deserializeCollection<AudioGainTraits>(doc, child, gains, NULL);
    mixPort->setGains(gains);
 
    return NO_ERROR;
}

3.1、MixPortTraits首先判断了namerole 的值,这里比较简单,就不细说怎么获取和判断了、
3.2、MixPortTraits 创建了 mixPort 对象,其对象类型为 IOProfile,将nameportRole传入构造函数
\frameworks\av\services\audiopolicy\common\managerdefinitions\include\IOProfile.h
IOProfile 继承自AudioPort,位于
\frameworks\av\services\audiopolicy\common\managerdefinitions\src\AudioPort.h
现在我们可以知道 .<mixPort>{}</mixPort> 通过 IOProfile 继承自AudioPort 去封装
3.3 mixPort 对象创建完之后,便可以开始解析 <mixPort>{}</mixPort>

AudioProfileTraits::Collection profiles;
    deserializeCollection<AudioProfileTraits>(doc, child, profiles, NULL);
    if (profiles.isEmpty()) {
        sp <AudioProfile> dynamicProfile = new AudioProfile(gDynamicFormat,
                                                            ChannelsVector(), SampleRateVector());
        dynamicProfile->setDynamicFormat(true);
        dynamicProfile->setDynamicChannels(true);
        dynamicProfile->setDynamicRate(true);
        profiles.add(dynamicProfile);
    }
    mixPort->setAudioProfiles(profiles);

也就是对应.xml
<module>
{
<mixPorts>
{
<mixPort>
{
<profile/>
}
</mixPort>
}
</mixPorts>
}
</module>
,通过 AudioProfileTraits 去解析AudioProfileTraits 实现源码如下:

const char *const AudioProfileTraits::collectionTag = "profiles";
const char *const AudioProfileTraits::tag = "profile";
 
const char AudioProfileTraits::Attributes::name[] = "name";
const char AudioProfileTraits::Attributes::samplingRates[] = "samplingRates";
const char AudioProfileTraits::Attributes::format[] = "format";
const char AudioProfileTraits::Attributes::channelMasks[] = "channelMasks";
 
/**
root = profile {} /profile
profile = sp<AudioProfile>
PtrSerializingCtx = void*
 
2.
root = profile {} /profile
profile = sp<AudioProfile>
PtrSerializingCtx = void*
*/
status_t AudioProfileTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &profile,
                                         PtrSerializingCtx /*serializingContext*/)
{
    /** 
        Attributes::samplingRates = "samplingRates"; samplingRates = "48000"
        Attributes::format = "format"; format = "AUDIO_FORMAT_PCM_16_BIT"
        Attributes::channelMasks = "channelMasks"; channels = "AUDIO_CHANNEL_OUT_STEREO"
 
        2.
         Attributes::samplingRates = "samplingRates"; samplingRates = "48000"
        Attributes::format = "format"; format = "AUDIO_FORMAT_PCM_16_BIT"
        Attributes::channelMasks = "channelMasks"; channels = "AUDIO_CHANNEL_IN_MONO"
	*/
    string samplingRates = getXmlAttribute(root, Attributes::samplingRates);
    string format = getXmlAttribute(root, Attributes::format);
    string channels = getXmlAttribute(root, Attributes::channelMasks);
 
    profile = new Element(formatFromString(format), channelMasksFromString(channels, ","),
                          samplingRatesFromString(samplingRates, ","));
 
    profile->setDynamicFormat(profile->getFormat() == gDynamicFormat);
    profile->setDynamicChannels(profile->getChannels().isEmpty());
    profile->setDynamicRate(profile->getSampleRates().isEmpty());
 
    return NO_ERROR;
}

通过AudioPort去封装<mixPort>{<profile/>}</mixPort>,又接着通过代码获取flag属性的值

/**
         Attributes::flags = "flags"; flags = "AUDIO_OUTPUT_FLAG_PRIMARY"
*/
string flags = getXmlAttribute(child, Attributes::flags);
if (!flags.empty()) {
    // Source role
    if (portRole == AUDIO_PORT_ROLE_SOURCE) {
        mixPort-&gt;setFlags(OutputFlagConverter::maskFromString(flags));
    } else {
        // Sink role
        mixPort-&gt;setFlags(InputFlagConverter::maskFromString(flags));
    }
}

最后通过AudioGainTraits解析<mixPort>{<gains/>}</mixPort>

// Deserialize children
    AudioGainTraits::Collection gains;
    deserializeCollection<AudioGainTraits>(doc, child, gains, NULL);
    mixPort->setGains(gains);

AudioGainTraits实现源码如下:

const char *const AudioGainTraits::tag = "gain";
const char *const AudioGainTraits::collectionTag = "gains";
 
const char AudioGainTraits::Attributes::mode[] = "mode";
const char AudioGainTraits::Attributes::channelMask[] = "channel_mask";
const char AudioGainTraits::Attributes::minValueMB[] = "minValueMB";
const char AudioGainTraits::Attributes::maxValueMB[] = "maxValueMB";
const char AudioGainTraits::Attributes::defaultValueMB[] = "defaultValueMB";
const char AudioGainTraits::Attributes::stepValueMB[] = "stepValueMB";
const char AudioGainTraits::Attributes::minRampMs[] = "minRampMs";
const char AudioGainTraits::Attributes::maxRampMs[] = "maxRampMs";
 
status_t AudioGainTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &gain,
                                      PtrSerializingCtx /*serializingContext*/)
{
    static uint32_t index = 0;
    gain = new Element(index++, true);
 
    string mode = getXmlAttribute(root, Attributes::mode);
    if (!mode.empty()) {
        gain->setMode(GainModeConverter::maskFromString(mode));
    }
 
    string channelsLiteral = getXmlAttribute(root, Attributes::channelMask);
    if (!channelsLiteral.empty()) {
        gain->setChannelMask(channelMaskFromString(channelsLiteral));
    }
 
    string minValueMBLiteral = getXmlAttribute(root, Attributes::minValueMB);
    uint32_t minValueMB;
    if (!minValueMBLiteral.empty() && convertTo(minValueMBLiteral, minValueMB)) {
        gain->setMinValueInMb(minValueMB);
    }
 
    string maxValueMBLiteral = getXmlAttribute(root, Attributes::maxValueMB);
    uint32_t maxValueMB;
    if (!maxValueMBLiteral.empty() && convertTo(maxValueMBLiteral, maxValueMB)) {
        gain->setMaxValueInMb(maxValueMB);
    }
 
    string defaultValueMBLiteral = getXmlAttribute(root, Attributes::defaultValueMB);
    uint32_t defaultValueMB;
    if (!defaultValueMBLiteral.empty() && convertTo(defaultValueMBLiteral, defaultValueMB)) {
        gain->setDefaultValueInMb(defaultValueMB);
    }
 
    string stepValueMBLiteral = getXmlAttribute(root, Attributes::stepValueMB);
    uint32_t stepValueMB;
    if (!stepValueMBLiteral.empty() && convertTo(stepValueMBLiteral, stepValueMB)) {
        gain->setStepValueInMb(stepValueMB);
    }
 
    string minRampMsLiteral = getXmlAttribute(root, Attributes::minRampMs);
    uint32_t minRampMs;
    if (!minRampMsLiteral.empty() && convertTo(minRampMsLiteral, minRampMs)) {
        gain->setMinRampInMs(minRampMs);
    }
 
    string maxRampMsLiteral = getXmlAttribute(root, Attributes::maxRampMs);
    uint32_t maxRampMs;
    if (!maxRampMsLiteral.empty() && convertTo(maxRampMsLiteral, maxRampMs)) {
        gain->setMaxRampInMs(maxRampMs);
    }
    ALOGV("%s: adding new gain mode %08x channel mask %08x min mB %d max mB %d", __FUNCTION__,
          gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
          gain->getMaxValueInMb());
 
    if (gain->getMode() == 0) {
        return BAD_VALUE;
    }
    return NO_ERROR;
}

通过 AudioGain去封装<mixPort>{<gains/>}</mixPort>
位于\frameworks\av\services\audiopolicy\common\managerdefinitions\include\AudioGain.h

到这里<mixPorts></mixPorts>就解析完了。

4、接着回到代码ModuleTraits

 DevicePortTraits::Collection devicePorts;
    deserializeCollection<DevicePortTraits>(doc, root, devicePorts, NULL);
    module->setDeclaredDevices(devicePorts);

开始解析
<module>
{
<devicePorts>
{}
</devicePorts>
}
</module>
,
通过DevicePortTraits去解析,实现源码如下:

const char *const DevicePortTraits::tag = "devicePort";
const char *const DevicePortTraits::collectionTag = "devicePorts";
 
const char DevicePortTraits::Attributes::tagName[] = "tagName";
const char DevicePortTraits::Attributes::type[] = "type";
const char DevicePortTraits::Attributes::role[] = "role";
const char DevicePortTraits::Attributes::address[] = "address";
const char DevicePortTraits::Attributes::roleSource[] = "source";
 
/**
root = devicePort {} /devicePort
deviceDesc = sp<DeviceDescriptor>
PtrSerializingCtx = void*
*/
status_t DevicePortTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &deviceDesc,
                                       PtrSerializingCtx /*serializingContext*/)
{
   /**
       Attributes::tagName = "tagName"; name = "Earpiece"
   */
 
    string name = getXmlAttribute(root, Attributes::tagName);
    if (name.empty()) {
        ALOGE("%s: No %s found", __FUNCTION__, Attributes::tagName);
        return BAD_VALUE;
    }
    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::tagName, name.c_str());
 
	/**
          Attributes::type =  "type" typeName = "AUDIO_DEVICE_OUT_EARPIECE"
	*/
    string typeName = getXmlAttribute(root, Attributes::type);
    if (typeName.empty()) {
        ALOGE("%s: no type for %s", __FUNCTION__, name.c_str());
        return BAD_VALUE;
    }
    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::type, typeName.c_str());
 
	/**
          Attributes::role = "role"; role = "sink"       
	*/
    string role = getXmlAttribute(root, Attributes::role);
    if (role.empty()) {
        ALOGE("%s: No %s found", __FUNCTION__, Attributes::role);
        return BAD_VALUE;
    }
    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::role, role.c_str());
    audio_port_role_t portRole = (role == Attributes::roleSource) ?
                AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
                 
    audio_devices_t type = AUDIO_DEVICE_NONE;
    if (!DeviceConverter::fromString(typeName, type) ||
            (!audio_is_input_device(type) && portRole == AUDIO_PORT_ROLE_SOURCE) ||
            (!audio_is_output_devices(type) && portRole == AUDIO_PORT_ROLE_SINK)) {
        ALOGW("%s: bad type %08x", __FUNCTION__, type);
        return BAD_VALUE;
    }
    deviceDesc = new Element(type, String8(name.c_str()));
 
      /**
          Attributes::address = "address"; address = ""
	  */
    string address = getXmlAttribute(root, Attributes::address);
    if (!address.empty()) {
        ALOGV("%s: address=%s for %s", __FUNCTION__, address.c_str(), name.c_str());
        deviceDesc->mAddress = String8(address.c_str());
    }
 
    AudioProfileTraits::Collection profiles;
    deserializeCollection<AudioProfileTraits>(doc, root, profiles, NULL);
    if (profiles.isEmpty()) {
        sp <AudioProfile> dynamicProfile = new AudioProfile(gDynamicFormat,
                                                            ChannelsVector(), SampleRateVector());
        dynamicProfile->setDynamicFormat(true);
        dynamicProfile->setDynamicChannels(true);
        dynamicProfile->setDynamicRate(true);
        profiles.add(dynamicProfile);
    }
    deviceDesc->setAudioProfiles(profiles);
 
    // Deserialize AudioGain children
    deserializeCollection<AudioGainTraits>(doc, root, deviceDesc->mGains, NULL);
    ALOGV("%s: adding device tag %s type %08x address %s", __FUNCTION__,
          deviceDesc->getName().string(), type, deviceDesc->mAddress.string());
    return NO_ERROR;
}

经过前面那么多的介绍,其实会发现每个Traits都是类似的,

  • 都是开始获取当前节点的一些属性值判断,
  • 创建一个特定的父对象,
  • 然后再去获取子节点,通过特定的子对象再封装起来,进行解析。

4.1、DevicePortTraits开始也是获取 tagNametyperole属性的值,
4.2、然后创建了一个deviceDesc对象,类型为 DeviceDescriptor 去封装<devicePort>
DeviceDescriptor 继承自AudioPort,声明位于:
\frameworks\av\services\audiopolicy\common\managerdefinitions\include\DeviceDescriptor.h
4.3、获取子节点解析,即
<module>
{
<devicePorts>
{
<profile>
}
</devicePorts>
}
</module>
,
这里也是跟前面mixPort子节点<profile> 一样通过 AudioProfileTraits去解析,这不在累赘
4.4、再获取子节点解析,即
<module>
{
<devicePorts>
{
<gains>
}
</devicePorts>
}
</module>
,
,这里也是跟前面mixPort子节点<gains> 一样通过 AudioGainTraits去解析,这不在累赘.

到这里<devicePorts></devicePorts>就解析完了。

5、接着回到代码ModuleTraits

RouteTraits::Collection routes;
    deserializeCollection<RouteTraits>(doc, root, routes, module.get());
    module->setRoutes(routes);

接着通过 RouteTraits 解析
<module>
{
<routes>
{</route>}
</routes>
}
</module>
, RouteTraits 实现源码如下:

const char *const RouteTraits::tag = "route";
const char *const RouteTraits::collectionTag = "routes";
 
const char RouteTraits::Attributes::type[] = "type";
const char RouteTraits::Attributes::typeMix[] = "mix";
const char RouteTraits::Attributes::sink[] = "sink";
const char RouteTraits::Attributes::sources[] = "sources";
 
 
status_t RouteTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &element,
                                  PtrSerializingCtx ctx)
{
    string type = getXmlAttribute(root, Attributes::type);
    if (type.empty()) {
        ALOGE("%s: No %s found", __FUNCTION__, Attributes::type);
        return BAD_VALUE;
    }
    audio_route_type_t routeType = (type == Attributes::typeMix) ?
                AUDIO_ROUTE_MIX : AUDIO_ROUTE_MUX;
 
    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::type, type.c_str());
    element = new Element(routeType);
 
    string sinkAttr = getXmlAttribute(root, Attributes::sink);
    if (sinkAttr.empty()) {
        ALOGE("%s: No %s found", __FUNCTION__, Attributes::sink);
        return BAD_VALUE;
    }
    // Convert Sink name to port pointer
    sp<AudioPort> sink = ctx->findPortByTagName(String8(sinkAttr.c_str()));
    if (sink == NULL) {
        ALOGE("%s: no sink found with name=%s", __FUNCTION__, sinkAttr.c_str());
        return BAD_VALUE;
    }
    element->setSink(sink);
 
    string sourcesAttr = getXmlAttribute(root, Attributes::sources);
    if (sourcesAttr.empty()) {
        ALOGE("%s: No %s found", __FUNCTION__, Attributes::sources);
        return BAD_VALUE;
    }
    // Tokenize and Convert Sources name to port pointer
    AudioPortVector sources;
    char *sourcesLiteral = strndup(sourcesAttr.c_str(), strlen(sourcesAttr.c_str()));
    char *devTag = strtok(sourcesLiteral, ",");
    while (devTag != NULL) {
        if (strlen(devTag) != 0) {
            sp<AudioPort> source = ctx->findPortByTagName(String8(devTag));
            if (source == NULL) {
                ALOGE("%s: no source found with name=%s", __FUNCTION__, devTag);
                return BAD_VALUE;
            }
            sources.add(source);
        }
        devTag = strtok(NULL, ",");
    }
    free(sourcesLiteral);
 
    sink->addRoute(element);
    for (size_t i = 0; i < sources.size(); i++) {
        sp<AudioPort> source = sources.itemAt(i);
        source->addRoute(element);
    }
    element->setSources(sources);
    return NO_ERROR;
}

5.1首先获取属性 type 的值,创建 element 对象,其类型为 AudioRoute,在获取属性 sinksources 的值, sources属性的值可以通过,分开有多个,</route> 对象通过 AudioRoute分装起来
AudioRoute 声明位于:
\frameworks\av\services\audiopolicy\common\managerdefinitions\include\AudioRoute .h
到这里<routes></routes>就解析完了。

6、接着回到代码ModuleTraits

const xmlNode *children = root->xmlChildrenNode;
    while (children != NULL) {
        if (!xmlStrcmp(children->name, (const xmlChar *)childAttachedDevicesTag)) {
            ALOGV("%s: %s %s found", __FUNCTION__, tag, childAttachedDevicesTag);
            const xmlNode *child = children->xmlChildrenNode;
            while (child != NULL) {
                if (!xmlStrcmp(child->name, (const xmlChar *)childAttachedDeviceTag)) {
                    xmlChar *attachedDevice = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
                    if (attachedDevice != NULL) {
                        ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childAttachedDeviceTag,
                              (const char*)attachedDevice);
                        sp<DeviceDescriptor> device =
                                module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice));
                        ctx->addAvailableDevice(device);
                        xmlFree(attachedDevice);
                    }
                }
                child = child->next;
            }
        }
        if (!xmlStrcmp(children->name, (const xmlChar *)childDefaultOutputDeviceTag)) {
            xmlChar *defaultOutputDevice = xmlNodeListGetString(doc, children->xmlChildrenNode, 1);;
            if (defaultOutputDevice != NULL) {
                ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childDefaultOutputDeviceTag,
                      (const char*)defaultOutputDevice);
                sp<DeviceDescriptor> device =
                        module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)defaultOutputDevice));
                if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
                    ctx->setDefaultOutputDevice(device);
                    ALOGV("%s: default is %08x", __FUNCTION__, ctx->getDefaultOutputDevice()->type());
                }
                xmlFree(defaultOutputDevice);
            }
        }
        children = children->next;
    }

6.1首先找到 名字为<childAttachedDevicesTag=attachedDevices>节点,如果找到再去解析字节点<childAttachedDeviceTag=item> 并获取其值,通过
module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice)); 找到其中对用的DeviceDescriptor
6.2找到 名字为<childDefaultOutputDeviceTag=defaultOutputDevice>节点,并获取其值,通过
module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice)); 找到其中对用的DeviceDescriptor
最后一个完整的</module> 就解析完成了

我们最后接着回到 PolicySerializer 类的解析入口函数

// deserialize volume section
    VolumeTraits::Collection volumes;
    deserializeCollection<VolumeTraits>(doc, cur, volumes, &config);
    config.setVolumes(volumes);
 
    // Global Configuration
    GlobalConfigTraits::deserialize(cur, config);

最后两个一个是解析音量,一个是全局配置,解析的方式都是跟modules一样,这里就不累赘了,最后我门再跟之前.conf文章中一样,总结一下,

//AudioPolicyConfig
<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
 
......
 
//HwModuleCollection--->AudioPolicyConfig.setHwModules(HwModuleCollection);
<modules>
	 
		......
	 
		<!-- Primary Audio HAL -->
		/**
			name="primary" 
			halVersion="2.0"
		*/
		// HwModule(name,version )   -->HwModuleCollection.add(HwModule)
        <module name="primary" halVersion="2.0">
 
			......
         
            <attachedDevices>
            // sp<DeviceDescriptor> device=HwModule->getDeclaredDevices().getDeviceFromTagName(Earpiece)
            //AudioPolicyConfig->addAvailableDevice(device);
                <item>Earpiece</item>
                ....
            </attachedDevices>
             
            //sp<DeviceDescriptor> device=HwModule->getDeclaredDevices().getDeviceFromTagName(Speaker)
            //AudioPolicyConfig->setDefaultOutputDevice(device);
             <defaultOutputDevice>Speaker</defaultOutputDevice>
             
            //IOProfileCollection-->HwModule->setProfiles(IOProfileCollection);
            <mixPorts>
            /**
				name="primary output"
				 role="source"
				     audio_port_role_t portRole = role == "source" ? AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
 
			*/
            //IOProfile(name,portRole) extends AudioPort     -->IOProfileCollection.add(IOProfile ); 
                <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
                 /**
				AudioProfile.setDynamicFormat(format)
				AudioProfile->setDynamicChannels(channelMasks);
				AudioProfile->setDynamicRate(samplingRates);
				*/
                //sp <AudioProfile>  -->AudioProfileVector.add(AudioProfile);  --> IOProfile ->setAudioProfiles(AudioProfileVector);
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                              
                           .....
                            
                </mixPort>
                 
                ......
                 
            </mixPorts>
             
            //DeviceVector   --> HwModule->setDeclaredDevices(DeviceVector)
            <devicePorts>
                <!-- Output devices declaration, i.e. Sink DEVICE PORT -->
                //typeName="AUDIO_DEVICE_OUT_EARPIECE"  role="sink"
                /**
				audio_port_role_t portRole = (role == Attributes::roleSource) ?
                AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
    			audio_devices_t type = AUDIO_DEVICE_NONE;
   			 	if (!DeviceConverter::fromString(typeName, type) ||
           	 		(!audio_is_input_device(type) && portRole == AUDIO_PORT_ROLE_SOURCE) ||
            		(!audio_is_output_devices(type) && portRole == AUDIO_PORT_ROLE_SINK)) {
        				ALOGW("%s: bad type %08x", __FUNCTION__, type);
       					 return BAD_VALUE;
   				 }
				*/
                //DeviceDescriptor(type,name)  extends AudioPort,AudioPortConfig   --> DeviceVector.add(DeviceDescriptor)
                <devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink">
                /**
				AudioProfile.setDynamicFormat(format)
				AudioProfile->setDynamicChannels(channelMasks);
				AudioProfile->setDynamicRate(samplingRates);
				*/
                //sp <AudioProfile>  -->AudioProfileVector.add(AudioProfile);  --> DeviceDescriptor  ->setAudioProfiles(profiles);
                   <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
                             
                            ......
                </devicePort>
 
				......
 
           </devicePorts>
            
            <!-- route declaration, i.e. list all available sources for a given sink -->
            //AudioRouteVector   --> HwModule->setRoutes(AudioRouteVector)
            <routes>
            //type="mix"
            //AudioRoute(type)  -->  AudioRouteVector.add(AudioRoute);
            //sink="Earpiece"  --->  sp<AudioPort> sink = AudioPolicyConfig->findPortByTagName(sink);
            //sink->addRoute(AudioRoute);  -->   AudioRoute->setSink(AudioPort);
            //sources=""primary output,......"    ->  AudioPortVector.add(sp<AudioPort> source = AudioPolicyConfig->findPortByTagName("primary output");)  -->   AudioRoute  ->setSources(AudioPortVector);
                <route type="mix" sink="Earpiece"
                       sources="primary output,low_latency,compressed_offload,voip_rx,BT SCO Headset Mic"/>
                        
                       ......
                        
            </routes>
 
			......
 
        </module>
         
        ......
         
</modules>
 
......
 
</audioPolicyConfiguration>

本文基于android7.0分析

一、前言

audio_policy.conf解析

前面我们已经介绍了audio_policy.conf 的解析全过程,但是,.conf 是一种简单的专有格式,有较大的局限性,无法描述电视和汽车等应用的复杂拓扑。Android 7.0 弃用了audio_policy.conf,并增加了对使用 XML 文件格式来定义音频拓扑的支持,这种文件格式更通俗易懂,具有多种编辑和解析工具,并且足够灵活,可以描述复杂的音频拓扑。

注意Android 7.0 仍支持使用 audio_policy.conf;系统会默认使用这种旧版格式。要使用 XML 文件格式,需要在设备 Makefile 中添加构建选项 USE_XML_AUDIO_POLICY_CONF := 1


二、XML 格式的优势

与在 .conf 文件中一样,新的 XML 文件支持定义输出输入流配置文件、可用于播放和捕获的设备以及音频属性的数量和类型。此外,XML 格式还提供以下增强功能:

  • 音频配置文件目前的结构类似于 HDMI 简单音频描述符,支持每种音频格式使用一组不同的采样率/声道掩码。
  • 设备和流之间所有可能连接的显式定义。以前,借助隐式规则,可以使连接到同一 HAL 模块的所有设备互连,从而阻止音频政策控制使用音频补丁程序 API 请求的连接。现在,在 XML 格式中,拓扑描述定义了连接限制。
  • 对“包含”的支持可避免出现重复的标准 A2DP、USB 或重新导向提交定义。
  • 可自定义的音量曲线。以前,音量表采用硬编码格式。在 XML 格式中,音量表通过描述来定义,并且可自定义。

frameworks/av/services/audiopolicy/config/audio_policy_configuration.xml 中的模板展示了很多已在使用的上述功能。


三、文件格式和位置

新的音频政策配置文件是 audio_policy_configuration.xml,位于 /system/etc。要查看采用新的 XML 文件格式的简单音频政策配置,请查看以下示例。

显示音频政策示例

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
    <globalConfiguration speaker_drc_enabled="true"/>
    <modules>
        <module name="primary" halVersion="3.0">
            <attachedDevices>
                <item>Speaker</item>
                <item>Earpiece</item>
                <item>Built-In 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="primary input" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000,48000"
                             channelMasks="AUDIO_CHANNEL_IN_MONO"/>
                </mixPort>
            </mixPorts>
            <devicePorts>
                <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" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </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="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000,48000"
                             channelMasks="AUDIO_CHANNEL_IN_MONO"/>
                </devicePort>
                <devicePort tagName="Wired Headset Mic" type="AUDIO_DEVICE_IN_WIRED_HEADSET" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000,48000"
                             channelMasks="AUDIO_CHANNEL_IN_MONO"/>
                </devicePort>
            </devicePorts>
            <routes>
                <route type="mix" sink="Earpiece" sources="primary output"/>
                <route type="mix" sink="Speaker" sources="primary output"/>
                <route type="mix" sink="Wired Headset" sources="primary output"/>
                <route type="mix" sink="primary input" sources="Built-In Mic,Wired Headset Mic"/>
            </routes>
        </module>
        <xi:include href="a2dp_audio_policy_configuration.xml"/>
    </modules>    
     
	<xi:include href="audio_policy_volumes.xml"/>
    <xi:include href="default_volume_tables.xml"/>
</audioPolicyConfiguration>

猜你喜欢

转载自blog.csdn.net/weixin_45437140/article/details/120614008