当前位置:   article > 正文

Audio解析strategy配置文件_productstrategy audio中

productstrategy audio中

Audio解析strategy配置文件

简介

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. 1. EngineBase.cpploadAudioPolicyEngineConfig()
  2. 2. EngineConfig.cppparse()

奇怪,查看自己的手机Android11,发现没找到audio_policy_engine_configuration这个文件,难道阉割了吗?

配置文件与实体类

audio_policy_engine_default_stream_volumes.xml

  1. <volumeGroup>
  2. <name>voice_call</name>
  3. <indexMin>1</indexMin>
  4. <indexMax>7</indexMax>
  5. <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_HEADSET">
  6. <point>0,-4200</point>
  7. <point>33,-2800</point>
  8. <point>66,-1400</point>
  9. <point>100,0</point>
  10. </volume>
  11. <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
  12. </volumeGroup>

上面ref标签是引用了另一个文件内的内容,内容类似于这个样子:

  1. <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
  2. <!-- Default Media reference Volume Curve -->
  3. <point>1,-5800</point>
  4. <point>20,-4000</point>
  5. <point>60,-1700</point>
  6. <point>100,0</point>
  7. </reference>

最终结果就是每个volume标签完全是一样的,没有什么不同!

实体类

  1. class VolumeGroup {
  2. const std::string mName; //对应name标签
  3. const volume_group_t mId; //代码生成ID,与配置文件内容无关
  4. VolumeCurves mGroupVolumeCurves; //音量曲线集合,集合内为VolumeCurve类型
  5. }

VolumeCurves与上面VolumeGroup是包含关系,其内部结构如下:

  1. class VolumeCurves : public KeyedVector<device_category, sp<VolumeCurve> >,
  2. public IVolumeCurves {
  3. int mIndexMin; //对应indexMix标签
  4. int mIndexMax; //对应indexMax标签
  5. AttributesVector mAttributes; //与ProductStrategy里面绑定的strategy的attribute里面的volumeGroup,虽然这里是vector,实际上是一一对应的
  6. StreamTypeVector mStreams; //集合类,哪些stream可以使用我的音乐曲线类,此stream来源于product的attribute里面的streamType
  7. KeyedVector<device_category, sp<VolumeCurve> > mOriginVolumeCurves; //同上标签,device对应的音量曲线
  8. }
  9. class VolumeCurve {
  10. const device_category mDeviceCategory; //对应deviceCategory标签
  11. SortedVector<CurvePoint> mCurvePoints; //集合类型
  12. }
  13. struct CurvePoint
  14. {
  15. uint32_t mIndex; //对应标签point第一个值
  16. int mAttenuationInMb; //对应point标签第二个值
  17. }

最后的结果是是每个volumeGroup标签对应VolumeGroup实体类,每个volume标签对应一个VolumeCures音乐曲线类;并且和indexMix、indexMax标签组合对应成一个VolumeCurves音乐曲线集合类;主要注意两点:

  1. VolumeCurves是一个Vector集合类型,内部元素是VolumeCurve类型
  2. VolumeCurves的mStreams也是集合类型,会与后面的strategies配置文件中的streamType联系在一起,表明我这些音乐曲线支持哪些streamType

audio_policy_engine_product_strategies.xml策略文件

许多项目里面可能没有配置audio_policy_engine_product_strategies.xml这个文件,而是使用代码里面定义好的策略,如gDefaultEngineConfig(./av/services/audiopolicy/engine/common/src/EngineDefaultConfig.h),这个全局Config和策略文件分析的结果是一致的,我们看懂了分析xml策略文件,就懂了这个gDefaultEngineConfig是啥?

  1. <ProductStrategy name="STRATEGY_PHONE">
  2. <AttributesGroup streamType="AUDIO_STREAM_VOICE_CALL" volumeGroup="voice_call">
  3. <Attributes> <Usage value="AUDIO_USAGE_VOICE_COMMUNICATION"/> </Attributes>
  4. </AttributesGroup>
  5. <AttributesGroup streamType="AUDIO_STREAM_BLUETOOTH_SCO" volumeGroup="bluetooth_sco">
  6. <Attributes> <Flags value="AUDIO_FLAG_SCO"/> </Attributes>
  7. </AttributesGroup>
  8. </ProductStrategy>

ProductStrategy实体类

  1. class ProductStrategy {
  2. std::string mName = "STRATEGY_PHONE";
  3. //集合类型,但是有点特殊,针对一个Attributes标签,其内部就有1个AudioAttributes元素;有n个AudioAttributes标签,就有n个AudioAttributes元素
  4. AudioAttributesVector mAttributesVector;
  5. product_strategy_t mId; //代码自动生成
  6. }
  7. using AudioAttributesVector = std::vector<AudioAttributes>;
  8. //AudioAttributes封装了一个streamType支持某个volumeGroup
  9. struct AudioAttributes {
  10. audio_stream_type_t mStream ; //对应streamType标签
  11. volume_group_t mVolumeGroup ; //支持音乐曲线group的id,指向上面的VolumeGroup实体类对象的id
  12. audio_attributes_t mAttributes; //对应一个Attributes标签
  13. };
  14. //对应一个Attributes标签标签里面的内容,content_typeusage等等
  15. typedef struct {
  16. audio_content_type_t content_type;
  17. audio_usage_t usage;
  18. audio_source_t source;
  19. audio_flags_mask_t flags;
  20. char tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE]; /* UTF8 */
  21. } __attribute__((packed)) audio_attributes_t; // sent through Binder;

这里有点奇怪,AudioAttributesVector内部元素有多少,是根据Attributes标签来的,有多个标签,就有多少个AudioAttributes,并且每个AudioAttributes类型里面指向了当前streamType支持哪些音乐曲线;Attributes标签内部的内容主要是指明stream的用途,如AUDIO_USAGE_VOICE_COMMUNICATION是用于语音通话;最后联系图如下:
在这里插入图片描述

针对ProductStrategy来说

  • 每一个ProductStrategy标签对应一个实体类ProductStrategy
  • 每一个Attributes标签对应一个AudioAttributes结构体,结构体内部mStream代表streamType标签,mAttributes代表Attributes标签,mVolumeGroup是一个id,与VolumeGroup对象的id建立连接

针对VolumeGroup来说

  • 每个volumeGroup标签对应一个volumeGroup实体类,并且有一个mId成员
  • 每个volume标签对应一个VolumeCurve实体类
  • VolumeCurves实体类是集合类型,集合内元素是VolumeCurve实体类,并且是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音量曲线文件不是按照以下这种格式:

  1. <volumeGroup>
  2. <name>voice_call</name>
  3. <indexMin>1</indexMin>
  4. <indexMax>7</indexMax>
  5. <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_HEADSET">
  6. <point>0,-4200</point>
  7. <point>33,-2800</point>
  8. <point>66,-1400</point>
  9. <point>100,0</point>
  10. </volume>
  11. <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
  12. </volumeGroup>

这种很明显的指定了volumeGroup的name、indexMin、indexMax和volume-point,而是以下面这种格式来配置:

  1. <volumes>
  2. <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_HEADSET">
  3. <point>0,-4200</point>
  4. <point>33,-2800</point>
  5. <point>66,-1400</point>
  6. <point>100,0</point>
  7. </volume>
  8. <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_SPEAKER">
  9. <point>0,-2400</point>
  10. <point>33,-1600</point>
  11. <point>66,-800</point>
  12. <point>100,0</point>
  13. </volume>
  14. <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_EARPIECE">
  15. <point>0,-2400</point>
  16. <point>33,-1600</point>
  17. <point>66,-800</point>
  18. <point>100,0</point>
  19. </volume>
  20. .....

这种以volumes标签开头,没有找到volumeGroup标签,那按照我上面的解析xml的阐述,岂不是错误的,一开始我也不是很理解,后面找到了这段代码才开始释怀了,如下c++:

  1. engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig()
  2. {
  3. .......
  4. //我们这个这个项目没有audio_policy_engine_product_strategies的配置文件
  5. auto result = engineConfig::parse();
  6. if (result.parsedConfig == nullptr) {
  7. ALOGW("%s: No configuration found, using default matching phone experience.", __FUNCTION__);
  8. //所以使用默认的gDefaultEngineConfig
  9. engineConfig::Config config = gDefaultEngineConfig;
  10. android::status_t ret = engineConfig::parseLegacyVolumes(config.volumeGroups);
  11. result = {std::make_unique<engineConfig::Config>(config),
  12. static_cast<size_t>(ret == NO_ERROR ? 0 : 1)};
  13. }
  14. ALOGE_IF(result.nbSkippedElement != 0, "skipped %zu elements", result.nbSkippedElement);
  15. loadVolumeGroups(result.parsedConfig->volumeGroups, mVolumeGroups);
  16. loadProductStrategies(result.parsedConfig->productStrategies, mProductStrategies,
  17. mVolumeGroups);
  18. mProductStrategies.initialize();
  19. return result;
  20. }

如上代码,在if条件中,如果parseConfig解析的结果为空,也就是我们上面的文件找不到,没有解析到正确的audio config相关文件,就会使用默认的gDefaultEngineConfig和parseLegacyVolumes,在parseLegacyVolumes函数中,会依次调用parseLegacyVolumeFile -->> deserializeLegacyVolumeCollection函数:

  1. static constexpr const char *legacyVolumecollectionTag = "volumes";
  2. static status_t deserializeLegacyVolumeCollection(_xmlDoc *doc, const _xmlNode *cur,
  3. VolumeGroups &volumeGroups,
  4. size_t &nbSkippedElement)
  5. {
  6. std::map<std::string, VolumeCurves> legacyVolumeMap;
  7. for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
  8. if (xmlStrcmp(cur->name, (const xmlChar *)legacyVolumecollectionTag)) {
  9. continue;
  10. }
  11. const xmlNode *child = cur->xmlChildrenNode;
  12. for (; child != NULL; child = child->next) {
  13. //legacyVolumeTag = volume
  14. if (!xmlStrcmp(child->name, (const xmlChar *)legacyVolumeTag)) {
  15. status_t status = deserializeLegacyVolume(doc, child, legacyVolumeMap);
  16. if (status != NO_ERROR) {
  17. nbSkippedElement += 1;
  18. }
  19. }
  20. }
  21. }
  22. for (const auto &volumeMapIter : legacyVolumeMap) {
  23. // In order to let AudioService setting the min and max (compatibility), set Min and Max
  24. // to -1 except for private streams
  25. audio_stream_type_t streamType;
  26. if (!StreamTypeConverter::fromString(volumeMapIter.first, streamType)) {
  27. ALOGE("%s: Invalid stream %s", __func__, volumeMapIter.first.c_str());
  28. return BAD_VALUE;
  29. }
  30. int indexMin = streamType >= AUDIO_STREAM_PUBLIC_CNT ? 0 : -1;
  31. int indexMax = streamType >= AUDIO_STREAM_PUBLIC_CNT ? 100 : -1;
  32. volumeGroups.push_back({ volumeMapIter.first, indexMin, indexMax, volumeMapIter.second });
  33. }
  34. return NO_ERROR;
  35. }

上面这段代码就是解析文件开头以<volumes>标签开头,这不正好就是我们上面那个配置文件开头吗?也就是说明这段代码就是应对上面那种配置文件开头的,最后解析得到legacyVolumeMap结构如下:
在这里插入图片描述
而volumeGroups是一个vector数组集合,其中的每一个元素是volumeGroup,volumeGroup的内容大致由以下内容组成:
在这里插入图片描述
如上,最终解析的结果对得上,无论哪种audio配置文件,Android都提供对应的解析方法,保障最后得到的数据。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码探险家/article/detail/875968
推荐阅读
相关标签
  

闽ICP备14008679号