From 812d5b4ce07f6235a485bc6e0f2bd95c67c279d5 Mon Sep 17 00:00:00 2001 From: Shunkai Yao Date: Wed, 16 Nov 2022 18:08:50 +0000 Subject: [PATCH] AIDL effect vts test cases refinement Bug: 255361653 Test: atest VtsHalAudioEffectTargetTest atest VtsHalAudioEffectFactoryTargetTest atest VtsHalEqualizerTargetTest Change-Id: I4d4c4de97a73d4ea6dedd9c9e1733da03860430b --- audio/aidl/default/Android.bp | 5 +- audio/aidl/default/audio_effects_config.xml | 8 +- audio/aidl/default/bassboost/BassBoostSw.cpp | 4 +- audio/aidl/default/bassboost/BassBoostSw.h | 9 +- .../DynamicsProcessingSw.cpp | 4 +- .../dynamicProcessing/DynamicsProcessingSw.h | 9 +- .../default/{reverb => envReverb}/Android.bp | 4 +- .../EnvReverbSw.cpp} | 28 +- .../ReverbSw.h => envReverb/EnvReverbSw.h} | 21 +- audio/aidl/default/equalizer/EqualizerSw.cpp | 4 +- audio/aidl/default/equalizer/EqualizerSw.h | 11 +- .../hapticGenerator/HapticGeneratorSw.cpp | 4 +- .../hapticGenerator/HapticGeneratorSw.h | 9 +- .../default/include/effect-impl/EffectImpl.h | 9 +- .../default/include/effect-impl/EffectUUID.h | 303 +++--- .../loudnessEnhancer/LoudnessEnhancerSw.cpp | 4 +- .../loudnessEnhancer/LoudnessEnhancerSw.h | 9 +- audio/aidl/default/presetReverb/Android.bp | 40 + .../default/presetReverb/PresetReverbSw.cpp | 118 +++ .../default/presetReverb/PresetReverbSw.h | 73 ++ .../default/virtualizer/VirtualizerSw.cpp | 4 +- .../aidl/default/virtualizer/VirtualizerSw.h | 9 +- .../aidl/default/visualizer/VisualizerSw.cpp | 4 +- audio/aidl/default/visualizer/VisualizerSw.h | 9 +- audio/aidl/default/volume/VolumeSw.cpp | 4 +- audio/aidl/default/volume/VolumeSw.h | 9 +- audio/aidl/vts/EffectFactoryHelper.h | 127 +-- audio/aidl/vts/EffectHelper.h | 336 ++----- .../VtsHalAudioEffectFactoryTargetTest.cpp | 308 ++++--- .../aidl/vts/VtsHalAudioEffectTargetTest.cpp | 862 +++++++++++++----- audio/aidl/vts/VtsHalEqualizerTargetTest.cpp | 317 ++++--- .../vts/VtsHalLoudnessEnhancerTargetTest.cpp | 118 +-- 32 files changed, 1679 insertions(+), 1104 deletions(-) rename audio/aidl/default/{reverb => envReverb}/Android.bp (95%) rename audio/aidl/default/{reverb/ReverbSw.cpp => envReverb/EnvReverbSw.cpp} (78%) rename audio/aidl/default/{reverb/ReverbSw.h => envReverb/EnvReverbSw.h} (79%) create mode 100644 audio/aidl/default/presetReverb/Android.bp create mode 100644 audio/aidl/default/presetReverb/PresetReverbSw.cpp create mode 100644 audio/aidl/default/presetReverb/PresetReverbSw.h diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp index 0a92e99254..2b9ed5bab0 100644 --- a/audio/aidl/default/Android.bp +++ b/audio/aidl/default/Android.bp @@ -66,6 +66,7 @@ cc_defaults { name: "aidlaudioeffectservice_defaults", defaults: [ "latest_android_media_audio_common_types_ndk_shared", + "latest_android_hardware_audio_effect_ndk_shared", ], vendor: true, shared_libs: [ @@ -78,7 +79,6 @@ cc_defaults { "libutils", "android.hardware.common-V2-ndk", "android.hardware.common.fmq-V1-ndk", - "android.hardware.audio.effect-V1-ndk", ], header_libs: [ "libaudioaidl_headers", @@ -111,10 +111,11 @@ cc_binary { "libbassboostsw", "libbundleaidl", "libdynamicsprocessingsw", + "libenvreverbsw", "libequalizersw", "libhapticgeneratorsw", "libloudnessenhancersw", - "libreverbsw", + "libpresetreverbsw", "libtinyxml2", "libvirtualizersw", "libvisualizersw", diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml index b6fea27159..f4ac8fece9 100644 --- a/audio/aidl/default/audio_effects_config.xml +++ b/audio/aidl/default/audio_effects_config.xml @@ -34,7 +34,8 @@ - + + @@ -64,11 +65,12 @@ - + + - + diff --git a/audio/aidl/default/bassboost/BassBoostSw.cpp b/audio/aidl/default/bassboost/BassBoostSw.cpp index 3c39824445..c52d16f897 100644 --- a/audio/aidl/default/bassboost/BassBoostSw.cpp +++ b/audio/aidl/default/bassboost/BassBoostSw.cpp @@ -26,14 +26,14 @@ #include "BassBoostSw.h" using aidl::android::hardware::audio::effect::BassBoostSw; -using aidl::android::hardware::audio::effect::BassBoostSwImplUUID; using aidl::android::hardware::audio::effect::IEffect; +using aidl::android::hardware::audio::effect::kBassBoostSwImplUUID; using aidl::android::hardware::audio::effect::State; using aidl::android::media::audio::common::AudioUuid; extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid, std::shared_ptr* instanceSpp) { - if (!in_impl_uuid || *in_impl_uuid != BassBoostSwImplUUID) { + if (!in_impl_uuid || *in_impl_uuid != kBassBoostSwImplUUID) { LOG(ERROR) << __func__ << "uuid not supported"; return EX_ILLEGAL_ARGUMENT; } diff --git a/audio/aidl/default/bassboost/BassBoostSw.h b/audio/aidl/default/bassboost/BassBoostSw.h index fe9c640ff0..90a8887264 100644 --- a/audio/aidl/default/bassboost/BassBoostSw.h +++ b/audio/aidl/default/bassboost/BassBoostSw.h @@ -39,8 +39,8 @@ class BassBoostSw final : public EffectImpl { public: BassBoostSw() { LOG(DEBUG) << __func__; } ~BassBoostSw() { + cleanUp(); LOG(DEBUG) << __func__; - releaseContext(); } ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override; @@ -57,13 +57,14 @@ class BassBoostSw final : public EffectImpl { const BassBoost::Capability kCapability; /* Effect descriptor */ const Descriptor kDescriptor = { - .common = {.id = {.type = BassBoostTypeUUID, - .uuid = BassBoostSwImplUUID, + .common = {.id = {.type = kBassBoostTypeUUID, + .uuid = kBassBoostSwImplUUID, .proxy = std::nullopt}, .flags = {.type = Flags::Type::INSERT, .insert = Flags::Insert::FIRST, .volume = Flags::Volume::CTRL}, - .name = "BassBoostSw"}, + .name = "BassBoostSw", + .implementor = "The Android Open Source Project"}, .capability = Capability::make(kCapability)}; /* parameters */ diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp index 52403e17c7..3920a58ed7 100644 --- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp +++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp @@ -26,14 +26,14 @@ #include "DynamicsProcessingSw.h" using aidl::android::hardware::audio::effect::DynamicsProcessingSw; -using aidl::android::hardware::audio::effect::DynamicsProcessingSwImplUUID; using aidl::android::hardware::audio::effect::IEffect; +using aidl::android::hardware::audio::effect::kDynamicsProcessingSwImplUUID; using aidl::android::hardware::audio::effect::State; using aidl::android::media::audio::common::AudioUuid; extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid, std::shared_ptr* instanceSpp) { - if (!in_impl_uuid || *in_impl_uuid != DynamicsProcessingSwImplUUID) { + if (!in_impl_uuid || *in_impl_uuid != kDynamicsProcessingSwImplUUID) { LOG(ERROR) << __func__ << "uuid not supported"; return EX_ILLEGAL_ARGUMENT; } diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h index fc26902a17..2bc2762611 100644 --- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h +++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h @@ -39,8 +39,8 @@ class DynamicsProcessingSw final : public EffectImpl { public: DynamicsProcessingSw() { LOG(DEBUG) << __func__; } ~DynamicsProcessingSw() { + cleanUp(); LOG(DEBUG) << __func__; - releaseContext(); } ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override; @@ -57,13 +57,14 @@ class DynamicsProcessingSw final : public EffectImpl { const DynamicsProcessing::Capability kCapability; /* Effect descriptor */ const Descriptor kDescriptor = { - .common = {.id = {.type = DynamicsProcessingTypeUUID, - .uuid = DynamicsProcessingSwImplUUID, + .common = {.id = {.type = kDynamicsProcessingTypeUUID, + .uuid = kDynamicsProcessingSwImplUUID, .proxy = std::nullopt}, .flags = {.type = Flags::Type::INSERT, .insert = Flags::Insert::FIRST, .volume = Flags::Volume::CTRL}, - .name = "DynamicsProcessingSw"}, + .name = "DynamicsProcessingSw", + .implementor = "The Android Open Source Project"}, .capability = Capability::make(kCapability)}; /* parameters */ diff --git a/audio/aidl/default/reverb/Android.bp b/audio/aidl/default/envReverb/Android.bp similarity index 95% rename from audio/aidl/default/reverb/Android.bp rename to audio/aidl/default/envReverb/Android.bp index 955038cdb2..c239ee5930 100644 --- a/audio/aidl/default/reverb/Android.bp +++ b/audio/aidl/default/envReverb/Android.bp @@ -24,14 +24,14 @@ package { } cc_library_shared { - name: "libreverbsw", + name: "libenvreverbsw", defaults: [ "aidlaudioeffectservice_defaults", "latest_android_media_audio_common_types_ndk_shared", "latest_android_hardware_audio_effect_ndk_shared", ], srcs: [ - "ReverbSw.cpp", + "EnvReverbSw.cpp", ":effectCommonFile", ], visibility: [ diff --git a/audio/aidl/default/reverb/ReverbSw.cpp b/audio/aidl/default/envReverb/EnvReverbSw.cpp similarity index 78% rename from audio/aidl/default/reverb/ReverbSw.cpp rename to audio/aidl/default/envReverb/EnvReverbSw.cpp index 639f1a2e76..ad447abb76 100644 --- a/audio/aidl/default/reverb/ReverbSw.cpp +++ b/audio/aidl/default/envReverb/EnvReverbSw.cpp @@ -15,7 +15,7 @@ */ #include -#define LOG_TAG "AHAL_ReverbSw" +#define LOG_TAG "AHAL_EnvReverbSw" #include #include #include @@ -23,22 +23,22 @@ #include #include -#include "ReverbSw.h" +#include "EnvReverbSw.h" +using aidl::android::hardware::audio::effect::EnvReverbSw; using aidl::android::hardware::audio::effect::IEffect; -using aidl::android::hardware::audio::effect::ReverbSw; -using aidl::android::hardware::audio::effect::ReverbSwImplUUID; +using aidl::android::hardware::audio::effect::kEnvReverbSwImplUUID; using aidl::android::hardware::audio::effect::State; using aidl::android::media::audio::common::AudioUuid; extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid, std::shared_ptr* instanceSpp) { - if (!in_impl_uuid || *in_impl_uuid != ReverbSwImplUUID) { + if (!in_impl_uuid || *in_impl_uuid != kEnvReverbSwImplUUID) { LOG(ERROR) << __func__ << "uuid not supported"; return EX_ILLEGAL_ARGUMENT; } if (instanceSpp) { - *instanceSpp = ndk::SharedRefBase::make(); + *instanceSpp = ndk::SharedRefBase::make(); LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created"; return EX_NONE; } else { @@ -64,13 +64,13 @@ extern "C" binder_exception_t destroyEffect(const std::shared_ptr& inst namespace aidl::android::hardware::audio::effect { -ndk::ScopedAStatus ReverbSw::getDescriptor(Descriptor* _aidl_return) { +ndk::ScopedAStatus EnvReverbSw::getDescriptor(Descriptor* _aidl_return) { LOG(DEBUG) << __func__ << kDescriptor.toString(); *_aidl_return = kDescriptor; return ndk::ScopedAStatus::ok(); } -ndk::ScopedAStatus ReverbSw::setParameterSpecific(const Parameter::Specific& specific) { +ndk::ScopedAStatus EnvReverbSw::setParameterSpecific(const Parameter::Specific& specific) { RETURN_IF(Parameter::Specific::reverb != specific.getTag(), EX_ILLEGAL_ARGUMENT, "EffectNotSupported"); std::lock_guard lg(mMutex); @@ -81,24 +81,24 @@ ndk::ScopedAStatus ReverbSw::setParameterSpecific(const Parameter::Specific& spe return ndk::ScopedAStatus::ok(); } -ndk::ScopedAStatus ReverbSw::getParameterSpecific(const Parameter::Id& id, - Parameter::Specific* specific) { +ndk::ScopedAStatus EnvReverbSw::getParameterSpecific(const Parameter::Id& id, + Parameter::Specific* specific) { auto tag = id.getTag(); RETURN_IF(Parameter::Id::reverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag"); specific->set(mSpecificParam); return ndk::ScopedAStatus::ok(); } -std::shared_ptr ReverbSw::createContext(const Parameter::Common& common) { +std::shared_ptr EnvReverbSw::createContext(const Parameter::Common& common) { if (mContext) { LOG(DEBUG) << __func__ << " context already exist"; return mContext; } - mContext = std::make_shared(1 /* statusFmqDepth */, common); + mContext = std::make_shared(1 /* statusFmqDepth */, common); return mContext; } -RetCode ReverbSw::releaseContext() { +RetCode EnvReverbSw::releaseContext() { if (mContext) { mContext.reset(); } @@ -106,7 +106,7 @@ RetCode ReverbSw::releaseContext() { } // Processing method running in EffectWorker thread. -IEffect::Status ReverbSw::effectProcessImpl(float* in, float* out, int process) { +IEffect::Status EnvReverbSw::effectProcessImpl(float* in, float* out, int process) { // TODO: get data buffer and process. LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process; for (int i = 0; i < process; i++) { diff --git a/audio/aidl/default/reverb/ReverbSw.h b/audio/aidl/default/envReverb/EnvReverbSw.h similarity index 79% rename from audio/aidl/default/reverb/ReverbSw.h rename to audio/aidl/default/envReverb/EnvReverbSw.h index e00956f7d0..5a9ab2740d 100644 --- a/audio/aidl/default/reverb/ReverbSw.h +++ b/audio/aidl/default/envReverb/EnvReverbSw.h @@ -26,21 +26,21 @@ namespace aidl::android::hardware::audio::effect { -class ReverbSwContext final : public EffectContext { +class EnvReverbSwContext final : public EffectContext { public: - ReverbSwContext(int statusDepth, const Parameter::Common& common) + EnvReverbSwContext(int statusDepth, const Parameter::Common& common) : EffectContext(statusDepth, common) { LOG(DEBUG) << __func__; } // TODO: add specific context here }; -class ReverbSw final : public EffectImpl { +class EnvReverbSw final : public EffectImpl { public: - ReverbSw() { LOG(DEBUG) << __func__; } - ~ReverbSw() { + EnvReverbSw() { LOG(DEBUG) << __func__; } + ~EnvReverbSw() { + cleanUp(); LOG(DEBUG) << __func__; - releaseContext(); } ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override; @@ -52,18 +52,19 @@ class ReverbSw final : public EffectImpl { RetCode releaseContext() override; private: - std::shared_ptr mContext; + std::shared_ptr mContext; /* capabilities */ const Reverb::Capability kCapability; /* Effect descriptor */ const Descriptor kDescriptor = { - .common = {.id = {.type = ReverbTypeUUID, - .uuid = ReverbSwImplUUID, + .common = {.id = {.type = kEnvReverbTypeUUID, + .uuid = kEnvReverbSwImplUUID, .proxy = std::nullopt}, .flags = {.type = Flags::Type::INSERT, .insert = Flags::Insert::FIRST, .volume = Flags::Volume::CTRL}, - .name = "ReverbSw"}, + .name = "EnvReverbSw", + .implementor = "The Android Open Source Project"}, .capability = Capability::make(kCapability)}; /* parameters */ diff --git a/audio/aidl/default/equalizer/EqualizerSw.cpp b/audio/aidl/default/equalizer/EqualizerSw.cpp index 32c39690b3..d61ef97f24 100644 --- a/audio/aidl/default/equalizer/EqualizerSw.cpp +++ b/audio/aidl/default/equalizer/EqualizerSw.cpp @@ -26,14 +26,14 @@ #include "EqualizerSw.h" using aidl::android::hardware::audio::effect::EqualizerSw; -using aidl::android::hardware::audio::effect::EqualizerSwImplUUID; using aidl::android::hardware::audio::effect::IEffect; +using aidl::android::hardware::audio::effect::kEqualizerSwImplUUID; using aidl::android::hardware::audio::effect::State; using aidl::android::media::audio::common::AudioUuid; extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid, std::shared_ptr* instanceSpp) { - if (!in_impl_uuid || *in_impl_uuid != EqualizerSwImplUUID) { + if (!in_impl_uuid || *in_impl_uuid != kEqualizerSwImplUUID) { LOG(ERROR) << __func__ << "uuid not supported"; return EX_ILLEGAL_ARGUMENT; } diff --git a/audio/aidl/default/equalizer/EqualizerSw.h b/audio/aidl/default/equalizer/EqualizerSw.h index 8762f5d5f1..aa4587a4c0 100644 --- a/audio/aidl/default/equalizer/EqualizerSw.h +++ b/audio/aidl/default/equalizer/EqualizerSw.h @@ -82,8 +82,8 @@ class EqualizerSw final : public EffectImpl { public: EqualizerSw() { LOG(DEBUG) << __func__; } ~EqualizerSw() { + cleanUp(); LOG(DEBUG) << __func__; - releaseContext(); } ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override; @@ -109,13 +109,14 @@ class EqualizerSw final : public EffectImpl { const Equalizer::Capability kEqCap = {.bandFrequencies = mBandFrequency, .presets = mPresets}; // Effect descriptor. - const Descriptor kDesc = {.common = {.id = {.type = EqualizerTypeUUID, - .uuid = EqualizerSwImplUUID, - .proxy = std::nullopt}, + const Descriptor kDesc = {.common = {.id = {.type = kEqualizerTypeUUID, + .uuid = kEqualizerSwImplUUID, + .proxy = kEqualizerProxyUUID}, .flags = {.type = Flags::Type::INSERT, .insert = Flags::Insert::FIRST, .volume = Flags::Volume::CTRL}, - .name = "EqualizerSw"}, + .name = "EqualizerSw", + .implementor = "The Android Open Source Project"}, .capability = Capability::make(kEqCap)}; ndk::ScopedAStatus getParameterEqualizer(const Equalizer::Tag& tag, diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp index 90675c2372..fd5ea34239 100644 --- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp +++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp @@ -26,14 +26,14 @@ #include "HapticGeneratorSw.h" using aidl::android::hardware::audio::effect::HapticGeneratorSw; -using aidl::android::hardware::audio::effect::HapticGeneratorSwImplUUID; using aidl::android::hardware::audio::effect::IEffect; +using aidl::android::hardware::audio::effect::kHapticGeneratorSwImplUUID; using aidl::android::hardware::audio::effect::State; using aidl::android::media::audio::common::AudioUuid; extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid, std::shared_ptr* instanceSpp) { - if (!in_impl_uuid || *in_impl_uuid != HapticGeneratorSwImplUUID) { + if (!in_impl_uuid || *in_impl_uuid != kHapticGeneratorSwImplUUID) { LOG(ERROR) << __func__ << "uuid not supported"; return EX_ILLEGAL_ARGUMENT; } diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h index b5a5036a27..518aa877ed 100644 --- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h +++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h @@ -39,8 +39,8 @@ class HapticGeneratorSw final : public EffectImpl { public: HapticGeneratorSw() { LOG(DEBUG) << __func__; } ~HapticGeneratorSw() { + cleanUp(); LOG(DEBUG) << __func__; - releaseContext(); } ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override; @@ -57,13 +57,14 @@ class HapticGeneratorSw final : public EffectImpl { const HapticGenerator::Capability kCapability; /* Effect descriptor */ const Descriptor kDescriptor = { - .common = {.id = {.type = HapticGeneratorTypeUUID, - .uuid = HapticGeneratorSwImplUUID, + .common = {.id = {.type = kHapticGeneratorTypeUUID, + .uuid = kHapticGeneratorSwImplUUID, .proxy = std::nullopt}, .flags = {.type = Flags::Type::INSERT, .insert = Flags::Insert::FIRST, .volume = Flags::Volume::CTRL}, - .name = "HapticGeneratorSw"}, + .name = "HapticGeneratorSw", + .implementor = "The Android Open Source Project"}, .capability = Capability::make(kCapability)}; /* parameters */ diff --git a/audio/aidl/default/include/effect-impl/EffectImpl.h b/audio/aidl/default/include/effect-impl/EffectImpl.h index cb395b729a..d9825da7ad 100644 --- a/audio/aidl/default/include/effect-impl/EffectImpl.h +++ b/audio/aidl/default/include/effect-impl/EffectImpl.h @@ -30,11 +30,8 @@ namespace aidl::android::hardware::audio::effect { class EffectImpl : public BnEffect, public EffectWorker { public: - EffectImpl() { LOG(DEBUG) << __func__; } - ~EffectImpl() { - cleanUp(); - LOG(DEBUG) << __func__; - } + EffectImpl() = default; + virtual ~EffectImpl() = default; /** * Each effect implementation CAN override these methods if necessary @@ -78,9 +75,9 @@ class EffectImpl : public BnEffect, public EffectWorker { State mState GUARDED_BY(mMutex) = State::INIT; IEffect::Status status(binder_status_t status, size_t consumed, size_t produced); + void cleanUp(); private: - void cleanUp(); std::shared_ptr mContext GUARDED_BY(mMutex); }; } // namespace aidl::android::hardware::audio::effect diff --git a/audio/aidl/default/include/effect-impl/EffectUUID.h b/audio/aidl/default/include/effect-impl/EffectUUID.h index 184a587291..7709eabf78 100644 --- a/audio/aidl/default/include/effect-impl/EffectUUID.h +++ b/audio/aidl/default/include/effect-impl/EffectUUID.h @@ -23,150 +23,160 @@ namespace aidl::android::hardware::audio::effect { using ::aidl::android::media::audio::common::AudioUuid; -// Null UUID -static const AudioUuid EffectNullUuid = {static_cast(0xec7178ec), - 0xe5e1, - 0x4432, - 0xa3f4, - {0x46, 0x57, 0xe6, 0x79, 0x52, 0x10}}; - +// ec7178ec-e5e1-4432-a3f4-4657e6795210 +static const AudioUuid kEffectNullUuid = {static_cast(0xec7178ec), + 0xe5e1, + 0x4432, + 0xa3f4, + {0x46, 0x57, 0xe6, 0x79, 0x52, 0x10}}; // Zero UUID -static const AudioUuid EffectZeroUuid = { +static const AudioUuid kEffectZeroUuid = { static_cast(0x0), 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; -// Equalizer type UUID. -static const AudioUuid EqualizerTypeUUID = {static_cast(0x0bed4300), - 0xddd6, - 0x11db, - 0x8f34, - {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}; - -// 0bed4300-847d-11df-bb17-0002a5d5c51b -static const AudioUuid EqualizerSwImplUUID = {static_cast(0x0bed4300), - 0x847d, - 0x11df, - 0xbb17, - {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}; - -// ce772f20-847d-11df-bb17-0002a5d5c51b -static const AudioUuid EqualizerBundleImplUUID = {static_cast(0xce772f20), - 0x847d, - 0x11df, - 0xbb17, - {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}; - -// fa8184a4-588b-11ed-9b6a-0242ac120002 -static const AudioUuid BassBoostTypeUUID = {static_cast(0xfa8184a4), - 0x588b, - 0x11ed, - 0x9b6a, - {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; +// 0634f220-ddd4-11db-a0fc-0002a5d5c51b +static const AudioUuid kBassBoostTypeUUID = {static_cast(0x0634f220), + 0xddd4, + 0x11db, + 0xa0fc, + {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}; // fa8181f2-588b-11ed-9b6a-0242ac120002 -static const AudioUuid BassBoostSwImplUUID = {static_cast(0xfa8181f2), - 0x588b, - 0x11ed, - 0x9b6a, - {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; -// fa81862a-588b-11ed-9b6a-0242ac120002 -static const AudioUuid DownmixTypeUUID = {static_cast(0xfa81862a), - 0x588b, - 0x11ed, - 0x9b6a, - {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; -// fa8187ba-588b-11ed-9b6a-0242ac120002 -static const AudioUuid DownmixSwImplUUID = {static_cast(0xfa8187ba), - 0x588b, - 0x11ed, - 0x9b6a, - {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; -// fa818954-588b-11ed-9b6a-0242ac120002 -static const AudioUuid DynamicsProcessingTypeUUID = {static_cast(0xfa818954), - 0x588b, - 0x11ed, - 0x9b6a, - {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; -// fa818d78-588b-11ed-9b6a-0242ac120002 -static const AudioUuid DynamicsProcessingSwImplUUID = {static_cast(0xfa818d78), - 0x588b, - 0x11ed, - 0x9b6a, - {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; -// fa818f62-588b-11ed-9b6a-0242ac120002 -static const AudioUuid HapticGeneratorTypeUUID = {static_cast(0xfa818f62), - 0x588b, - 0x11ed, - 0x9b6a, - {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; -// fa819110-588b-11ed-9b6a-0242ac120002 -static const AudioUuid HapticGeneratorSwImplUUID = {static_cast(0xfa819110), - 0x588b, - 0x11ed, - 0x9b6a, - {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; - -// fa8194a8-588b-11ed-9b6a-0242ac120002 -static const AudioUuid LoudnessEnhancerTypeUUID = {static_cast(0xfa8194a8), - 0x588b, - 0x11ed, - 0x9b6a, - {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; -// fa819610-588b-11ed-9b6a-0242ac120002 -static const AudioUuid LoudnessEnhancerSwImplUUID = {static_cast(0xfa819610), - 0x588b, - 0x11ed, - 0x9b6a, - {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; -// fa819886-588b-11ed-9b6a-0242ac120002 -static const AudioUuid ReverbTypeUUID = {static_cast(0xfa819886), - 0x588b, - 0x11ed, - 0x9b6a, - {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; -// fa8199c6-588b-11ed-9b6a-0242ac120002 -static const AudioUuid ReverbSwImplUUID = {static_cast(0xfa8199c6), - 0x588b, - 0x11ed, - 0x9b6a, - {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; - -// fa819af2-588b-11ed-9b6a-0242ac120002 -static const AudioUuid VirtualizerTypeUUID = {static_cast(0xfa819af2), - 0x588b, - 0x11ed, - 0x9b6a, - {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; -// fa819d86-588b-11ed-9b6a-0242ac120002 -static const AudioUuid VirtualizerSwImplUUID = {static_cast(0xfa819d86), - 0x588b, - 0x11ed, - 0x9b6a, - {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; - -// fa819f3e-588b-11ed-9b6a-0242ac120002 -static const AudioUuid VisualizerTypeUUID = {static_cast(0xfa819f3e), - 0x588b, - 0x11ed, - 0x9b6a, - {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; -// fa81a0f6-588b-11ed-9b6a-0242ac120002 -static const AudioUuid VisualizerSwImplUUID = {static_cast(0xfa81a0f6), +static const AudioUuid kBassBoostSwImplUUID = {static_cast(0xfa8181f2), 0x588b, 0x11ed, 0x9b6a, {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; - -// fa81a2b8-588b-11ed-9b6a-0242ac120002 -static const AudioUuid VolumeTypeUUID = {static_cast(0xfa81a2b8), - 0x588b, - 0x11ed, - 0x9b6a, - {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; -// fa81a718-588b-11ed-9b6a-0242ac120002 -static const AudioUuid VolumeSwImplUUID = {static_cast(0xfa81a718), +// fa81862a-588b-11ed-9b6a-0242ac120002 +static const AudioUuid kDownmixTypeUUID = {static_cast(0xfa81862a), 0x588b, 0x11ed, 0x9b6a, {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; +// fa8187ba-588b-11ed-9b6a-0242ac120002 +static const AudioUuid kDownmixSwImplUUID = {static_cast(0xfa8187ba), + 0x588b, + 0x11ed, + 0x9b6a, + {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; +// 0bed4300-ddd6-11db-8f34-0002a5d5c51b. +static const AudioUuid kEqualizerTypeUUID = {static_cast(0x0bed4300), + 0xddd6, + 0x11db, + 0x8f34, + {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}; +// 0bed4300-847d-11df-bb17-0002a5d5c51b +static const AudioUuid kEqualizerSwImplUUID = {static_cast(0x0bed4300), + 0x847d, + 0x11df, + 0xbb17, + {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}; +// ce772f20-847d-11df-bb17-0002a5d5c51b +static const AudioUuid kEqualizerBundleImplUUID = {static_cast(0xce772f20), + 0x847d, + 0x11df, + 0xbb17, + {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}; +// c8e70ecd-48ca-456e-8a4f-0002a5d5c51b +static const AudioUuid kEqualizerProxyUUID = {static_cast(0xc8e70ecd), + 0x48ca, + 0x456e, + 0x8a4f, + {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}; +// 7261676f-6d75-7369-6364-28e2fd3ac39e +static const AudioUuid kDynamicsProcessingTypeUUID = {static_cast(0x7261676f), + 0x6d75, + 0x7369, + 0x6364, + {0x28, 0xe2, 0xfd, 0x3a, 0xc3, 0x9e}}; +// fa818d78-588b-11ed-9b6a-0242ac120002 +static const AudioUuid kDynamicsProcessingSwImplUUID = {static_cast(0xfa818d78), + 0x588b, + 0x11ed, + 0x9b6a, + {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; +// 1411e6d6-aecd-4021-a1cf-a6aceb0d71e5 +static const AudioUuid kHapticGeneratorTypeUUID = {static_cast(0x1411e6d6), + 0xaecd, + 0x4021, + 0xa1cf, + {0xa6, 0xac, 0xeb, 0x0d, 0x71, 0xe5}}; +// fa819110-588b-11ed-9b6a-0242ac120002 +static const AudioUuid kHapticGeneratorSwImplUUID = {static_cast(0xfa819110), + 0x588b, + 0x11ed, + 0x9b6a, + {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; +// fe3199be-aed0-413f-87bb-11260eb63cf1 +static const AudioUuid kLoudnessEnhancerTypeUUID = {static_cast(0xfe3199be), + 0xaed0, + 0x413f, + 0x87bb, + {0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}; +// fa819610-588b-11ed-9b6a-0242ac120002 +static const AudioUuid kLoudnessEnhancerSwImplUUID = {static_cast(0xfa819610), + 0x588b, + 0x11ed, + 0x9b6a, + {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; +// c2e5d5f0-94bd-4763-9cac-4e234d06839e +static const AudioUuid kEnvReverbTypeUUID = {static_cast(0xc2e5d5f0), + 0x94bd, + 0x4763, + 0x9cac, + {0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}}; +// fa819886-588b-11ed-9b6a-0242ac120002 +static const AudioUuid kEnvReverbSwImplUUID = {static_cast(0xfa819886), + 0x588b, + 0x11ed, + 0x9b6a, + {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; +// 47382d60-ddd8-11db-bf3a-0002a5d5c51b +static const AudioUuid kPresetReverbTypeUUID = {static_cast(0x47382d60), + 0xddd8, + 0x11db, + 0xbf3a, + {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}; +// fa8199c6-588b-11ed-9b6a-0242ac120002 +static const AudioUuid kPresetReverbSwImplUUID = {static_cast(0xfa8199c6), + 0x588b, + 0x11ed, + 0x9b6a, + {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; +// 37cc2c00-dddd-11db-8577-0002a5d5c51b +static const AudioUuid kVirtualizerTypeUUID = {static_cast(0x37cc2c00), + 0xdddd, + 0x11db, + 0x8577, + {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}; +// fa819d86-588b-11ed-9b6a-0242ac120002 +static const AudioUuid kVirtualizerSwImplUUID = {static_cast(0xfa819d86), + 0x588b, + 0x11ed, + 0x9b6a, + {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; +// fa819f3e-588b-11ed-9b6a-0242ac120002 +static const AudioUuid kVisualizerTypeUUID = {static_cast(0xfa819f3e), + 0x588b, + 0x11ed, + 0x9b6a, + {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; +// fa81a0f6-588b-11ed-9b6a-0242ac120002 +static const AudioUuid kVisualizerSwImplUUID = {static_cast(0xfa81a0f6), + 0x588b, + 0x11ed, + 0x9b6a, + {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; +// fa81a2b8-588b-11ed-9b6a-0242ac120002 +static const AudioUuid kVolumeTypeUUID = {static_cast(0xfa81a2b8), + 0x588b, + 0x11ed, + 0x9b6a, + {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; +// fa81a718-588b-11ed-9b6a-0242ac120002 +static const AudioUuid kVolumeSwImplUUID = {static_cast(0xfa81a718), + 0x588b, + 0x11ed, + 0x9b6a, + {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; /** * @brief A map between effect name and effect type UUID. @@ -174,20 +184,21 @@ static const AudioUuid VolumeSwImplUUID = {static_cast(0xfa81a718), * We need this map is because existing audio_effects.xml don't have a type UUID defined. */ static const std::map kUuidNameTypeMap = { - {"bassboost", BassBoostTypeUUID}, - {"downmix", DownmixTypeUUID}, - {"dynamics_processing", DynamicsProcessingTypeUUID}, - {"equalizer", EqualizerTypeUUID}, - {"haptic_generator", HapticGeneratorTypeUUID}, - {"loudness_enhancer", LoudnessEnhancerTypeUUID}, - {"reverb", ReverbTypeUUID}, - {"reverb_env_aux", ReverbTypeUUID}, - {"reverb_env_ins", ReverbTypeUUID}, - {"reverb_pre_aux", ReverbTypeUUID}, - {"reverb_pre_ins", ReverbTypeUUID}, - {"virtualizer", VirtualizerTypeUUID}, - {"visualizer", VisualizerTypeUUID}, - {"volume", VolumeTypeUUID}, + {"bassboost", kBassBoostTypeUUID}, + {"downmix", kDownmixTypeUUID}, + {"dynamics_processing", kDynamicsProcessingTypeUUID}, + {"equalizer", kEqualizerTypeUUID}, + {"haptic_generator", kHapticGeneratorTypeUUID}, + {"loudness_enhancer", kLoudnessEnhancerTypeUUID}, + {"env_reverb", kEnvReverbTypeUUID}, + {"preset_reverb", kPresetReverbTypeUUID}, + {"reverb_env_aux", kEnvReverbTypeUUID}, + {"reverb_env_ins", kEnvReverbTypeUUID}, + {"reverb_pre_aux", kPresetReverbTypeUUID}, + {"reverb_pre_ins", kPresetReverbTypeUUID}, + {"virtualizer", kVirtualizerTypeUUID}, + {"visualizer", kVisualizerTypeUUID}, + {"volume", kVolumeTypeUUID}, }; } // namespace aidl::android::hardware::audio::effect diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp index 27b9169cef..9d2b978fa4 100644 --- a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp +++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp @@ -26,14 +26,14 @@ #include "LoudnessEnhancerSw.h" using aidl::android::hardware::audio::effect::IEffect; +using aidl::android::hardware::audio::effect::kLoudnessEnhancerSwImplUUID; using aidl::android::hardware::audio::effect::LoudnessEnhancerSw; -using aidl::android::hardware::audio::effect::LoudnessEnhancerSwImplUUID; using aidl::android::hardware::audio::effect::State; using aidl::android::media::audio::common::AudioUuid; extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid, std::shared_ptr* instanceSpp) { - if (!in_impl_uuid || *in_impl_uuid != LoudnessEnhancerSwImplUUID) { + if (!in_impl_uuid || *in_impl_uuid != kLoudnessEnhancerSwImplUUID) { LOG(ERROR) << __func__ << "uuid not supported"; return EX_ILLEGAL_ARGUMENT; } diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h index 478aebc1ae..856bf0b5c6 100644 --- a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h +++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h @@ -48,8 +48,8 @@ class LoudnessEnhancerSw final : public EffectImpl { public: LoudnessEnhancerSw() { LOG(DEBUG) << __func__; } ~LoudnessEnhancerSw() { + cleanUp(); LOG(DEBUG) << __func__; - releaseContext(); } ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override; @@ -66,13 +66,14 @@ class LoudnessEnhancerSw final : public EffectImpl { const LoudnessEnhancer::Capability kCapability; /* Effect descriptor */ const Descriptor kDescriptor = { - .common = {.id = {.type = LoudnessEnhancerTypeUUID, - .uuid = LoudnessEnhancerSwImplUUID, + .common = {.id = {.type = kLoudnessEnhancerTypeUUID, + .uuid = kLoudnessEnhancerSwImplUUID, .proxy = std::nullopt}, .flags = {.type = Flags::Type::INSERT, .insert = Flags::Insert::FIRST, .volume = Flags::Volume::CTRL}, - .name = "LoudnessEnhancerSw"}, + .name = "LoudnessEnhancerSw", + .implementor = "The Android Open Source Project"}, .capability = Capability::make(kCapability)}; ndk::ScopedAStatus getParameterLoudnessEnhancer(const LoudnessEnhancer::Tag& tag, diff --git a/audio/aidl/default/presetReverb/Android.bp b/audio/aidl/default/presetReverb/Android.bp new file mode 100644 index 0000000000..41485112e4 --- /dev/null +++ b/audio/aidl/default/presetReverb/Android.bp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2022 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. + */ + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "hardware_interfaces_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["hardware_interfaces_license"], +} + +cc_library_shared { + name: "libpresetreverbsw", + defaults: [ + "aidlaudioeffectservice_defaults", + "latest_android_media_audio_common_types_ndk_shared", + "latest_android_hardware_audio_effect_ndk_shared", + ], + srcs: [ + "PresetReverbSw.cpp", + ":effectCommonFile", + ], + visibility: [ + "//hardware/interfaces/audio/aidl/default", + ], +} diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.cpp b/audio/aidl/default/presetReverb/PresetReverbSw.cpp new file mode 100644 index 0000000000..069d0ff87a --- /dev/null +++ b/audio/aidl/default/presetReverb/PresetReverbSw.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2022 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 +#define LOG_TAG "AHAL_PresetReverbSw" +#include +#include +#include + +#include +#include + +#include "PresetReverbSw.h" + +using aidl::android::hardware::audio::effect::IEffect; +using aidl::android::hardware::audio::effect::kPresetReverbSwImplUUID; +using aidl::android::hardware::audio::effect::PresetReverbSw; +using aidl::android::hardware::audio::effect::State; +using aidl::android::media::audio::common::AudioUuid; + +extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid, + std::shared_ptr* instanceSpp) { + if (!in_impl_uuid || *in_impl_uuid != kPresetReverbSwImplUUID) { + LOG(ERROR) << __func__ << "uuid not supported"; + return EX_ILLEGAL_ARGUMENT; + } + if (instanceSpp) { + *instanceSpp = ndk::SharedRefBase::make(); + LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created"; + return EX_NONE; + } else { + LOG(ERROR) << __func__ << " invalid input parameter!"; + return EX_ILLEGAL_ARGUMENT; + } +} + +extern "C" binder_exception_t destroyEffect(const std::shared_ptr& instanceSp) { + if (!instanceSp) { + return EX_NONE; + } + State state; + ndk::ScopedAStatus status = instanceSp->getState(&state); + if (!status.isOk() || State::INIT != state) { + LOG(ERROR) << __func__ << " instance " << instanceSp.get() + << " in state: " << toString(state) << ", status: " << status.getDescription(); + return EX_ILLEGAL_STATE; + } + LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed"; + return EX_NONE; +} + +namespace aidl::android::hardware::audio::effect { + +ndk::ScopedAStatus PresetReverbSw::getDescriptor(Descriptor* _aidl_return) { + LOG(DEBUG) << __func__ << kDescriptor.toString(); + *_aidl_return = kDescriptor; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus PresetReverbSw::setParameterSpecific(const Parameter::Specific& specific) { + RETURN_IF(Parameter::Specific::reverb != specific.getTag(), EX_ILLEGAL_ARGUMENT, + "EffectNotSupported"); + std::lock_guard lg(mMutex); + RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext"); + + mSpecificParam = specific.get(); + LOG(DEBUG) << __func__ << " success with: " << specific.toString(); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus PresetReverbSw::getParameterSpecific(const Parameter::Id& id, + Parameter::Specific* specific) { + auto tag = id.getTag(); + RETURN_IF(Parameter::Id::reverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag"); + specific->set(mSpecificParam); + return ndk::ScopedAStatus::ok(); +} + +std::shared_ptr PresetReverbSw::createContext(const Parameter::Common& common) { + if (mContext) { + LOG(DEBUG) << __func__ << " context already exist"; + return mContext; + } + mContext = std::make_shared(1 /* statusFmqDepth */, common); + return mContext; +} + +RetCode PresetReverbSw::releaseContext() { + if (mContext) { + mContext.reset(); + } + return RetCode::SUCCESS; +} + +// Processing method running in EffectWorker thread. +IEffect::Status PresetReverbSw::effectProcessImpl(float* in, float* out, int process) { + // TODO: get data buffer and process. + LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process; + for (int i = 0; i < process; i++) { + *out++ = *in++; + } + return {STATUS_OK, process, process}; +} + +} // namespace aidl::android::hardware::audio::effect diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.h b/audio/aidl/default/presetReverb/PresetReverbSw.h new file mode 100644 index 0000000000..75a5a9432a --- /dev/null +++ b/audio/aidl/default/presetReverb/PresetReverbSw.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2022 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. + */ + +#pragma once + +#include +#include +#include +#include + +#include "effect-impl/EffectImpl.h" +#include "effect-impl/EffectUUID.h" + +namespace aidl::android::hardware::audio::effect { + +class PresetReverbSwContext final : public EffectContext { + public: + PresetReverbSwContext(int statusDepth, const Parameter::Common& common) + : EffectContext(statusDepth, common) { + LOG(DEBUG) << __func__; + } + // TODO: add specific context here +}; + +class PresetReverbSw final : public EffectImpl { + public: + PresetReverbSw() { LOG(DEBUG) << __func__; } + ~PresetReverbSw() { + cleanUp(); + LOG(DEBUG) << __func__; + } + + ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override; + ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override; + ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, + Parameter::Specific* specific) override; + IEffect::Status effectProcessImpl(float* in, float* out, int process) override; + std::shared_ptr createContext(const Parameter::Common& common) override; + RetCode releaseContext() override; + + private: + std::shared_ptr mContext; + /* capabilities */ + const Reverb::Capability kCapability; + /* Effect descriptor */ + const Descriptor kDescriptor = { + .common = {.id = {.type = kPresetReverbTypeUUID, + .uuid = kPresetReverbSwImplUUID, + .proxy = std::nullopt}, + .flags = {.type = Flags::Type::INSERT, + .insert = Flags::Insert::FIRST, + .volume = Flags::Volume::CTRL}, + .name = "PresetReverbSw", + .implementor = "The Android Open Source Project"}, + .capability = Capability::make(kCapability)}; + + /* parameters */ + Reverb mSpecificParam; +}; +} // namespace aidl::android::hardware::audio::effect diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.cpp b/audio/aidl/default/virtualizer/VirtualizerSw.cpp index ccb7b4bd5b..9688fc8e7c 100644 --- a/audio/aidl/default/virtualizer/VirtualizerSw.cpp +++ b/audio/aidl/default/virtualizer/VirtualizerSw.cpp @@ -26,14 +26,14 @@ #include "VirtualizerSw.h" using aidl::android::hardware::audio::effect::IEffect; +using aidl::android::hardware::audio::effect::kVirtualizerSwImplUUID; using aidl::android::hardware::audio::effect::State; using aidl::android::hardware::audio::effect::VirtualizerSw; -using aidl::android::hardware::audio::effect::VirtualizerSwImplUUID; using aidl::android::media::audio::common::AudioUuid; extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid, std::shared_ptr* instanceSpp) { - if (!in_impl_uuid || *in_impl_uuid != VirtualizerSwImplUUID) { + if (!in_impl_uuid || *in_impl_uuid != kVirtualizerSwImplUUID) { LOG(ERROR) << __func__ << "uuid not supported"; return EX_ILLEGAL_ARGUMENT; } diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.h b/audio/aidl/default/virtualizer/VirtualizerSw.h index da1998b89a..e4de8b321d 100644 --- a/audio/aidl/default/virtualizer/VirtualizerSw.h +++ b/audio/aidl/default/virtualizer/VirtualizerSw.h @@ -39,8 +39,8 @@ class VirtualizerSw final : public EffectImpl { public: VirtualizerSw() { LOG(DEBUG) << __func__; } ~VirtualizerSw() { + cleanUp(); LOG(DEBUG) << __func__; - releaseContext(); } ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override; @@ -57,13 +57,14 @@ class VirtualizerSw final : public EffectImpl { const Virtualizer::Capability kCapability; /* Effect descriptor */ const Descriptor kDescriptor = { - .common = {.id = {.type = VirtualizerTypeUUID, - .uuid = VirtualizerSwImplUUID, + .common = {.id = {.type = kVirtualizerTypeUUID, + .uuid = kVirtualizerSwImplUUID, .proxy = std::nullopt}, .flags = {.type = Flags::Type::INSERT, .insert = Flags::Insert::FIRST, .volume = Flags::Volume::CTRL}, - .name = "VirtualizerSw"}, + .name = "VirtualizerSw", + .implementor = "The Android Open Source Project"}, .capability = Capability::make(kCapability)}; /* parameters */ diff --git a/audio/aidl/default/visualizer/VisualizerSw.cpp b/audio/aidl/default/visualizer/VisualizerSw.cpp index 5a24f18950..24a7bef25c 100644 --- a/audio/aidl/default/visualizer/VisualizerSw.cpp +++ b/audio/aidl/default/visualizer/VisualizerSw.cpp @@ -26,14 +26,14 @@ #include "VisualizerSw.h" using aidl::android::hardware::audio::effect::IEffect; +using aidl::android::hardware::audio::effect::kVisualizerSwImplUUID; using aidl::android::hardware::audio::effect::State; using aidl::android::hardware::audio::effect::VisualizerSw; -using aidl::android::hardware::audio::effect::VisualizerSwImplUUID; using aidl::android::media::audio::common::AudioUuid; extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid, std::shared_ptr* instanceSpp) { - if (!in_impl_uuid || *in_impl_uuid != VisualizerSwImplUUID) { + if (!in_impl_uuid || *in_impl_uuid != kVisualizerSwImplUUID) { LOG(ERROR) << __func__ << "uuid not supported"; return EX_ILLEGAL_ARGUMENT; } diff --git a/audio/aidl/default/visualizer/VisualizerSw.h b/audio/aidl/default/visualizer/VisualizerSw.h index 21101ddeb0..bccd6e978d 100644 --- a/audio/aidl/default/visualizer/VisualizerSw.h +++ b/audio/aidl/default/visualizer/VisualizerSw.h @@ -39,8 +39,8 @@ class VisualizerSw final : public EffectImpl { public: VisualizerSw() { LOG(DEBUG) << __func__; } ~VisualizerSw() { + cleanUp(); LOG(DEBUG) << __func__; - releaseContext(); } ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override; @@ -57,13 +57,14 @@ class VisualizerSw final : public EffectImpl { const Visualizer::Capability kCapability; /* Effect descriptor */ const Descriptor kDescriptor = { - .common = {.id = {.type = VisualizerTypeUUID, - .uuid = VisualizerSwImplUUID, + .common = {.id = {.type = kVisualizerTypeUUID, + .uuid = kVisualizerSwImplUUID, .proxy = std::nullopt}, .flags = {.type = Flags::Type::INSERT, .insert = Flags::Insert::FIRST, .volume = Flags::Volume::CTRL}, - .name = "VisualizerSw"}, + .name = "VisualizerSw", + .implementor = "The Android Open Source Project"}, .capability = Capability::make(kCapability)}; /* parameters */ diff --git a/audio/aidl/default/volume/VolumeSw.cpp b/audio/aidl/default/volume/VolumeSw.cpp index e2f42d7413..b8af921a8a 100644 --- a/audio/aidl/default/volume/VolumeSw.cpp +++ b/audio/aidl/default/volume/VolumeSw.cpp @@ -26,14 +26,14 @@ #include "VolumeSw.h" using aidl::android::hardware::audio::effect::IEffect; +using aidl::android::hardware::audio::effect::kVolumeSwImplUUID; using aidl::android::hardware::audio::effect::State; using aidl::android::hardware::audio::effect::VolumeSw; -using aidl::android::hardware::audio::effect::VolumeSwImplUUID; using aidl::android::media::audio::common::AudioUuid; extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid, std::shared_ptr* instanceSpp) { - if (!in_impl_uuid || *in_impl_uuid != VolumeSwImplUUID) { + if (!in_impl_uuid || *in_impl_uuid != kVolumeSwImplUUID) { LOG(ERROR) << __func__ << "uuid not supported"; return EX_ILLEGAL_ARGUMENT; } diff --git a/audio/aidl/default/volume/VolumeSw.h b/audio/aidl/default/volume/VolumeSw.h index e46c8645bf..86e01c10cd 100644 --- a/audio/aidl/default/volume/VolumeSw.h +++ b/audio/aidl/default/volume/VolumeSw.h @@ -39,8 +39,8 @@ class VolumeSw final : public EffectImpl { public: VolumeSw() { LOG(DEBUG) << __func__; } ~VolumeSw() { + cleanUp(); LOG(DEBUG) << __func__; - releaseContext(); } ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override; @@ -57,13 +57,14 @@ class VolumeSw final : public EffectImpl { const Volume::Capability kCapability; /* Effect descriptor */ const Descriptor kDescriptor = { - .common = {.id = {.type = VolumeTypeUUID, - .uuid = VolumeSwImplUUID, + .common = {.id = {.type = kVolumeTypeUUID, + .uuid = kVolumeSwImplUUID, .proxy = std::nullopt}, .flags = {.type = Flags::Type::INSERT, .insert = Flags::Insert::FIRST, .volume = Flags::Volume::CTRL}, - .name = "VolumeSw"}, + .name = "VolumeSw", + .implementor = "The Android Open Source Project"}, .capability = Capability::make(kCapability)}; /* parameters */ diff --git a/audio/aidl/vts/EffectFactoryHelper.h b/audio/aidl/vts/EffectFactoryHelper.h index d58fcf259b..dc766dd297 100644 --- a/audio/aidl/vts/EffectFactoryHelper.h +++ b/audio/aidl/vts/EffectFactoryHelper.h @@ -29,10 +29,7 @@ using namespace android; using aidl::android::hardware::audio::effect::Descriptor; -using aidl::android::hardware::audio::effect::EffectNullUuid; -using aidl::android::hardware::audio::effect::IEffect; using aidl::android::hardware::audio::effect::IFactory; -using aidl::android::hardware::audio::effect::Processing; using aidl::android::media::audio::common::AudioUuid; class EffectFactoryHelper { @@ -48,122 +45,36 @@ class EffectFactoryHelper { ASSERT_NE(mEffectFactory, nullptr); mEffectFactory = IFactory::fromBinder(binderUtil.restartService()); ASSERT_NE(mEffectFactory, nullptr); - ClearEffectMap(); } - void QueryEffects(const std::optional& in_type, - const std::optional& in_instance, - const std::optional& in_proxy, - std::vector* _aidl_return) { - ASSERT_NE(mEffectFactory, nullptr); - EXPECT_IS_OK(mEffectFactory->queryEffects(in_type, in_instance, in_proxy, _aidl_return)); - mIds = *_aidl_return; - } + std::shared_ptr GetFactory() const { return mEffectFactory; } - void QueryProcessing(const std::optional& in_type, - std::vector* _aidl_return) { - ASSERT_NE(mEffectFactory, nullptr); - EXPECT_IS_OK(mEffectFactory->queryProcessing(in_type, _aidl_return)); - // only update the whole list if no filter applied - if (!in_type.has_value()) { - mProcesses = *_aidl_return; - } - } + static std::vector, Descriptor::Identity>> + getAllEffectDescriptors(std::string serviceName, std::optional type = std::nullopt) { + AudioHalBinderServiceUtil util; + auto names = android::getAidlHalInstanceNames(serviceName); + std::vector, Descriptor::Identity>> result; - void CreateEffects() { - for (const auto& id : mIds) { - std::shared_ptr effect; - EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect)); - EXPECT_NE(effect, nullptr) << id.toString(); - if (effect) { - mEffectIdMap[effect] = id; + for (const auto& name : names) { + auto factory = IFactory::fromBinder(util.connectToService(name)); + if (factory) { + if (std::vector ids; + factory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids).isOk()) { + for (const auto& id : ids) { + if (type.has_value() && id.type != type.value()) { + continue; + } + result.emplace_back(factory, id); + } + } } } - } - void QueryAndCreateEffects(const AudioUuid& type = EffectNullUuid) { - std::vector ids; - ASSERT_NE(mEffectFactory, nullptr); - - if (type == EffectNullUuid) { - EXPECT_IS_OK( - mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids)); - } else { - EXPECT_IS_OK(mEffectFactory->queryEffects(type, std::nullopt, std::nullopt, &ids)); - } - for (const auto& id : ids) { - ASSERT_EQ(id.type, type); - std::shared_ptr effect; - EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect)); - EXPECT_NE(effect, nullptr) << id.toString(); - if (effect) { - mEffectIdMap[effect] = id; - } - } + return result; } - void CreateEffectsAndExpect( - const std::vector>& uuid_status) { - ASSERT_NE(mEffectFactory, nullptr); - for (const auto& it : uuid_status) { - std::shared_ptr effect; - auto status = mEffectFactory->createEffect(it.first.uuid, &effect); - EXPECT_STATUS(it.second, status); - if (effect) { - mEffectIdMap[effect] = it.first; - } - } - } - - void DestroyEffectAndExpect(std::shared_ptr& instance, binder_exception_t exception) { - ASSERT_NE(mEffectFactory, nullptr); - auto status = mEffectFactory->destroyEffect(instance); - EXPECT_STATUS(exception, status); - } - - void QueryAndCreateAllEffects() { - ASSERT_NE(mEffectFactory, nullptr); - EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, - &mCompleteIds)); - for (const auto& id : mCompleteIds) { - std::shared_ptr effect; - EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect)); - EXPECT_NE(effect, nullptr) << id.toString(); - mEffectIdMap[effect] = id; - } - } - - void DestroyEffects(const binder_exception_t expected = EX_NONE, const int remaining = 0) { - ASSERT_NE(mEffectFactory, nullptr); - - for (auto it = mEffectIdMap.begin(); it != mEffectIdMap.end();) { - auto erased = it++; - auto status = mEffectFactory->destroyEffect(erased->first); - EXPECT_STATUS(expected, status); - if (status.isOk()) { - mEffectIdMap.erase(erased); - } - } - EXPECT_EQ((unsigned int)remaining, mEffectIdMap.size()); - } - - std::shared_ptr GetFactory() { return mEffectFactory; } - const std::vector& GetEffectIds() { return mIds; } - const std::vector& GetCompleteEffectIdList() const { - return mCompleteIds; - } - const std::map, Descriptor::Identity>& GetEffectMap() const { - return mEffectIdMap; - } - void ClearEffectMap() { mEffectIdMap.clear(); } - private: std::shared_ptr mEffectFactory; std::string mServiceName; AudioHalBinderServiceUtil binderUtil; - std::vector mIds; - std::vector mCompleteIds; - std::vector mProcesses; - - std::map, Descriptor::Identity> mEffectIdMap; }; diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h index 623ac3749d..73a1f4936b 100644 --- a/audio/aidl/vts/EffectHelper.h +++ b/audio/aidl/vts/EffectHelper.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include #include @@ -24,7 +25,6 @@ #include #include #include -#include #include #include @@ -35,275 +35,139 @@ using namespace android; using aidl::android::hardware::audio::effect::CommandId; using aidl::android::hardware::audio::effect::Descriptor; -using aidl::android::hardware::audio::effect::EffectNullUuid; -using aidl::android::hardware::audio::effect::EffectZeroUuid; using aidl::android::hardware::audio::effect::IEffect; using aidl::android::hardware::audio::effect::Parameter; using aidl::android::hardware::audio::effect::State; using aidl::android::hardware::common::fmq::SynchronizedReadWrite; using aidl::android::media::audio::common::AudioChannelLayout; -using aidl::android::media::audio::common::AudioDeviceType; using aidl::android::media::audio::common::AudioFormatDescription; using aidl::android::media::audio::common::AudioFormatType; using aidl::android::media::audio::common::AudioUuid; using aidl::android::media::audio::common::PcmType; -const AudioFormatDescription DefaultFormat = { +const AudioFormatDescription kDefaultFormatDescription = { .type = AudioFormatType::PCM, .pcm = PcmType::FLOAT_32_BIT, .encoding = ""}; +typedef ::android::AidlMessageQueue + StatusMQ; +typedef ::android::AidlMessageQueue + DataMQ; + class EffectHelper { public: - explicit EffectHelper(const std::string& name) : mFactoryHelper(EffectFactoryHelper(name)) { - mFactoryHelper.ConnectToFactoryService(); + static void create(std::shared_ptr factory, std::shared_ptr& effect, + Descriptor::Identity id, binder_status_t status = EX_NONE) { + ASSERT_NE(factory, nullptr); + EXPECT_STATUS(status, factory->createEffect(id.uuid, &effect)); + if (status == EX_NONE) { + ASSERT_NE(effect, nullptr) << id.uuid.toString(); + } } - void OpenEffects(const AudioUuid& type = EffectNullUuid) { - auto open = [&](const std::shared_ptr& effect) { - ASSERT_NE(effect, nullptr); - IEffect::OpenEffectReturn ret; - EXPECT_IS_OK(effect->open(mCommon, mSpecific, &ret)); - EffectParam params; - params.statusMQ = std::make_unique(ret.statusMQ); - params.inputMQ = std::make_unique(ret.inputDataMQ); - params.outputMQ = std::make_unique(ret.outputDataMQ); - mEffectParams.push_back(std::move(params)); - }; - EXPECT_NO_FATAL_FAILURE(ForEachEffect(open, type)); + static void destroy(std::shared_ptr factory, std::shared_ptr effect, + binder_status_t status = EX_NONE) { + ASSERT_NE(factory, nullptr); + ASSERT_NE(effect, nullptr); + EXPECT_STATUS(status, factory->destroyEffect(effect)); } - void CloseEffects(const binder_status_t status = EX_NONE) { - auto close = [&](const std::shared_ptr& effect) { - ASSERT_NE(effect, nullptr); + static void open(std::shared_ptr effect, const Parameter::Common& common, + const std::optional& specific, + IEffect::OpenEffectReturn* ret, binder_status_t status = EX_NONE) { + ASSERT_NE(effect, nullptr); + EXPECT_STATUS(status, effect->open(common, specific, ret)); + } + + static void open(std::shared_ptr effect, int session = 0, + binder_status_t status = EX_NONE) { + ASSERT_NE(effect, nullptr); + Parameter::Common common = EffectHelper::createParamCommon(session); + IEffect::OpenEffectReturn ret; + open(effect, common, std::nullopt /* specific */, &ret, status); + } + + static void close(std::shared_ptr effect, binder_status_t status = EX_NONE) { + if (effect) { EXPECT_STATUS(status, effect->close()); - }; - - EXPECT_NO_FATAL_FAILURE(ForEachEffect(close)); - } - - void CreateEffects(const int n = 1) { - for (int i = 0; i < n; i++) { - ASSERT_NO_FATAL_FAILURE(mFactoryHelper.QueryAndCreateAllEffects()); } } - - void CreateEffectsWithUUID(const AudioUuid& type = EffectNullUuid) { - ASSERT_NO_FATAL_FAILURE(mFactoryHelper.QueryAndCreateEffects(type)); + static void getDescriptor(std::shared_ptr effect, Descriptor& desc, + binder_status_t status = EX_NONE) { + ASSERT_NE(effect, nullptr); + EXPECT_STATUS(status, effect->getDescriptor(&desc)); } - - void QueryEffects() { ASSERT_NO_FATAL_FAILURE(mFactoryHelper.QueryAndCreateAllEffects()); } - - void DestroyEffects(const binder_status_t status = EX_NONE, const int remaining = 0) { - ASSERT_NO_FATAL_FAILURE(mFactoryHelper.DestroyEffects(status, remaining)); - mEffectDescriptors.clear(); + static void expectState(std::shared_ptr effect, State expectState, + binder_status_t status = EX_NONE) { + ASSERT_NE(effect, nullptr); + State state; + EXPECT_STATUS(status, effect->getState(&state)); + EXPECT_EQ(expectState, state); } - - void GetEffectDescriptors() { - auto get = [&](const std::shared_ptr& effect) { - ASSERT_NE(effect, nullptr); - Descriptor desc; - EXPECT_IS_OK(effect->getDescriptor(&desc)); - mEffectDescriptors.push_back(std::move(desc)); - }; - EXPECT_NO_FATAL_FAILURE(ForEachEffect(get)); + static void command(std::shared_ptr effect, CommandId command, + binder_status_t status = EX_NONE) { + ASSERT_NE(effect, nullptr); + EXPECT_STATUS(status, effect->command(command)); } - - void CommandEffects(CommandId command) { - auto close = [&](const std::shared_ptr& effect) { - ASSERT_NE(effect, nullptr); - EXPECT_IS_OK(effect->command(command)); - }; - EXPECT_NO_FATAL_FAILURE(ForEachEffect(close)); + static void allocateInputData(const Parameter::Common common, std::unique_ptr& mq, + std::vector& buffer) { + ASSERT_NE(mq, nullptr); + auto frameSize = android::hardware::audio::common::getFrameSizeInBytes( + common.input.base.format, common.input.base.channelMask); + const size_t floatsToWrite = mq->availableToWrite(); + EXPECT_NE(0UL, floatsToWrite); + EXPECT_EQ(frameSize * common.input.frameCount, floatsToWrite * sizeof(float)); + buffer.resize(floatsToWrite); + std::fill(buffer.begin(), buffer.end(), 0x5a); } - - void CommandEffectsExpectStatus(CommandId command, const binder_status_t status) { - auto func = [&](const std::shared_ptr& effect) { - ASSERT_NE(effect, nullptr); - EXPECT_STATUS(status, effect->command(command)); - }; - EXPECT_NO_FATAL_FAILURE(ForEachEffect(func)); + static void writeToFmq(std::unique_ptr& mq, const std::vector& buffer) { + const size_t available = mq->availableToWrite(); + EXPECT_NE(0Ul, available); + auto bufferFloats = buffer.size(); + auto floatsToWrite = std::min(available, bufferFloats); + EXPECT_TRUE(mq->write(buffer.data(), floatsToWrite)); } - - void ExpectState(State expected) { - auto get = [&](const std::shared_ptr& effect) { - ASSERT_NE(effect, nullptr); - State state = State::INIT; - EXPECT_IS_OK(effect->getState(&state)); - EXPECT_EQ(expected, state); - }; - EXPECT_NO_FATAL_FAILURE(ForEachEffect(get)); - } - - void SetParameter() { - auto func = [&](const std::shared_ptr& effect) { - ASSERT_NE(effect, nullptr); - Parameter param; - param.set(mCommon); - EXPECT_IS_OK(effect->setParameter(param)); - }; - EXPECT_NO_FATAL_FAILURE(ForEachEffect(func)); - } - - void VerifyParameters() { - auto func = [&](const std::shared_ptr& effect) { - ASSERT_NE(effect, nullptr); - Parameter paramCommonGet = Parameter(), paramCommonExpect = Parameter(); - Parameter::Id id; - id.set(Parameter::common); - paramCommonExpect.set(mCommon); - EXPECT_IS_OK(effect->getParameter(id, ¶mCommonGet)); - EXPECT_EQ(paramCommonExpect, paramCommonGet) - << paramCommonExpect.toString() << " vs " << paramCommonGet.toString(); - }; - EXPECT_NO_FATAL_FAILURE(ForEachEffect(func)); - } - - void QueryEffects(const std::optional& in_type, - const std::optional& in_instance, - const std::optional& in_proxy, - std::vector* _aidl_return) { - mFactoryHelper.QueryEffects(in_type, in_instance, in_proxy, _aidl_return); - } - - template - void ForEachEffect(Functor functor, const std::optional& type = EffectNullUuid) { - auto effectMap = mFactoryHelper.GetEffectMap(); - for (const auto& it : effectMap) { - SCOPED_TRACE(it.second.toString()); - if (type != EffectNullUuid && it.second.type != type) continue; - functor(it.first); + static void readFromFmq(std::unique_ptr& statusMq, size_t statusNum, + std::unique_ptr& dataMq, size_t expectFloats, + std::vector& buffer) { + IEffect::Status status{}; + EXPECT_TRUE(statusMq->readBlocking(&status, statusNum)); + EXPECT_EQ(STATUS_OK, status.status); + if (statusNum != 0) { + EXPECT_EQ(expectFloats, (unsigned)status.fmqProduced); + EXPECT_EQ(expectFloats, dataMq->availableToRead()); + if (expectFloats != 0) { + EXPECT_TRUE(dataMq->read(buffer.data(), expectFloats)); + } } } + static Parameter::Common createParamCommon( + int session = 0, int ioHandle = -1, int iSampleRate = 48000, int oSampleRate = 48000, + long iFrameCount = 0x100, long oFrameCount = 0x100, + AudioChannelLayout inputChannelLayout = + AudioChannelLayout::make( + AudioChannelLayout::LAYOUT_STEREO), + AudioChannelLayout outputChannelLayout = + AudioChannelLayout::make( + AudioChannelLayout::LAYOUT_STEREO)) { + Parameter::Common common; + common.session = session; + common.ioHandle = ioHandle; - template - void ForEachDescriptor(Functor functor) { - for (size_t i = 0; i < mEffectDescriptors.size(); i++) { - SCOPED_TRACE(mEffectDescriptors[i].toString()); - functor(i, mEffectDescriptors[i]); - } - } - - static const size_t mWriteMQBytes = 0x400; - - enum class IO : char { INPUT = 0, OUTPUT = 1, INOUT = 2 }; - - void initParamCommonFormat(IO io = IO::INOUT, - const AudioFormatDescription& format = DefaultFormat) { - if (io == IO::INPUT || io == IO::INOUT) { - mCommon.input.base.format = format; - } - if (io == IO::OUTPUT || io == IO::INOUT) { - mCommon.output.base.format = format; - } - } - - void initParamCommonSampleRate(IO io = IO::INOUT, const int& sampleRate = 48000) { - if (io == IO::INPUT || io == IO::INOUT) { - mCommon.input.base.sampleRate = sampleRate; - } - if (io == IO::OUTPUT || io == IO::INOUT) { - mCommon.output.base.sampleRate = sampleRate; - } - } - - void initParamCommonFrameCount(IO io = IO::INOUT, const long& frameCount = 48000) { - if (io == IO::INPUT || io == IO::INOUT) { - mCommon.input.frameCount = frameCount; - } - if (io == IO::OUTPUT || io == IO::INOUT) { - mCommon.output.frameCount = frameCount; - } - } - void initParamCommon(int session = 0, int ioHandle = -1, int iSampleRate = 48000, - int oSampleRate = 48000, long iFrameCount = 0x100, - long oFrameCount = 0x100) { - mCommon.session = session; - mCommon.ioHandle = ioHandle; - - auto& input = mCommon.input; - auto& output = mCommon.output; + auto& input = common.input; + auto& output = common.output; input.base.sampleRate = iSampleRate; - input.base.channelMask = mInputChannelLayout; + input.base.channelMask = inputChannelLayout; + input.base.format = kDefaultFormatDescription; input.frameCount = iFrameCount; - input.base.format = DefaultFormat; output.base.sampleRate = oSampleRate; - output.base.channelMask = mOutputChannelLayout; - output.base.format = DefaultFormat; + output.base.channelMask = outputChannelLayout; + output.base.format = kDefaultFormatDescription; output.frameCount = oFrameCount; - output.base.format = DefaultFormat; - inputFrameSize = android::hardware::audio::common::getFrameSizeInBytes( - input.base.format, input.base.channelMask); - outputFrameSize = android::hardware::audio::common::getFrameSizeInBytes( - output.base.format, output.base.channelMask); + return common; } - void setSpecific(Parameter::Specific& specific) { mSpecific = specific; } - - // usually this function only call once. - void PrepareInputData(size_t bytes = mWriteMQBytes) { - size_t maxInputBytes = mWriteMQBytes; - for (auto& it : mEffectParams) { - auto& mq = it.inputMQ; - EXPECT_NE(nullptr, mq); - EXPECT_TRUE(mq->isValid()); - const size_t bytesToWrite = mq->availableToWrite() * sizeof(float); - EXPECT_EQ(inputFrameSize * mCommon.input.frameCount, bytesToWrite); - EXPECT_NE(0UL, bytesToWrite); - EXPECT_TRUE(bytes <= bytesToWrite); - maxInputBytes = std::max(maxInputBytes, bytesToWrite); - } - mInputBuffer.resize(maxInputBytes / sizeof(float)); - std::fill(mInputBuffer.begin(), mInputBuffer.end(), 0x5a); - } - - void writeToFmq(size_t bytes = mWriteMQBytes) { - for (auto& it : mEffectParams) { - auto& mq = it.inputMQ; - EXPECT_NE(nullptr, mq); - const size_t bytesToWrite = mq->availableToWrite() * sizeof(float); - EXPECT_NE(0Ul, bytesToWrite); - EXPECT_TRUE(bytes <= bytesToWrite); - EXPECT_TRUE(mq->write(mInputBuffer.data(), bytes / sizeof(float))); - } - } - - void readFromFmq(size_t expectBytes = mWriteMQBytes) { - for (auto& it : mEffectParams) { - IEffect::Status status{}; - auto& statusMq = it.statusMQ; - EXPECT_NE(nullptr, statusMq); - EXPECT_TRUE(statusMq->readBlocking(&status, 1)); - EXPECT_EQ(STATUS_OK, status.status); - EXPECT_EQ(expectBytes, (unsigned)status.fmqProduced * sizeof(float)); - - auto& outputMq = it.outputMQ; - EXPECT_NE(nullptr, outputMq); - EXPECT_EQ(expectBytes, outputMq->availableToRead() * sizeof(float)); - } - } - - void setInputChannelLayout(AudioChannelLayout input) { mInputChannelLayout = input; } - void setOutputChannelLayout(AudioChannelLayout output) { mOutputChannelLayout = output; } - const std::vector& GetCompleteEffectIdList() const { - return mFactoryHelper.GetCompleteEffectIdList(); - } - const std::vector& getDescriptorVec() const { return mEffectDescriptors; } - - private: - EffectFactoryHelper mFactoryHelper; - - AudioChannelLayout mInputChannelLayout = - AudioChannelLayout::make( - AudioChannelLayout::LAYOUT_STEREO); - AudioChannelLayout mOutputChannelLayout = - AudioChannelLayout::make( - AudioChannelLayout::LAYOUT_STEREO); - - Parameter::Common mCommon; - std::optional mSpecific = std::nullopt; - - size_t inputFrameSize, outputFrameSize; - std::vector mInputBuffer; // reuse same buffer for all effects testing - typedef ::android::AidlMessageQueue< IEffect::Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> StatusMQ; @@ -317,6 +181,4 @@ class EffectHelper { std::unique_ptr inputMQ; std::unique_ptr outputMQ; }; - std::vector mEffectParams; - std::vector mEffectDescriptors; }; diff --git a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp index d30dff47aa..8ae963e430 100644 --- a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include @@ -37,23 +38,81 @@ using namespace android; using aidl::android::hardware::audio::effect::Descriptor; -using aidl::android::hardware::audio::effect::EffectNullUuid; -using aidl::android::hardware::audio::effect::EffectZeroUuid; +using aidl::android::hardware::audio::effect::IEffect; using aidl::android::hardware::audio::effect::IFactory; +using aidl::android::hardware::audio::effect::kEffectNullUuid; +using aidl::android::hardware::audio::effect::kEffectZeroUuid; using aidl::android::hardware::audio::effect::Processing; +using aidl::android::media::audio::common::AudioSource; +using aidl::android::media::audio::common::AudioStreamType; using aidl::android::media::audio::common::AudioUuid; /// Effect factory testing. class EffectFactoryTest : public testing::TestWithParam { public: - void SetUp() override { ASSERT_NO_FATAL_FAILURE(mFactory.ConnectToFactoryService()); } + void SetUp() override { + mFactoryHelper = std::make_unique(GetParam()); + connectAndGetFactory(); + } - void TearDown() override { mFactory.DestroyEffects(); } + void TearDown() override { + for (auto& effect : mEffects) { + const auto status = mEffectFactory->destroyEffect(effect); + EXPECT_STATUS(EX_NONE, status); + } + } - EffectFactoryHelper mFactory = EffectFactoryHelper(GetParam()); + std::unique_ptr mFactoryHelper; + std::shared_ptr mEffectFactory; + std::vector> mEffects; + const Descriptor::Identity kNullDesc = {.uuid = kEffectNullUuid}; + const Descriptor::Identity kZeroDesc = {.uuid = kEffectZeroUuid}; - const Descriptor::Identity nullDesc = {.uuid = EffectNullUuid}; - const Descriptor::Identity zeroDesc = {.uuid = EffectZeroUuid}; + template + void ForEachId(const std::vector ids, Functor functor) { + for (const auto& id : ids) { + SCOPED_TRACE(id.toString()); + functor(id); + } + } + template + void ForEachEffect(std::vector> effects, Functor functor) { + for (auto& effect : effects) { + functor(effect); + } + } + + std::vector> createWithIds( + const std::vector ids, + const binder_status_t expectStatus = EX_NONE) { + std::vector> effects; + for (const auto& id : ids) { + std::shared_ptr effect; + EXPECT_STATUS(expectStatus, mEffectFactory->createEffect(id.uuid, &effect)); + if (expectStatus == EX_NONE) { + EXPECT_NE(effect, nullptr) << " null effect with uuid: " << id.uuid.toString(); + effects.push_back(std::move(effect)); + } + } + return effects; + } + void destroyEffects(std::vector> effects, + const binder_status_t expectStatus = EX_NONE) { + for (const auto& effect : effects) { + EXPECT_STATUS(expectStatus, mEffectFactory->destroyEffect(effect)); + } + } + void creatAndDestroyIds(const std::vector ids) { + for (const auto& id : ids) { + auto effects = createWithIds({id}); + ASSERT_NO_FATAL_FAILURE(destroyEffects(effects)); + } + } + void connectAndGetFactory() { + ASSERT_NO_FATAL_FAILURE(mFactoryHelper->ConnectToFactoryService()); + mEffectFactory = mFactoryHelper->GetFactory(); + ASSERT_NE(mEffectFactory, nullptr); + } }; TEST_P(EffectFactoryTest, SetupAndTearDown) { @@ -61,165 +120,160 @@ TEST_P(EffectFactoryTest, SetupAndTearDown) { } TEST_P(EffectFactoryTest, CanBeRestarted) { - ASSERT_NO_FATAL_FAILURE(mFactory.RestartFactoryService()); + ASSERT_NO_FATAL_FAILURE(mFactoryHelper->RestartFactoryService()); } -TEST_P(EffectFactoryTest, QueriedDescriptorList) { - std::vector descriptors; - mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors); - EXPECT_NE(descriptors.size(), 0UL); -} +/** + * @brief Check at least support list of effect must be supported by aosp: + * https://developer.android.com/reference/android/media/audiofx/AudioEffect + */ +TEST_P(EffectFactoryTest, ExpectAllAospEffectTypes) { + std::vector ids; + std::set typeUuidSet( + {aidl::android::hardware::audio::effect::kBassBoostTypeUUID, + aidl::android::hardware::audio::effect::kEqualizerTypeUUID, + aidl::android::hardware::audio::effect::kEnvReverbTypeUUID, + aidl::android::hardware::audio::effect::kPresetReverbTypeUUID, + aidl::android::hardware::audio::effect::kDynamicsProcessingTypeUUID, + aidl::android::hardware::audio::effect::kHapticGeneratorTypeUUID, + aidl::android::hardware::audio::effect::kVirtualizerTypeUUID}); -TEST_P(EffectFactoryTest, DescriptorUUIDNotNull) { - std::vector descriptors; - mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors); - // TODO: Factory eventually need to return the full list of MUST supported AOSP effects. - for (auto& desc : descriptors) { - EXPECT_NE(desc.type, EffectNullUuid); - EXPECT_NE(desc.uuid, EffectNullUuid); + EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids)); + EXPECT_TRUE(ids.size() >= typeUuidSet.size()); + for (const auto& id : ids) { + typeUuidSet.erase(id.type); } + std::string msg = " missing type UUID:\n"; + for (const auto& uuid : typeUuidSet) { + msg += (uuid.toString() + "\n"); + } + SCOPED_TRACE(msg); + EXPECT_EQ(0UL, typeUuidSet.size()); } -TEST_P(EffectFactoryTest, QueriedDescriptorNotExistType) { - std::vector descriptors; - mFactory.QueryEffects(EffectNullUuid, std::nullopt, std::nullopt, &descriptors); - EXPECT_EQ(descriptors.size(), 0UL); +TEST_P(EffectFactoryTest, QueryNullTypeUuid) { + std::vector ids; + EXPECT_IS_OK(mEffectFactory->queryEffects(kEffectNullUuid, std::nullopt, std::nullopt, &ids)); + EXPECT_EQ(ids.size(), 0UL); } -TEST_P(EffectFactoryTest, QueriedDescriptorNotExistInstance) { - std::vector descriptors; - mFactory.QueryEffects(std::nullopt, EffectNullUuid, std::nullopt, &descriptors); - EXPECT_EQ(descriptors.size(), 0UL); +TEST_P(EffectFactoryTest, QueriedNullImplUuid) { + std::vector ids; + EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, kEffectNullUuid, std::nullopt, &ids)); + EXPECT_EQ(ids.size(), 0UL); } -TEST_P(EffectFactoryTest, CreateAndDestroyOnce) { - std::vector descriptors; - mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors); - auto numIds = mFactory.GetEffectIds().size(); - EXPECT_NE(numIds, 0UL); - - auto& effectMap = mFactory.GetEffectMap(); - EXPECT_EQ(effectMap.size(), 0UL); - mFactory.CreateEffects(); - EXPECT_EQ(effectMap.size(), numIds); - mFactory.DestroyEffects(); - EXPECT_EQ(effectMap.size(), 0UL); +TEST_P(EffectFactoryTest, QueriedNullProxyUuid) { + std::vector ids; + EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, kEffectNullUuid, &ids)); + EXPECT_EQ(ids.size(), 0UL); } -TEST_P(EffectFactoryTest, CreateAndDestroyRepeat) { - std::vector descriptors; - mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors); - auto numIds = mFactory.GetEffectIds().size(); - EXPECT_NE(numIds, 0UL); +// create all effects, and then destroy them all together +TEST_P(EffectFactoryTest, CreateAndDestroyEffects) { + std::vector ids; + EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids)); + EXPECT_NE(ids.size(), 0UL); - auto& effectMap = mFactory.GetEffectMap(); - EXPECT_EQ(effectMap.size(), 0UL); - mFactory.CreateEffects(); - EXPECT_EQ(effectMap.size(), numIds); - mFactory.DestroyEffects(); - EXPECT_EQ(effectMap.size(), 0UL); - - // Create and destroy again - mFactory.CreateEffects(); - EXPECT_EQ(effectMap.size(), numIds); - mFactory.DestroyEffects(); - EXPECT_EQ(effectMap.size(), 0UL); + std::vector> effects; + effects = createWithIds(ids); + EXPECT_EQ(ids.size(), effects.size()); + destroyEffects(effects); } TEST_P(EffectFactoryTest, CreateMultipleInstanceOfSameEffect) { - std::vector descriptors; - mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors); - auto numIds = mFactory.GetEffectIds().size(); - EXPECT_NE(numIds, 0UL); + std::vector ids; + EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids)); + EXPECT_NE(ids.size(), 0UL); - auto& effectMap = mFactory.GetEffectMap(); - EXPECT_EQ(effectMap.size(), 0UL); - mFactory.CreateEffects(); - EXPECT_EQ(effectMap.size(), numIds); - // Create effect instances of same implementation - mFactory.CreateEffects(); - EXPECT_EQ(effectMap.size(), 2 * numIds); + std::vector> effects = createWithIds(ids); + EXPECT_EQ(ids.size(), effects.size()); + std::vector> effects2 = createWithIds(ids); + EXPECT_EQ(ids.size(), effects2.size()); + std::vector> effects3 = createWithIds(ids); + EXPECT_EQ(ids.size(), effects3.size()); - mFactory.CreateEffects(); - EXPECT_EQ(effectMap.size(), 3 * numIds); + destroyEffects(effects); + destroyEffects(effects2); + destroyEffects(effects3); +} - mFactory.DestroyEffects(); - EXPECT_EQ(effectMap.size(), 0UL); +// create and destroy each effect one by one +TEST_P(EffectFactoryTest, CreateAndDestroyEffectsOneByOne) { + std::vector ids; + EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids)); + EXPECT_NE(ids.size(), 0UL); + + creatAndDestroyIds(ids); +} + +// for each effect: repeat 3 times create and destroy +TEST_P(EffectFactoryTest, CreateAndDestroyRepeat) { + std::vector ids; + EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids)); + EXPECT_NE(ids.size(), 0UL); + + creatAndDestroyIds(ids); + creatAndDestroyIds(ids); + creatAndDestroyIds(ids); } // Expect EX_ILLEGAL_ARGUMENT when create with invalid UUID. TEST_P(EffectFactoryTest, CreateWithInvalidUuid) { - std::vector> descriptors; - descriptors.push_back(std::make_pair(nullDesc, EX_ILLEGAL_ARGUMENT)); - descriptors.push_back(std::make_pair(zeroDesc, EX_ILLEGAL_ARGUMENT)); - - auto& effectMap = mFactory.GetEffectMap(); - mFactory.CreateEffectsAndExpect(descriptors); - EXPECT_EQ(effectMap.size(), 0UL); + std::vector ids = {kNullDesc, kZeroDesc}; + auto effects = createWithIds(ids, EX_ILLEGAL_ARGUMENT); + EXPECT_EQ(effects.size(), 0UL); } // Expect EX_ILLEGAL_ARGUMENT when destroy null interface. TEST_P(EffectFactoryTest, DestroyWithInvalidInterface) { std::shared_ptr spDummyEffect(nullptr); - - mFactory.DestroyEffectAndExpect(spDummyEffect, EX_ILLEGAL_ARGUMENT); + destroyEffects({spDummyEffect}, EX_ILLEGAL_ARGUMENT); } -TEST_P(EffectFactoryTest, CreateAndRemoveReference) { - std::vector descriptors; - mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors); - auto numIds = mFactory.GetEffectIds().size(); - EXPECT_NE(numIds, 0UL); +// Same descriptor ID should work after service restart. +TEST_P(EffectFactoryTest, CreateDestroyWithRestart) { + std::vector ids; + EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids)); + EXPECT_NE(ids.size(), 0UL); + creatAndDestroyIds(ids); - auto& effectMap = mFactory.GetEffectMap(); - EXPECT_EQ(effectMap.size(), 0UL); - mFactory.CreateEffects(); - EXPECT_EQ(effectMap.size(), numIds); - // remove all reference - mFactory.ClearEffectMap(); - EXPECT_EQ(effectMap.size(), 0UL); + mFactoryHelper->RestartFactoryService(); + + connectAndGetFactory(); + creatAndDestroyIds(ids); } -TEST_P(EffectFactoryTest, CreateRemoveReferenceAndCreateDestroy) { - std::vector descriptors; - mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors); - auto numIds = mFactory.GetEffectIds().size(); - EXPECT_NE(numIds, 0UL); +// Effect handle invalid after restart. +TEST_P(EffectFactoryTest, EffectInvalidAfterRestart) { + std::vector ids; + EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids)); + EXPECT_NE(ids.size(), 0UL); + std::vector> effects = createWithIds(ids); - auto& effectMap = mFactory.GetEffectMap(); - EXPECT_EQ(effectMap.size(), 0UL); - mFactory.CreateEffects(); - EXPECT_EQ(effectMap.size(), numIds); - // remove all reference - mFactory.ClearEffectMap(); - EXPECT_EQ(effectMap.size(), 0UL); + ASSERT_NO_FATAL_FAILURE(mFactoryHelper->RestartFactoryService()); - // Create and destroy again - mFactory.CreateEffects(); - EXPECT_EQ(effectMap.size(), numIds); - mFactory.DestroyEffects(); - EXPECT_EQ(effectMap.size(), 0UL); -} - -TEST_P(EffectFactoryTest, CreateRestartAndCreateDestroy) { - std::vector descriptors; - mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors); - auto numIds = mFactory.GetEffectIds().size(); - auto& effectMap = mFactory.GetEffectMap(); - mFactory.CreateEffects(); - EXPECT_EQ(effectMap.size(), numIds); - ASSERT_NO_FATAL_FAILURE(mFactory.RestartFactoryService()); - - mFactory.CreateEffects(); - EXPECT_EQ(effectMap.size(), numIds); - mFactory.DestroyEffects(); - EXPECT_EQ(effectMap.size(), 0UL); + connectAndGetFactory(); + destroyEffects(effects, EX_ILLEGAL_ARGUMENT); } +// expect no error with the queryProcessing interface, but don't check number of processing TEST_P(EffectFactoryTest, QueryProcess) { std::vector processing; - mFactory.QueryProcessing(std::nullopt, &processing); - // TODO: verify the number of process in example implementation after audio_effects.xml migrated + EXPECT_IS_OK(mEffectFactory->queryProcessing(std::nullopt, &processing)); + + Processing::Type streamType = + Processing::Type::make(AudioStreamType::SYSTEM); + std::vector processingFilteredByStream; + EXPECT_IS_OK(mEffectFactory->queryProcessing(streamType, &processingFilteredByStream)); + + Processing::Type source = + Processing::Type::make(AudioSource::DEFAULT); + std::vector processingFilteredBySource; + EXPECT_IS_OK(mEffectFactory->queryProcessing(source, &processingFilteredBySource)); + + EXPECT_TRUE(processing.size() >= processingFilteredByStream.size()); + EXPECT_TRUE(processing.size() >= processingFilteredBySource.size()); } INSTANTIATE_TEST_SUITE_P(EffectFactoryTest, EffectFactoryTest, diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp index 3ea67bc96b..8212149f03 100644 --- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp @@ -16,26 +16,24 @@ #define LOG_TAG "VtsHalAudioEffectTargetTest" +#include #include #include -#include -#include #include +#include #include #include +#include +#include #include -#include #include #include #include - -#include -#include -#include -#include +#include #include "AudioHalBinderServiceUtil.h" +#include "EffectFactoryHelper.h" #include "EffectHelper.h" #include "TestUtils.h" @@ -49,309 +47,725 @@ using aidl::android::hardware::audio::effect::IEffect; using aidl::android::hardware::audio::effect::IFactory; using aidl::android::hardware::audio::effect::Parameter; using aidl::android::hardware::audio::effect::State; -using aidl::android::media::audio::common::AudioDeviceType; -class AudioEffectTest : public testing::TestWithParam, public EffectHelper { +enum ParamName { PARAM_INSTANCE_NAME }; +using EffectTestParam = std::tuple, Descriptor::Identity>>; + +class AudioEffectTest : public testing::TestWithParam, public EffectHelper { public: - AudioEffectTest() : EffectHelper(GetParam()) {} + AudioEffectTest() { std::tie(mFactory, mIdentity) = std::get(GetParam()); } - void SetUp() override { - CreateEffects(); - initParamCommonFormat(); - initParamCommon(); - } + void SetUp() override {} + void TearDown() override {} - void TearDown() override { - CloseEffects(); - DestroyEffects(); - } + static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100; + std::shared_ptr mFactory; + Descriptor::Identity mIdentity; }; -TEST_P(AudioEffectTest, OpenEffectTest) { - OpenEffects(); +TEST_P(AudioEffectTest, SetupAndTearDown) { + // Intentionally empty test body. } -TEST_P(AudioEffectTest, OpenAndCloseEffect) { - OpenEffects(); - CloseEffects(); +TEST_P(AudioEffectTest, CreateAndDestroy) { + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } -TEST_P(AudioEffectTest, CloseUnopenedEffectTest) { - CloseEffects(); +TEST_P(AudioEffectTest, OpenAndClose) { + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } -TEST_P(AudioEffectTest, DoubleOpenCloseEffects) { - OpenEffects(); - CloseEffects(); - OpenEffects(); - CloseEffects(); - - OpenEffects(); - OpenEffects(); - CloseEffects(); - - OpenEffects(); - CloseEffects(); - CloseEffects(); +TEST_P(AudioEffectTest, CloseUnopenedEffect) { + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } -TEST_P(AudioEffectTest, GetDescriptors) { - GetEffectDescriptors(); +TEST_P(AudioEffectTest, DoubleOpenAndClose) { + std::shared_ptr effect1, effect2; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity)); + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect1)); + ASSERT_NO_FATAL_FAILURE(open(effect2, 1 /* session */)); + ASSERT_NO_FATAL_FAILURE(close(effect1)); + ASSERT_NO_FATAL_FAILURE(close(effect2)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect1)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect2)); } -TEST_P(AudioEffectTest, DescriptorIdExistAndUnique) { - auto checker = [&](const std::shared_ptr& effect) { - Descriptor desc; - std::vector idList; - EXPECT_IS_OK(effect->getDescriptor(&desc)); - QueryEffects(desc.common.id.type, desc.common.id.uuid, desc.common.id.proxy, &idList); - // Must have at least one instance. - EXPECT_NE(idList.size(), 0UL); - }; - ForEachEffect(checker); +TEST_P(AudioEffectTest, TripleOpenAndClose) { + std::shared_ptr effect1, effect2, effect3; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity)); + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity)); + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect3, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect1)); + ASSERT_NO_FATAL_FAILURE(open(effect2, 1 /* session */)); + ASSERT_NO_FATAL_FAILURE(open(effect3, 2 /* session */)); + ASSERT_NO_FATAL_FAILURE(close(effect1)); + ASSERT_NO_FATAL_FAILURE(close(effect2)); + ASSERT_NO_FATAL_FAILURE(close(effect3)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect1)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect2)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect3)); +} - // Check unique with a set - auto stringHash = [](const Descriptor::Identity& id) { - return std::hash()(id.toString()); - }; - auto vec = GetCompleteEffectIdList(); - std::unordered_set idSet(0, stringHash); - for (auto it : vec) { - EXPECT_EQ(idSet.count(it), 0UL) << it.toString(); - idSet.insert(it); +TEST_P(AudioEffectTest, GetDescritorBeforeOpen) { + std::shared_ptr effect; + Descriptor desc; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, desc)); + EXPECT_EQ(mIdentity.toString(), desc.common.id.toString()); + EXPECT_NE("", desc.common.name); + EXPECT_NE("", desc.common.implementor); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); +} + +TEST_P(AudioEffectTest, GetDescritorAfterOpen) { + std::shared_ptr effect; + Descriptor beforeOpen, afterOpen, afterClose; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, beforeOpen)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, afterOpen)); + EXPECT_EQ(beforeOpen.toString(), afterOpen.toString()) << "\n" + << beforeOpen.toString() << "\n" + << afterOpen.toString(); + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, afterClose)); + EXPECT_EQ(beforeOpen.toString(), afterClose.toString()) << "\n" + << beforeOpen.toString() << "\n" + << afterClose.toString(); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); +} + +TEST_P(AudioEffectTest, DescriptorExistAndUnique) { + std::shared_ptr effect; + Descriptor desc; + + auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor); + std::set idSet; + for (const auto& it : descList) { + auto& id = it.second; + EXPECT_EQ(0ul, idSet.count(id)); + idSet.insert(id); } + + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, desc)); + EXPECT_EQ(1ul, idSet.count(desc.common.id)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } /// State testing. // An effect instance is in INIT state by default after it was created. TEST_P(AudioEffectTest, InitStateAfterCreation) { - ExpectState(State::INIT); + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } -// An effect instance transfer to INIT state after it was open successfully with IEffect.open(). +// An effect instance transfer to IDLE state after IEffect.ASSERT_NO_FATAL_FAILURE(open(). TEST_P(AudioEffectTest, IdleStateAfterOpen) { - OpenEffects(); - ExpectState(State::IDLE); - CloseEffects(); + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } // An effect instance is in PROCESSING state after it receive an START command. TEST_P(AudioEffectTest, ProcessingStateAfterStart) { - OpenEffects(); - CommandEffects(CommandId::START); - ExpectState(State::PROCESSING); - CommandEffects(CommandId::STOP); - CloseEffects(); + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } // An effect instance transfer to IDLE state after Command.Id.STOP in PROCESSING state. TEST_P(AudioEffectTest, IdleStateAfterStop) { - OpenEffects(); - CommandEffects(CommandId::START); - ExpectState(State::PROCESSING); - CommandEffects(CommandId::STOP); - ExpectState(State::IDLE); - CloseEffects(); + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } // An effect instance transfer to IDLE state after Command.Id.RESET in PROCESSING state. TEST_P(AudioEffectTest, IdleStateAfterReset) { - OpenEffects(); - CommandEffects(CommandId::START); - ExpectState(State::PROCESSING); - CommandEffects(CommandId::RESET); - ExpectState(State::IDLE); - CloseEffects(); + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } -// An effect instance transfer to INIT if instance receive a close() call. +// An effect instance transfer to INIT after IEffect.ASSERT_NO_FATAL_FAILURE(close(). TEST_P(AudioEffectTest, InitStateAfterClose) { - OpenEffects(); - CommandEffects(CommandId::START); - ExpectState(State::PROCESSING); - CommandEffects(CommandId::STOP); - ExpectState(State::IDLE); - CloseEffects(); - ExpectState(State::INIT); + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } // An effect instance shouldn't accept any command before open. TEST_P(AudioEffectTest, NoCommandAcceptedBeforeOpen) { - ExpectState(State::INIT); - CommandEffectsExpectStatus(CommandId::START, EX_ILLEGAL_STATE); - CommandEffectsExpectStatus(CommandId::STOP, EX_ILLEGAL_STATE); - CommandEffectsExpectStatus(CommandId::RESET, EX_ILLEGAL_STATE); - ExpectState(State::INIT); + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START, EX_ILLEGAL_STATE)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP, EX_ILLEGAL_STATE)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET, EX_ILLEGAL_STATE)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } // No-op when receive STOP command in IDLE state. TEST_P(AudioEffectTest, StopCommandInIdleStateNoOp) { - ExpectState(State::INIT); - OpenEffects(); - ExpectState(State::IDLE); - CommandEffects(CommandId::STOP); - ExpectState(State::IDLE); - CloseEffects(); + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } -// No-op when receive STOP command in IDLE state. +// No-op when receive RESET command in IDLE state. TEST_P(AudioEffectTest, ResetCommandInIdleStateNoOp) { - ExpectState(State::INIT); - OpenEffects(); - ExpectState(State::IDLE); - CommandEffects(CommandId::RESET); - ExpectState(State::IDLE); - CloseEffects(); + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } // Repeat START and STOP command. TEST_P(AudioEffectTest, RepeatStartAndStop) { - OpenEffects(); - CommandEffects(CommandId::START); - ExpectState(State::PROCESSING); - CommandEffects(CommandId::STOP); - ExpectState(State::IDLE); - CommandEffects(CommandId::START); - ExpectState(State::PROCESSING); - CommandEffects(CommandId::STOP); - ExpectState(State::IDLE); - CloseEffects(); + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } // Repeat START and RESET command. TEST_P(AudioEffectTest, RepeatStartAndReset) { - OpenEffects(); - CommandEffects(CommandId::START); - ExpectState(State::PROCESSING); - CommandEffects(CommandId::RESET); - ExpectState(State::IDLE); - CommandEffects(CommandId::START); - ExpectState(State::PROCESSING); - CommandEffects(CommandId::RESET); - ExpectState(State::IDLE); - CloseEffects(); + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } -// Repeat START and STOP command, try to close at PROCESSING state. +// Try to close an effect instance at PROCESSING state. TEST_P(AudioEffectTest, CloseProcessingStateEffects) { - OpenEffects(); - CommandEffects(CommandId::START); - ExpectState(State::PROCESSING); - CommandEffects(CommandId::STOP); - ExpectState(State::IDLE); - CommandEffects(CommandId::START); - ExpectState(State::PROCESSING); - CloseEffects(EX_ILLEGAL_STATE); - // cleanup - CommandEffects(CommandId::STOP); - ExpectState(State::IDLE); + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + + ASSERT_NO_FATAL_FAILURE(close(effect, EX_ILLEGAL_STATE)); + + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } // Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed. TEST_P(AudioEffectTest, DestroyOpenEffects) { - // cleanup all effects. - CloseEffects(); - DestroyEffects(); + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); - // open effects, destroy without close, expect to get EX_ILLEGAL_STATE status. - CreateEffects(); - OpenEffects(); - auto vec = GetCompleteEffectIdList(); - DestroyEffects(EX_ILLEGAL_STATE, vec.size()); - CloseEffects(); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect, EX_ILLEGAL_STATE)); +} + +// Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed. +TEST_P(AudioEffectTest, DestroyProcessingEffects) { + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect, EX_ILLEGAL_STATE)); +} + +TEST_P(AudioEffectTest, NormalSequenceStates) { + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } /// Parameter testing. // Verify parameters pass in open can be successfully get. -TEST_P(AudioEffectTest, VerifyParametersAfterOpen) { - OpenEffects(); - VerifyParameters(); - CloseEffects(); +TEST_P(AudioEffectTest, VerifyCommonParametersAfterOpen) { + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + + Parameter::Common common = EffectHelper::createParamCommon(); + IEffect::OpenEffectReturn ret; + ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE)); + + Parameter get = Parameter(), expect = Parameter(); + expect.set(common); + Parameter::Id id; + id.set(Parameter::common); + EXPECT_IS_OK(effect->getParameter(id, &get)); + EXPECT_EQ(expect, get) << expect.toString() << " vs " << get.toString(); + + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } // Verify parameters pass in set can be successfully get. -TEST_P(AudioEffectTest, SetAndGetParameter) { - OpenEffects(); - VerifyParameters(); - initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, - 44100 /* oSampleRate */); - SetParameter(); - VerifyParameters(); - CloseEffects(); +TEST_P(AudioEffectTest, SetAndGetCommonParameter) { + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + + Parameter::Common common = EffectHelper::createParamCommon( + 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */); + Parameter get = Parameter(), set = Parameter(); + set.set(common); + EXPECT_IS_OK(effect->setParameter(set)); + + Parameter::Id id; + id.set(Parameter::common); + EXPECT_IS_OK(effect->getParameter(id, &get)); + EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString(); + + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } -// Verify parameters pass in set can be successfully get. +// Verify parameters set and get in PROCESSING state. TEST_P(AudioEffectTest, SetAndGetParameterInProcessing) { - OpenEffects(); - VerifyParameters(); - CommandEffects(CommandId::START); - ExpectState(State::PROCESSING); - initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, - 44100 /* oSampleRate */); - SetParameter(); - VerifyParameters(); - CommandEffects(CommandId::STOP); - ExpectState(State::IDLE); - CloseEffects(); + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + + Parameter::Common common = EffectHelper::createParamCommon( + 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */); + Parameter get = Parameter(), set = Parameter(); + set.set(common); + EXPECT_IS_OK(effect->setParameter(set)); + + Parameter::Id id; + id.set(Parameter::common); + EXPECT_IS_OK(effect->getParameter(id, &get)); + EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString(); + + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } -// Parameters kept after reset. -TEST_P(AudioEffectTest, ResetAndVerifyParameter) { - OpenEffects(); - VerifyParameters(); - CommandEffects(CommandId::START); - ExpectState(State::PROCESSING); - initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, - 44100 /* oSampleRate */); - SetParameter(); - VerifyParameters(); - CommandEffects(CommandId::RESET); - ExpectState(State::IDLE); - VerifyParameters(); - CloseEffects(); +// Verify parameters set and get in IDLE state. +TEST_P(AudioEffectTest, SetAndGetParameterInIdle) { + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + + Parameter::Common common = EffectHelper::createParamCommon( + 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */); + Parameter get = Parameter(), set = Parameter(); + set.set(common); + EXPECT_IS_OK(effect->setParameter(set)); + + Parameter::Id id; + id.set(Parameter::common); + EXPECT_IS_OK(effect->getParameter(id, &get)); + EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString(); + + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } -// TODO: need a way to support setting different sessionId to different effect instances -#if 0 -// Multiple instances of same implementation running. -TEST_P(AudioEffectTest, MultipleInstancesRunningWithDiffSessionId) { - CreateEffects(); - ExpectState(State::INIT); - OpenEffects(); - ExpectState(State::IDLE); - CommandEffects(CommandId::START); - ExpectState(State::PROCESSING); - initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, - 44100 /* oSampleRate */); - SetParameter(); - VerifyParameters(); - CommandEffects(CommandId::STOP); - ExpectState(State::IDLE); - VerifyParameters(); - CloseEffects(); -} -#endif +// Verify Parameters kept after stop. +TEST_P(AudioEffectTest, SetAndGetParameterAfterStop) { + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); -// Send data to effects and expect it to consume by check statusMQ. -TEST_P(AudioEffectTest, ExpectEffectsToConsumeDataInMQ) { - OpenEffects(); - PrepareInputData(mWriteMQBytes); + Parameter::Common common = EffectHelper::createParamCommon( + 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */); + Parameter get = Parameter(), set = Parameter(); + set.set(common); + EXPECT_IS_OK(effect->setParameter(set)); - CommandEffects(CommandId::START); - writeToFmq(mWriteMQBytes); - readFromFmq(mWriteMQBytes); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); - ExpectState(State::PROCESSING); - CommandEffects(CommandId::STOP); - // cleanup - CommandEffects(CommandId::STOP); - ExpectState(State::IDLE); - CloseEffects(); + Parameter::Id id; + id.set(Parameter::common); + EXPECT_IS_OK(effect->getParameter(id, &get)); + EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString(); + + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); } -INSTANTIATE_TEST_SUITE_P(AudioEffectTestTest, AudioEffectTest, - testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)), - android::PrintInstanceNameToString); +// Verify Parameters kept after reset. +TEST_P(AudioEffectTest, SetAndGetParameterAfterReset) { + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + ASSERT_NO_FATAL_FAILURE(open(effect)); + + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + + Parameter::Common common = EffectHelper::createParamCommon( + 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */); + Parameter get = Parameter(), set = Parameter(); + set.set(common); + EXPECT_IS_OK(effect->setParameter(set)); + + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + + Parameter::Id id; + id.set(Parameter::common); + EXPECT_IS_OK(effect->getParameter(id, &get)); + EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString(); + + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); +} + +/// Data processing test +// Send data to effects and expect it to be consumed by checking statusMQ. +TEST_P(AudioEffectTest, ConsumeDataInProcessingState) { + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + + Parameter::Common common = EffectHelper::createParamCommon( + 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */, + kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */); + IEffect::OpenEffectReturn ret; + ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE)); + auto statusMQ = std::make_unique(ret.statusMQ); + auto inputMQ = std::make_unique(ret.inputDataMQ); + auto outputMQ = std::make_unique(ret.outputDataMQ); + + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + + std::vector buffer; + EffectHelper::allocateInputData(common, inputMQ, buffer); + EffectHelper::writeToFmq(inputMQ, buffer); + EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer); + + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); +} + +// Send data to effects and expect it to be consumed after effect restart. +TEST_P(AudioEffectTest, ConsumeDataAfterRestart) { + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + + Parameter::Common common = EffectHelper::createParamCommon( + 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */, + kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */); + IEffect::OpenEffectReturn ret; + ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE)); + auto statusMQ = std::make_unique(ret.statusMQ); + auto inputMQ = std::make_unique(ret.inputDataMQ); + auto outputMQ = std::make_unique(ret.outputDataMQ); + + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + + std::vector buffer; + EffectHelper::allocateInputData(common, inputMQ, buffer); + EffectHelper::writeToFmq(inputMQ, buffer); + EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer); + + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); +} + +// Send data to IDLE effects and expect it to be consumed after effect start. +TEST_P(AudioEffectTest, SendDataAtIdleAndConsumeDataInProcessing) { + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + + Parameter::Common common = EffectHelper::createParamCommon( + 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */, + kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */); + IEffect::OpenEffectReturn ret; + ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE)); + auto statusMQ = std::make_unique(ret.statusMQ); + auto inputMQ = std::make_unique(ret.inputDataMQ); + auto outputMQ = std::make_unique(ret.outputDataMQ); + + std::vector buffer; + EffectHelper::allocateInputData(common, inputMQ, buffer); + EffectHelper::writeToFmq(inputMQ, buffer); + EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer); + + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + + EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer); + + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); +} + +// Send data multiple times. +TEST_P(AudioEffectTest, ProcessDataMultipleTimes) { + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + + Parameter::Common common = EffectHelper::createParamCommon( + 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */, + kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */); + IEffect::OpenEffectReturn ret; + ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE)); + auto statusMQ = std::make_unique(ret.statusMQ); + auto inputMQ = std::make_unique(ret.inputDataMQ); + auto outputMQ = std::make_unique(ret.outputDataMQ); + + std::vector buffer; + EffectHelper::allocateInputData(common, inputMQ, buffer); + EffectHelper::writeToFmq(inputMQ, buffer); + EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer); + + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + + EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer); + // expect no status and data after consume + EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer); + + EffectHelper::writeToFmq(inputMQ, buffer); + EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer); + // expect no status and data after consume + EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer); + + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); +} + +// Send data to IDLE state effects and expect it not be consumed. +TEST_P(AudioEffectTest, NotConsumeDataInIdleState) { + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + + Parameter::Common common = EffectHelper::createParamCommon( + 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */, + kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */); + IEffect::OpenEffectReturn ret; + ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE)); + auto statusMQ = std::make_unique(ret.statusMQ); + auto inputMQ = std::make_unique(ret.inputDataMQ); + auto outputMQ = std::make_unique(ret.outputDataMQ); + + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + + std::vector buffer; + EffectHelper::allocateInputData(common, inputMQ, buffer); + EffectHelper::writeToFmq(inputMQ, buffer); + EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer); + + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING)); + EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer); + + ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE)); + + ASSERT_NO_FATAL_FAILURE(close(effect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); +} + +// Send data to closed effects and expect it not be consumed. +TEST_P(AudioEffectTest, NotConsumeDataByClosedEffect) { + std::shared_ptr effect; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity)); + + Parameter::Common common = EffectHelper::createParamCommon( + 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */, + kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */); + IEffect::OpenEffectReturn ret; + ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE)); + ASSERT_NO_FATAL_FAILURE(close(effect)); + + auto statusMQ = std::make_unique(ret.statusMQ); + auto inputMQ = std::make_unique(ret.inputDataMQ); + auto outputMQ = std::make_unique(ret.outputDataMQ); + + std::vector buffer; + EffectHelper::allocateInputData(common, inputMQ, buffer); + EffectHelper::writeToFmq(inputMQ, buffer); + EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer); + + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect)); +} + +// Send data to multiple effects. +TEST_P(AudioEffectTest, ConsumeDataMultipleEffects) { + std::shared_ptr effect1, effect2; + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity)); + ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity)); + + Parameter::Common common1 = EffectHelper::createParamCommon( + 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */, + kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */); + Parameter::Common common2 = EffectHelper::createParamCommon( + 1 /* session */, 1 /* ioHandle */, 48000 /* iSampleRate */, 48000 /* oSampleRate */, + 2 * kInputFrameCount /* iFrameCount */, 2 * kOutputFrameCount /* oFrameCount */); + IEffect::OpenEffectReturn ret1, ret2; + ASSERT_NO_FATAL_FAILURE(open(effect1, common1, std::nullopt /* specific */, &ret1, EX_NONE)); + ASSERT_NO_FATAL_FAILURE(open(effect2, common2, std::nullopt /* specific */, &ret2, EX_NONE)); + ASSERT_NO_FATAL_FAILURE(command(effect1, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect1, State::PROCESSING)); + ASSERT_NO_FATAL_FAILURE(command(effect2, CommandId::START)); + ASSERT_NO_FATAL_FAILURE(expectState(effect2, State::PROCESSING)); + + auto statusMQ1 = std::make_unique(ret1.statusMQ); + auto inputMQ1 = std::make_unique(ret1.inputDataMQ); + auto outputMQ1 = std::make_unique(ret1.outputDataMQ); + + std::vector buffer1, buffer2; + EffectHelper::allocateInputData(common1, inputMQ1, buffer1); + EffectHelper::writeToFmq(inputMQ1, buffer1); + EffectHelper::readFromFmq(statusMQ1, 1, outputMQ1, buffer1.size(), buffer1); + + auto statusMQ2 = std::make_unique(ret2.statusMQ); + auto inputMQ2 = std::make_unique(ret2.inputDataMQ); + auto outputMQ2 = std::make_unique(ret2.outputDataMQ); + EffectHelper::allocateInputData(common2, inputMQ2, buffer2); + EffectHelper::writeToFmq(inputMQ2, buffer2); + EffectHelper::readFromFmq(statusMQ2, 1, outputMQ2, buffer2.size(), buffer2); + + ASSERT_NO_FATAL_FAILURE(command(effect1, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(expectState(effect1, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(close(effect1)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect1)); + + ASSERT_NO_FATAL_FAILURE(command(effect2, CommandId::STOP)); + ASSERT_NO_FATAL_FAILURE(expectState(effect2, State::IDLE)); + ASSERT_NO_FATAL_FAILURE(close(effect2)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect2)); +} + +INSTANTIATE_TEST_SUITE_P( + SingleEffectInstanceTest, AudioEffectTest, + ::testing::Combine(testing::ValuesIn( + EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor))), + [](const testing::TestParamInfo& info) { + auto msSinceEpoch = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); + auto instance = std::get(info.param); + std::ostringstream address; + address << msSinceEpoch << "_factory_" << instance.first.get(); + std::string name = address.str() + "_UUID_timeLow_" + + ::android::internal::ToString(instance.second.uuid.timeLow) + + "_timeMid_" + + ::android::internal::ToString(instance.second.uuid.timeMid); + std::replace_if( + name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); + return name; + }); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioEffectTest); int main(int argc, char** argv) { diff --git a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp index 4162551ba4..f19dff6b00 100644 --- a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp +++ b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp @@ -35,8 +35,6 @@ #include #include #include -#include -#include #include "AudioHalBinderServiceUtil.h" #include "EffectHelper.h" @@ -47,103 +45,126 @@ using namespace android; using aidl::android::hardware::audio::effect::Capability; using aidl::android::hardware::audio::effect::Descriptor; -using aidl::android::hardware::audio::effect::EffectNullUuid; using aidl::android::hardware::audio::effect::Equalizer; -using aidl::android::hardware::audio::effect::EqualizerTypeUUID; using aidl::android::hardware::audio::effect::IEffect; using aidl::android::hardware::audio::effect::IFactory; +using aidl::android::hardware::audio::effect::kEqualizerTypeUUID; using aidl::android::hardware::audio::effect::Parameter; /** - * Here we focus on specific parameter checking, general IEffect interfaces testing performed in - * VtsAudioEfectTargetTest. + * Here we focus on specific effect (equalizer) parameter checking, general IEffect interfaces + * testing performed in VtsAudioEfectTargetTest. */ -enum ParamName { PARAM_INSTANCE_NAME, PARAM_PRESET_INDEX, PARAM_BAND_INDEX, PARAM_BAND_LEVEL }; -using EqualizerParamTestParam = std::tuple; + +enum ParamName { PARAM_INSTANCE_NAME, PARAM_BAND_LEVEL }; +using EqualizerParamTestParam = + std::tuple, Descriptor::Identity>, int>; /* Testing parameter range, assuming the parameter supported by effect is in this range. This range is verified with IEffect.getDescriptor(), for any index supported vts expect EX_NONE from IEffect.setParameter(), otherwise expect EX_ILLEGAL_ARGUMENT. */ -constexpr std::pair kPresetIndexRange = {-1, 10}; // valid range [0, 9] -constexpr std::pair kBandIndexRange = {-1, 5}; // valid range [0, 4] -constexpr std::pair kBandLevelRange = {-5, 5}; // needs update with implementation +const std::vector kBandLevels = {0, -10, 10}; // needs update with implementation -class EqualizerParamTest : public ::testing::TestWithParam, - public EffectHelper { +class EqualizerTest : public ::testing::TestWithParam, + public EffectHelper { public: - EqualizerParamTest() - : EffectHelper(std::get(GetParam())), - mParamPresetIndex(std::get(GetParam())), - mParamBandIndex(std::get(GetParam())), - mParamBandLevel(std::get(GetParam())) {} + EqualizerTest() : mBandLevel(std::get(GetParam())) { + std::tie(mFactory, mIdentity) = std::get(GetParam()); + } void SetUp() override { - CreateEffectsWithUUID(EqualizerTypeUUID); - initParamCommonFormat(); - initParamCommon(); - initParamSpecific(); - OpenEffects(EqualizerTypeUUID); - SCOPED_TRACE(testing::Message() << "preset: " << mParamPresetIndex << " bandIdx " - << mParamBandIndex << " level " << mParamBandLevel); - } + ASSERT_NE(nullptr, mFactory); + ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity)); + Parameter::Specific specific = getDefaultParamSpecific(); + Parameter::Common common = EffectHelper::createParamCommon( + 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */, + kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */); + IEffect::OpenEffectReturn ret; + ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE)); + ASSERT_NE(nullptr, mEffect); + ASSERT_NO_FATAL_FAILURE(setTagRange()); + } void TearDown() override { - CloseEffects(); - DestroyEffects(); - CleanUp(); + ASSERT_NO_FATAL_FAILURE(close(mEffect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect)); } - int mParamPresetIndex = 0; - int mParamBandIndex = 0; - int mParamBandLevel = 0; + std::pair setPresetIndexRange(const Equalizer::Capability& cap) const { + const auto [min, max] = + std::minmax_element(cap.presets.begin(), cap.presets.end(), + [](const auto& a, const auto& b) { return a.index < b.index; }); + return {min->index, max->index}; + } + std::pair setBandIndexRange(const Equalizer::Capability& cap) const { + const auto [min, max] = + std::minmax_element(cap.bandFrequencies.begin(), cap.bandFrequencies.end(), + [](const auto& a, const auto& b) { return a.index < b.index; }); + return {min->index, max->index}; + } + void setTagRange() { + Descriptor desc; + ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc)); + Equalizer::Capability& eqCap = desc.capability.get(); + mPresetIndex = setPresetIndexRange(eqCap); + mBandIndex = setBandIndexRange(eqCap); + } + + static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100; + std::shared_ptr mFactory; + std::shared_ptr mEffect; + Descriptor::Identity mIdentity; + std::pair mPresetIndex; + std::pair mBandIndex; + const int mBandLevel; + Descriptor mDesc; void SetAndGetEqualizerParameters() { - auto functor = [&](const std::shared_ptr& effect) { - for (auto& it : mTags) { - auto& tag = it.first; - auto& eq = it.second; + ASSERT_NE(nullptr, mEffect); + for (auto& it : mTags) { + auto& tag = it.first; + auto& eq = it.second; - // validate parameter - Descriptor desc; - ASSERT_STATUS(EX_NONE, effect->getDescriptor(&desc)); - const bool valid = isTagInRange(it.first, it.second, desc); - const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT; + // validate parameter + const bool valid = isTagInRange(it.first, it.second); + const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT; - // set - Parameter expectParam; - Parameter::Specific specific; - specific.set(*eq.get()); - expectParam.set(specific); - EXPECT_STATUS(expected, effect->setParameter(expectParam)) - << expectParam.toString(); + // set + Parameter expectParam; + Parameter::Specific specific; + specific.set(eq); + expectParam.set(specific); + EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) + << expectParam.toString() << "\n" + << mDesc.toString(); - // only get if parameter in range and set success - if (expected == EX_NONE) { - Parameter getParam; - Parameter::Id id; - Equalizer::Id eqId; - eqId.set(tag); - id.set(eqId); - // if set success, then get should match - EXPECT_STATUS(expected, effect->getParameter(id, &getParam)); - EXPECT_TRUE(isEqParameterExpected(expectParam, getParam)); - } + // only get if parameter in range and set success + if (expected == EX_NONE) { + Parameter getParam; + Parameter::Id id; + Equalizer::Id eqId; + eqId.set(tag); + id.set(eqId); + // if set success, then get should match + EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam)); + EXPECT_TRUE(isEqParameterExpected(expectParam, getParam)) + << "\nexpect:" << expectParam.toString() + << "\ngetParam:" << getParam.toString(); } - }; - EXPECT_NO_FATAL_FAILURE(ForEachEffect(functor)); + } } bool isEqParameterExpected(const Parameter& expect, const Parameter& target) { - // if parameter same, then for sure matched + // if parameter same, then for sure they are matched if (expect == target) return true; // if not, see if target include the expect parameter, and others all default (0). /* - This is verify the case of client setParameter to a single bandLevel ({3, -1} for - example), and return of getParameter must be [{0, 0}, {1, 0}, {2, 0}, {3, -1}, {4, 0}] - */ + * This is to verify the case of client setParameter to a single bandLevel ({3, -1} for + * example), and return of getParameter must be [{0, 0}, {1, 0}, {2, 0}, {3, -1}, {4, 0}] + */ EXPECT_EQ(expect.getTag(), Parameter::specific); EXPECT_EQ(target.getTag(), Parameter::specific); @@ -160,10 +181,16 @@ class EqualizerParamTest : public ::testing::TestWithParam(); + std::sort(expectBl.begin(), expectBl.end(), + [](const auto& a, const auto& b) { return a.index < b.index; }); + expectBl.erase(std::unique(expectBl.begin(), expectBl.end()), expectBl.end()); auto targetBl = targetEq.get(); return std::includes(targetBl.begin(), targetBl.end(), expectBl.begin(), expectBl.end()); } + case Equalizer::preset: { + return expectEq.get() == targetEq.get(); + } default: return false; } @@ -173,27 +200,24 @@ class EqualizerParamTest : public ::testing::TestWithParam(preset); - mTags.push_back({Equalizer::preset, std::make_unique(std::move(eq))}); + mTags.push_back({Equalizer::preset, eq}); } void addBandLevelsParam(std::vector& bandLevels) { Equalizer eq; eq.set(bandLevels); - mTags.push_back({Equalizer::bandLevels, std::make_unique(std::move(eq))}); + mTags.push_back({Equalizer::bandLevels, eq}); } - bool isTagInRange(const Equalizer::Tag& tag, const std::unique_ptr& eq, - const Descriptor& desc) const { - std::cout << "xxx" << toString(tag) << " " << desc.toString(); - const Equalizer::Capability& eqCap = desc.capability.get(); + bool isTagInRange(const Equalizer::Tag& tag, const Equalizer& eq) const { switch (tag) { case Equalizer::preset: { - int index = eq->get(); - return isPresetIndexInRange(eqCap, index); + int index = eq.get(); + return index >= mPresetIndex.first && index <= mPresetIndex.second; } case Equalizer::bandLevels: { - auto& bandLevel = eq->get(); - return isBandIndexInRange(eqCap, bandLevel); + auto& bandLevel = eq.get(); + return isBandInRange(bandLevel); } default: return false; @@ -201,78 +225,125 @@ class EqualizerParamTest : public ::testing::TestWithParam= min->index && idx <= max->index; - } - - bool isBandIndexInRange(const Equalizer::Capability& cap, - const std::vector& bandLevel) const { + bool isBandInRange(const std::vector& bandLevel) const { for (auto& it : bandLevel) { - if (!isBandIndexInRange(cap, it.index)) return false; + if (it.index < mBandIndex.first || it.index > mBandIndex.second) return false; } return true; } - bool isBandIndexInRange(const Equalizer::Capability& cap, int idx) const { - const auto [min, max] = - std::minmax_element(cap.bandFrequencies.begin(), cap.bandFrequencies.end(), - [](const auto& a, const auto& b) { return a.index < b.index; }); - return idx >= min->index && idx <= max->index; + Parameter::Specific getDefaultParamSpecific() { + Equalizer eq = Equalizer::make(0); + Parameter::Specific specific = + Parameter::Specific::make(eq); + return specific; } private: - std::vector>> mTags; + std::vector> mTags; bool validCapabilityTag(Capability& cap) { return cap.getTag() == Capability::equalizer; } - void initParamSpecific() { - Equalizer eq; - eq.set(0); - Parameter::Specific specific; - specific.set(eq); - setSpecific(specific); - } - void CleanUp() { mTags.clear(); } }; -TEST_P(EqualizerParamTest, SetAndGetPreset) { - EXPECT_NO_FATAL_FAILURE(addPresetParam(mParamPresetIndex)); - SetAndGetEqualizerParameters(); +TEST_P(EqualizerTest, SetAndGetPresetOutOfLowerBound) { + addPresetParam(mPresetIndex.second - 1); + ASSERT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters()); } -TEST_P(EqualizerParamTest, SetAndGetSingleBand) { - std::vector bandLevels; - Equalizer::BandLevel bandLevel = {mParamBandIndex, mParamBandLevel}; - bandLevels.push_back(bandLevel); - EXPECT_NO_FATAL_FAILURE(addBandLevelsParam(bandLevels)); - SetAndGetEqualizerParameters(); +TEST_P(EqualizerTest, SetAndGetPresetOutOfUpperBound) { + addPresetParam(mPresetIndex.second + 1); + EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters()); +} + +TEST_P(EqualizerTest, SetAndGetPresetAtLowerBound) { + addPresetParam(mPresetIndex.first); + EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters()); +} + +TEST_P(EqualizerTest, SetAndGetPresetAtHigherBound) { + addPresetParam(mPresetIndex.second); + EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters()); +} + +TEST_P(EqualizerTest, SetAndGetPresetInBound) { + addPresetParam((mPresetIndex.first + mPresetIndex.second) >> 1); + EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters()); +} + +TEST_P(EqualizerTest, SetAndGetBandOutOfLowerBound) { + std::vector bandLevels{{mBandIndex.first - 1, mBandLevel}}; + addBandLevelsParam(bandLevels); + EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters()); +} + +TEST_P(EqualizerTest, SetAndGetBandOutOfUpperBound) { + std::vector bandLevels{{mBandIndex.second + 1, mBandLevel}}; + addBandLevelsParam(bandLevels); + EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters()); +} + +TEST_P(EqualizerTest, SetAndGetBandAtLowerBound) { + std::vector bandLevels{{mBandIndex.first, mBandLevel}}; + addBandLevelsParam(bandLevels); + EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters()); +} + +TEST_P(EqualizerTest, SetAndGetBandAtHigherBound) { + std::vector bandLevels{{mBandIndex.second, mBandLevel}}; + addBandLevelsParam(bandLevels); + EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters()); +} + +TEST_P(EqualizerTest, SetAndGetBandInBound) { + std::vector bandLevels{ + {(mBandIndex.first + mBandIndex.second) >> 1, mBandLevel}}; + addBandLevelsParam(bandLevels); + EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters()); +} + +TEST_P(EqualizerTest, SetAndGetMultiBands) { + addPresetParam(mPresetIndex.first); + std::vector bandLevels{ + {mBandIndex.first, mBandLevel}, + {mBandIndex.second, mBandLevel}, + {(mBandIndex.first + mBandIndex.second) >> 1, mBandLevel}}; + addBandLevelsParam(bandLevels); + EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters()); +} + +TEST_P(EqualizerTest, SetAndGetMultipleParams) { + std::vector bandLevels{ + {(mBandIndex.first + mBandIndex.second) >> 1, mBandLevel}}; + addBandLevelsParam(bandLevels); + addPresetParam((mPresetIndex.first + mPresetIndex.second) >> 1); + EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters()); } INSTANTIATE_TEST_SUITE_P( - EqualizerTest, EqualizerParamTest, - ::testing::Combine( - testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)), - testing::Range(kPresetIndexRange.first, kPresetIndexRange.second), - testing::Range(kBandIndexRange.first, kBandIndexRange.second), - testing::Range(kBandLevelRange.first, kBandLevelRange.second)), - [](const testing::TestParamInfo& info) { - std::string instance = std::get(info.param); - std::string presetIdx = std::to_string(std::get(info.param)); - std::string bandIdx = std::to_string(std::get(info.param)); + EqualizerTest, EqualizerTest, + ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors( + IFactory::descriptor, kEqualizerTypeUUID)), + testing::ValuesIn(kBandLevels)), + [](const testing::TestParamInfo& info) { + auto msSinceEpoch = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); + auto instance = std::get(info.param); std::string bandLevel = std::to_string(std::get(info.param)); - - std::string name = instance + "_presetIndex" + presetIdx + "_bandIndex" + bandIdx + - "_bandLevel" + bandLevel; + std::ostringstream address; + address << msSinceEpoch << "_factory_" << instance.first.get(); + std::string name = address.str() + "_UUID_timeLow_" + + ::android::internal::ToString(instance.second.uuid.timeLow) + + "_timeMid_" + + ::android::internal::ToString(instance.second.uuid.timeMid) + + "_bandLevel_" + bandLevel; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); return name; }); - -GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EqualizerParamTest); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EqualizerTest); int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); diff --git a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp index 2ad016d7df..1485657cc5 100644 --- a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp +++ b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp @@ -27,8 +27,8 @@ using aidl::android::hardware::audio::effect::Capability; 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::kLoudnessEnhancerTypeUUID; using aidl::android::hardware::audio::effect::LoudnessEnhancer; -using aidl::android::hardware::audio::effect::LoudnessEnhancerTypeUUID; using aidl::android::hardware::audio::effect::Parameter; /** @@ -36,7 +36,8 @@ using aidl::android::hardware::audio::effect::Parameter; * VtsAudioEffectTargetTest. */ enum ParamName { PARAM_INSTANCE_NAME, PARAM_GAIN_MB }; -using LoudnessEnhancerParamTestParam = std::tuple; +using LoudnessEnhancerParamTestParam = + std::tuple, Descriptor::Identity>, int>; // Every int 32 bit value is a valid gain, so testing the corner cases and one regular value. // TODO : Update the test values once range/capability is updated by implementation. @@ -46,53 +47,64 @@ const std::vector kGainMbValues = {std::numeric_limits::min(), 100, class LoudnessEnhancerParamTest : public ::testing::TestWithParam, public EffectHelper { public: - LoudnessEnhancerParamTest() - : EffectHelper(std::get(GetParam())), - mParamGainMb(std::get(GetParam())) {} + LoudnessEnhancerParamTest() : mParamGainMb(std::get(GetParam())) { + std::tie(mFactory, mIdentity) = std::get(GetParam()); + } void SetUp() override { - CreateEffectsWithUUID(LoudnessEnhancerTypeUUID); - initParamCommonFormat(); - initParamCommon(); - initParamSpecific(); - OpenEffects(LoudnessEnhancerTypeUUID); - SCOPED_TRACE(testing::Message() << "gainMb: " << mParamGainMb); - } + ASSERT_NE(nullptr, mFactory); + ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity)); + Parameter::Specific specific = getDefaultParamSpecific(); + Parameter::Common common = EffectHelper::createParamCommon( + 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */, + kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */); + IEffect::OpenEffectReturn ret; + ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE)); + ASSERT_NE(nullptr, mEffect); + } void TearDown() override { - CloseEffects(); - DestroyEffects(); - CleanUp(); + ASSERT_NO_FATAL_FAILURE(close(mEffect)); + ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect)); } + Parameter::Specific getDefaultParamSpecific() { + LoudnessEnhancer le = LoudnessEnhancer::make(0); + Parameter::Specific specific = + Parameter::Specific::make(le); + return specific; + } + + static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100; + std::shared_ptr mFactory; + std::shared_ptr mEffect; + Descriptor::Identity mIdentity; int mParamGainMb = 0; - void SetAndGetLoudnessEnhancerParameters() { - auto functor = [&](const std::shared_ptr& effect) { - for (auto& it : mTags) { - auto& tag = it.first; - auto& le = it.second; + void SetAndGetParameters() { + for (auto& it : mTags) { + auto& tag = it.first; + auto& le = it.second; - // set parameter - Parameter expectParam; - Parameter::Specific specific; - specific.set(le); - expectParam.set(specific); - // All values are valid, set parameter should succeed - EXPECT_STATUS(EX_NONE, effect->setParameter(expectParam)) << expectParam.toString(); + // set parameter + Parameter expectParam; + Parameter::Specific specific; + specific.set(le); + expectParam.set(specific); + // All values are valid, set parameter should succeed + EXPECT_STATUS(EX_NONE, mEffect->setParameter(expectParam)) << expectParam.toString(); - // get parameter - Parameter getParam; - Parameter::Id id; - LoudnessEnhancer::Id leId; - leId.set(tag); - id.set(leId); - EXPECT_STATUS(EX_NONE, effect->getParameter(id, &getParam)); + // get parameter + Parameter getParam; + Parameter::Id id; + LoudnessEnhancer::Id leId; + leId.set(tag); + id.set(leId); + EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam)); - EXPECT_EQ(expectParam, getParam); - } - }; - EXPECT_NO_FATAL_FAILURE(ForEachEffect(functor)); + EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString() + << "\ngetParam:" << getParam.toString(); + } } void addGainMbParam(int gainMb) { @@ -103,33 +115,33 @@ class LoudnessEnhancerParamTest : public ::testing::TestWithParam> mTags; - - void initParamSpecific() { - LoudnessEnhancer le; - le.set(0); - Parameter::Specific specific; - specific.set(le); - setSpecific(specific); - } - void CleanUp() { mTags.clear(); } }; TEST_P(LoudnessEnhancerParamTest, SetAndGetGainMb) { EXPECT_NO_FATAL_FAILURE(addGainMbParam(mParamGainMb)); - SetAndGetLoudnessEnhancerParameters(); + SetAndGetParameters(); } INSTANTIATE_TEST_SUITE_P( LoudnessEnhancerTest, LoudnessEnhancerParamTest, - ::testing::Combine( - testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)), - testing::ValuesIn(kGainMbValues)), + ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors( + IFactory::descriptor, kLoudnessEnhancerTypeUUID)), + testing::ValuesIn(kGainMbValues)), [](const testing::TestParamInfo& info) { - std::string instance = std::get(info.param); + auto msSinceEpoch = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); + auto instance = std::get(info.param); std::string gainMb = std::to_string(std::get(info.param)); - std::string name = instance + "_gainMb" + gainMb; + std::ostringstream address; + address << msSinceEpoch << "_factory_" << instance.first.get(); + std::string name = address.str() + "_UUID_timeLow_" + + ::android::internal::ToString(instance.second.uuid.timeLow) + + "_timeMid_" + + ::android::internal::ToString(instance.second.uuid.timeMid) + + "_gainMb" + gainMb; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); return name;