【AudioPolicy To AudioHAL笔记(三)】安卓S上audio_policy_configuration.xml 加载过程分析

安卓S上audio_policy_configuration.xml 加载过程分析


/*****************************************************************************************************************/

声明: 本博客内容均由https://blog.csdn.net/weixin_47702410原创,转载or引用请注明出处,谢谢!

创作不易,如果文章对你有帮助,麻烦点赞 收藏支持~感谢

/*****************************************************************************************************************/

上一篇文章启动过程提到:

/frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
void AudioPolicyManager::loadConfig() {ALOGE("Mylog_AP:AudioPolicyManager::loadConfig() !");if (deserializeAudioPolicyXmlConfig(getConfig()) != NO_ERROR) {ALOGE("could not load audio policy configuration file, setting defaults");getConfig().setDefault();}
}

本文详细讲一下这个解析配置文件的过程。

deserializeAudioPolicyXmlConfig()的定义在:

/frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
static status_t deserializeAudioPolicyXmlConfig(AudioPolicyConfig &config) {if (std::string audioPolicyXmlConfigFile = audio_get_audio_policy_config_file();!audioPolicyXmlConfigFile.empty()) {status_t ret = deserializeAudioPolicyFile(audioPolicyXmlConfigFile.c_str(), &config);if (ret == NO_ERROR) {config.setSource(audioPolicyXmlConfigFile);}return ret;}return BAD_VALUE;
}

这个函数主要做了两个事情:

  • 调用函数audio_get_audio_policy_config_file获取配置文件的信息
  • 调用函数deserializeAudioPolicyFile处理配置文件

其中第一步骤的函数在如下的定义(有可能这个函数会被客制化修改):

//https://cs.android.com/android/platform/superproject/+/android-12.0.0_r8:system/media/audio/include/system/audio_config.h?hl=zh-cn
/system/media/audio/include/system/audio_config.h
static inline std::string audio_get_audio_policy_config_file() 

函数内容不是很难,感兴趣可以自己阅读源码,我这里总结一下:
这个函数主要是根据系统的属性选择不同的配置文件,简单的画个系统属性和配置文件的关系图:
系统属性与配置文件的关系

这里我们主要分析第二个函数deserializeAudioPolicyFile.但在分析这个函数前需要了解一下知识:

也就是audio_policy_config_file中child的概念,我画一张简图表示一下这个关系(以audio_policy_configuration.xml为例):
audio_policy_config_file中child的概念

看图应该不难分析,就是套娃又套娃。一个modules对应一个so文件,例如,这个就是对于一个primary HAL;其中一个module允许有多个设备列表。

有上面的了解后,再看一下源码:

/frameworks/av/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
status_t deserializeAudioPolicyFile(const char *fileName, AudioPolicyConfig *config)
{PolicySerializer serializer;status_t status = serializer.deserialize(fileName, config);   --> 重构+函数模板if (status != OK) config->clear();return status;
}

结合C++的语法,上面函数调用到:

/frameworks/av/services/audiopolicy/common/managerdefinitions/src/Serializer.cppstatus_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig *config,bool ignoreVendorExtensions)
{mIgnoreVendorExtensions = ignoreVendorExtensions;auto doc = make_xmlUnique(xmlParseFile(configFile));    --> 解析XML配置文件if (doc == nullptr) {ALOGE("%s: Could not parse %s document.", __func__, configFile);return BAD_VALUE;}xmlNodePtr root = xmlDocGetRootElement(doc.get());     --> 获取XML文档的根节点if (root == NULL) {ALOGE("%s: Could not parse %s document: empty.", __func__, configFile);return BAD_VALUE;}if (xmlXIncludeProcess(doc.get()) < 0) {               --> 处理XML文档中的XInclude指令ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __func__, configFile);}if (xmlStrcmp(root->name, reinterpret_cast<const xmlChar*>(rootName)))  {   -->// 检查根节点的名称是否与"rootName = "audioPolicyConfiguration""的一致ALOGE("%s: No %s root element found in xml data %s.", __func__, rootName,reinterpret_cast<const char*>(root->name));return BAD_VALUE;}std::string version = getXmlAttribute(root, versionAttribute);     --> 获取根节点的版本属性if (version.empty()) {ALOGE("%s: No version found in root node %s", __func__, rootName);return BAD_VALUE;}if (version == "7.0") {mChannelMasksSeparator = mSamplingRatesSeparator = mFlagsSeparator = " ";} else if (version != "1.0") {ALOGE("%s: Version does not match; expected \"1.0\" or \"7.0\" got \"%s\"",__func__, version.c_str());return BAD_VALUE;}// Let's deserialize children// ModulesModuleTraits::Collection modules;status_t status = deserializeCollection<ModuleTraits>(root, &modules, config);if (status != NO_ERROR) {return status;}config->setHwModules(modules);// Global Configurationdeserialize<GlobalConfigTraits>(root, config);  --> 利用C++的函数模板语法调用到不同的deserialize// Surround configurationdeserialize<SurroundSoundTraits>(root, config);return android::OK;
}

上面这个函数重点关注一下下面的语句,其是在这个函数中解析文件的:

status_t status = deserializeCollection<ModuleTraits>(root, &modules, config);
其调用的函数是:
/frameworks/av/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
template <class Trait>
status_t PolicySerializer::deserializeCollection(const xmlNode *cur,typename Trait::Collection *collection,typename Trait::PtrSerializingCtx serializingContext)
{--> 用两个for循环,遍历当前xml节点的所有子节点for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {const xmlNode *child = NULL;if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::collectionTag))) {child = cur->xmlChildrenNode;} else if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {child = cur;}for (; child != NULL; child = child->next) {if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {auto maybeElement = deserialize<Trait>(child, serializingContext);if (maybeElement.index() == 1) {status_t status = Trait::addElementToCollection(std::get<1>(maybeElement), collection);if (status != NO_ERROR) {ALOGE("%s: could not add element to %s collection", __func__,Trait::collectionTag);return status;}} else if (mIgnoreVendorExtensions && std::get<status_t>(maybeElement) == NO_INIT) {// Skip a vendor extension element.} else {return BAD_VALUE;}}}if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {return NO_ERROR;}}return NO_ERROR;
}

单从函数分析并不难,找到对应模板的名字,然后再调用

auto maybeElement = deserialize<Trait>(child, serializingContext);

最后的结果就是:

/frameworks/av/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
class AudioPolicyConfig
{
public:....private:std::string mSource;std::string mEngineLibraryNameSuffix;HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */DeviceVector &mOutputDevices;   // xm中所以output devices模块集合DeviceVector &mInputDevices;    //xml中所以input devices模块集合sp<DeviceDescriptor> &mDefaultOutputDevice;   //默认的output device...
};

推荐阅读:

  • https://www.twblogs.net/a/5d42bfc7bd9eee51fbf9ebab
  • https://anvydon.github.io/2020/09/01/Android%E9%9F%B3%E9%A2%91%E7%AD%96%E7%95%A5%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E8%A7%A3%E6%9E%90/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/449329.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用于录制培训视频的前 6 名顶级录屏软件

教程视频是当今互联网上最受欢迎的视频类别之一。许多人都在寻找如何使用他们购买的东西的说明&#xff0c;但由于没有时间&#xff0c;文本中编写的教程无法实现目标。人们更喜欢观看互联网教程视频的可能性是参考产品手册的三倍。此外&#xff0c;由于程序的可访问性&#xf…

web前端--------渐变和过渡

线性渐变&#xff0c;是指颜色沿一条直线进行渐变&#xff0c;例如从上到下、从左到右。 当然&#xff0c;CSS中也支持使用角度来设置渐变的方向&#xff0c;角度单位为deg。 0deg&#xff0c;为12点钟方向&#xff0c;表示从下到上渐变。 90deg&#xff0c;为3点钟方向&…

Cmake语法学习3:语法

1.双引号 1.1 命令参数 1&#xff09;介绍 命令中多个参数之间使用空格进行分隔&#xff0c;而 cmake 会将双引号引起来的内容作为一个整体&#xff0c;当它当成一个参数&#xff0c;假如你的参数中有空格&#xff08;空格是参数的一部分&#xff09;&#xff0c;那么就可以使…

【巧用异或】单身狗2题解

✨✨欢迎大家来到Celia的博客✨✨ &#x1f389;&#x1f389;创作不易&#xff0c;请点赞关注&#xff0c;多多支持哦&#x1f389;&#x1f389; 所属专栏&#xff1a;【每日刷题】C语言 个人主页&#xff1a;Celias blog~ 题目 一个数组中只有两个数字是出现一次&#xff0c…

spring boot yaml文件中如何设置duration对象值

Spring Boot对表示持续时间有专门的支持。如果您公开java.time.Duration属性&#xff0c;则应用程序对应Duration类型的属性有以下格式可用: long类型的常规表示(使用毫秒作为默认单位&#xff0c;除非指定了DurationUnit)java.time.Duration 使用的标准ISO-8601格式其中值和单…

Leetcode—2881. 创建新列【简单】

2024每日刷题&#xff08;一零九&#xff09; Leetcode—2881. 创建新列 实现代码 import pandas as pddef createBonusColumn(employees: pd.DataFrame) -> pd.DataFrame:employees[bonus] employees[salary] * 2return employees 运行结果 之后我会持续更新&#xf…

第十一章[文件系统]:11.1:文件的读写

一,文件的读取 1,open()函数 open()函数: 功能:open() 函数用于打开一个文件,并返回文件对象, 在对文件进行处理过程都需要使用到这个函数, 如果该文件无法被打开,会抛出 OSError。 open(file, mode=r) 参数:file: 必需,文件路径(相对或者绝对路径) mode: 可选,文…

大模型实践笔记(1)——GLM-6B实践

目录 在Ubuntu上的配置Git Large File Storage 安装Git LFS&#xff1a; 设置Git LFS&#xff1a; 使用Git LFS&#xff1a; 安装GLM-6B 环境依赖 ChatGLM2-6B介绍 配置GLM 下载代码 构建环境 安装依赖 本地部署 网页UI 很多模型在hugging face上面&#xff0c;…

线性代数:线性方程组

目录 一、线性方程组概念 二、消元法求线性方程组 三、系数阵的秩与线性方程组的解 无解 唯一解 无数解 相关定理 一、线性方程组概念 二、消元法求线性方程组 三、系数阵的秩与线性方程组的解 无解 唯一解 无数解 相关定理

【笔记】React Native实战练习(仿网易云游戏网页移动端)

/** * 如果系统看一遍RN相关官方文档&#xff0c;可能很快就忘记了。一味看文档也很枯燥无味&#xff0c; * 于是大概看了关键文档后&#xff0c;想着直接开发一个Demo出来&#xff0c;边学边写&#xff0c;对往后工作 * 开发衔接上能够更顺。这期间肯定会遇到各种各样的问题&a…

STM32F407移植OpenHarmony笔记8

继上一篇笔记&#xff0c;成功开启了littlefs文件系统&#xff0c;能读写FLASH上的文件了。 今天继续研究网络功能&#xff0c;让控制台的ping命令能工作。 轻量级系统使用的是liteos_m内核lwip协议栈实现网络功能&#xff0c;需要进行配置开启lwip支持。 lwip的移植分为两部分…

计算机图形学 实验

题目要求 1.1 实验一&#xff1a;图元的生成&#xff1a;直线、圆椭区域填充 你需要完成基本的图元生成算法&#xff0c;包括直线和椭圆。 在区域填充中&#xff0c;要求你对一个封闭图形进行填充。你需要绘制一个封 闭图形&#xff08;例如多边形&#xff09;&#xff0c;并选…