赞
踩
audio_policy_configuration配置文件配置了音频Audio的设备、数据流信息,而strategy相关配置文件则配置某种streamType的音频使用哪种音量曲线,如voice_call和music他们的音量曲线是不一样,后者这种关系叫做strategy策略.
默认解析路径在/vendor/etc/audio_policy_engine_configuration.xml下,如果找不到可以去:
char* POLICY_USAGE_LIBRARY_PATH[] = {"/odm/etc/", "/vendor/etc/", "/system/etc/"};
下去寻找,解析过程同audio_policy_configuration解析一样,解析时机就在audio_policy_configuration解析完成后,初始化时就立即解析strategy部分,这里直接给出xml文件解析后对应c++实体类,解析过程不在分析,如需要了解解析过程可按照以下逻辑去查看:
- 1. EngineBase.cpp的loadAudioPolicyEngineConfig()
- 2. EngineConfig.cpp的parse()
奇怪,查看自己的手机Android11,发现没找到audio_policy_engine_configuration这个文件,难道阉割了吗?
- <volumeGroup>
- <name>voice_call</name>
- <indexMin>1</indexMin>
- <indexMax>7</indexMax>
- <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 deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
- </volumeGroup>
上面ref标签是引用了另一个文件内的内容,内容类似于这个样子:
- <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
- <!-- Default Media reference Volume Curve -->
- <point>1,-5800</point>
- <point>20,-4000</point>
- <point>60,-1700</point>
- <point>100,0</point>
- </reference>
最终结果就是每个volume标签完全是一样的,没有什么不同!
- class VolumeGroup {
- const std::string mName; //对应name标签
- const volume_group_t mId; //代码生成ID,与配置文件内容无关
- VolumeCurves mGroupVolumeCurves; //音量曲线集合,集合内为VolumeCurve类型
- }
VolumeCurves与上面VolumeGroup是包含关系,其内部结构如下:
- class VolumeCurves : public KeyedVector<device_category, sp<VolumeCurve> >,
- public IVolumeCurves {
- int mIndexMin; //对应indexMix标签
- int mIndexMax; //对应indexMax标签
- AttributesVector mAttributes; //与ProductStrategy里面绑定的strategy的attribute里面的volumeGroup,虽然这里是vector,实际上是一一对应的
- StreamTypeVector mStreams; //集合类,哪些stream可以使用我的音乐曲线类,此stream来源于product的attribute里面的streamType
- KeyedVector<device_category, sp<VolumeCurve> > mOriginVolumeCurves; //同上标签,device对应的音量曲线
- }
-
- class VolumeCurve {
- const device_category mDeviceCategory; //对应deviceCategory标签
- SortedVector<CurvePoint> mCurvePoints; //集合类型
- }
-
- struct CurvePoint
- {
- uint32_t mIndex; //对应标签point第一个值
- int mAttenuationInMb; //对应point标签第二个值
- }

最后的结果是是每个volumeGroup标签对应VolumeGroup实体类,每个volume标签对应一个VolumeCures音乐曲线类;并且和indexMix、indexMax标签组合对应成一个VolumeCurves音乐曲线集合类;主要注意两点:
许多项目里面可能没有配置audio_policy_engine_product_strategies.xml这个文件,而是使用代码里面定义好的策略,如gDefaultEngineConfig(./av/services/audiopolicy/engine/common/src/EngineDefaultConfig.h),这个全局Config和策略文件分析的结果是一致的,我们看懂了分析xml策略文件,就懂了这个gDefaultEngineConfig是啥?
- <ProductStrategy name="STRATEGY_PHONE">
- <AttributesGroup streamType="AUDIO_STREAM_VOICE_CALL" volumeGroup="voice_call">
- <Attributes> <Usage value="AUDIO_USAGE_VOICE_COMMUNICATION"/> </Attributes>
- </AttributesGroup>
- <AttributesGroup streamType="AUDIO_STREAM_BLUETOOTH_SCO" volumeGroup="bluetooth_sco">
- <Attributes> <Flags value="AUDIO_FLAG_SCO"/> </Attributes>
- </AttributesGroup>
- </ProductStrategy>
- class ProductStrategy {
- std::string mName = "STRATEGY_PHONE";
- //集合类型,但是有点特殊,针对一个Attributes标签,其内部就有1个AudioAttributes元素;有n个AudioAttributes标签,就有n个AudioAttributes元素
- AudioAttributesVector mAttributesVector;
- product_strategy_t mId; //代码自动生成
- }
-
- using AudioAttributesVector = std::vector<AudioAttributes>;
- //AudioAttributes封装了一个streamType支持某个volumeGroup
- struct AudioAttributes {
- audio_stream_type_t mStream ; //对应streamType标签
- volume_group_t mVolumeGroup ; //支持音乐曲线group的id,指向上面的VolumeGroup实体类对象的id
- audio_attributes_t mAttributes; //对应一个Attributes标签
- };
- //对应一个Attributes标签标签里面的内容,content_type,usage等等
- 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;

这里有点奇怪,AudioAttributesVector内部元素有多少,是根据Attributes标签来的,有多个标签,就有多少个AudioAttributes,并且每个AudioAttributes类型里面指向了当前streamType支持哪些音乐曲线;Attributes标签内部的内容主要是指明stream的用途,如AUDIO_USAGE_VOICE_COMMUNICATION是用于语音通话;最后联系图如下:
针对ProductStrategy来说
针对VolumeGroup来说
ProductStrategy策略实体类表示内部有多个AudioAttributes属性集合,这个AudioAttributes表示特定的streamType和mAttributes的音频支持特定的音乐属性VolumeGroup,通过AudioAttributes的mVolumeGroup成员变量与VolumeGroup的mId成员相等建立连接,而VolumeGroup内也有多个VolumeCurve音乐曲线属性集合,可以任由AudioAttributes来选择
通常我们在播放音频时,我们会指定音频的content_type、usage等等attr属性,通过这些属性决定这个音频是哪个streamType?
这个过程就是上面的文件配置好的,转化为c++实体类建立好映射,在ProductStrategy实体类的AudioAttributes成员的audio_attributes_t mAttributes成员,封装了音频的content_type、usage等等,找到这个就能决定它是哪个streamType,以及后续的工作
从实际项目出发,在odm、vendor、system的etc配置目录下,发现的strategy、volume配置相关的文件,有的是缺少strategy配置文件,有的volume音量曲线文件不是按照以下这种格式:
- <volumeGroup>
- <name>voice_call</name>
- <indexMin>1</indexMin>
- <indexMax>7</indexMax>
- <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 deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
- </volumeGroup>
这种很明显的指定了volumeGroup的name、indexMin、indexMax和volume-point,而是以下面这种格式来配置:
- <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_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_EARPIECE">
- <point>0,-2400</point>
- <point>33,-1600</point>
- <point>66,-800</point>
- <point>100,0</point>
- </volume>
- .....

这种以volumes标签开头,没有找到volumeGroup标签,那按照我上面的解析xml的阐述,岂不是错误的,一开始我也不是很理解,后面找到了这段代码才开始释怀了,如下c++:
- engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig()
- {
- .......
- //我们这个这个项目没有audio_policy_engine_product_strategies的配置文件
- auto result = engineConfig::parse();
- if (result.parsedConfig == nullptr) {
- ALOGW("%s: No configuration found, using default matching phone experience.", __FUNCTION__);
- //所以使用默认的gDefaultEngineConfig
- engineConfig::Config config = gDefaultEngineConfig;
- android::status_t ret = engineConfig::parseLegacyVolumes(config.volumeGroups);
- result = {std::make_unique<engineConfig::Config>(config),
- static_cast<size_t>(ret == NO_ERROR ? 0 : 1)};
- }
- ALOGE_IF(result.nbSkippedElement != 0, "skipped %zu elements", result.nbSkippedElement);
- loadVolumeGroups(result.parsedConfig->volumeGroups, mVolumeGroups);
- loadProductStrategies(result.parsedConfig->productStrategies, mProductStrategies,
- mVolumeGroups);
- mProductStrategies.initialize();
- return result;
- }

如上代码,在if条件中,如果parseConfig解析的结果为空,也就是我们上面的文件找不到,没有解析到正确的audio config相关文件,就会使用默认的gDefaultEngineConfig和parseLegacyVolumes,在parseLegacyVolumes函数中,会依次调用parseLegacyVolumeFile -->> deserializeLegacyVolumeCollection函数:
- static constexpr const char *legacyVolumecollectionTag = "volumes";
-
- 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)) {
- continue;
- }
- const xmlNode *child = cur->xmlChildrenNode;
- for (; child != NULL; child = child->next) {
- //legacyVolumeTag = volume
- if (!xmlStrcmp(child->name, (const xmlChar *)legacyVolumeTag)) {
-
- status_t status = deserializeLegacyVolume(doc, child, legacyVolumeMap);
- if (status != NO_ERROR) {
- nbSkippedElement += 1;
- }
- }
- }
- }
- for (const auto &volumeMapIter : legacyVolumeMap) {
- // In order to let AudioService setting the min and max (compatibility), set Min and Max
- // to -1 except for private streams
- audio_stream_type_t streamType;
- if (!StreamTypeConverter::fromString(volumeMapIter.first, streamType)) {
- ALOGE("%s: Invalid stream %s", __func__, volumeMapIter.first.c_str());
- return BAD_VALUE;
- }
- 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 });
- }
- return NO_ERROR;
- }

上面这段代码就是解析文件开头以<volumes>标签开头,这不正好就是我们上面那个配置文件开头吗?也就是说明这段代码就是应对上面那种配置文件开头的,最后解析得到legacyVolumeMap结构如下:
而volumeGroups是一个vector数组集合,其中的每一个元素是volumeGroup,volumeGroup的内容大致由以下内容组成:
如上,最终解析的结果对得上,无论哪种audio配置文件,Android都提供对应的解析方法,保障最后得到的数据。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。