Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b7f45516 authored by Mikhail Naganov's avatar Mikhail Naganov Committed by Automerger Merge Worker
Browse files

Merge changes from topic "CAP_AIDL_AUDIO_HAL" into main am: 6e26bafe

parents 1a8da88a 6e26bafe
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -32,10 +32,12 @@ cc_library {
    header_libs: [
        "libbase_headers",
        "libsystem_headers",
        "libutils_headers",
    ],
    export_header_lib_headers: [
        "libbase_headers",
        "libsystem_headers",
        "libutils_headers",
    ],
    srcs: [
        "StreamWorker.cpp",
+6 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
#include <aidl/android/media/audio/common/AudioPolicyForcedConfig.h>
#include <aidl/android/media/audio/common/PcmType.h>
#include <android/binder_auto_utils.h>
#include <utils/FastStrcmp.h>

namespace ndk {

@@ -87,6 +88,11 @@ constexpr std::array<::aidl::android::media::audio::common::AudioPolicyForcedCon
                ::aidl::android::media::audio::common::AudioPolicyForcedConfig::BT_BLE,
};

constexpr bool iequals(const std::string& str1, const std::string& str2) {
    return str1.length() == str2.length() &&
           !fasticmp<strncmp>(str1.c_str(), str2.c_str(), str1.length());
}

constexpr size_t getPcmSampleSizeInBytes(::aidl::android::media::audio::common::PcmType pcm) {
    using ::aidl::android::media::audio::common::PcmType;
    switch (pcm) {
+4 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ cc_library {
        "AidlConversionXsdc.cpp",
        "AudioPolicyConfigXmlConverter.cpp",
        "Bluetooth.cpp",
        "CapEngineConfigXmlConverter.cpp",
        "Config.cpp",
        "Configuration.cpp",
        "EngineConfigXmlConverter.cpp",
@@ -83,14 +84,17 @@ cc_library {
        "usb/UsbAlsaMixerControl.cpp",
    ],
    generated_sources: [
        "audio_policy_capengine_configuration_aidl_default",
        "audio_policy_configuration_aidl_default",
        "audio_policy_engine_configuration_aidl_default",
    ],
    generated_headers: [
        "audio_policy_capengine_configuration_aidl_default",
        "audio_policy_configuration_aidl_default",
        "audio_policy_engine_configuration_aidl_default",
    ],
    export_generated_headers: [
        "audio_policy_capengine_configuration_aidl_default",
        "audio_policy_configuration_aidl_default",
        "audio_policy_engine_configuration_aidl_default",
    ],
+386 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "AHAL_Config"

#include <aidl/android/media/audio/common/AudioProductStrategyType.h>
#include <android-base/logging.h>
#include <media/AidlConversionCppNdk.h>
#include <media/TypeConverter.h>
#include <media/convert.h>
#include <utils/FastStrcmp.h>

#include "core-impl/CapEngineConfigXmlConverter.h"
#include "core-impl/XsdcConversion.h"

using aidl::android::hardware::audio::common::iequals;
using aidl::android::media::audio::common::AudioDeviceAddress;
using aidl::android::media::audio::common::AudioDeviceDescription;
using aidl::android::media::audio::common::AudioHalCapConfiguration;
using aidl::android::media::audio::common::AudioHalCapCriterionV2;
using aidl::android::media::audio::common::AudioHalCapDomain;
using aidl::android::media::audio::common::AudioHalCapParameter;
using aidl::android::media::audio::common::AudioHalCapRule;
using aidl::android::media::audio::common::AudioPolicyForceUse;
using aidl::android::media::audio::common::AudioSource;
using aidl::android::media::audio::common::AudioStreamType;

using ::android::BAD_VALUE;
using ::android::base::unexpected;
using ::android::utilities::convertTo;

namespace eng_xsd = android::audio::policy::capengine::configuration;

namespace aidl::android::hardware::audio::core::internal {

static constexpr const char* gStrategiesParameter = "product_strategies";
static constexpr const char* gInputSourcesParameter = "input_sources";
static constexpr const char* gStreamsParameter = "streams";
static constexpr const char* gOutputDevicesParameter = "selected_output_devices";
static constexpr const char* gOutputDeviceAddressParameter = "device_address";
static constexpr const char* gStrategyPrefix = "vx_";
static constexpr const char* gLegacyOutputDevicePrefix = "AUDIO_DEVICE_OUT_";
static constexpr const char* gLegacyInputDevicePrefix = "AUDIO_DEVICE_IN_";
static constexpr const char* gLegacyStreamPrefix = "AUDIO_STREAM_";
static constexpr const char* gLegacySourcePrefix = "AUDIO_SOURCE_";

std::optional<std::vector<std::optional<AudioHalCapDomain>>>&
CapEngineConfigXmlConverter::getAidlCapEngineConfig() {
    return mAidlCapDomains;
}

ConversionResult<AudioHalCapRule::CriterionRule> convertCriterionRuleToAidl(
        const eng_xsd::SelectionCriterionRuleType& xsdcRule) {
    using Tag = AudioHalCapCriterionV2::Tag;
    AudioHalCapRule::CriterionRule rule{};
    std::string criterionName = xsdcRule.getSelectionCriterion();
    std::string criterionValue = xsdcRule.getValue();
    if (iequals(criterionName, toString(Tag::availableInputDevices))) {
        rule.criterion = AudioHalCapCriterionV2::make<Tag::availableInputDevices>();
        rule.criterionTypeValue =
                VALUE_OR_RETURN(convertDeviceTypeToAidl(gLegacyInputDevicePrefix + criterionValue));
    } else if (iequals(criterionName, toString(Tag::availableOutputDevices))) {
        rule.criterion = AudioHalCapCriterionV2::make<Tag::availableOutputDevices>();
        rule.criterionTypeValue = VALUE_OR_RETURN(
                convertDeviceTypeToAidl(gLegacyOutputDevicePrefix + criterionValue));
    } else if (iequals(criterionName, toString(Tag::availableInputDevicesAddresses))) {
        rule.criterion = AudioHalCapCriterionV2::make<Tag::availableInputDevicesAddresses>();
        rule.criterionTypeValue =
                AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(criterionValue);
    } else if (iequals(criterionName, toString(Tag::availableOutputDevicesAddresses))) {
        rule.criterion = AudioHalCapCriterionV2::make<Tag::availableOutputDevicesAddresses>();
        rule.criterionTypeValue =
                AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(criterionValue);
    } else if (iequals(criterionName, toString(Tag::telephonyMode))) {
        rule.criterion = AudioHalCapCriterionV2::make<Tag::telephonyMode>();
        rule.criterionTypeValue = VALUE_OR_RETURN(convertTelephonyModeToAidl(criterionValue));
    } else if (!fastcmp<strncmp>(criterionName.c_str(), kXsdcForceConfigForUse,
            strlen(kXsdcForceConfigForUse))) {
        rule.criterion = AudioHalCapCriterionV2::make<Tag::forceConfigForUse>(
                VALUE_OR_RETURN(convertForceUseCriterionToAidl(criterionName)));
        rule.criterionTypeValue = VALUE_OR_RETURN(convertForcedConfigToAidl(criterionValue));
    } else {
        LOG(ERROR) << __func__ << " unrecognized criterion " << criterionName;
        return unexpected(BAD_VALUE);
    }
    if (xsdcRule.getMatchesWhen() == eng_xsd::MatchesWhenEnum::Excludes) {
        rule.matchingRule = AudioHalCapRule::MatchingRule::EXCLUDES;
    } else if (xsdcRule.getMatchesWhen() == eng_xsd::MatchesWhenEnum::Includes) {
        rule.matchingRule = AudioHalCapRule::MatchingRule::INCLUDES;
    } else if (xsdcRule.getMatchesWhen() == eng_xsd::MatchesWhenEnum::Is) {
        rule.matchingRule = AudioHalCapRule::MatchingRule::IS;
    } else if (xsdcRule.getMatchesWhen() == eng_xsd::MatchesWhenEnum::IsNot) {
        rule.matchingRule = AudioHalCapRule::MatchingRule::IS_NOT;
    } else {
        LOG(ERROR) << "Unsupported match when rule.";
        return unexpected(BAD_VALUE);
    }
    return rule;
}

ConversionResult<AudioHalCapRule> convertRule(const eng_xsd::CompoundRuleType& xsdcCompoundRule) {
    AudioHalCapRule rule{};
    bool isPreviousCompoundRule = true;
    if (xsdcCompoundRule.getType() == eng_xsd::TypeEnum::Any) {
        rule.compoundRule = AudioHalCapRule::CompoundRule::ANY;
    } else if (xsdcCompoundRule.getType() == eng_xsd::TypeEnum::All) {
        rule.compoundRule = AudioHalCapRule::CompoundRule::ALL;
    } else {
        LOG(ERROR) << "Unsupported compound rule type.";
        return unexpected(BAD_VALUE);
    }
    for (const auto& childXsdcCoumpoundRule : xsdcCompoundRule.getCompoundRule_optional()) {
        if (childXsdcCoumpoundRule.hasCompoundRule_optional()) {
            rule.nestedRules.push_back(VALUE_OR_FATAL(convertRule(childXsdcCoumpoundRule)));
        } else if (childXsdcCoumpoundRule.hasSelectionCriterionRule_optional()) {
            rule.nestedRules.push_back(VALUE_OR_FATAL(convertRule(childXsdcCoumpoundRule)));
        }
    }
    if (xsdcCompoundRule.hasSelectionCriterionRule_optional()) {
        for (const auto& xsdcRule : xsdcCompoundRule.getSelectionCriterionRule_optional()) {
            rule.criterionRules.push_back(VALUE_OR_FATAL(convertCriterionRuleToAidl(xsdcRule)));
        }
    }
    return rule;
}

ConversionResult<int> getAudioProductStrategyId(const std::string& path) {
    std::vector<std::string> strings;
    std::istringstream pathStream(path);
    std::string stringToken;
    while (getline(pathStream, stringToken, '/')) {
        std::size_t pos = stringToken.find(gStrategyPrefix);
        if (pos != std::string::npos) {
            std::string strategyIdLiteral = stringToken.substr(pos + std::strlen(gStrategyPrefix));
            int strategyId;
            if (!convertTo(strategyIdLiteral, strategyId)) {
                LOG(ERROR) << "Invalid strategy " << stringToken << " from path " << path;
                return unexpected(BAD_VALUE);
            }
            return strategyId;
        }
    }
    return unexpected(BAD_VALUE);
}

ConversionResult<AudioSource> getAudioSource(const std::string& path) {
    std::vector<std::string> strings;
    std::istringstream pathStream(path);
    std::string stringToken;
    while (getline(pathStream, stringToken, '/')) {
        if (stringToken.find(gInputSourcesParameter) != std::string::npos) {
            getline(pathStream, stringToken, '/');
            std::transform(stringToken.begin(), stringToken.end(), stringToken.begin(),
                           [](char c) { return std::toupper(c); });
            std::string legacySourceLiteral = "AUDIO_SOURCE_" + stringToken;
            audio_source_t legacySource;
            if (!::android::SourceTypeConverter::fromString(legacySourceLiteral, legacySource)) {
                LOG(ERROR) << "Invalid source " << stringToken << " from path " << path;
                return unexpected(BAD_VALUE);
            }
            return legacy2aidl_audio_source_t_AudioSource(legacySource);
        }
    }
    return unexpected(BAD_VALUE);
}

ConversionResult<AudioStreamType> getAudioStreamType(const std::string& path) {
    std::vector<std::string> strings;
    std::istringstream pathStream(path);
    std::string stringToken;

    while (getline(pathStream, stringToken, '/')) {
        if (stringToken.find(gStreamsParameter) != std::string::npos) {
            getline(pathStream, stringToken, '/');
            std::transform(stringToken.begin(), stringToken.end(), stringToken.begin(),
                           [](char c) { return std::toupper(c); });
            std::string legacyStreamLiteral = std::string(gLegacyStreamPrefix) + stringToken;
            audio_stream_type_t legacyStream;
            if (!::android::StreamTypeConverter::fromString(legacyStreamLiteral, legacyStream)) {
                LOG(ERROR) << "Invalid stream " << stringToken << " from path " << path;
                return unexpected(BAD_VALUE);
            }
            return legacy2aidl_audio_stream_type_t_AudioStreamType(legacyStream);
        }
    }
    return unexpected(BAD_VALUE);
}

ConversionResult<std::string> toUpperAndAppendPrefix(const std::string& capName,
                                                     const std::string& legacyPrefix) {
    std::string legacyName = capName;
    std::transform(legacyName.begin(), legacyName.end(), legacyName.begin(),
                   [](char c) { return std::toupper(c); });
    return legacyPrefix + legacyName;
}

ConversionResult<AudioHalCapParameter> CapEngineConfigXmlConverter::convertParamToAidl(
        const eng_xsd::ConfigurableElementSettingsType& element) {
    const auto& path = element.getPath();

    AudioHalCapParameter parameterSetting;
    if (path.find(gStrategiesParameter) != std::string::npos) {
        int strategyId = VALUE_OR_FATAL(getAudioProductStrategyId(path));
        if (path.find(gOutputDevicesParameter) != std::string::npos) {
            // Value is 1 or 0
            if (!element.hasBitParameter_optional()) {
                LOG(ERROR) << "Invalid strategy value type";
                return unexpected(BAD_VALUE);
            }
            // Convert name to output device type
            const auto* xsdcParam = element.getFirstBitParameter_optional();
            std::string outputDevice = VALUE_OR_FATAL(toUpperAndAppendPrefix(
                    eng_xsd::toString(xsdcParam->getName()), gLegacyOutputDevicePrefix));
            audio_devices_t legacyType;
            if (!::android::OutputDeviceConverter::fromString(outputDevice, legacyType)) {
                LOG(ERROR) << "Invalid strategy device type " << outputDevice;
                return unexpected(BAD_VALUE);
            }
            AudioDeviceDescription aidlDevice =
                    VALUE_OR_FATAL(legacy2aidl_audio_devices_t_AudioDeviceDescription(legacyType));
            bool isSelected;
            if (!convertTo(xsdcParam->getValue(), isSelected)) {
                LOG(ERROR) << "Invalid strategy device selection value " << xsdcParam->getValue();
                return unexpected(BAD_VALUE);
            }
            parameterSetting =
                    AudioHalCapParameter::StrategyDevice(aidlDevice, strategyId, isSelected);
        } else if (path.find(gOutputDeviceAddressParameter) != std::string::npos) {
            // Value is the address
            if (!element.hasStringParameter_optional()) {
                return unexpected(BAD_VALUE);
            }
            std::string address = element.getFirstStringParameter_optional()->getValue();
            parameterSetting = AudioHalCapParameter::StrategyDeviceAddress(
                    AudioDeviceAddress(address), strategyId);
        }
    } else if (path.find(gInputSourcesParameter) != std::string::npos) {
        // Value is 1 or 0
        if (!element.hasBitParameter_optional()) {
            LOG(ERROR) << "Invalid source value type";
            return unexpected(BAD_VALUE);
        }
        AudioSource audioSourceAidl = VALUE_OR_FATAL(getAudioSource(path));
        const auto* xsdcParam = element.getFirstBitParameter_optional();
        std::string inputDeviceLiteral = VALUE_OR_FATAL(toUpperAndAppendPrefix(
                eng_xsd::toString(xsdcParam->getName()), gLegacyInputDevicePrefix));
        audio_devices_t inputDeviceType;
        if (!::android::InputDeviceConverter::fromString(inputDeviceLiteral, inputDeviceType)) {
            LOG(ERROR) << "Invalid source device type " << inputDeviceLiteral;
            return unexpected(BAD_VALUE);
        }
        AudioDeviceDescription aidlDevice =
                VALUE_OR_FATAL(legacy2aidl_audio_devices_t_AudioDeviceDescription(inputDeviceType));

        bool isSelected;
        if (!convertTo(xsdcParam->getValue(), isSelected)) {
            LOG(ERROR) << "Invalid source value type " << xsdcParam->getValue();
            return unexpected(BAD_VALUE);
        }
        parameterSetting =
                AudioHalCapParameter::InputSourceDevice(aidlDevice, audioSourceAidl, isSelected);
    } else if (path.find(gStreamsParameter) != std::string::npos) {
        AudioStreamType audioStreamAidl = VALUE_OR_FATAL(getAudioStreamType(path));
        if (!element.hasEnumParameter_optional()) {
            LOG(ERROR) << "Invalid stream value type";
            return unexpected(BAD_VALUE);
        }
        const auto* xsdcParam = element.getFirstEnumParameter_optional();
        std::string profileLiteral =
                VALUE_OR_FATAL(toUpperAndAppendPrefix(xsdcParam->getValue(), gLegacyStreamPrefix));
        audio_stream_type_t profileLegacyStream;
        if (!::android::StreamTypeConverter::fromString(profileLiteral, profileLegacyStream)) {
            LOG(ERROR) << "Invalid stream value " << profileLiteral;
            return unexpected(BAD_VALUE);
        }
        AudioStreamType profileStreamAidl = VALUE_OR_FATAL(
                legacy2aidl_audio_stream_type_t_AudioStreamType(profileLegacyStream));
        parameterSetting =
                AudioHalCapParameter::StreamVolumeProfile(audioStreamAidl, profileStreamAidl);
    }
    return parameterSetting;
}

ConversionResult<std::vector<AudioHalCapParameter>>
CapEngineConfigXmlConverter::convertSettingToAidl(
        const eng_xsd::SettingsType::Configuration& xsdcSetting) {
    std::vector<AudioHalCapParameter> aidlCapParameterSettings;
    for (const auto& element : xsdcSetting.getConfigurableElement()) {
        aidlCapParameterSettings.push_back(VALUE_OR_FATAL(convertParamToAidl(element)));
    }
    return aidlCapParameterSettings;
}

ConversionResult<AudioHalCapConfiguration> CapEngineConfigXmlConverter::convertConfigurationToAidl(
        const eng_xsd::ConfigurationsType::Configuration& xsdcConfiguration,
        const eng_xsd::SettingsType::Configuration& xsdcSettingConfiguration) {
    AudioHalCapConfiguration aidlCapConfiguration;
    aidlCapConfiguration.name = xsdcConfiguration.getName();
    if (xsdcConfiguration.hasCompoundRule()) {
        if (xsdcConfiguration.getCompoundRule().size() != 1) {
            return unexpected(BAD_VALUE);
        }
        aidlCapConfiguration.rule =
                VALUE_OR_FATAL(convertRule(xsdcConfiguration.getCompoundRule()[0]));
        aidlCapConfiguration.parameterSettings =
                VALUE_OR_FATAL(convertSettingToAidl(xsdcSettingConfiguration));
    }
    return aidlCapConfiguration;
}

ConversionResult<eng_xsd::SettingsType::Configuration> getConfigurationByName(
        const std::string& name, const std::vector<eng_xsd::SettingsType>& xsdcSettingsVec) {
    for (const auto& xsdcSettings : xsdcSettingsVec) {
        for (const auto& xsdcConfiguration : xsdcSettings.getConfiguration()) {
            if (xsdcConfiguration.getName() == name) {
                return xsdcConfiguration;
            }
        }
    }
    LOG(ERROR) << __func__ << " failed to find configuration " << name;
    return unexpected(BAD_VALUE);
}

ConversionResult<std::vector<AudioHalCapConfiguration>>
CapEngineConfigXmlConverter::convertConfigurationsToAidl(
        const std::vector<eng_xsd::ConfigurationsType>& xsdcConfigurationsVec,
        const std::vector<eng_xsd::SettingsType>& xsdcSettingsVec) {
    if (xsdcConfigurationsVec.empty() || xsdcSettingsVec.empty()) {
        LOG(ERROR) << __func__ << " empty configurations/settings";
        return unexpected(BAD_VALUE);
    }
    std::vector<AudioHalCapConfiguration> aidlConfigurations;
    for (const auto& xsdcConfigurations : xsdcConfigurationsVec) {
        for (const auto& xsdcConfiguration : xsdcConfigurations.getConfiguration()) {
            auto xsdcSettingConfiguration = VALUE_OR_FATAL(
                    getConfigurationByName(xsdcConfiguration.getName(), xsdcSettingsVec));
            aidlConfigurations.push_back(VALUE_OR_FATAL(
                    convertConfigurationToAidl(xsdcConfiguration, xsdcSettingConfiguration)));
        }
    }
    return aidlConfigurations;
}

ConversionResult<AudioHalCapDomain> CapEngineConfigXmlConverter::convertConfigurableDomainToAidl(
        const eng_xsd::ConfigurableDomainType& xsdcConfigurableDomain) {
    AudioHalCapDomain aidlConfigurableDomain;

    aidlConfigurableDomain.name = xsdcConfigurableDomain.getName();
    if (xsdcConfigurableDomain.hasSequenceAware() && xsdcConfigurableDomain.getSequenceAware()) {
        LOG(ERROR) << "sequence aware not supported.";
        return unexpected(BAD_VALUE);
    }
    if (xsdcConfigurableDomain.hasConfigurations() && xsdcConfigurableDomain.hasSettings()) {
        aidlConfigurableDomain.configurations = VALUE_OR_FATAL(convertConfigurationsToAidl(
                xsdcConfigurableDomain.getConfigurations(), xsdcConfigurableDomain.getSettings()));
    }
    return aidlConfigurableDomain;
}

void CapEngineConfigXmlConverter::init() {
    if (getXsdcConfig()->hasConfigurableDomain()) {
        mAidlCapDomains = std::make_optional<>(VALUE_OR_FATAL(
                (convertCollectionToAidlOptionalValues<eng_xsd::ConfigurableDomainType,
                                                       AudioHalCapDomain>(
                        getXsdcConfig()->getConfigurableDomain(),
                        std::bind(&CapEngineConfigXmlConverter::convertConfigurableDomainToAidl,
                                  this, std::placeholders::_1)))));
    } else {
        mAidlCapDomains = std::nullopt;
    }
}

}  // namespace aidl::android::hardware::audio::core::internal
+40 −27

File changed.

Preview size limit exceeded, changes collapsed.

Loading