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

Commit 741c347b authored by Mikhail Naganov's avatar Mikhail Naganov Committed by Cherrypicker Worker
Browse files

APM: Implementing configuration loading from AIDL HAL

The main change is to utilize 'getAudioPolicyConfig'
to receive the HAL-provided configuration from
the AudioFlinger and initialize runtime structures
from it.

Accompanying changes:
 - made `libaudiopolicycomponents` a shared library;
 - added or moved around necessary conversion functions;

Bug: 205884982
Test: run CF with AIDL HAL and compare APM dump A/B
Test: m audiopolicy_fuzzer
Test: atest audio_health_tests
Test: atest audio_aidl_ndk_conversion_tests
(cherry picked from https://android-review.googlesource.com/q/commit:9e459d7393179e7df286601c7536210c6011f090)
Merged-In: I7d0f48bf4d9d4bdaa46246aa4dfbcc49e835c6b6
Change-Id: I7d0f48bf4d9d4bdaa46246aa4dfbcc49e835c6b6
parent f83f648f
Loading
Loading
Loading
Loading
+190 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@

#include <algorithm>
#include <map>
#include <sstream>
#include <regex>
#include <utility>
#include <vector>

@@ -50,6 +52,7 @@ using ::android::String8;
using ::android::status_t;
using ::android::base::unexpected;

using media::audio::common::AudioAttributes;
using media::audio::common::AudioChannelLayout;
using media::audio::common::AudioConfig;
using media::audio::common::AudioConfigBase;
@@ -62,6 +65,7 @@ using media::audio::common::AudioDualMonoMode;
using media::audio::common::AudioEncapsulationMetadataType;
using media::audio::common::AudioEncapsulationMode;
using media::audio::common::AudioEncapsulationType;
using media::audio::common::AudioFlag;
using media::audio::common::AudioFormatDescription;
using media::audio::common::AudioFormatType;
using media::audio::common::AudioGain;
@@ -95,6 +99,26 @@ using media::audio::common::PcmType;
////////////////////////////////////////////////////////////////////////////////////////////////////
// Converters

namespace {

bool isVendorExtension(const std::string& s) {
    // Must be the same as defined in AudioAttributes.aidl and {Playback|Record}TrackMetadata.aidl
    static const std::regex vendorExtension("VX_[A-Z0-9]{3,}_[_A-Z0-9]+");
    return std::regex_match(s.begin(), s.end(), vendorExtension);
}

std::vector<std::string> splitString(const std::string& s, char separator) {
    std::istringstream iss(s);
    std::string t;
    std::vector<std::string> result;
    while (std::getline(iss, t, separator)) {
        result.push_back(std::move(t));
    }
    return result;
}

}  // namespace

::android::status_t aidl2legacy_string(std::string_view aidl, char* dest, size_t maxSize) {
    if (aidl.size() > maxSize - 1) {
        return BAD_VALUE;
@@ -1799,6 +1823,172 @@ legacy2aidl_audio_usage_t_AudioUsage(audio_usage_t legacy) {
    return unexpected(BAD_VALUE);
}

namespace {

// TODO(b/281850726): Expose publicly once android.media.AudioFlag is removed.
// Until that, `legacy2aidl_audio_flags_mask_t_AudioFlag` function is ambiguous.

ConversionResult<audio_flags_mask_t>
aidl2legacy_AudioFlag_audio_flags_mask_t(AudioFlag aidl) {
    switch (aidl) {
        case AudioFlag::NONE:
            return AUDIO_FLAG_NONE;
        case AudioFlag::AUDIBILITY_ENFORCED:
            return AUDIO_FLAG_AUDIBILITY_ENFORCED;
        // The is no AudioFlag::SECURE, see the comment in the AudioFlag.aidl
        //  return AUDIO_FLAG_SECURE;
        case AudioFlag::SCO:
            return AUDIO_FLAG_SCO;
        case AudioFlag::BEACON:
            return AUDIO_FLAG_BEACON;
        case AudioFlag::HW_AV_SYNC:
            return AUDIO_FLAG_HW_AV_SYNC;
        case AudioFlag::HW_HOTWORD:
            return AUDIO_FLAG_HW_HOTWORD;
        case AudioFlag::BYPASS_INTERRUPTION_POLICY:
            return AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY;
        case AudioFlag::BYPASS_MUTE:
            return AUDIO_FLAG_BYPASS_MUTE;
        case AudioFlag::LOW_LATENCY:
            return AUDIO_FLAG_LOW_LATENCY;
        case AudioFlag::DEEP_BUFFER:
            return AUDIO_FLAG_DEEP_BUFFER;
        case AudioFlag::NO_MEDIA_PROJECTION:
            return AUDIO_FLAG_NO_MEDIA_PROJECTION;
        case AudioFlag::MUTE_HAPTIC:
            return AUDIO_FLAG_MUTE_HAPTIC;
        case AudioFlag::NO_SYSTEM_CAPTURE:
            return AUDIO_FLAG_NO_SYSTEM_CAPTURE;
        case AudioFlag::CAPTURE_PRIVATE:
            return AUDIO_FLAG_CAPTURE_PRIVATE;
        case AudioFlag::CONTENT_SPATIALIZED:
            return AUDIO_FLAG_CONTENT_SPATIALIZED;
        case AudioFlag::NEVER_SPATIALIZE:
            return AUDIO_FLAG_NEVER_SPATIALIZE;
        case AudioFlag::CALL_REDIRECTION:
            return AUDIO_FLAG_CALL_REDIRECTION;
    }
    return unexpected(BAD_VALUE);
}

ConversionResult<AudioFlag>
legacy2aidl_audio_flags_mask_t_AudioFlag(audio_flags_mask_t legacy) {
    switch (legacy) {
        case AUDIO_FLAG_NONE:
            return AudioFlag::NONE;
        case AUDIO_FLAG_AUDIBILITY_ENFORCED:
            return AudioFlag::AUDIBILITY_ENFORCED;
        case AUDIO_FLAG_SECURE:
            return unexpected(BAD_VALUE);
        case AUDIO_FLAG_SCO:
            return AudioFlag::SCO;
        case AUDIO_FLAG_BEACON:
            return AudioFlag::BEACON;
        case AUDIO_FLAG_HW_AV_SYNC:
            return AudioFlag::HW_AV_SYNC;
        case AUDIO_FLAG_HW_HOTWORD:
            return AudioFlag::HW_HOTWORD;
        case AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY:
            return AudioFlag::BYPASS_INTERRUPTION_POLICY;
        case AUDIO_FLAG_BYPASS_MUTE:
            return AudioFlag::BYPASS_MUTE;
        case AUDIO_FLAG_LOW_LATENCY:
            return AudioFlag::LOW_LATENCY;
        case AUDIO_FLAG_DEEP_BUFFER:
            return AudioFlag::DEEP_BUFFER;
        case AUDIO_FLAG_NO_MEDIA_PROJECTION:
            return AudioFlag::NO_MEDIA_PROJECTION;
        case AUDIO_FLAG_MUTE_HAPTIC:
            return AudioFlag::MUTE_HAPTIC;
        case AUDIO_FLAG_NO_SYSTEM_CAPTURE:
            return AudioFlag::NO_SYSTEM_CAPTURE;
        case AUDIO_FLAG_CAPTURE_PRIVATE:
            return AudioFlag::CAPTURE_PRIVATE;
        case AUDIO_FLAG_CONTENT_SPATIALIZED:
            return AudioFlag::CONTENT_SPATIALIZED;
        case AUDIO_FLAG_NEVER_SPATIALIZE:
            return AudioFlag::NEVER_SPATIALIZE;
        case AUDIO_FLAG_CALL_REDIRECTION:
            return AudioFlag::CALL_REDIRECTION;
    }
    return unexpected(BAD_VALUE);
}

ConversionResult<audio_flags_mask_t>
aidl2legacy_int32_t_audio_flags_mask_t_mask(int32_t aidl) {
    return convertBitmask<audio_flags_mask_t, int32_t, audio_flags_mask_t, AudioFlag>(
            aidl, aidl2legacy_AudioFlag_audio_flags_mask_t, indexToEnum_bitmask<AudioFlag>,
            enumToMask_bitmask<audio_flags_mask_t, audio_flags_mask_t>);
}

ConversionResult<int32_t>
legacy2aidl_audio_flags_mask_t_int32_t_mask(audio_flags_mask_t legacy) {
    return convertBitmask<int32_t, audio_flags_mask_t, AudioFlag, audio_flags_mask_t>(
            legacy, legacy2aidl_audio_flags_mask_t_AudioFlag,
            indexToEnum_bitmask<audio_flags_mask_t>,
            enumToMask_bitmask<int32_t, AudioFlag>);
}

}  // namespace

ConversionResult<std::string>
aidl2legacy_AudioTags_string(const std::vector<std::string>& aidl) {
    std::ostringstream tagsBuffer;
    bool hasValue = false;
    for (const auto& tag : aidl) {
        if (hasValue) {
            tagsBuffer << AUDIO_ATTRIBUTES_TAGS_SEPARATOR;
        }
        if (isVendorExtension(tag)) {
            // Note: with the current regex for vendor tags: VX_[A-Z0-9]{3,}_[_A-Z0-9]+
            // it's impossible to create a vendor tag that would contain the separator, but in case
            // the criteria changes, we double check it here.
            if (strchr(tag.c_str(), AUDIO_ATTRIBUTES_TAGS_SEPARATOR) == nullptr) {
                tagsBuffer << tag;
                hasValue = true;
            } else {
                ALOGE("Vendor extension tag is ill-formed: \"%s\"", tag.c_str());
                return unexpected(BAD_VALUE);
            }
        }
    }
    return tagsBuffer.str();
}

ConversionResult<std::vector<std::string>>
legacy2aidl_string_AudioTags(const std::string& legacy) {
    auto allTags = splitString(legacy, AUDIO_ATTRIBUTES_TAGS_SEPARATOR);
    std::vector<std::string> result;
    std::copy_if(std::make_move_iterator(allTags.begin()), std::make_move_iterator(allTags.end()),
                    std::back_inserter(result), isVendorExtension);
    return result;
}

ConversionResult<audio_attributes_t>
aidl2legacy_AudioAttributes_audio_attributes_t(const AudioAttributes& aidl) {
    audio_attributes_t legacy;
    legacy.content_type = VALUE_OR_RETURN(
            aidl2legacy_AudioContentType_audio_content_type_t(aidl.contentType));
    legacy.usage = VALUE_OR_RETURN(aidl2legacy_AudioUsage_audio_usage_t(aidl.usage));
    legacy.source = VALUE_OR_RETURN(aidl2legacy_AudioSource_audio_source_t(aidl.source));
    legacy.flags = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_flags_mask_t_mask(aidl.flags));
    auto tagsString = VALUE_OR_RETURN(aidl2legacy_AudioTags_string(aidl.tags));
    RETURN_IF_ERROR(aidl2legacy_string(tagsString, legacy.tags, sizeof(legacy.tags)));
    return legacy;
}

ConversionResult<AudioAttributes>
legacy2aidl_audio_attributes_t_AudioAttributes(const audio_attributes_t& legacy) {
    AudioAttributes aidl;
    aidl.contentType = VALUE_OR_RETURN(
            legacy2aidl_audio_content_type_t_AudioContentType(legacy.content_type));
    aidl.usage = VALUE_OR_RETURN(legacy2aidl_audio_usage_t_AudioUsage(legacy.usage));
    aidl.source = VALUE_OR_RETURN(legacy2aidl_audio_source_t_AudioSource(legacy.source));
    aidl.flags = VALUE_OR_RETURN(legacy2aidl_audio_flags_mask_t_int32_t_mask(legacy.flags));
    auto tagsString = VALUE_OR_RETURN(legacy2aidl_string(legacy.tags, sizeof(legacy.tags)));
    aidl.tags = VALUE_OR_RETURN(legacy2aidl_string_AudioTags(tagsString));
    return aidl;
}

ConversionResult<audio_encapsulation_mode_t>
aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t(AudioEncapsulationMode aidl) {
+12 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#define PREFIX(f) <f>
#endif

#include PREFIX(android/media/audio/common/AudioAttributes.h)
#include PREFIX(android/media/audio/common/AudioChannelLayout.h)
#include PREFIX(android/media/audio/common/AudioConfig.h)
#include PREFIX(android/media/audio/common/AudioConfigBase.h)
@@ -46,6 +47,7 @@
#include PREFIX(android/media/audio/common/AudioEncapsulationMetadataType.h)
#include PREFIX(android/media/audio/common/AudioEncapsulationMode.h)
#include PREFIX(android/media/audio/common/AudioEncapsulationType.h)
#include PREFIX(android/media/audio/common/AudioFlag.h)
#include PREFIX(android/media/audio/common/AudioFormatDescription.h)
#include PREFIX(android/media/audio/common/AudioGain.h)
#include PREFIX(android/media/audio/common/AudioGainConfig.h)
@@ -355,6 +357,16 @@ ConversionResult<audio_usage_t> aidl2legacy_AudioUsage_audio_usage_t(
ConversionResult<media::audio::common::AudioUsage> legacy2aidl_audio_usage_t_AudioUsage(
        audio_usage_t legacy);

ConversionResult<std::string>
aidl2legacy_AudioTags_string(const std::vector<std::string>& aidl);
ConversionResult<std::vector<std::string>>
legacy2aidl_string_AudioTags(const std::string& legacy);

ConversionResult<audio_attributes_t>
aidl2legacy_AudioAttributes_audio_attributes_t(const media::audio::common::AudioAttributes& aidl);
ConversionResult<media::audio::common::AudioAttributes>
legacy2aidl_audio_attributes_t_AudioAttributes(const audio_attributes_t& legacy);

ConversionResult<audio_uuid_t> aidl2legacy_AudioUuid_audio_uuid_t(
        const media::audio::common::AudioUuid &aidl);
ConversionResult<media::audio::common::AudioUuid> legacy2aidl_audio_uuid_t_AudioUuid(
+42 −0
Original line number Diff line number Diff line
@@ -118,6 +118,20 @@ template<typename InputIterator, typename OutputIterator, typename Func>
    return ::android::OK;
}

/**
 * A generic template that helps convert containers of convertible types without
 * using an intermediate container.
 */
template<typename InputContainer, typename OutputContainer, typename Func>
::android::status_t convertContainer(const InputContainer& input, OutputContainer* output,
        const Func& itemConversion) {
    auto ins = std::inserter(*output, output->begin());
    for (const auto& item : input) {
        *ins = VALUE_OR_RETURN_STATUS(itemConversion(item));
    }
    return ::android::OK;
}

/**
 * A generic template that helps convert containers of convertible types.
 */
@@ -208,6 +222,34 @@ using IntegralTypeOf = typename IntegralTypeOfStruct<T>::Type;

////////////////////////////////////////////////////////////////////////////////////////////////////
// Utilities for handling bitmasks.
// Some AIDL enums are specified using bit indices, for example:
//   `AidlEnum { FOO = 0, BAR = 1, BAZ = 2' }`
// while corresponding legacy types universally uses actual bitmasks, for example:
//   `enum legacy_enum_t { LEGACY_FOO = 1 << 0, LEGACY_BAR = 1 << 1, LEGACY_BAZ = 1 << 2 }`
// There is also the third type used to store the resulting mask, which is combined
// from individual bits. In AIDL this is typically an int (`int32_t`), in legacy types this
// is often the enum type itself (although, strictly this is not correct since masks are not
// declared as part of the enum type). The bit index value always has an integer type.
//
// `indexToEnum_index` constructs an instance of the enum from an index,
// for example `AidlEnum::BAR` from `1`.
// `indexToEnum_bitmask` produces a corresponding legacy bitmask enum instance,
// for example, `LEGACY_BAR` (`2`) from `1`.
// `enumToMask_bitmask` simply casts an enum type to a bitmask type.
// `enumToMask_index` creates a mask from an enum type which specifies an index.
//
// All these functions can be plugged into `convertBitmask`. For example, to implement
// conversion from `AidlEnum` to `legacy_enum_t`, with a mask stored in `int32_t`,
// the following call needs to be made:
//   convertBitmask<legacy_enum_t /*DestMask*/, int32_t /*SrcMask*/,
//                  legacy_enum_t /*DestEnum*/, AidlEnum /*SrcEnum*/>(
//     maskField /*int32_t*/, aidl2legacy_AidlEnum_legacy_enum_t /*enumConversion*/,
//     indexToEnum_index<AidlEnum> /*srcIndexToEnum*/,
//     enumToMask_bitmask<legacy_enum_t, legacy_enum_t> /*destEnumToMask*/)
//
// The only extra function needed is for mapping between corresponding enum values
// of the AidlEnum and the legacy_enum_t. Note that the mapping is between values
// of enums, for example, `AidlEnum::BAZ` maps to `LEGACY_BAZ` and vice versa.

template<typename Enum>
Enum indexToEnum_index(int index) {
+40 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@

#include <gtest/gtest.h>

#include <media/AidlConversionCppNdk.h>
#include <media/AidlConversionNdk.h>

namespace {
@@ -89,3 +90,42 @@ TEST(AudioRecordTrackMetadata, NonVendorTags) {
    ASSERT_EQ(1, convBack.value().tags.size());
    EXPECT_EQ(initial.tags[1], convBack.value().tags[0]);
}

class AudioTagsRoundTripTest : public testing::TestWithParam<std::vector<std::string>>
{
};
TEST_P(AudioTagsRoundTripTest, Aidl2Legacy2Aidl) {
    const auto& initial = GetParam();
    auto conv = aidl2legacy_AudioTags_string(initial);
    ASSERT_TRUE(conv.ok());
    auto convBack = legacy2aidl_string_AudioTags(conv.value());
    ASSERT_TRUE(convBack.ok());
    EXPECT_EQ(initial, convBack.value());
}
INSTANTIATE_TEST_SUITE_P(AudioTagsRoundTrip, AudioTagsRoundTripTest,
        testing::Values(std::vector<std::string>{},
                std::vector<std::string>{"VX_GOOGLE_41"},
                std::vector<std::string>{"VX_GOOGLE_41", "VX_GOOGLE_42"}));

TEST(AudioTags, NonVendorTags) {
    const std::string separator(1, AUDIO_ATTRIBUTES_TAGS_SEPARATOR);
    const std::vector<std::string> initial{
        "random_string", "random" + separator + "string", "VX_GOOGLE_42"};
    auto conv = aidl2legacy_AudioTags_string(initial);
    ASSERT_TRUE(conv.ok());
    EXPECT_EQ("VX_GOOGLE_42", conv.value());
}

TEST(AudioTags, IllFormedAidlTag) {
    const std::string separator(1, AUDIO_ATTRIBUTES_TAGS_SEPARATOR);
    const std::vector<std::string> initial{"VX_GOOGLE" + separator + "42", "VX_GOOGLE_42"};
    auto conv = aidl2legacy_AudioTags_string(initial);
    // Note: with the current regex for vendor tags: VX_[A-Z0-9]{3,}_[_A-Z0-9]+
    // it's impossible to create a vendor tag that would contain the separator, but in case
    // the criteria changes, we ensure that either such tags get filtered out or an error happens.
    if (conv.ok()) {
        EXPECT_EQ("VX_GOOGLE_42", conv.value());
    } else {
        EXPECT_FALSE(conv.ok()) << conv.value();
    }
}
+9 −0
Original line number Diff line number Diff line
@@ -125,3 +125,12 @@ TEST_P(AudioFormatDescriptionRoundTripTest, Ndk2Cpp2Ndk) {
INSTANTIATE_TEST_SUITE_P(AudioFormatDescriptionRoundTrip, AudioFormatDescriptionRoundTripTest,
        testing::Values(make_AFD_Invalid(), make_AFD_Default(), make_AFD_Pcm16Bit(),
                make_AFD_Bitstream(), make_AFD_Encap(), make_AFD_Encap_with_Enc()));

TEST(AudioPortRoundTripTest, Ndk2Cpp2Ndk) {
    const AudioPort initial;
    auto conv = ndk2cpp_AudioPort(initial);
    ASSERT_TRUE(conv.ok());
    auto convBack = cpp2ndk_AudioPort(conv.value());
    ASSERT_TRUE(convBack.ok());
    EXPECT_EQ(initial, convBack.value());
}
Loading