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

news2024/11/18 1:42:13

安卓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.cpp

status_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
    // Modules
    ModuleTraits::Collection modules;
    status_t status = deserializeCollection<ModuleTraits>(root, &modules, config);
    if (status != NO_ERROR) {
        return status;
    }
    config->setHwModules(modules);

    // Global Configuration
    deserialize<GlobalConfigTraits>(root, config);  --> 利用C++的函数模板语法调用到不同的deserialize

    // Surround configuration
    deserialize<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.coloradmin.cn/o/1428784.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Iceberg从入门到精通系列之二十三:Spark查询

Iceberg从入门到精通系列之二十三&#xff1a;Spark查询 一、使用 SQL 查询二、使用 DataFrame 进行查询三、Time travel四.Incremental read五、检查表六、History七、元数据日志条目八、Snapshots九、Files十、Manifests十一、Partitions十二、所有元数据表十三、参考十四、使…

flv视频格式批量截取封面图(不占内存版)--其他视频格式也通用

flv视频格式批量截取封面图&#xff08;不占内存版&#xff09;--其他视频格式也通用 需求&#xff08;实现的效果&#xff09;功能实现htmlcssjs 需求&#xff08;实现的效果&#xff09; 批量显示视频&#xff0c;后端若返回有imgUrl,则直接显示图1&#xff0c; 若无&#xf…

安卓SurfaceTexture中updateTexImage使用及源码分析

文章目录 引言updateTexImage 简单使用SurfaceTexture 初始化相关源码分析Surface 绘制流程源码分析createBufferQueue 源码分析SurfaceTexture 之 updateTexImage 源码分析结尾 本文首发地址 https://h89.cn/archives/140.html 最新更新地址 https://gitee.com/chenjim/chenji…

2024数模美赛C题F题完整代码结果展示

C&#xff1a;Momentum in Tennis 实在精力有限&#xff0c;完整讲解可以移步去看我的讲解视频啦&#xff1a; 美赛C题每一问代码结果讲解及进度说明 F&#xff1a;Reducing lllegal Wildlife Trade 实在精力有限&#xff0c;完整讲解可以移步去看我的讲解视频啦&#xff1a; ​…

近期CCF系列会议截稿时间

专属领域会议订阅 关注{晓理紫}&#xff0c;每日更新会议信息&#xff0c;如感兴趣&#xff0c;请转发给有需要的同学&#xff0c;谢谢支持 如果你感觉对你有所帮助&#xff0c;请关注我&#xff0c;每日准时为你推送最新会议信息。 CSFW (CCF B) IEEE Computer Security Foun…

【gcc】webrtc发送侧计算 丢包率

大神的分析 : 提到: 每当收到cc-feedback或者收到RR-report的时候就能统计出丢包率,在cc-controller中就会调用SendSideBandwidthEstimation::UpdatePacketsLost()去更新丢包率,同时进行码率预估 G:\CDN\rtcCli\m98\src\modules\congestion_controller\goog_cc\send_side_b…

假期无忧!这个微信自动回复工具助您高效管理与客户互动

在繁忙的现代生活中&#xff0c;尤其是在假期期间&#xff0c;处理大量微信消息可能会成为一项艰巨的任务。今天就给大家分享一个能够让微信自动回复消息的工具&#xff0c;帮助你解放双手&#xff0c;让你的假期无忧&#xff01; 通过微信管理系统&#xff0c;您可以同时登录…

152基于matlab的GUI滚动轴承特征频率计算

基于matlab的GUI滚动轴承特征频率计算&#xff0c;输入轴承参数&#xff0c;包括转速&#xff0c;节圆直径、滚子直径、滚子数、接触角&#xff0c;就可得滚动特征频率结果&#xff0c;程序已调通&#xff0c;可直接运行。 152 matlab 轴承特征频率 GUI (xiaohongshu.com)

uni-app 经验分享,从入门到离职(三)——关于 uni-app 生命周期快速了解上手

文章目录 &#x1f4cb;前言⏬关于专栏 &#x1f3af;什么是生命周期&#x1f9e9;应用生命周期&#x1f4cc; 关于 App.vue/App.uvue &#x1f9e9;页面生命周期&#x1f4cc;关于 onShow 与 onLoad 的区别 &#x1f9e9;组件生命周期 &#x1f4dd;最后 &#x1f4cb;前言 这…

C# SSH.NET 长命令及时返回

在SSH中执行长时间的命令&#xff0c;SSH.NET及时在文本框中返回连续显示结果。 c# - Execute long time command in SSH.NET and display the results continuously in TextBox - Stack Overflow 博主管理了一个服务器集群&#xff0c;准备上自动巡检工具&#xff0c;测试在…

clickhouse如何清除多个分区数据 alter table drop partition操作

官网drop partition操作 官网链接&#xff1a;https://clickhouse.com/docs/zh/sql-reference/statements/alter/partition#drop-partitionpart 官网上之有清除单个分区的例子&#xff0c;并没有对清除多个分区的场景进行描述&#xff0c;之前清除分区时也是按照官网例子进行…

python爬虫4

#1.练习 # &#xff08;1&#xff09; 获取网页的源码 # &#xff08;2&#xff09; 解析 解析的服务器响应的文件 etree.HTML # (3) 打印 import urllib.request urlhttps://www.baidu.com/ headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit…

2024年美赛B题潜水器定位和搜救建模代码和完整论文文档

目前已完成2024年美赛B题潜水器定位和搜救的建模代码和论文编写&#xff0c;部分文章内容和代码如下&#xff1a; 摘要 在海洋探险和搜救领域&#xff0c;潜水器的定位和搜救任务具有重要意义。本文旨在开发一系列模型来预测潜水器位置、分析不确定性、确定信息传递策略、建议…

关于配置系统环境变量 点击确定就显示,此环境变量过大2047

使用了网络上的所有办法,均无效 最终解决办法:把系统path环境变量里的变量环境删掉一些之后,成功加入! 原因就是path里面的内容太多了导致的,删掉一些变量就好了&#xff01;

3D打印、自动升降超静电机驱动方案TMC2209

TMC2209步进电机驱动芯片介绍 TMC2209是一款用于两相步进电机的超静音电机驱动IC。Trinamic的精密StealthChop波器确保了无噪音运行、最大效率和最佳电机转矩。它的快速电流调节和与SpreadCycle的可选组合允许高度动态运动&#xff0c;同时为无传感器归位添加了StallGuard4。集…

qt -chart控件设计器可拖拉

qt -chart控件设计器可拖拉 一、演示效果二、安装过程三、核心程序四、程序链接 一、演示效果 二、安装过程 三、核心程序 #include <QtGui> #include <QColor>#include <cstdlib> #include <cassert> #include <numeric>#include <chartwor…

FANUC机器人示教器的菜单变成了图标,如何改成列表的形式?

FANUC机器人示教器的菜单变成了图标&#xff0c;如何改成列表的形式&#xff1f; 如下图所示&#xff0c;开机后按下MENU菜单键时&#xff0c;发现原来的列表形式变成了菜单图标的形式&#xff0c;同时在按F1-F5键时&#xff0c;提示&#xff1a;HMI模式-键不可用&#xff0c; …

缓存框架jetcache

在实际应用中&#xff0c;并不是单一的使用本地缓存或者redis&#xff0c;更多是组合使用来满足不同的业务场景。 jetcache组件实现了优雅的组合本地缓存和远程缓存。 支持多种缓存类型&#xff1a;本地缓存、分布式缓存、多级缓存。 官网地址&#xff1a;https://github.com…

解决Docker打包Eureka注册中心,其他服务无法注册问题

​前言 本文主要是介绍利用docker打包Eureka注册中心&#xff0c;并且发布镜像到服务器&#xff0c;遇到的一个比较坑的问题。主要是服务镜像部署完毕之后&#xff0c;docker容器都能启动&#xff0c;并且也能访问&#xff0c;但是其他服务就是无法注册到注册中心。排除问题&a…

【Java程序设计】【C00239】基于Springboot的漫画之家管理系统(有论文)

基于Springboot的漫画之家管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的漫画之家系统 本系统分为系统功能模块、管理员功能模块以及用户功能模块。 系统功能模块&#xff1a;在系统首页可以查看首页&a…