[audio] AudioTrack (三) dumpsys media.audio_policy

https://blog.youkuaiyun.com/we1less/article/details/156362906?spm=1001.2014.3001.5502
        继续分析上文中提到的  dumpsys media.audio_policy 

        streamType 是如何从老版本转向新版本的 mContentType mUsage

这个方法就是使用 LegacyStreamType 根据传进来的 streamType 参数获取 mUsage

这里的策略可以使用 dumpsys media.audio_policy 查看


dumpsys media.audio_policy 

主要分析两部分        

        Product Strategies dump:产品策略

        Volume Groups dump:音频曲线

Policy Engine dump:

  Product Strategies dump:
    -STRATEGY_PHONE (id: 0)
      Selected Device: {AUDIO_DEVICE_OUT_EARPIECE, @:}
       Group: 13 stream: AUDIO_STREAM_VOICE_CALL
        Attributes: { Content type: AUDIO_CONTENT_TYPE_UNKNOWN Usage: AUDIO_USAGE_VOICE_COMMUNICATION Source: AUDIO_SOURCE_INVALID Flags: 0x0 Tags:  }
       Group: 3 stream: AUDIO_STREAM_BLUETOOTH_SCO
        Attributes: { Content type: AUDIO_CONTENT_TYPE_UNKNOWN Usage: AUDIO_USAGE_UNKNOWN Source: AUDIO_SOURCE_INVALID Flags: 0x4 Tags:  }

//...

  Volume Groups dump:
    -AUDIO_STREAM_ACCESSIBILITY (id: 1)
      Volume Curves Streams/Attributes, Curve points Streams for device category (index, attenuation in millibel)
       Streams: AUDIO_STREAM_ACCESSIBILITY(10)  
       Attributes: { Content type: AUDIO_CONTENT_TYPE_UNKNOWN Usage: AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY Source: AUDIO_SOURCE_DEFAULT Flags: 0x0 Tags:  }
       DEVICE_CATEGORY_HEADSET : { (  0, -5800),  ( 20, -4000),  ( 60, -1700),  (100,     0) }
       DEVICE_CATEGORY_SPEAKER : { (  0, -5800),  ( 20, -4000),  ( 60, -1700),  (100,     0) }
       DEVICE_CATEGORY_EARPIECE : { (  0, -5800),  ( 20, -4000),  ( 60, -1700),  (100,     0) }
       DEVICE_CATEGORY_EXT_MEDIA : { (  0, -5800),  ( 20, -4000),  ( 60, -1700),  (100,     0) }
       DEVICE_CATEGORY_HEARING_AID : { (  0, -12700),  ( 20, -8000),  ( 60, -4000),  (100,     0) }
        Can be muted  Index Min  Index Max  Index Cur [device : index]...
        true          01         15         0002 : 06, 0080 : 02, 0100 : 02, 4000000 : 05, 20000000 : 02, 20000002 : 02, 40000000 : 06, 

//...


这些信息是如何被装载的呢


产品策略 Product Strategies

av/services/audiopolicy/engine/common/src/EngineBase.cpp

        这个函数的 xmlFilePath 入参为空,

        engineConfig::DEFAULT_PATH  这个在设备中也没有

constexpr char DEFAULT_PATH[] = "/vendor/etc/audio_policy_engine_configuration.xml";

        所以使用的是 gDefaultEngineConfig

engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig(
        const std::string& xmlFilePath, bool isConfigurable)
{
//...

    const std::string filePath = xmlFilePath.empty() ? engineConfig::DEFAULT_PATH : xmlFilePath;
    engineConfig::ParsingResult result =
            fileExists(filePath.c_str()) ?
            engineConfig::parse(filePath.c_str(), isConfigurable) : engineConfig::ParsingResult{};
    if (result.parsedConfig == nullptr) {

        ALOGD("%s: No configuration found, using default matching phone experience.", __FUNCTION__);

        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)};
    } else {
        //...
    }

//...
    return processParsingResult(std::move(result));
}

av/services/audiopolicy/engine/common/src/EngineDefaultConfig.h  gDefaultEngineConfig

        可以看到产品策略的信息 Product Strategies 是在代码里面写死的

        可以使用 xml 进行配置,参考

av/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_configuration.xml

const engineConfig::Config gDefaultEngineConfig = {
    1.0,
    gOrderedStrategies,
    {},
    {},
    {}
};


const engineConfig::ProductStrategies gOrderedStrategies = {
    {"STRATEGY_PHONE", STRATEGY_PHONE,
     {
         {AUDIO_STREAM_VOICE_CALL, "AUDIO_STREAM_VOICE_CALL",
          {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_VOICE_COMMUNICATION, AUDIO_SOURCE_DEFAULT,
            AUDIO_FLAG_NONE, ""}},
         },
         {AUDIO_STREAM_BLUETOOTH_SCO, "AUDIO_STREAM_BLUETOOTH_SCO",
          {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_SCO,
            ""}},
         }
     },
    },
//...
//...
};

av/services/audiopolicy/engine/config/include/EngineConfig.h  ProductStrategies

        是一个链表类型,是 ProductStrategy 的集合

using ProductStrategies = std::vector<ProductStrategy>;

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

using AttributesGroups = std::vector<AttributesGroup>;

struct AttributesGroup {
    audio_stream_type_t stream;
    std::string volumeGroup;
    AttributesVector attributesVect;
};

using AttributesVector = std::vector<audio_attributes_t>;


// audio_attributes_t 定义 
// media/audio/include/system/audio.h

static const audio_attributes_t AUDIO_ATTRIBUTES_INITIALIZER = {
    /* .content_type = */ AUDIO_CONTENT_TYPE_UNKNOWN,
    /* .usage = */ AUDIO_USAGE_UNKNOWN,
    /* .source = */ AUDIO_SOURCE_DEFAULT,
    /* .flags = */ AUDIO_FLAG_NONE,
    /* .tags = */ ""
};

// #### 对应关系 

// ProductStrategies 对应 ProductStrategies = std::vector<ProductStrategy>;

const engineConfig::ProductStrategies gOrderedStrategies = {

// 这一层元素对应 ProductStrategy 结构体
// ProductStrategy::name 对应 "STRATEGY_MEDIA"
// ProductStrategy::id 对应 STRATEGY_MEDIA

    {"STRATEGY_MEDIA", STRATEGY_MEDIA,

        {  // ProductStrategy::AttributesGroups 集合

// 这一层元素对应 AttributesGroup 结构体
// AttributesGroup::audio_stream_type_t 对应 AUDIO_STREAM_MUSIC
// AttributesGroup::volumeGroup 对应 "AUDIO_STREAM_MUSIC"

            {AUDIO_STREAM_MUSIC, "AUDIO_STREAM_MUSIC",

                {    // ProductStrategy::AttributesGroups 集合

// 这一层元素对应 audio_attributes_t 结构体

                    {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_MEDIA, AUDIO_SOURCE_DEFAULT,
               AUDIO_FLAG_NONE, ""},
                    {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_GAME, AUDIO_SOURCE_DEFAULT,
               AUDIO_FLAG_NONE, ""},
                },
            },
            {AUDIO_STREAM_SYSTEM, "AUDIO_STREAM_SYSTEM",
                {
                    {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_ASSISTANCE_SONIFICATION,
            AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""}
                },
            }
        },
    },


//...
}

// ProductStrategy::id 参考路径
// av/services/audiopolicy/common/include/policy.h

#define AUDIO_LEGACY_STRATEGY_LIST_DEF(V)      \
    V(STRATEGY_NONE, -1)                       \
    V(STRATEGY_PHONE, 0)                       \
    V(STRATEGY_SONIFICATION, 1)                \
    V(STRATEGY_ENFORCED_AUDIBLE, 2)            \
    V(STRATEGY_ACCESSIBILITY, 3)               \
    V(STRATEGY_SONIFICATION_RESPECTFUL, 4)     \
    V(STRATEGY_MEDIA, 5)                       \
    V(STRATEGY_DTMF, 6)                        \
    V(STRATEGY_CALL_ASSISTANT, 7)              \
    V(STRATEGY_TRANSMITTED_THROUGH_SPEAKER, 8) \
    V(STRATEGY_REROUTING, 9)                   \
    V(STRATEGY_PATCH, 10)


音频曲线 Volume Groups

av/services/audiopolicy/engine/config/src/EngineConfig.cpp

        调用 audio_get_audio_policy_config_file

android::status_t parseLegacyVolumes(VolumeGroups &volumeGroups) {
    if (std::string audioPolicyXmlConfigFile = audio_get_audio_policy_config_file();
            !audioPolicyXmlConfigFile.empty()) {
        return parseLegacyVolumeFile(audioPolicyXmlConfigFile.c_str(), volumeGroups);
    } else {
        ALOGE("No readable audio policy config file found");
        return BAD_VALUE;
    }
}

media/audio/include/system/audio_config.h

        vendor/etc/audio_policy_configuration.xml

static inline std::string audio_get_audio_policy_config_file() {
    static constexpr const char *apmXmlConfigFileName = "audio_policy_configuration.xml";
    static constexpr const char *apmA2dpOffloadDisabledXmlConfigFileName =
            "audio_policy_configuration_a2dp_offload_disabled.xml";
    static constexpr const char *apmLeOffloadDisabledXmlConfigFileName =
            "audio_policy_configuration_le_offload_disabled.xml";
    static constexpr const char *apmBluetoothLegacyHalXmlConfigFileName =
            "audio_policy_configuration_bluetooth_legacy_hal.xml";

    std::string audioPolicyXmlConfigFile;
    // First try alternative files if needed
    if (property_get_bool("ro.bluetooth.a2dp_offload.supported", false)) {
        if (property_get_bool("persist.bluetooth.bluetooth_audio_hal.disabled", false) &&
            property_get_bool("persist.bluetooth.a2dp_offload.disabled", false)) {
            // Both BluetoothAudio@2.0 and BluetoothA2dp@1.0 (Offload) are disabled, and uses
            // the legacy hardware module for A2DP and hearing aid.
            audioPolicyXmlConfigFile = audio_find_readable_configuration_file(
                    apmBluetoothLegacyHalXmlConfigFileName);
        } else if (property_get_bool("persist.bluetooth.a2dp_offload.disabled", false)) {
            // A2DP offload supported but disabled: try to use special XML file
            // assume that if a2dp offload is not supported, le offload is not supported as well
            audioPolicyXmlConfigFile = audio_find_readable_configuration_file(
                    apmA2dpOffloadDisabledXmlConfigFileName);
        } else if (!property_get_bool("ro.bluetooth.leaudio_offload.supported", false) ||
            property_get_bool("persist.bluetooth.leaudio_offload.disabled", false)) {
            // A2DP offload supported but LE offload disabled: try to use special XML file
            audioPolicyXmlConfigFile = audio_find_readable_configuration_file(
                    apmLeOffloadDisabledXmlConfigFileName);
        }
    } else if (property_get_bool("persist.bluetooth.bluetooth_audio_hal.disabled", false)) {
        audioPolicyXmlConfigFile = audio_find_readable_configuration_file(
                apmBluetoothLegacyHalXmlConfigFileName);
    } else {
        audioPolicyXmlConfigFile = audio_find_readable_configuration_file(
                apmA2dpOffloadDisabledXmlConfigFileName);
    }
    return audioPolicyXmlConfigFile.empty() ?
            audio_find_readable_configuration_file(apmXmlConfigFileName) : audioPolicyXmlConfigFile;
}

vendor/etc/audio_policy_configuration.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">

    <!-- Volume section -->

    <xi:include href="/vendor/etc/audio_policy_volumes.xml"/>
    <xi:include href="/vendor/etc/default_volume_tables.xml"/>

    <!-- End of Volume section -->

</audioPolicyConfiguration>

vendor/etc/audio_policy_volumes.xml

<?xml version="1.0" encoding="UTF-8"?>

<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_TTS" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
                                      ref="SILENT_VOLUME_CURVE"/>
<!-- ... -->

</volumes>

/vendor/etc/default_volume_tables.xml

<?xml version="1.0" encoding="UTF-8"?>

<volumes>

<!-- ... -->
    <reference name="SILENT_VOLUME_CURVE">
        <point>0,-9600</point>
        <point>100,-9600</point>
    </reference>

<!-- ... -->

</volumes>

av/services/audiopolicy/engine/config/src/EngineConfig.cpp  parseLegacyVolumeFile

android::status_t parseLegacyVolumeFile(const char* path, VolumeGroups &volumeGroups) {

//...

    return deserializeLegacyVolumeCollection(doc.get(), cur, volumeGroups, nbSkippedElements);

}


// 入参 装载 volumeGroups
static status_t deserializeLegacyVolumeCollection(_xmlDoc *doc, const _xmlNode *cur,
                                                  VolumeGroups &volumeGroups,
                                                  size_t &nbSkippedElement)
{
    //填充的legacyVolumeMap

    std::map<std::string, VolumeCurves> legacyVolumeMap;

    for (...) {


        for (...) {
            if (!xmlStrcmp(child->name, (const xmlChar *)legacyVolumeTag)) {

                status_t status = deserializeLegacyVolume(doc, child, legacyVolumeMap);


            }
        }
    }

    VolumeGroups tempVolumeGroups = volumeGroups;

    for (legacyVolumeMap) {

        audio_stream_type_t streamType;
            // 对应第一个元素 stream
            StreamTypeConverter::fromString(volumeMapIter.first, streamType)

        int indexMin = streamType >= AUDIO_STREAM_PUBLIC_CNT ? 0 : -1;
        int indexMax = streamType >= AUDIO_STREAM_PUBLIC_CNT ? 100 : -1;

// 把结果装载到 tempVolumeGroups

        tempVolumeGroups.push_back(
                { volumeMapIter.first, indexMin, indexMax, volumeMapIter.second });
    }

    return NO_ERROR;
}


//入参 根据 xml 装载 legacyVolumeMap

status_t deserializeLegacyVolume(_xmlDoc *doc, const _xmlNode *cur,
                                 std::map<std::string, VolumeCurves> &legacyVolumes)
{
    std::string streamTypeLiteral = getXmlAttribute(cur, "stream");

    std::string deviceCategoryLiteral = getXmlAttribute(cur, "deviceCategory");


    CurvePoints curvePoints;

    for (...) {
        
            curvePoints.push_back({point[0], point[1]});
        }
    }

// legacyVolumes 类型 std::map<std::string, VolumeCurves> &legacyVolumes

    legacyVolumes[streamTypeLiteral].push_back({ deviceCategoryLiteral, curvePoints });
 
    return NO_ERROR;
}

// VolumeCurves 参考
// av/services/audiopolicy/engine/config/include/EngineConfig.h

using VolumeGroups = std::vector<VolumeGroup>;

struct VolumeGroup {
    std::string name;
    int indexMin;
    int indexMax;
    VolumeCurves volumeCurves;
};

using VolumeCurves = std::vector<VolumeCurve>;

struct VolumeCurve {
    std::string deviceCategory;

    CurvePoints curvePoints;

};

using CurvePoints = std::vector<CurvePoint>;

struct CurvePoint {
    int index;
    int attenuationInMb;
};

// /vendor/etc/audio_policy_volumes.xml

<volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER">
    <point>1,-6600</point>
    <point>30,-2000</point>
    <point>85,-800</point>
    <point>100,0</point>
</volume>


现在两个结构体都被填充完毕了,回到最开始解析的地方

av/services/audiopolicy/engine/common/src/EngineBase.cpp

        首先看入参是怎么装载的

        engineConfig::Config config = gDefaultEngineConfig; 这里面包含了 Product Strategies

        config.volumeGroups 这里面包含了 Volume Groups

        调用 processParsingResult 入参 config

engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig(
        const std::string& xmlFilePath, bool isConfigurable)
{

    engineConfig::Config config = gDefaultEngineConfig;

    engineConfig::parseLegacyVolumes(config.volumeGroups);
    
    result = {std::make_unique<engineConfig::Config>(config),
                  static_cast<size_t>(ret == NO_ERROR ? 0 : 1)};

    return processParsingResult(std::move(result));
}

        loadVolumeConfig 函数,将上述装载的 config.volumeGroups 结构体结合转换为 VolumeGroup 类,将音频曲线转换成 VolumeCurve 装进 volumeGroup 中,最终放在 volumeGroups

        执行 loadVolumeConfig 装载到 mVolumeGroups

        找到 name 一样的,ProductStrategy::AttributesGroup::volumeGroup == volumeGroup::name

        addSupportedAttributesToGroup 函数,将 Attributes 关联到 volumeGroup

        将关联好后的 ProductStrategy 装载到 mProductStrategies

engineConfig::ParsingResult EngineBase::processParsingResult(
        engineConfig::ParsingResult&& rawResult)
{

    auto loadVolumeConfig = [](auto &volumeGroups, auto &volumeConfig) {
            sp<VolumeGroup> volumeGroup = new VolumeGroup(volumeConfig.name, volumeConfig.indexMin,
                                                      volumeConfig.indexMax);

            // 将上述装载的 config.volumeGroups 结构体转换为 VolumeGroup 类,最终放在 volumeGroups 中

            volumeGroups[volumeGroup->getId()] = volumeGroup;

            for (auto &configCurve : volumeConfig.volumeCurves) {

                sp<VolumeCurve> curve = new VolumeCurve(deviceCat);

                for (auto &point : configCurve.curvePoints) {
                    curve->add({point.index, point.attenuationInMb});
                }
                //将音频曲线转换成 VolumeCurve 塞进 volumeGroup 中
                volumeGroup->add(curve);
            }

        return volumeGroup;
    };

    auto addSupportedAttributesToGroup = [](auto &group, auto &volumeGroup, auto &strategy) {
        // 将 Attributes 关联到 volumeGroup
    };
    
// 执行 loadVolumeConfig 装载到 mVolumeGroups
// 参考 av/services/audiopolicy/engine/common/include/EngineBase.h 
// VolumeGroupMap mVolumeGroups;

    for (auto &volumeConfig : result.parsedConfig->volumeGroups) {
        loadVolumeConfig(mVolumeGroups, volumeConfig);
    }

    // 构造 ProductStrategy
    for (auto& strategyConfig : result.parsedConfig->productStrategies) {

        sp<ProductStrategy> strategy = new ProductStrategy(strategyConfig.name, strategyConfig.id);
    
        // 找到name一样的 
        // ProductStrategy::AttributesGroup::volumeGroup == volumeGroup::name
    
        // <volume stream="AUDIO_STREAM_MUSIC"> ==  {AUDIO_STREAM_MUSIC, "AUDIO_STREAM_MUSIC",

        const auto &iter = std::find_if(begin(mVolumeGroups), end(mVolumeGroups),
                                         [&group](const auto &volumeGroup) {
                    return group.volumeGroup == volumeGroup.second->getName(); });

        if (iter == end(mVolumeGroups)) {
            //找不到
        } else {
            // 这样根据这个 name 就能锁定音频曲线了
            volumeGroup = iter->second;
        }

        addSupportedAttributesToGroup(group, volumeGroup, strategy);

        // 参考 av/services/audiopolicy/engine/common/include/EngineBase.h 
        // ProductStrategyMap mProductStrategies;
        mProductStrategies[strategyId] = strategy;

    }

    mProductStrategies.initialize();
    return result;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值