目錄
一、audio_policy_configuration.xml文件被加載流程
1、AudioPolicyService 創建階段
2、createAudioPolicyManager 實現
3、AudioPolicyManager 構造
4、配置文件解析 loadConfig
5、核心解析邏輯 PolicySerializer::deserialize
二、AudioPolicyConfig類解析
1、AudioPolicyConfig 類定義
2、module標簽
3、MixPort標簽
4、DevicePort標簽
5、route標簽
一、audio_policy_configuration.xml文件被加載流程
1、AudioPolicyService 創建階段
文件路徑:frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
void AudioPolicyService::onFirstRef() {mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient);
}
系統服務啟動后,調用 createAudioPolicyManager
,創建 AudioPolicyManager
對象。
2、createAudioPolicyManager 實現
extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface) {AudioPolicyManager *apm = new AudioPolicyManager(clientInterface);status_t status = apm->initialize();if (status != NO_ERROR) {delete apm;apm = nullptr;}return apm;
}
作用:
-
創建
AudioPolicyManager
; -
立即調用
initialize()
初始化流程; -
如果失敗,釋放資源
3、AudioPolicyManager 構造
文件:
frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface): AudioPolicyManager(clientInterface, false /*forTesting*/)
{loadConfig();
}void AudioPolicyManager::loadConfig() {if (deserializeAudioPolicyXmlConfig(getConfig()) != NO_ERROR) {ALOGE("could not load audio policy configuration file, setting defaults");getConfig().setDefault();}
}
構造時直接調用 loadConfig()
,開始讀取音頻配置文件。
4、配置文件解析 loadConfig
文件:
frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
status_t deserializeAudioPolicyFile(const char *fileName, AudioPolicyConfig *config) {PolicySerializer serializer;return serializer.deserialize(fileName, config);
}
調用 PolicySerializer::deserialize
,使用 libxml2 解析音頻 XML 配置文件。
5、核心解析邏輯 PolicySerializer::deserialize
status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig *config)
{// 使用智能指針包裝 libxml2 的解析接口,解析傳入的 XML 文件auto doc = make_xmlUnique(xmlParseFile(configFile));if (doc == nullptr) {// 如果解析失敗,打印錯誤并返回 BAD_VALUEALOGE("%s: Could not parse %s document.", __func__, configFile);return BAD_VALUE;}// 獲取 XML 文檔的根節點xmlNodePtr root = xmlDocGetRootElement(doc.get());if (root == NULL) {// 如果根節點為空,打印錯誤并返回 BAD_VALUEALOGE("%s: Could not parse %s document: empty.", __func__, configFile);return BAD_VALUE;}// 處理 XInclude(XML文件可以引用其他XML文件的機制)if (xmlXIncludeProcess(doc.get()) < 0) {// 如果包含文件處理失敗,記錄錯誤,但不直接返回ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __func__, configFile);}// 檢查根節點名稱是否符合預期if (xmlStrcmp(root->name, reinterpret_cast<const xmlChar*>(rootName))) {ALOGE("%s: No %s root element found in xml data %s.", __func__, rootName,reinterpret_cast<const char*>(root->name));return BAD_VALUE;}// 獲取根節點的 version 屬性std::string version = getXmlAttribute(root, versionAttribute);if (version.empty()) {// 如果 version 屬性不存在,返回錯誤ALOGE("%s: No version found in root node %s", __func__, rootName);return BAD_VALUE;}// 驗證版本是否與期望版本一致if (version != mVersion) {ALOGE("%s: Version does not match; expect %s got %s", __func__, mVersion.c_str(),version.c_str());return BAD_VALUE;}// 開始解析子節點// Step 1: 解析 Module 列表ModuleTraits::Collection modules;status_t status = deserializeCollection<ModuleTraits>(root, &modules, config);if (status != NO_ERROR) {// 如果模塊解析失敗,直接返回錯誤狀態return status;}// 將解析到的模塊設置到 config 對象中config->setHwModules(modules);// Step 2: 解析全局配置GlobalConfigTraits::deseria
功能拆解:
-
xmlParseFile
:加載并解析 XML 文件。 -
xmlDocGetRootElement
:獲取根節點,確保結構有效。 -
xmlXIncludeProcess
:處理 XInclude,允許配置文件嵌套引用子文件。 -
驗證 root 名稱、版本號。
如果通過校驗,進入內容解析:
deserializeCollection<ModuleTraits>(root, &modules, config);
config->setHwModules(modules);
GlobalConfigTraits::deserialize(root, config);
SurroundSoundTraits::deserialize(root, config);
經過以上代碼之后,最終audio_policy_configuration.xml配置文件會轉化為以下的C++類AudioPolicyConfig。
二、AudioPolicyConfig類解析
audio_policy_configuration.xml配置文件配置了Android Audio的設備、流以及設備和流之間的路由等相關信息。寫明了Android Audio支持哪些設備、哪些流以及它們支持的編碼格式、采樣率等信息。文件大致內容如下。
1、AudioPolicyConfig
類定義
class AudioPolicyConfig {static const constexpr char* const kDefaultEngineLibraryNameSuffix = "default";std::string mSource; //為config字符串目錄,一般在odm/etc、/vendor/etc、/system/etc下的audio_policy_configuration.xmlstd::string mEngineLibraryNameSuffix;HwModuleCollection &mHwModules; //保存了配置文件中所有的所有module標簽集合,每個module標簽對應一個HwModule類DeviceVector &mOutputDevices; //attchedDevices標簽中,設備名稱名字和devicePort標簽的tagName相同,且type中有OUT字眼的DeviceDescriptor實體類集合DeviceVector &mInputDevices; //attchedDevices標簽中,設備名稱名字和devicePort標簽的tagName相同,且type中有in字眼的DeviceDescriptor實體類集合sp<DeviceDescriptor> &mDefaultOutputDevice; //保存defaultOutputDevice標簽內名字和devicePort標簽的tagName相同// TODO: remove when legacy conf file is removed. true on devices that use DRC on the// DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.// Note: remove also speaker_drc_enabled from global configuration of XML config file.bool mIsSpeakerDrcEnabled;bool mIsCallScreenModeSupported;SurroundFormats mSurroundFormats;
};
<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>……</mixPorts><devicePorts>……</devicePorts><!-- route declaration, i.e. list all available sources for a given sink --><routes>……</routes></module><!-- A2dp Input Audio HAL --><xi:include href="a2dp_in_audio_policy_configuration.xml"/>……</modules><!-- End of Modules section -->
2、module標簽
每個module標簽對應著相應的hal層實現,如primary、usb、a2dp等
<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>……</module><!-- A2dp Input Audio HAL --><xi:include href="a2dp_in_audio_policy_configuration.xml"/>……</modules><!-- End of Modules section -->
module標簽對應C++實體類HWModule。
class HwModule {const String8 mName; // hal層模塊對應的module名字(primary, a2dp ...)audio_module_handle_t mHandle;OutputProfileCollection mOutputProfiles; // mixport標簽role為source類型,對應IOProfle實體類集合InputProfileCollection mInputProfiles; // mixport標簽role為sink的類型,對應IOProfle實體類集合uint32_t mHalVersion; // hal層模塊的版本信息DeviceVector mDeclaredDevices; // 所有的deviceport標簽,對應DeviceDescriptor實體類的集合DeviceVector mDynamicDevices; /**< devices that can be added/removed at runtime (e.g. rsbumix)*/AudioRouteVector mRoutes; // 所有的routePolicyAudioPortVector mPorts; // 所有的mixport,deviceport標簽對應的實體類,因為IOProfle和DeviceDescriptor都繼承了AudioPort,所以相當于這是一個AudioPort集合
};
3、MixPort標簽
mixport標簽可以理解為stream流,配置了相應的格式、采樣率以及mask,且分為輸出、輸入流。一個mixport標簽可能有多個profile屬性,也就是支持很多編碼格式等屬性。
<mixPort name="compressed_offload" role="source"flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING"><profile name="" format="AUDIO_FORMAT_MP3"samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/><profile name="" format="AUDIO_FORMAT_AAC"samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/><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標簽對應一個IOProfile實體類。
class IOProfile : public AudioPort, public PolicyAudioPort {// 可以同時打開的流的最大數量,默認為1。賦值為0時,表示無窮大。uint32_t maxOpenCount;// 目前已打開的流的數量。uint32_t curOpenCount;// 同時處于活躍狀態的流的最大數量,默認為1。賦值為0時,表示無窮大。uint32_t maxActiveCount;// 正處于活躍狀態的流的數量。 針對于Hal層的流而言。uint32_t curActiveCount;private:/** 當前流支持的設備集合;* 如果是sink輸入流,查找規則如下:* 1. 遍歷其父類的成員mRoutes,因為是輸入流,所以遍歷mRoute集合中sink為自己的route,也就是找有哪些源source設備把數據傳給自己。* 2. 找到route后,根據route中source保存的對象,且對象type是AUDIO_PORT_TYPE_DEVICE類型(就是devicesPort標簽對應的實體類DeviceDescriptor)* 3. 把DeviceDescriptor保存在集合中,保存在以下mSupportedDevices中,作為其支持的設備;* 輸出流,同理;最終的結果就是:* 作為輸出流source,mSupportedDevices保存此流可以輸出到對應的device,stream -> device* 作為輸入流sink,mSupportedDevices保存了其他device能輸出數據到此流, device -> stream**/DeviceVector mSupportedDevices;
};class AudioPort : public virtual RefBase, public virtual Parcelable
{AudioGains mGains; // gain controllers
protected:std::string mName; // 對應mixport的nameaudio_port_type_t mType; // AUDIO_PORT_TYPE_MIX (此處固定)audio_port_role_t mRole; // AUDIO_PORT_ROLE_SOURCE/AUDIO_PORT_ROLE_SINK(由mixport的role決定)AudioProfileVector mProfiles; // AudioProfile的集合,對應mixport里面的多個profile// Audio capabilities that are defined by hardware descriptors when the format is unrecognized// by the platform, e.g. short audio descriptor in EDID for HDMI.std::vector<media::ExtraAudioDescriptor> mExtraAudioDescriptors;
};class PolicyAudioPort : public virtual RefBase, private HandleGenerator<audio_port_handle_t>
{uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).sp<HwModule> mModule; // 通過attach函數與HwModule綁定AudioRouteVector mRoutes; // 相關連的route標簽集合
};
mixport內部的Profile標簽對應的C++類AudioProfile 如下。在解析以上標簽至profile時,會單獨創建AudioProfile。
class AudioProfile final : public RefBase, public Parcelable
{std::string mName; // profile的name// 以下三個變量對應配置文件中profile中的置,由初始化時進行賦值audio_format_t mFormat; // The format for an audio profile should only be set when initialized.ChannelMaskSet mChannelMasks;SampleRateSet mSamplingRates;// 以下三個對應上面三位,如果三位都有值,則為false固定的,如果xml沒有指定值,則為true表示是動態的值bool mIsDynamicFormat = false;bool mIsDynamicChannels = false;bool mIsDynamicRate = false;audio_encapsulation_type_t mEncapsulationType = AUDIO_ENCAPSULATION_TYPE_NONE;AudioProfile() = default;AudioProfile& operator=(const AudioProfile& other);
};
4、DevicePort標簽
devicePort標簽可以理解為一個device設備,設備也分output和input,以type中的關鍵字“IN”和“OUT”進行區分。
<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對應一個C++類DeviceDescriptor。
class DeviceDescriptor : public DeviceDescriptorBase,public PolicyAudioPort, public PolicyAudioPortConfig
{std::string mTagName; // 對應的tagName字段FormatVector mEncodedFormats; // encodedFormats轉換的枚舉值audio_format_t mCurrentEncodedFormat;bool mIsDynamic = false;const std::string mDeclaredAddress; // address字段對應的地址
};class DeviceDescriptorBase : public AudioPort, public AudioPortConfig
{AudioDeviceTypeAddr mDeviceTypeAddr;uint32_t mEncapsulationModes = 0;uint32_t mEncapsulationMetadataTypes = 0;
};class AudioPort : public virtual RefBase, public virtual Parcelable
{AudioGains mGains; // gain controllers
protected:std::string mName; // 對應devicePort的nameaudio_port_type_t mType; // AUDIO_PORT_TYPE_DEVICE(此處固定)audio_port_role_t mRole; // AUDIO_PORT_ROLE_SOURCE/AUDIO_PORT_ROLE_SINK(由mixport的role決定)AudioProfileVector mProfiles; // AudioProfile的集合,對應devicePort里面的多個profile// Audio capabilities that are defined by hardware descriptors when the format is unrecognized// by the platform, e.g. short audio descriptor in EDID for HDMI.std::vector<media::ExtraAudioDescriptor> mExtraAudioDescriptors;
};
同MixPort一樣,devicePort也會解析內部的profile標簽,創建新的AudioProfile。
class AudioProfile final : public RefBase, public Parcelable
{std::string mName; // profile的name// 以下三個變量對應配置文件中profile中的置,由初始化時進行賦值audio_format_t mFormat; // The format for an audio profile should only be set when initialized.ChannelMaskSet mChannelMasks;SampleRateSet mSamplingRates;// 以下三個對應上面三位,如果三位都有值,則為false固定的,如果xml沒有指定值,則為true表示是動態的值bool mIsDynamicFormat = false;bool mIsDynamicChannels = false;bool mIsDynamicRate = false;audio_encapsulation_type_t mEncapsulationType = AUDIO_ENCAPSULATION_TYPE_NONE;AudioProfile() = default;AudioProfile& operator=(const AudioProfile& other);
};
5、route標簽
route是把deviceport和mixport連接起來的路由,數據由一個stream輸出到另一個device,或者從一個device輸出到另一個stream。
<route type="mix" sink="Speaker"sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
route標簽對應C++的AudioRoute類。
class AudioRoute : public virtual RefBase
{PolicyAudioPortVector mSources; //所有的deviceport、mixport標簽轉化的實體類都保存到HwModule的mPorts成員了,所以是用name去mPorts里面查找,只是source可能是多個,這里用集合保存sp<PolicyAudioPort> mSink; //同上audio_route_type_t mType; //AUDIO_ROUTE_MIX/AUDIO_ROUTE_MUX:根據type而定是互斥還是可融合
};
在Primary的module配置文件中通過如下語句去配置a2dp、usb的module。
<!-- A2dp Input Audio HAL --><xi:include href="a2dp_in_audio_policy_configuration.xml"/>