Loading media/libaudiohal/impl/Android.bp +33 −26 Original line number Diff line number Diff line Loading @@ -41,7 +41,7 @@ cc_defaults { ], header_libs: [ "android.hardware.audio.common.util@all-versions", ] ], } cc_defaults { Loading Loading @@ -71,7 +71,7 @@ cc_defaults { ], header_libs: [ "libaudioclient_headers", "libaudiohal_headers" "libaudiohal_headers", ], defaults: [ "latest_android_media_audio_common_types_cpp_export_shared", Loading @@ -86,7 +86,7 @@ cc_library_shared { name: "libaudiohal@5.0", defaults: [ "libaudiohal_default", "libaudiohal_hidl_default" "libaudiohal_hidl_default", ], srcs: [ ":audio_core_hal_client_sources", Loading @@ -105,14 +105,14 @@ cc_library_shared { "-DMAJOR_VERSION=5", "-DMINOR_VERSION=0", "-include common/all-versions/VersionMacro.h", ] ], } cc_library_shared { name: "libaudiohal@6.0", defaults: [ "libaudiohal_default", "libaudiohal_hidl_default" "libaudiohal_hidl_default", ], srcs: [ ":audio_core_hal_client_sources", Loading @@ -131,14 +131,14 @@ cc_library_shared { "-DMAJOR_VERSION=6", "-DMINOR_VERSION=0", "-include common/all-versions/VersionMacro.h", ] ], } cc_library_static { name: "libaudiohal.effect@7.0", defaults: [ "libaudiohal_default", "libaudiohal_hidl_default" "libaudiohal_hidl_default", ], srcs: [ ":audio_effect_hidl_hal_client_sources", Loading @@ -153,14 +153,14 @@ cc_library_static { "-DMAJOR_VERSION=7", "-DMINOR_VERSION=0", "-include common/all-versions/VersionMacro.h", ] ], } cc_library_shared { name: "libaudiohal@7.0", defaults: [ "libaudiohal_default", "libaudiohal_hidl_default" "libaudiohal_hidl_default", ], srcs: [ ":audio_core_hal_client_sources", Loading @@ -180,7 +180,7 @@ cc_library_shared { "-DMAJOR_VERSION=7", "-DMINOR_VERSION=0", "-include common/all-versions/VersionMacro.h", ] ], } cc_library_shared { Loading @@ -189,7 +189,7 @@ cc_library_shared { "latest_android_hardware_audio_core_sounddose_ndk_shared", "latest_android_hardware_audio_sounddose_ndk_shared", "libaudiohal_default", "libaudiohal_hidl_default" "libaudiohal_hidl_default", ], srcs: [ ":audio_core_hal_client_sources", Loading @@ -216,7 +216,7 @@ cc_library_shared { "-DCOMMON_TYPES_MINOR_VERSION=0", "-DCORE_TYPES_MINOR_VERSION=0", "-include common/all-versions/VersionMacro.h", ] ], } cc_defaults { Loading Loading @@ -261,9 +261,30 @@ cc_library_shared { ], srcs: [ "DevicesFactoryHalEntry.cpp", "EffectsFactoryHalEntry.cpp", ":audio_effect_hal_aidl_src_files", ":core_audio_hal_aidl_src_files", ], } filegroup { name: "core_audio_hal_aidl_src_files", srcs: [ "ConversionHelperAidl.cpp", "DeviceHalAidl.cpp", "DevicesFactoryHalAidl.cpp", "Hal2AidlMapper.cpp", "StreamHalAidl.cpp", ], } filegroup { name: "audio_effect_hal_aidl_src_files", srcs: [ "EffectConversionHelperAidl.cpp", "EffectBufferHalAidl.cpp", "EffectHalAidl.cpp", "EffectsFactoryHalAidl.cpp", "effectsAidlConversion/AidlConversionAec.cpp", "effectsAidlConversion/AidlConversionAgc1.cpp", "effectsAidlConversion/AidlConversionAgc2.cpp", Loading @@ -280,21 +301,7 @@ cc_library_shared { "effectsAidlConversion/AidlConversionVendorExtension.cpp", "effectsAidlConversion/AidlConversionVirtualizer.cpp", "effectsAidlConversion/AidlConversionVisualizer.cpp", "EffectsFactoryHalAidl.cpp", "EffectsFactoryHalEntry.cpp", ":audio_effectproxy_src_files", ":core_audio_hal_aidl_src_files", ], } filegroup { name: "core_audio_hal_aidl_src_files", srcs: [ "ConversionHelperAidl.cpp", "DeviceHalAidl.cpp", "DevicesFactoryHalAidl.cpp", "Hal2AidlMapper.cpp", "StreamHalAidl.cpp", ], } Loading media/libaudiohal/tests/Android.bp +11 −0 Original line number Diff line number Diff line Loading @@ -63,3 +63,14 @@ cc_test { ], header_libs: ["libaudiohalimpl_headers"], } cc_test { name: "EffectHalVersionCompatibilityTest", srcs: [ "EffectHalVersionCompatibility_test.cpp", ":audio_effect_hal_aidl_src_files", ], defaults: ["libaudiohal_aidl_test_default"], header_libs: ["libaudiohalimpl_headers"], static_libs: ["libgmock"], } media/libaudiohal/tests/EffectHalVersionCompatibility_test.cpp 0 → 100644 +319 −0 Original line number Diff line number Diff line /* * Copyright 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. */ #include <cstddef> #include <unordered_map> #define LOG_TAG "EffectHalVersionCompatibilityTest" #include <EffectHalAidl.h> #include <aidl/android/hardware/audio/effect/IEffect.h> #include <aidl/android/hardware/audio/effect/IFactory.h> #include <android-base/logging.h> #include <android/binder_manager.h> #include <android/binder_process.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <media/audiohal/EffectsFactoryHalInterface.h> #include <system/audio_aidl_utils.h> #include <system/audio_config.h> #include <system/audio_effects/audio_effects_utils.h> #include <system/audio_effects/effect_uuid.h> #include <utils/Log.h> using aidl::android::hardware::audio::effect::CommandId; using aidl::android::hardware::audio::effect::Descriptor; using aidl::android::hardware::audio::effect::IEffect; using aidl::android::hardware::audio::effect::IFactory; using aidl::android::hardware::audio::effect::kReopenSupportedVersion; using aidl::android::hardware::audio::effect::Parameter; using aidl::android::hardware::audio::effect::Processing; using aidl::android::hardware::audio::effect::State; using aidl::android::media::audio::common::AudioUuid; using android::OK; using android::sp; using android::effect::EffectHalAidl; using testing::_; using testing::Eq; namespace { /** * Maps of parameter and the version it was introduced. */ // parameters defined directly in the Parameter union, except Parameter::specific (defined in // kParamIdEffectVersionMap). static const std::unordered_map<Parameter::Tag, int /* version */> kParamTagVersionMap = { {Parameter::common, 1}, {Parameter::deviceDescription, 1}, {Parameter::mode, 1}, {Parameter::source, 1}, {Parameter::offload, 1}, {Parameter::volumeStereo, 1}, {Parameter::sourceMetadata, 2}, {Parameter::sinkMetadata, 2}, }; // Map of the version a specific effect type introduction // Id tags defined Parameter::Id union, except Parameter::Id::commonTag (defined in // kParamTagVersionMap). static const std::unordered_map<Parameter::Id::Tag, int /* version */> kParamIdEffectVersionMap = { {Parameter::Id::vendorEffectTag, 1}, {Parameter::Id::acousticEchoCancelerTag, 1}, {Parameter::Id::automaticGainControlV1Tag, 1}, {Parameter::Id::automaticGainControlV2Tag, 1}, {Parameter::Id::bassBoostTag, 1}, {Parameter::Id::downmixTag, 1}, {Parameter::Id::dynamicsProcessingTag, 1}, {Parameter::Id::environmentalReverbTag, 1}, {Parameter::Id::equalizerTag, 1}, {Parameter::Id::hapticGeneratorTag, 1}, {Parameter::Id::loudnessEnhancerTag, 1}, {Parameter::Id::noiseSuppressionTag, 1}, {Parameter::Id::presetReverbTag, 1}, {Parameter::Id::virtualizerTag, 1}, {Parameter::Id::visualizerTag, 1}, {Parameter::Id::volumeTag, 1}, {Parameter::Id::spatializerTag, 2}, }; // Tags defined Parameter::Specific union. static const std::unordered_map<Parameter::Specific::Tag, int /* version */> kParamEffectVersionMap = { {Parameter::Specific::vendorEffect, 1}, {Parameter::Specific::acousticEchoCanceler, 1}, {Parameter::Specific::automaticGainControlV1, 1}, {Parameter::Specific::automaticGainControlV2, 1}, {Parameter::Specific::bassBoost, 1}, {Parameter::Specific::downmix, 1}, {Parameter::Specific::dynamicsProcessing, 1}, {Parameter::Specific::environmentalReverb, 1}, {Parameter::Specific::equalizer, 1}, {Parameter::Specific::hapticGenerator, 1}, {Parameter::Specific::loudnessEnhancer, 1}, {Parameter::Specific::noiseSuppression, 1}, {Parameter::Specific::presetReverb, 1}, {Parameter::Specific::virtualizer, 1}, {Parameter::Specific::visualizer, 1}, {Parameter::Specific::volume, 1}, {Parameter::Specific::spatializer, 2}, }; class MockFactory : public IFactory { public: explicit MockFactory(int version) : IFactory(), mVersion(version) {} MOCK_METHOD(ndk::ScopedAStatus, queryEffects, (const std::optional<AudioUuid>& in_type_uuid, const std::optional<AudioUuid>& in_impl_uuid, const std::optional<AudioUuid>& in_proxy_uuid, std::vector<Descriptor>* _aidl_return), (override)); MOCK_METHOD(ndk::ScopedAStatus, queryProcessing, (const std::optional<Processing::Type>& in_type, std::vector<Processing>* _aidl_return), (override)); MOCK_METHOD(ndk::ScopedAStatus, createEffect, (const AudioUuid& in_impl_uuid, std::shared_ptr<IEffect>* _aidl_return), (override)); MOCK_METHOD(ndk::ScopedAStatus, destroyEffect, (const std::shared_ptr<IEffect>& in_handle), (override)); ndk::ScopedAStatus getInterfaceVersion(int32_t* _aidl_return) { *_aidl_return = mVersion; return ndk::ScopedAStatus::ok(); } // these must be implemented but won't be used in this testing ::ndk::SpAIBinder asBinder() { return ::ndk::SpAIBinder(); } bool isRemote() { return false; } ::ndk::ScopedAStatus getInterfaceHash(std::string*) { return ndk::ScopedAStatus::ok(); } private: const int mVersion; }; class MockEffect : public IEffect { public: explicit MockEffect(int version) : IEffect(), mVersion(version) {} MOCK_METHOD(ndk::ScopedAStatus, open, (const Parameter::Common& common, const std::optional<Parameter::Specific>& specific, IEffect::OpenEffectReturn* ret), (override)); MOCK_METHOD(ndk::ScopedAStatus, close, (), (override)); MOCK_METHOD(binder_status_t, dump, (int fd, const char** args, uint32_t numArgs), (override)); MOCK_METHOD(ndk::ScopedAStatus, command, (CommandId id), (override)); MOCK_METHOD(ndk::ScopedAStatus, getState, (State * state), (override)); MOCK_METHOD(ndk::ScopedAStatus, getDescriptor, (Descriptor * desc), (override)); MOCK_METHOD(ndk::ScopedAStatus, destroy, (), ()); // reopen introduced in version kReopenSupportedVersion ndk::ScopedAStatus reopen(IEffect::OpenEffectReturn*) override { return mVersion < kReopenSupportedVersion ? ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION) : ndk::ScopedAStatus::ok(); } // for all parameters introduced ndk::ScopedAStatus setParameter(const Parameter& param) override { const auto paramTag = param.getTag(); switch (paramTag) { case Parameter::common: case Parameter::deviceDescription: case Parameter::mode: case Parameter::source: case Parameter::offload: case Parameter::volumeStereo: case Parameter::sinkMetadata: FALLTHROUGH_INTENDED; case Parameter::sourceMetadata: { if (kParamTagVersionMap.find(paramTag) != kParamTagVersionMap.end() && kParamTagVersionMap.at(paramTag) >= mVersion) { return ndk::ScopedAStatus::ok(); } break; } case Parameter::specific: { // TODO break; } } return ndk::ScopedAStatus::fromStatus(STATUS_BAD_VALUE); } /** * Only care about version compatibility here: * @return BAD_VALUE if a tag is not supported by current AIDL version. * @return OK if a tag is supported by current AIDL version. */ ndk::ScopedAStatus getParameter(const Parameter::Id& id, Parameter*) override { const auto idTag = id.getTag(); switch (idTag) { case Parameter::Id::commonTag: { const auto paramTag = id.get<Parameter::Id::commonTag>(); if (kParamTagVersionMap.find(paramTag) != kParamTagVersionMap.end() && kParamTagVersionMap.at(paramTag) >= mVersion) { return ndk::ScopedAStatus::ok(); } break; } case Parameter::Id::vendorEffectTag: case Parameter::Id::acousticEchoCancelerTag: case Parameter::Id::automaticGainControlV1Tag: case Parameter::Id::automaticGainControlV2Tag: case Parameter::Id::bassBoostTag: case Parameter::Id::downmixTag: case Parameter::Id::dynamicsProcessingTag: case Parameter::Id::environmentalReverbTag: case Parameter::Id::equalizerTag: case Parameter::Id::hapticGeneratorTag: case Parameter::Id::loudnessEnhancerTag: case Parameter::Id::noiseSuppressionTag: case Parameter::Id::presetReverbTag: case Parameter::Id::virtualizerTag: case Parameter::Id::visualizerTag: case Parameter::Id::volumeTag: FALLTHROUGH_INTENDED; case Parameter::Id::spatializerTag: { if (kParamIdEffectVersionMap.find(idTag) != kParamIdEffectVersionMap.end() && kParamIdEffectVersionMap.at(idTag) >= mVersion) { return ndk::ScopedAStatus::ok(); } break; } } return ndk::ScopedAStatus::fromStatus(STATUS_BAD_VALUE); } ndk::ScopedAStatus getInterfaceVersion(int32_t* _aidl_return) { *_aidl_return = mVersion; return ndk::ScopedAStatus::ok(); } // these must be implemented but won't be used in this testing ::ndk::SpAIBinder asBinder() { return ::ndk::SpAIBinder(); } bool isRemote() { return false; } ::ndk::ScopedAStatus getInterfaceHash(std::string*) { return ndk::ScopedAStatus::ok(); } private: const int mVersion; }; static const std::vector<AudioUuid> kTestParamUUIDs = { ::aidl::android::hardware::audio::effect::getEffectTypeUuidAcousticEchoCanceler(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidAutomaticGainControlV1(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidAutomaticGainControlV2(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidBassBoost(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidDownmix(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidDynamicsProcessing(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidEnvReverb(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidEqualizer(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidHapticGenerator(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidLoudnessEnhancer(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidNoiseSuppression(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidPresetReverb(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidSpatializer(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidVirtualizer(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidVisualizer(), ::aidl::android::hardware::audio::effect::getEffectUuidNull(), }; static const std::vector<int> kTestParamVersion = {1, 2}; // Effect AIDL HAL versions to test enum ParamName { UUID, VERSION }; using TestParam = std::tuple<AudioUuid, int /* version */>; class EffectHalVersionCompatibilityTest : public ::testing::TestWithParam<TestParam> { public: void SetUp() override { mMockFactory = ndk::SharedRefBase::make<MockFactory>(mVersion); ASSERT_NE(mMockFactory, nullptr); mMockEffect = ndk::SharedRefBase::make<MockEffect>(mVersion); ASSERT_NE(mMockEffect, nullptr); mEffectHalAidl = sp<EffectHalAidl>::make(mMockFactory, mMockEffect, 0, 0, mDesc, false); ASSERT_NE(mEffectHalAidl, nullptr); } void TearDown() override { EXPECT_CALL(*mMockFactory, destroyEffect(_)); mEffectHalAidl.clear(); mMockEffect.reset(); mMockFactory.reset(); } protected: const int mVersion = std::get<VERSION>(GetParam()); const AudioUuid mTypeUuid = std::get<UUID>(GetParam()); const Descriptor mDesc = {.common.id.type = mTypeUuid}; std::shared_ptr<MockFactory> mMockFactory = nullptr; std::shared_ptr<MockEffect> mMockEffect = nullptr; sp<EffectHalAidl> mEffectHalAidl = nullptr; }; TEST_P(EffectHalVersionCompatibilityTest, testEffectAidlHalCreateDestroy) { // do nothing } INSTANTIATE_TEST_SUITE_P( EffectHalVersionCompatibilityTestWithVersion, EffectHalVersionCompatibilityTest, ::testing::Combine(testing::ValuesIn(kTestParamUUIDs), testing::ValuesIn(kTestParamVersion)), [](const testing::TestParamInfo<EffectHalVersionCompatibilityTest::ParamType>& info) { auto version = std::to_string(std::get<VERSION>(info.param)); auto uuid = android::audio::utils::toString(std::get<UUID>(info.param)); std::string name = "EffectHalVersionCompatibilityTest_V" + version + "_" + uuid; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); return name; }); } // namespace No newline at end of file Loading
media/libaudiohal/impl/Android.bp +33 −26 Original line number Diff line number Diff line Loading @@ -41,7 +41,7 @@ cc_defaults { ], header_libs: [ "android.hardware.audio.common.util@all-versions", ] ], } cc_defaults { Loading Loading @@ -71,7 +71,7 @@ cc_defaults { ], header_libs: [ "libaudioclient_headers", "libaudiohal_headers" "libaudiohal_headers", ], defaults: [ "latest_android_media_audio_common_types_cpp_export_shared", Loading @@ -86,7 +86,7 @@ cc_library_shared { name: "libaudiohal@5.0", defaults: [ "libaudiohal_default", "libaudiohal_hidl_default" "libaudiohal_hidl_default", ], srcs: [ ":audio_core_hal_client_sources", Loading @@ -105,14 +105,14 @@ cc_library_shared { "-DMAJOR_VERSION=5", "-DMINOR_VERSION=0", "-include common/all-versions/VersionMacro.h", ] ], } cc_library_shared { name: "libaudiohal@6.0", defaults: [ "libaudiohal_default", "libaudiohal_hidl_default" "libaudiohal_hidl_default", ], srcs: [ ":audio_core_hal_client_sources", Loading @@ -131,14 +131,14 @@ cc_library_shared { "-DMAJOR_VERSION=6", "-DMINOR_VERSION=0", "-include common/all-versions/VersionMacro.h", ] ], } cc_library_static { name: "libaudiohal.effect@7.0", defaults: [ "libaudiohal_default", "libaudiohal_hidl_default" "libaudiohal_hidl_default", ], srcs: [ ":audio_effect_hidl_hal_client_sources", Loading @@ -153,14 +153,14 @@ cc_library_static { "-DMAJOR_VERSION=7", "-DMINOR_VERSION=0", "-include common/all-versions/VersionMacro.h", ] ], } cc_library_shared { name: "libaudiohal@7.0", defaults: [ "libaudiohal_default", "libaudiohal_hidl_default" "libaudiohal_hidl_default", ], srcs: [ ":audio_core_hal_client_sources", Loading @@ -180,7 +180,7 @@ cc_library_shared { "-DMAJOR_VERSION=7", "-DMINOR_VERSION=0", "-include common/all-versions/VersionMacro.h", ] ], } cc_library_shared { Loading @@ -189,7 +189,7 @@ cc_library_shared { "latest_android_hardware_audio_core_sounddose_ndk_shared", "latest_android_hardware_audio_sounddose_ndk_shared", "libaudiohal_default", "libaudiohal_hidl_default" "libaudiohal_hidl_default", ], srcs: [ ":audio_core_hal_client_sources", Loading @@ -216,7 +216,7 @@ cc_library_shared { "-DCOMMON_TYPES_MINOR_VERSION=0", "-DCORE_TYPES_MINOR_VERSION=0", "-include common/all-versions/VersionMacro.h", ] ], } cc_defaults { Loading Loading @@ -261,9 +261,30 @@ cc_library_shared { ], srcs: [ "DevicesFactoryHalEntry.cpp", "EffectsFactoryHalEntry.cpp", ":audio_effect_hal_aidl_src_files", ":core_audio_hal_aidl_src_files", ], } filegroup { name: "core_audio_hal_aidl_src_files", srcs: [ "ConversionHelperAidl.cpp", "DeviceHalAidl.cpp", "DevicesFactoryHalAidl.cpp", "Hal2AidlMapper.cpp", "StreamHalAidl.cpp", ], } filegroup { name: "audio_effect_hal_aidl_src_files", srcs: [ "EffectConversionHelperAidl.cpp", "EffectBufferHalAidl.cpp", "EffectHalAidl.cpp", "EffectsFactoryHalAidl.cpp", "effectsAidlConversion/AidlConversionAec.cpp", "effectsAidlConversion/AidlConversionAgc1.cpp", "effectsAidlConversion/AidlConversionAgc2.cpp", Loading @@ -280,21 +301,7 @@ cc_library_shared { "effectsAidlConversion/AidlConversionVendorExtension.cpp", "effectsAidlConversion/AidlConversionVirtualizer.cpp", "effectsAidlConversion/AidlConversionVisualizer.cpp", "EffectsFactoryHalAidl.cpp", "EffectsFactoryHalEntry.cpp", ":audio_effectproxy_src_files", ":core_audio_hal_aidl_src_files", ], } filegroup { name: "core_audio_hal_aidl_src_files", srcs: [ "ConversionHelperAidl.cpp", "DeviceHalAidl.cpp", "DevicesFactoryHalAidl.cpp", "Hal2AidlMapper.cpp", "StreamHalAidl.cpp", ], } Loading
media/libaudiohal/tests/Android.bp +11 −0 Original line number Diff line number Diff line Loading @@ -63,3 +63,14 @@ cc_test { ], header_libs: ["libaudiohalimpl_headers"], } cc_test { name: "EffectHalVersionCompatibilityTest", srcs: [ "EffectHalVersionCompatibility_test.cpp", ":audio_effect_hal_aidl_src_files", ], defaults: ["libaudiohal_aidl_test_default"], header_libs: ["libaudiohalimpl_headers"], static_libs: ["libgmock"], }
media/libaudiohal/tests/EffectHalVersionCompatibility_test.cpp 0 → 100644 +319 −0 Original line number Diff line number Diff line /* * Copyright 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. */ #include <cstddef> #include <unordered_map> #define LOG_TAG "EffectHalVersionCompatibilityTest" #include <EffectHalAidl.h> #include <aidl/android/hardware/audio/effect/IEffect.h> #include <aidl/android/hardware/audio/effect/IFactory.h> #include <android-base/logging.h> #include <android/binder_manager.h> #include <android/binder_process.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <media/audiohal/EffectsFactoryHalInterface.h> #include <system/audio_aidl_utils.h> #include <system/audio_config.h> #include <system/audio_effects/audio_effects_utils.h> #include <system/audio_effects/effect_uuid.h> #include <utils/Log.h> using aidl::android::hardware::audio::effect::CommandId; using aidl::android::hardware::audio::effect::Descriptor; using aidl::android::hardware::audio::effect::IEffect; using aidl::android::hardware::audio::effect::IFactory; using aidl::android::hardware::audio::effect::kReopenSupportedVersion; using aidl::android::hardware::audio::effect::Parameter; using aidl::android::hardware::audio::effect::Processing; using aidl::android::hardware::audio::effect::State; using aidl::android::media::audio::common::AudioUuid; using android::OK; using android::sp; using android::effect::EffectHalAidl; using testing::_; using testing::Eq; namespace { /** * Maps of parameter and the version it was introduced. */ // parameters defined directly in the Parameter union, except Parameter::specific (defined in // kParamIdEffectVersionMap). static const std::unordered_map<Parameter::Tag, int /* version */> kParamTagVersionMap = { {Parameter::common, 1}, {Parameter::deviceDescription, 1}, {Parameter::mode, 1}, {Parameter::source, 1}, {Parameter::offload, 1}, {Parameter::volumeStereo, 1}, {Parameter::sourceMetadata, 2}, {Parameter::sinkMetadata, 2}, }; // Map of the version a specific effect type introduction // Id tags defined Parameter::Id union, except Parameter::Id::commonTag (defined in // kParamTagVersionMap). static const std::unordered_map<Parameter::Id::Tag, int /* version */> kParamIdEffectVersionMap = { {Parameter::Id::vendorEffectTag, 1}, {Parameter::Id::acousticEchoCancelerTag, 1}, {Parameter::Id::automaticGainControlV1Tag, 1}, {Parameter::Id::automaticGainControlV2Tag, 1}, {Parameter::Id::bassBoostTag, 1}, {Parameter::Id::downmixTag, 1}, {Parameter::Id::dynamicsProcessingTag, 1}, {Parameter::Id::environmentalReverbTag, 1}, {Parameter::Id::equalizerTag, 1}, {Parameter::Id::hapticGeneratorTag, 1}, {Parameter::Id::loudnessEnhancerTag, 1}, {Parameter::Id::noiseSuppressionTag, 1}, {Parameter::Id::presetReverbTag, 1}, {Parameter::Id::virtualizerTag, 1}, {Parameter::Id::visualizerTag, 1}, {Parameter::Id::volumeTag, 1}, {Parameter::Id::spatializerTag, 2}, }; // Tags defined Parameter::Specific union. static const std::unordered_map<Parameter::Specific::Tag, int /* version */> kParamEffectVersionMap = { {Parameter::Specific::vendorEffect, 1}, {Parameter::Specific::acousticEchoCanceler, 1}, {Parameter::Specific::automaticGainControlV1, 1}, {Parameter::Specific::automaticGainControlV2, 1}, {Parameter::Specific::bassBoost, 1}, {Parameter::Specific::downmix, 1}, {Parameter::Specific::dynamicsProcessing, 1}, {Parameter::Specific::environmentalReverb, 1}, {Parameter::Specific::equalizer, 1}, {Parameter::Specific::hapticGenerator, 1}, {Parameter::Specific::loudnessEnhancer, 1}, {Parameter::Specific::noiseSuppression, 1}, {Parameter::Specific::presetReverb, 1}, {Parameter::Specific::virtualizer, 1}, {Parameter::Specific::visualizer, 1}, {Parameter::Specific::volume, 1}, {Parameter::Specific::spatializer, 2}, }; class MockFactory : public IFactory { public: explicit MockFactory(int version) : IFactory(), mVersion(version) {} MOCK_METHOD(ndk::ScopedAStatus, queryEffects, (const std::optional<AudioUuid>& in_type_uuid, const std::optional<AudioUuid>& in_impl_uuid, const std::optional<AudioUuid>& in_proxy_uuid, std::vector<Descriptor>* _aidl_return), (override)); MOCK_METHOD(ndk::ScopedAStatus, queryProcessing, (const std::optional<Processing::Type>& in_type, std::vector<Processing>* _aidl_return), (override)); MOCK_METHOD(ndk::ScopedAStatus, createEffect, (const AudioUuid& in_impl_uuid, std::shared_ptr<IEffect>* _aidl_return), (override)); MOCK_METHOD(ndk::ScopedAStatus, destroyEffect, (const std::shared_ptr<IEffect>& in_handle), (override)); ndk::ScopedAStatus getInterfaceVersion(int32_t* _aidl_return) { *_aidl_return = mVersion; return ndk::ScopedAStatus::ok(); } // these must be implemented but won't be used in this testing ::ndk::SpAIBinder asBinder() { return ::ndk::SpAIBinder(); } bool isRemote() { return false; } ::ndk::ScopedAStatus getInterfaceHash(std::string*) { return ndk::ScopedAStatus::ok(); } private: const int mVersion; }; class MockEffect : public IEffect { public: explicit MockEffect(int version) : IEffect(), mVersion(version) {} MOCK_METHOD(ndk::ScopedAStatus, open, (const Parameter::Common& common, const std::optional<Parameter::Specific>& specific, IEffect::OpenEffectReturn* ret), (override)); MOCK_METHOD(ndk::ScopedAStatus, close, (), (override)); MOCK_METHOD(binder_status_t, dump, (int fd, const char** args, uint32_t numArgs), (override)); MOCK_METHOD(ndk::ScopedAStatus, command, (CommandId id), (override)); MOCK_METHOD(ndk::ScopedAStatus, getState, (State * state), (override)); MOCK_METHOD(ndk::ScopedAStatus, getDescriptor, (Descriptor * desc), (override)); MOCK_METHOD(ndk::ScopedAStatus, destroy, (), ()); // reopen introduced in version kReopenSupportedVersion ndk::ScopedAStatus reopen(IEffect::OpenEffectReturn*) override { return mVersion < kReopenSupportedVersion ? ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION) : ndk::ScopedAStatus::ok(); } // for all parameters introduced ndk::ScopedAStatus setParameter(const Parameter& param) override { const auto paramTag = param.getTag(); switch (paramTag) { case Parameter::common: case Parameter::deviceDescription: case Parameter::mode: case Parameter::source: case Parameter::offload: case Parameter::volumeStereo: case Parameter::sinkMetadata: FALLTHROUGH_INTENDED; case Parameter::sourceMetadata: { if (kParamTagVersionMap.find(paramTag) != kParamTagVersionMap.end() && kParamTagVersionMap.at(paramTag) >= mVersion) { return ndk::ScopedAStatus::ok(); } break; } case Parameter::specific: { // TODO break; } } return ndk::ScopedAStatus::fromStatus(STATUS_BAD_VALUE); } /** * Only care about version compatibility here: * @return BAD_VALUE if a tag is not supported by current AIDL version. * @return OK if a tag is supported by current AIDL version. */ ndk::ScopedAStatus getParameter(const Parameter::Id& id, Parameter*) override { const auto idTag = id.getTag(); switch (idTag) { case Parameter::Id::commonTag: { const auto paramTag = id.get<Parameter::Id::commonTag>(); if (kParamTagVersionMap.find(paramTag) != kParamTagVersionMap.end() && kParamTagVersionMap.at(paramTag) >= mVersion) { return ndk::ScopedAStatus::ok(); } break; } case Parameter::Id::vendorEffectTag: case Parameter::Id::acousticEchoCancelerTag: case Parameter::Id::automaticGainControlV1Tag: case Parameter::Id::automaticGainControlV2Tag: case Parameter::Id::bassBoostTag: case Parameter::Id::downmixTag: case Parameter::Id::dynamicsProcessingTag: case Parameter::Id::environmentalReverbTag: case Parameter::Id::equalizerTag: case Parameter::Id::hapticGeneratorTag: case Parameter::Id::loudnessEnhancerTag: case Parameter::Id::noiseSuppressionTag: case Parameter::Id::presetReverbTag: case Parameter::Id::virtualizerTag: case Parameter::Id::visualizerTag: case Parameter::Id::volumeTag: FALLTHROUGH_INTENDED; case Parameter::Id::spatializerTag: { if (kParamIdEffectVersionMap.find(idTag) != kParamIdEffectVersionMap.end() && kParamIdEffectVersionMap.at(idTag) >= mVersion) { return ndk::ScopedAStatus::ok(); } break; } } return ndk::ScopedAStatus::fromStatus(STATUS_BAD_VALUE); } ndk::ScopedAStatus getInterfaceVersion(int32_t* _aidl_return) { *_aidl_return = mVersion; return ndk::ScopedAStatus::ok(); } // these must be implemented but won't be used in this testing ::ndk::SpAIBinder asBinder() { return ::ndk::SpAIBinder(); } bool isRemote() { return false; } ::ndk::ScopedAStatus getInterfaceHash(std::string*) { return ndk::ScopedAStatus::ok(); } private: const int mVersion; }; static const std::vector<AudioUuid> kTestParamUUIDs = { ::aidl::android::hardware::audio::effect::getEffectTypeUuidAcousticEchoCanceler(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidAutomaticGainControlV1(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidAutomaticGainControlV2(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidBassBoost(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidDownmix(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidDynamicsProcessing(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidEnvReverb(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidEqualizer(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidHapticGenerator(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidLoudnessEnhancer(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidNoiseSuppression(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidPresetReverb(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidSpatializer(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidVirtualizer(), ::aidl::android::hardware::audio::effect::getEffectTypeUuidVisualizer(), ::aidl::android::hardware::audio::effect::getEffectUuidNull(), }; static const std::vector<int> kTestParamVersion = {1, 2}; // Effect AIDL HAL versions to test enum ParamName { UUID, VERSION }; using TestParam = std::tuple<AudioUuid, int /* version */>; class EffectHalVersionCompatibilityTest : public ::testing::TestWithParam<TestParam> { public: void SetUp() override { mMockFactory = ndk::SharedRefBase::make<MockFactory>(mVersion); ASSERT_NE(mMockFactory, nullptr); mMockEffect = ndk::SharedRefBase::make<MockEffect>(mVersion); ASSERT_NE(mMockEffect, nullptr); mEffectHalAidl = sp<EffectHalAidl>::make(mMockFactory, mMockEffect, 0, 0, mDesc, false); ASSERT_NE(mEffectHalAidl, nullptr); } void TearDown() override { EXPECT_CALL(*mMockFactory, destroyEffect(_)); mEffectHalAidl.clear(); mMockEffect.reset(); mMockFactory.reset(); } protected: const int mVersion = std::get<VERSION>(GetParam()); const AudioUuid mTypeUuid = std::get<UUID>(GetParam()); const Descriptor mDesc = {.common.id.type = mTypeUuid}; std::shared_ptr<MockFactory> mMockFactory = nullptr; std::shared_ptr<MockEffect> mMockEffect = nullptr; sp<EffectHalAidl> mEffectHalAidl = nullptr; }; TEST_P(EffectHalVersionCompatibilityTest, testEffectAidlHalCreateDestroy) { // do nothing } INSTANTIATE_TEST_SUITE_P( EffectHalVersionCompatibilityTestWithVersion, EffectHalVersionCompatibilityTest, ::testing::Combine(testing::ValuesIn(kTestParamUUIDs), testing::ValuesIn(kTestParamVersion)), [](const testing::TestParamInfo<EffectHalVersionCompatibilityTest::ParamType>& info) { auto version = std::to_string(std::get<VERSION>(info.param)); auto uuid = android::audio::utils::toString(std::get<UUID>(info.param)); std::string name = "EffectHalVersionCompatibilityTest_V" + version + "_" + uuid; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); return name; }); } // namespace No newline at end of file