Android 11 Audio strategy配置解析

在启动AudioPolicyService时,通过EngineBase的loadAudioPolicyEngineConfig函数去解析strategy配置。其调用流程如下

在这里插入图片描述
接下来就对loadAudioPolicyEngineConfig展开分析
1,解析volume标签

engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig()
{//省略auto result = engineConfig::parse();//1if (result.parsedConfig == nullptr) {engineConfig::Config config = gDefaultEngineConfig;//2android::status_t ret = engineConfig::parseLegacyVolumes(config.volumeGroups);//3result = {std::make_unique<engineConfig::Config>(config),static_cast<size_t>(ret == NO_ERROR ? 0 : 1)};} else {//省略}//省略
}

注释1处,parse函数会去解析/vendor/etc/audio_policy_engine_configuration.xml 文件,我的Android 11 源码环境没有这个文件,所以会进入if分支。注释2处设置默认配置为gDefaultEngineConfig。注释3处调用parseLegacyVolumes去解析audio_policy_configuration.xml文件下的volume标签。

parseLegacyVolumes找到audio_policy_configuration.xml文件后,调用到deserializeLegacyVolumeCollection函数继续解析

//frameworks/av/services/audiopolicy/engine/config/src/EngineConfig.cpp
static status_t deserializeLegacyVolumeCollection(_xmlDoc *doc, const _xmlNode *cur,VolumeGroups &volumeGroups,size_t &nbSkippedElement)
{std::map<std::string, VolumeCurves> legacyVolumeMap;for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {if (xmlStrcmp(cur->name, (const xmlChar *)legacyVolumecollectionTag)) {//legacyVolumecollectionTag:volumescontinue;}const xmlNode *child = cur->xmlChildrenNode;for (; child != NULL; child = child->next) {if (!xmlStrcmp(child->name, (const xmlChar *)legacyVolumeTag)) {//legacyVolumeTag:volumestatus_t status = deserializeLegacyVolume(doc, child, legacyVolumeMap);//1if (status != NO_ERROR) {nbSkippedElement += 1;}}}}for (const auto &volumeMapIter : legacyVolumeMap) {//省略int indexMin = streamType >= AUDIO_STREAM_PUBLIC_CNT ? 0 : -1;int indexMax = streamType >= AUDIO_STREAM_PUBLIC_CNT ? 100 : -1;volumeGroups.push_back({ volumeMapIter.first, indexMin, indexMax, volumeMapIter.second });//2}return NO_ERROR;
}

注释1处,对volumes标签下的每个volume,调用deserializeLegacyVolume处理,解析的结果放在legacyVolumeMap这个容器中。注释2处将map容器的内容保存到volumeGroups中

deserializeLegacyVolume

//frameworks/av/services/audiopolicy/engine/config/src/EngineConfig.cpp
status_t deserializeLegacyVolume(_xmlDoc *doc, const _xmlNode *cur,std::map<std::string, VolumeCurves> &legacyVolumes)
{std::string streamTypeLiteral = getXmlAttribute(cur, "stream");//解析streamstd::string deviceCategoryLiteral = getXmlAttribute(cur, "deviceCategory");//解析deviceCategorystd::string referenceName = getXmlAttribute(cur, "ref");//引用其它文件的内容,解析过程是一样的const xmlNode *ref = NULL;if (!referenceName.empty()) {getReference(xmlDocGetRootElement(doc), ref, referenceName, legacyVolumecollectionTag);}CurvePoints curvePoints;for (const xmlNode *child = referenceName.empty() ?cur->xmlChildrenNode : ref->xmlChildrenNode; child != NULL; child = child->next) {if (!xmlStrcmp(child->name, (const xmlChar *)VolumeTraits::volumePointTag)) {xmlCharUnique pointXml(xmlNodeListGetString(doc, child->xmlChildrenNode, 1), xmlFree);std::vector<int> point;collectionFromString<DefaultTraits<int>>(reinterpret_cast<const char*>(pointXml.get()), point, ",");curvePoints.push_back({point[0], point[1]});//将解析point标签的结果保存在curvePoints中}}legacyVolumes[streamTypeLiteral].push_back({ deviceCategoryLiteral, curvePoints });//保存到legacyVolumes中return NO_ERROR;
}

以以下内容场景为例

<volumes><volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_HEADSET"><point>0,-4200</point><point>33,-2800</point><point>66,-1400</point><point>100,0</point></volume><volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_SPEAKER"><point>0,-2400</point><point>33,-1600</point><point>66,-800</point><point>100,0</point></volume><volume stream="AUDIO_STREAM_SYSTEM" deviceCategory="DEVICE_CATEGORY_HEADSET"><point>1,-3000</point><point>33,-2600</point><point>66,-2200</point><point>100,-1800</point></volume>//省略
<volumes>

最后的解析结果为
在这里插入图片描述
再来看一下图中各结构体的定义。源码路径:frameworks/av/services/audiopolicy/engine/config/include/EngineConfig.h

VolumeCurve

struct VolumeCurve {std::string deviceCategory;//volume标签下的deviceCategory字段CurvePoints curvePoints;//volume标签下的point字段的集合
};

VolumeGroup

struct VolumeGroup {std::string name;//来自于volume标签下的stream字段int indexMin;int indexMax;VolumeCurves volumeCurves;//VolumeCurve 的集合
};

2,遍历volumeGroups,结果保存到EngineBase的mVolumeGroups集合中

engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig()
{//省略for (auto &volumeConfig : result.parsedConfig->volumeGroups) {//遍历// save default volume config for streams not defined in configurationif (volumeConfig.name.compare("AUDIO_STREAM_MUSIC") == 0) {defaultVolumeConfig = volumeConfig;}if (volumeConfig.name.compare("AUDIO_STREAM_PATCH") == 0) {defaultSystemVolumeConfig = volumeConfig;}loadVolumeConfig(mVolumeGroups, volumeConfig);}//省略
}

loadVolumeConfig

engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig()
{auto loadVolumeConfig = [](auto &volumeGroups, auto &volumeConfig) {//省略sp<VolumeGroup> volumeGroup = new VolumeGroup(volumeConfig.name, volumeConfig.indexMin,volumeConfig.indexMax);//创建VolumeGroup对象volumeGroups[volumeGroup->getId()] = volumeGroup;//放入mVolumeGroups集合中for (auto &configCurve : volumeConfig.volumeCurves) {device_category deviceCat = DEVICE_CATEGORY_SPEAKER;//省略sp<VolumeCurve> curve = new VolumeCurve(deviceCat);//创建VolumeCurve对象for (auto &point : configCurve.curvePoints) {curve->add({point.index, point.attenuationInMb});}volumeGroup->add(curve);//添加到volumeGroup对象中}return volumeGroup;};

可以看出,最后,EngineBase的mVolumeGroups保存了配置文件中volume字段的信息。

3,解析ProductStrategies,保存在EngineBase的mProductStrategies集合中
在分析之前,需要先了解几个结构体
ProductStrategy

struct ProductStrategy {std::string name;AttributesGroups attributesGroups;
};

AttributesGroup

struct AttributesGroup {std::string name;audio_stream_type_t stream;std::string volumeGroup;AttributesVector attributesVect;//using AttributesVector = std::vector<audio_attributes_t>;
};

audio_attributes_t

typedef struct {audio_content_type_t content_type;audio_usage_t        usage;audio_source_t       source;audio_flags_mask_t   flags;char                 tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE]; /* UTF8 */
} __attribute__((packed)) audio_attributes_t; // sent through Binder;

gDefaultEngineConfig

//frameworks/av/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
const engineConfig::Config gDefaultEngineConfig = {1.0,gOrderedStrategies,{},{},{}
};

接着来看解析ProductStrategies的过程

engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig()
{//省略for (auto& strategyConfig : result.parsedConfig->productStrategies) {//1,,result.parsedConfig指向前面说的默认配置gDefaultEngineConfigsp<ProductStrategy> strategy = new ProductStrategy(strategyConfig.name);//1,创建ProductStrategy类对象for (const auto &group : strategyConfig.attributesGroups) {//遍历const auto &iter = std::find_if(begin(mVolumeGroups), end(mVolumeGroups),[&group](const auto &volumeGroup) {return group.volumeGroup == volumeGroup.second->getName(); });//3,根据名字查找sp<VolumeGroup> volumeGroup = nullptr;if (iter == end(mVolumeGroups)) {//没有找到的//省略} else {volumeGroup = iter->second;//找到了}addSupportedAttributesToGroup(group, volumeGroup, strategy);//4,将支持的属性添加到volumeGroup和strategy中}product_strategy_t strategyId = strategy->getId();mProductStrategies[strategyId] = strategy;//5,保存在mProductStrategies中
}

注释1处遍历的就是gOrderedStrategies 集合。注释2处,创建ProductStrategy对象时,传入的名字就是gOrderedStrategies中各元素的名字,如:“STRATEGY_PHONE”,“STRATEGY_SONIFICATION” 。注释3处,遍历前面得到的mVolumeGroups集合,根据名字进行匹配(用volumeGroup 的名字和“AUDIO_STREAM_VOICE_CALL”,“AUDIO_STREAM_BLUETOOTH_SCO”等进行匹配),找到匹配的volumeGroup 。注释4处将支持的属性添加到volumeGroup和strategy中,注释5处将该strategy保存到EngineBase的mProductStrategies集合中

//frameworks/av/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
const engineConfig::ProductStrategies gOrderedStrategies = {{"STRATEGY_PHONE",{{"phone", AUDIO_STREAM_VOICE_CALL, "AUDIO_STREAM_VOICE_CALL",{{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_VOICE_COMMUNICATION, AUDIO_SOURCE_DEFAULT, 0,""}},},{"sco", AUDIO_STREAM_BLUETOOTH_SCO, "AUDIO_STREAM_BLUETOOTH_SCO",{{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_SCO,""}},}},},{"STRATEGY_SONIFICATION",{{"ring", AUDIO_STREAM_RING, "AUDIO_STREAM_RING",{{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,AUDIO_SOURCE_DEFAULT, 0, ""}}},{"alarm", AUDIO_STREAM_ALARM, "AUDIO_STREAM_ALARM",{{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_ALARM, AUDIO_SOURCE_DEFAULT, 0, ""}},}},},//省略

继续来看一下addSupportedAttributesToGroup函数

engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig()
{//省略auto addSupportedAttributesToGroup = [](auto &group, auto &volumeGroup, auto &strategy) {for (const auto &attr : group.attributesVect) {strategy->addAttributes({group.stream, volumeGroup->getId(), attr});//保存在strategy的mAttributesVector中volumeGroup->addSupportedAttributes(attr);//保存在volumeGroup中}};//省略
}

总结一下上面得到的结果
在这里插入图片描述
除了保存在ProductStrategy中之外,还会将attr保存到匹配的volumeGroup中(根据名字匹配)

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

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

相关文章

束测后台实操文档2-OpenWrt

束测后台实操文档1-PVE、PBS 上面文&#xff0c;把proxmox装好并添加好PBS上的镜像存储空间后&#xff0c;还原已经做好的镜像基本上就可以在已有的镜像下开展工作了。 调试的PVE环境一般两个网口&#xff0c;一个外网wan&#xff0c;一个子网lan&#xff0c;虚拟机一般在lan…

特征工程技巧——OneHot编码

我们以Kaggle比赛里面的一个数据集跟一个公开代码为例去解释我们的OneHot编码。 简单来说&#xff0c;独热编码是一种将类别型变量转换为二进制表示的方法&#xff0c;其中每个类别被表示为一个向量&#xff0c;向量的长度等于类别的数量&#xff0c;其中只有一个元素为1&…

Leetcode刷题笔记6

34. 在排序数组中查找元素的第一个和最后一个位置 34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣&#xff08;LeetCode&#xff09; 解法一&#xff1a;暴力查找 [1, 2, 3, 3, 3, 4, 5] t 3 从前往后扫描暴力查找&#xff0c;最坏情况下O(N) 优化 利用数组有序的…

TCP的重传机制

TCP 是一个可靠的传输协议&#xff0c;解决了IP层的丢包、乱序、重复等问题。这其中&#xff0c;TCP的重传机制起到重要的作用。 序列号和确认号 之前我们在讲解TCP三次握手时&#xff0c;提到过TCP包头结构&#xff0c;其中有序列号和确认号&#xff0c; 而TCP 实现可靠传输…

Artifactory清理二进制文件丢失的制品

一、摘要 当制品上传到 Artifactory 时&#xff0c;Artifactory 会在数据库中记录制品的相关元数据信息&#xff0c;包括文件路径、大小、校验和&#xff08;如 MD5、SHA1&#xff09;、上传时间、索引、依赖等。实际的制品二进制文件会存储在指定的存储后端&#xff0c;具体的…

基于Java+SpringBoot+Mybaties-plus+Vue+elememt + uniapp 新闻资讯 的设计与实现

一.项目介绍 本系统分为 后端 和 小程序端 后端&#xff1a;点击登录按钮 设置个人中心、 管理员账号数据维护、 基础数据维护、 短视频信息维护(包括查看短视频留言、短视频收藏)、 论坛维护(增删改查帖子信息&#xff0c;包括查…

docker查看容器目录挂载

查看命令 docker inspect --format{{ json .Mounts }} <container_id_or_name> | jq 示例 docker inspect --format{{ json .Mounts }} af656ae540af | jq输出

一篇文章让你学会专注

专注&#xff0c;字典的释义是&#xff1a;专心注意&#xff1b;精神贯注。 我个人理解的是&#xff1a;用力屏蔽无关的事物&#xff0c;全身心力地专门注意一个事物。 你关心的&#xff0c;才能注意到&#xff0c;注意到了&#xff0c;才能故意地注意&#xff0c;进而全身心力…

【Linux-RTC】

Linux-RTC ■ rtc_device 结构体■ RTC 时间查看与设置■ 1、时间 RTC 查看■ 2、设置 RTC 时间 ■ rtc_device 结构体 Linux 内核将 RTC 设备抽象为 rtc_device 结构体 rtc_device 结构体&#xff0c;此结构体定义在 include/linux/rtc.h 文件中 ■ RTC 时间查看与设置 ■ 1…

服务器主板电池

一、什么是服务器纽扣电池&#xff1f; 服务器纽扣电池&#xff0c;也叫CMOS电池&#xff0c;是一种非常小型的电池&#xff0c;通常与服务器主板上的CMOS芯片相结合&#xff0c;用于储存BIOS设置、时钟和其他关键系统信息。这种电池的体积通常比一枚硬币还小&#xff0c;而且…

d3dcompiler43.dll丢失怎么修复,分享几种有效的修复教程

电脑已经成为我们生活中不可或缺的一部分。然而&#xff0c;由于各种原因&#xff0c;电脑可能会出现一些问题&#xff0c;其中之一就是d3dcompiler43.dll文件丢失。这个文件是DirectX组件之一&#xff0c;用于编译和链接DirectX应用程序。当这个文件丢失时&#xff0c;可能会导…

DataCube 漏洞小结

在这里分享一下通过拖取 DataCube 代码审计后发现的一些漏洞&#xff0c;包括前台的文件上传&#xff0c;信息泄露出账号密码&#xff0c;后台的文件上传。当然还有部分 SQL 注入漏洞&#xff0c;因为 DataCube 采用的是 SQLite 的数据库&#xff0c;所以SQL 注入相对来说显得就…

MAB规范(2):Introduction 介绍

Chapter1 Introduction 1.1 指南目的 MathWorks咨询委员会&#xff08;MAB&#xff09;指南规定了Simulink和Stateflow建模的重要基本规则。这些建模指南的总体目的是让建模者和控制系统模型的使用者能够简单、共同地理解。 指南的主要目标是&#xff1a; • 可读性  提高…

Ubuntu 安装好虚拟环境后,找不到workon 命令

1、安装虚拟环境 pip3 install virtualenv pip3 install virtualenvwrapper 2、安装完成后 workon 命令。 找不到workon 命令 执行&#xff0c;source virtualenvwrapper.sh 执行后&#xff0c;在使用workon命令&#xff0c;即可完成。

day-36 删除链表的倒数第 N 个结点

思路 首先计算出链表的长度&#xff0c;然后删除第n个节点即可&#xff0c;但要注意考虑特殊情况 解题方法 特殊情况&#xff1a;1.删除节点为最后一个节点 2.删除节点为头结点 Code /*** Definition for singly-linked list.* public class ListNode {* int val;* …

MySQL十部曲之九:MySQL优化理论

文章目录 前言概述查询优化查询执行计划EXPLAIN获取表结构信息获取执行计划信息 EXPLAIN 输出格式如何使用EXPLAIN进行优化 范围访问优化单列索引的范围访问多列索引的范围访问 索引合并优化索引合并交叉访问算法索引合并联合访问算法索引合并排序联合访问算法 索引下推优化连接…

使用LeanCloud平台的即时通讯

LeanCloud 是领先的 Serverless 云服务&#xff0c;为产品开发提供强有力的后端支持&#xff0c;旨在帮助开发者降低研发、运营维护等阶段投入的精力和成本。 LeanCloud 整合了各项服务&#xff0c;让开发者能够聚焦在核心业务上&#xff0c;为客户创造更多价值。 *即时通讯 …

5月29日-shell复习

一.Shell概述 1&#xff09;Linux提供的Shell解析器有&#xff1a;sudo cat /etc/shells /bin/sh /bin/bash /usr/bin/sh /usr/bin/bash /bin/tcsh /bin/csh 2&#xff09;bash和sh的关系 cd /bin ll | grep bash 或者使用&#xff1a;ls -l /bin/ | grep bash 3&#xff0…

深入pandas:数据分析

目录 前言 第一点&#xff1a;导入模块 第二点&#xff1a;准备数据 第三点&#xff1a;简单的分析数据 第四点&#xff1a;【重点】数据透支 总结 前言 在数据分析与挖掘的领域&#xff0c;了解如何使用工具和方法来探索数据是至关重要的。本文将探讨如何利用Python中的…

MAB规范(1):概览介绍

前言 MATLAB的MAAB&#xff08;MathWorks Automotive Advisory Board&#xff09;建模规范是一套由MathWorks主导的建模指南&#xff0c;旨在提高基于Simulink和Stateflow进行建模的代码质量、可读性、可维护性和可重用性。这些规范最初是由汽车行业的主要厂商共同制定的&…