AudioHal: adapt effect_param_t handling with AIDL

Bug: 258124419
Test: atest EffectParamWrapper_tests
Test: Enable AIDL and build, run cts
Test: atest EffectsFactoryHalInterfaceTest

Change-Id: I404122422d4be70f6f24a1b4e40548fed41110b9
diff --git a/media/audioaidlconversion/AidlConversionNdk.cpp b/media/audioaidlconversion/AidlConversionNdk.cpp
index 9981435..8fec660 100644
--- a/media/audioaidlconversion/AidlConversionNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionNdk.cpp
@@ -30,7 +30,10 @@
 namespace android {
 
 using ::aidl::android::hardware::audio::effect::AcousticEchoCanceler;
+using ::aidl::android::hardware::audio::effect::AutomaticGainControl;
+using ::aidl::android::hardware::audio::effect::BassBoost;
 using ::aidl::android::hardware::audio::effect::Descriptor;
+using ::aidl::android::hardware::audio::effect::Downmix;
 using ::aidl::android::hardware::audio::effect::Flags;
 using ::aidl::android::hardware::audio::effect::Parameter;
 using ::aidl::android::media::audio::common::AudioDeviceDescription;
@@ -39,14 +42,6 @@
 using ::android::base::unexpected;
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
-// Utils
-
-ConversionResult<AcousticEchoCanceler> getParameterSpecificAec(const Parameter& aidl) {
-    const auto& specific = VALUE_OR_RETURN(UNION_GET(aidl, specific));
-    return VALUE_OR_RETURN(UNION_GET(specific, acousticEchoCanceler));
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
 // Converters
 
 ConversionResult<uint32_t> aidl2legacy_Flags_Type_uint32(Flags::Type type) {
@@ -65,6 +60,22 @@
     return unexpected(BAD_VALUE);
 }
 
+ConversionResult<Flags::Type> legacy2aidl_uint32_Flags_Type(uint32_t legacy) {
+    switch (legacy & EFFECT_FLAG_TYPE_MASK) {
+        case EFFECT_FLAG_TYPE_INSERT:
+            return Flags::Type::INSERT;
+        case EFFECT_FLAG_TYPE_AUXILIARY:
+            return Flags::Type::AUXILIARY;
+        case EFFECT_FLAG_TYPE_REPLACE:
+            return Flags::Type::REPLACE;
+        case EFFECT_FLAG_TYPE_PRE_PROC:
+            return Flags::Type::PRE_PROC;
+        case EFFECT_FLAG_TYPE_POST_PROC:
+            return Flags::Type::POST_PROC;
+    }
+    return unexpected(BAD_VALUE);
+}
+
 ConversionResult<uint32_t> aidl2legacy_Flags_Insert_uint32(Flags::Insert insert) {
     switch (insert) {
         case Flags::Insert::ANY:
@@ -79,6 +90,20 @@
     return unexpected(BAD_VALUE);
 }
 
+ConversionResult<Flags::Insert> legacy2aidl_uint32_Flags_Insert(uint32_t legacy) {
+    switch (legacy & EFFECT_FLAG_INSERT_MASK) {
+        case EFFECT_FLAG_INSERT_ANY:
+            return Flags::Insert::ANY;
+        case EFFECT_FLAG_INSERT_FIRST:
+            return Flags::Insert::FIRST;
+        case EFFECT_FLAG_INSERT_LAST:
+            return Flags::Insert::LAST;
+        case EFFECT_FLAG_INSERT_EXCLUSIVE:
+            return Flags::Insert::EXCLUSIVE;
+    }
+    return unexpected(BAD_VALUE);
+}
+
 ConversionResult<uint32_t> aidl2legacy_Flags_Volume_uint32(Flags::Volume volume) {
     switch (volume) {
         case Flags::Volume::NONE:
@@ -92,15 +117,17 @@
     }
     return unexpected(BAD_VALUE);
 }
-ConversionResult<uint32_t> aidl2legacy_Flags_HardwareAccelerator_uint32(
-        Flags::HardwareAccelerator hwAcceleratorMode) {
-    switch (hwAcceleratorMode) {
-        case Flags::HardwareAccelerator::NONE:
-            return 0;
-        case Flags::HardwareAccelerator::SIMPLE:
-            return EFFECT_FLAG_HW_ACC_SIMPLE;
-        case Flags::HardwareAccelerator::TUNNEL:
-            return EFFECT_FLAG_HW_ACC_TUNNEL;
+
+ConversionResult<Flags::Volume> legacy2aidl_uint32_Flags_Volume(uint32_t legacy) {
+    switch (legacy & EFFECT_FLAG_VOLUME_MASK) {
+        case EFFECT_FLAG_VOLUME_CTRL:
+            return Flags::Volume::CTRL;
+        case EFFECT_FLAG_VOLUME_IND:
+            return Flags::Volume::IND;
+        case EFFECT_FLAG_VOLUME_MONITOR:
+            return Flags::Volume::MONITOR;
+        case EFFECT_FLAG_VOLUME_NONE:
+            return Flags::Volume::NONE;
     }
     return unexpected(BAD_VALUE);
 }
@@ -130,59 +157,6 @@
     return legacy;
 }
 
-ConversionResult<Flags::Type> legacy2aidl_uint32_Flags_Type(uint32_t legacy) {
-    switch (legacy & EFFECT_FLAG_TYPE_MASK) {
-        case EFFECT_FLAG_TYPE_INSERT:
-            return Flags::Type::INSERT;
-        case EFFECT_FLAG_TYPE_AUXILIARY:
-            return Flags::Type::AUXILIARY;
-        case EFFECT_FLAG_TYPE_REPLACE:
-            return Flags::Type::REPLACE;
-        case EFFECT_FLAG_TYPE_PRE_PROC:
-            return Flags::Type::PRE_PROC;
-        case EFFECT_FLAG_TYPE_POST_PROC:
-            return Flags::Type::POST_PROC;
-    }
-    return unexpected(BAD_VALUE);
-}
-
-ConversionResult<Flags::Insert> legacy2aidl_uint32_Flags_Insert(uint32_t legacy) {
-    switch (legacy & EFFECT_FLAG_INSERT_MASK) {
-        case EFFECT_FLAG_INSERT_ANY:
-            return Flags::Insert::ANY;
-        case EFFECT_FLAG_INSERT_FIRST:
-            return Flags::Insert::FIRST;
-        case EFFECT_FLAG_INSERT_LAST:
-            return Flags::Insert::LAST;
-        case EFFECT_FLAG_INSERT_EXCLUSIVE:
-            return Flags::Insert::EXCLUSIVE;
-    }
-    return unexpected(BAD_VALUE);
-}
-
-ConversionResult<Flags::Volume> legacy2aidl_uint32_Flags_Volume(uint32_t legacy) {
-    switch (legacy & EFFECT_FLAG_VOLUME_MASK) {
-        case EFFECT_FLAG_VOLUME_IND:
-            return Flags::Volume::IND;
-        case EFFECT_FLAG_VOLUME_MONITOR:
-            return Flags::Volume::MONITOR;
-        case EFFECT_FLAG_VOLUME_NONE:
-            return Flags::Volume::NONE;
-    }
-    return unexpected(BAD_VALUE);
-}
-
-ConversionResult<Flags::HardwareAccelerator> legacy2aidl_uint32_Flags_HardwareAccelerator(
-        uint32_t legacy) {
-    switch (legacy & EFFECT_FLAG_HW_ACC_MASK) {
-        case EFFECT_FLAG_HW_ACC_SIMPLE:
-            return Flags::HardwareAccelerator::SIMPLE;
-        case EFFECT_FLAG_HW_ACC_TUNNEL:
-            return Flags::HardwareAccelerator::TUNNEL;
-    }
-    return unexpected(BAD_VALUE);
-}
-
 ConversionResult<Flags> legacy2aidl_uint32_Flags(uint32_t legacy) {
     Flags aidl;
 
@@ -198,6 +172,32 @@
     return aidl;
 }
 
+ConversionResult<uint32_t> aidl2legacy_Flags_HardwareAccelerator_uint32(
+        Flags::HardwareAccelerator hwAcceleratorMode) {
+    switch (hwAcceleratorMode) {
+        case Flags::HardwareAccelerator::NONE:
+            return 0;
+        case Flags::HardwareAccelerator::SIMPLE:
+            return EFFECT_FLAG_HW_ACC_SIMPLE;
+        case Flags::HardwareAccelerator::TUNNEL:
+            return EFFECT_FLAG_HW_ACC_TUNNEL;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<Flags::HardwareAccelerator> legacy2aidl_uint32_Flags_HardwareAccelerator(
+        uint32_t legacy) {
+    switch (legacy & EFFECT_FLAG_HW_ACC_MASK) {
+        case EFFECT_FLAG_HW_ACC_SIMPLE:
+            return Flags::HardwareAccelerator::SIMPLE;
+        case EFFECT_FLAG_HW_ACC_TUNNEL:
+            return Flags::HardwareAccelerator::TUNNEL;
+        case 0:
+            return Flags::HardwareAccelerator::NONE;
+    }
+    return unexpected(BAD_VALUE);
+}
+
 ConversionResult<effect_descriptor_t>
 aidl2legacy_Descriptor_effect_descriptor(const Descriptor& aidl) {
     effect_descriptor_t legacy;
@@ -231,6 +231,7 @@
     return aidl;
 }
 
+// buffer_provider_t is not supported thus skipped
 ConversionResult<buffer_config_t> aidl2legacy_AudioConfigBase_buffer_config_t(
         const media::audio::common::AudioConfigBase& aidl, bool isInput) {
     buffer_config_t legacy;
@@ -245,6 +246,7 @@
     legacy.format = VALUE_OR_RETURN(aidl2legacy_AudioFormatDescription_audio_format_t(aidl.format));
     legacy.mask |= EFFECT_CONFIG_FORMAT;
 
+    // TODO: add accessMode and mask
     return legacy;
 }
 
@@ -263,37 +265,100 @@
         aidl.format = VALUE_OR_RETURN(legacy2aidl_audio_format_t_AudioFormatDescription(
                 static_cast<audio_format_t>(legacy.format)));
     }
+
+    // TODO: add accessMode and mask
     return aidl;
 }
 
-ConversionResult<uint32_t> aidl2legacy_Parameter_uint32_echoDelay(const Parameter& aidl) {
-    const auto& aec = VALUE_OR_RETURN(getParameterSpecificAec(aidl));
-    const auto& echoDelay = VALUE_OR_RETURN(UNION_GET(aec, echoDelayUs));
-    return VALUE_OR_RETURN(convertIntegral<uint32_t>(echoDelay));
+ConversionResult<uint32_t> aidl2legacy_Parameter_aec_uint32_echoDelay(const Parameter& aidl) {
+    int echoDelay = VALUE_OR_RETURN(GET_PARAMETER_SPECIFIC_FIELD(
+            aidl, AcousticEchoCanceler, acousticEchoCanceler, echoDelayUs, int));
+    return VALUE_OR_RETURN(convertReinterpret<uint32_t>(echoDelay));
 }
 
-ConversionResult<Parameter> legacy2aidl_uint32_echoDelay_Parameter(const uint32_t& legacy) {
+ConversionResult<Parameter> legacy2aidl_uint32_echoDelay_Parameter_aec(uint32_t legacy) {
     int delay = VALUE_OR_RETURN(convertReinterpret<int32_t>(legacy));
-    AcousticEchoCanceler aec = AcousticEchoCanceler::make<AcousticEchoCanceler::echoDelayUs>(delay);
-    Parameter::Specific specific =
-            Parameter::Specific::make<Parameter::Specific::acousticEchoCanceler>(aec);
-
-    return Parameter::make<Parameter::specific>(specific);
+    return MAKE_SPECIFIC_PARAMETER(AcousticEchoCanceler, acousticEchoCanceler, echoDelayUs, delay);
 }
 
-ConversionResult<uint32_t> aidl2legacy_Parameter_uint32_mobileMode(const Parameter& aidl) {
-    const auto& aec = VALUE_OR_RETURN(getParameterSpecificAec(aidl));
-    const auto& mobileMode = VALUE_OR_RETURN(UNION_GET(aec, mobileMode));
+ConversionResult<uint32_t> aidl2legacy_Parameter_aec_uint32_mobileMode(const Parameter& aidl) {
+    bool mobileMode = VALUE_OR_RETURN(GET_PARAMETER_SPECIFIC_FIELD(
+            aidl, AcousticEchoCanceler, acousticEchoCanceler, mobileMode, bool));
     return VALUE_OR_RETURN(convertIntegral<uint32_t>(mobileMode));
 }
 
-ConversionResult<Parameter> legacy2aidl_uint32_mobileMode_Parameter(const uint32_t& legacy) {
+ConversionResult<Parameter> legacy2aidl_uint32_mobileMode_Parameter_aec(uint32_t legacy) {
     bool mode = VALUE_OR_RETURN(convertIntegral<bool>(legacy));
-    AcousticEchoCanceler aec = AcousticEchoCanceler::make<AcousticEchoCanceler::mobileMode>(mode);
-    Parameter::Specific specific =
-            Parameter::Specific::make<Parameter::Specific::acousticEchoCanceler>(aec);
+    return MAKE_SPECIFIC_PARAMETER(AcousticEchoCanceler, acousticEchoCanceler, mobileMode, mode);
+}
 
-    return Parameter::make<Parameter::specific>(specific);
+ConversionResult<uint32_t> aidl2legacy_Parameter_agc_uint32_fixedDigitalGain(
+        const Parameter& aidl) {
+    int gain = VALUE_OR_RETURN(GET_PARAMETER_SPECIFIC_FIELD(
+            aidl, AutomaticGainControl, automaticGainControl, fixedDigitalGainMb, int));
+    return VALUE_OR_RETURN(convertReinterpret<uint32_t>(gain));
+}
+
+ConversionResult<Parameter> legacy2aidl_uint32_fixedDigitalGain_Parameter_agc(uint32_t legacy) {
+    int gain = VALUE_OR_RETURN(convertReinterpret<int>(legacy));
+    return MAKE_SPECIFIC_PARAMETER(AutomaticGainControl, automaticGainControl, fixedDigitalGainMb,
+                                   gain);
+}
+
+ConversionResult<uint32_t> aidl2legacy_Parameter_agc_uint32_levelEstimator(
+        const Parameter& aidl) {
+    const auto& le = VALUE_OR_RETURN(
+            GET_PARAMETER_SPECIFIC_FIELD(aidl, AutomaticGainControl, automaticGainControl,
+                                         levelEstimator, AutomaticGainControl::LevelEstimator));
+    return static_cast<uint32_t>(le);
+}
+
+ConversionResult<Parameter> legacy2aidl_uint32_levelEstimator_Parameter_agc(uint32_t legacy) {
+    if (legacy > (uint32_t) AutomaticGainControl::LevelEstimator::PEAK) {
+        return unexpected(BAD_VALUE);
+    }
+    AutomaticGainControl::LevelEstimator le =
+            static_cast<AutomaticGainControl::LevelEstimator>(legacy);
+    return MAKE_SPECIFIC_PARAMETER(AutomaticGainControl, automaticGainControl, levelEstimator, le);
+}
+
+ConversionResult<uint32_t> aidl2legacy_Parameter_agc_uint32_saturationMargin(
+        const Parameter& aidl) {
+    int saturationMargin = VALUE_OR_RETURN(GET_PARAMETER_SPECIFIC_FIELD(
+            aidl, AutomaticGainControl, automaticGainControl, saturationMarginMb, int));
+    return VALUE_OR_RETURN(convertIntegral<uint32_t>(saturationMargin));
+}
+
+ConversionResult<Parameter> legacy2aidl_uint32_saturationMargin_Parameter_agc(uint32_t legacy) {
+    int saturationMargin = VALUE_OR_RETURN(convertIntegral<int>(legacy));
+    return MAKE_SPECIFIC_PARAMETER(AutomaticGainControl, automaticGainControl, saturationMarginMb,
+                                   saturationMargin);
+}
+
+ConversionResult<uint16_t> aidl2legacy_Parameter_BassBoost_uint16_strengthPm(
+        const Parameter& aidl) {
+    int strength = VALUE_OR_RETURN(
+            GET_PARAMETER_SPECIFIC_FIELD(aidl, BassBoost, bassBoost, strengthPm, int));
+    return VALUE_OR_RETURN(convertIntegral<uint16_t>(strength));
+}
+
+ConversionResult<Parameter> legacy2aidl_uint16_strengthPm_Parameter_BassBoost(uint16_t legacy) {
+    int strength = VALUE_OR_RETURN(convertIntegral<int>(legacy));
+    return MAKE_SPECIFIC_PARAMETER(BassBoost, bassBoost, strengthPm, strength);
+}
+
+ConversionResult<int16_t> aidl2legacy_Parameter_Downmix_int16_type(const Parameter& aidl) {
+    Downmix::Type aidlType = VALUE_OR_RETURN(
+            GET_PARAMETER_SPECIFIC_FIELD(aidl, Downmix, downmix, type, Downmix::Type));
+    return VALUE_OR_RETURN(convertIntegral<int16_t>(static_cast<uint32_t>(aidlType)));
+}
+
+ConversionResult<Parameter> legacy2aidl_int16_type_Parameter_Downmix(int16_t legacy) {
+    if (legacy > (uint32_t) Downmix::Type::FOLD) {
+        return unexpected(BAD_VALUE);
+    }
+    Downmix::Type aidlType = static_cast<Downmix::Type>(legacy);
+    return MAKE_SPECIFIC_PARAMETER(Downmix, downmix, type, aidlType);
 }
 
 }  // namespace android
diff --git a/media/audioaidlconversion/include/media/AidlConversionNdk.h b/media/audioaidlconversion/include/media/AidlConversionNdk.h
index a1c0da7..d094dff 100644
--- a/media/audioaidlconversion/include/media/AidlConversionNdk.h
+++ b/media/audioaidlconversion/include/media/AidlConversionNdk.h
@@ -32,8 +32,32 @@
 namespace aidl {
 namespace android {
 
-ConversionResult<::aidl::android::hardware::audio::effect::AcousticEchoCanceler>
-getParameterSpecificAec(const ::aidl::android::hardware::audio::effect::Parameter& aidl);
+template <typename P, typename T, typename P::Specific::Tag tag>
+ConversionResult<T> getParameterSpecific(const P& u) {
+    const auto& spec = VALUE_OR_RETURN(UNION_GET(u, specific));
+    return unionGetField<typename P::Specific, tag>(spec);
+}
+
+template <typename P, typename T, typename P::Specific::Tag tag, typename T::Tag field, typename F>
+ConversionResult<F> getParameterSpecificField(const P& u) {
+    const auto& spec =
+            VALUE_OR_RETURN((getParameterSpecific<std::decay_t<decltype(u)>, T, tag>(u)));
+    return VALUE_OR_RETURN((unionGetField<T, field>(spec)));
+}
+
+#define GET_PARAMETER_SPECIFIC_FIELD(u, specific, tag, field, fieldType)                        \
+    getParameterSpecificField<std::decay_t<decltype(u)>, specific,                              \
+                              aidl::android::hardware::audio::effect::Parameter::Specific::tag, \
+                              specific::field, fieldType>(u)
+
+#define MAKE_SPECIFIC_PARAMETER(spec, tag, field, value)                                    \
+    UNION_MAKE(aidl::android::hardware::audio::effect::Parameter, specific,                 \
+               UNION_MAKE(aidl::android::hardware::audio::effect::Parameter::Specific, tag, \
+                          UNION_MAKE(spec, field, value)))
+
+#define MAKE_SPECIFIC_PARAMETER_ID(spec, tag, field)                       \
+    UNION_MAKE(aidl::android::hardware::audio::effect::Parameter::Id, tag, \
+               UNION_MAKE(spec::Id, commonTag, spec::field))
 
 ConversionResult<uint32_t> aidl2legacy_Flags_Type_uint32(
         ::aidl::android::hardware::audio::effect::Flags::Type type);
@@ -67,16 +91,40 @@
 ConversionResult<media::audio::common::AudioConfigBase> legacy2aidl_buffer_config_t_AudioConfigBase(
         const buffer_config_t& legacy, bool isInput);
 
-ConversionResult<uint32_t> aidl2legacy_Parameter_uint32_echoDelay(
+ConversionResult<uint32_t> aidl2legacy_Parameter_aec_uint32_echoDelay(
         const ::aidl::android::hardware::audio::effect::Parameter& aidl);
 ConversionResult<::aidl::android::hardware::audio::effect::Parameter>
-legacy2aidl_uint32_echoDelay_Parameter(const uint32_t& legacy);
+legacy2aidl_uint32_echoDelay_Parameter_aec(uint32_t legacy);
 
-ConversionResult<uint32_t> aidl2legacy_Parameter_uint32_mobileMode(
+ConversionResult<uint32_t> aidl2legacy_Parameter_aec_uint32_mobileMode(
         const ::aidl::android::hardware::audio::effect::Parameter& aidl);
 ConversionResult<::aidl::android::hardware::audio::effect::Parameter>
-legacy2aidl_uint32_mobileMode_Parameter(const uint32_t& legacy);
+legacy2aidl_uint32_mobileMode_Parameter_aec(uint32_t legacy);
 
+ConversionResult<uint32_t> aidl2legacy_Parameter_agc_uint32_fixedDigitalGain(
+        const ::aidl::android::hardware::audio::effect::Parameter& aidl);
+ConversionResult<::aidl::android::hardware::audio::effect::Parameter>
+legacy2aidl_uint32_fixedDigitalGain_Parameter_agc(uint32_t legacy);
+
+ConversionResult<uint32_t> aidl2legacy_Parameter_agc_uint32_levelEstimator(
+        const ::aidl::android::hardware::audio::effect::Parameter& aidl);
+ConversionResult<::aidl::android::hardware::audio::effect::Parameter>
+legacy2aidl_uint32_levelEstimator_Parameter_agc(uint32_t legacy);
+
+ConversionResult<uint32_t> aidl2legacy_Parameter_agc_uint32_saturationMargin(
+        const ::aidl::android::hardware::audio::effect::Parameter& aidl);
+ConversionResult<::aidl::android::hardware::audio::effect::Parameter>
+legacy2aidl_uint32_saturationMargin_Parameter_agc(uint32_t legacy);
+
+ConversionResult<uint16_t> aidl2legacy_Parameter_BassBoost_uint16_strengthPm(
+        const ::aidl::android::hardware::audio::effect::Parameter& aidl);
+ConversionResult<::aidl::android::hardware::audio::effect::Parameter>
+legacy2aidl_uint16_strengthPm_Parameter_BassBoost(uint16_t legacy);
+
+ConversionResult<int16_t> aidl2legacy_Parameter_Downmix_int16_type(
+        const ::aidl::android::hardware::audio::effect::Parameter& aidl);
+ConversionResult<::aidl::android::hardware::audio::effect::Parameter>
+legacy2aidl_int16_type_Parameter_Downmix(int16_t legacy);
 
 }  // namespace android
 }  // namespace aidl
diff --git a/media/audioaidlconversion/include/media/AidlConversionUtil.h b/media/audioaidlconversion/include/media/AidlConversionUtil.h
index a0830fc..8b2e0de 100644
--- a/media/audioaidlconversion/include/media/AidlConversionUtil.h
+++ b/media/audioaidlconversion/include/media/AidlConversionUtil.h
@@ -278,6 +278,8 @@
 #define UNION_SET(u, field, value) \
     (u).set<std::decay_t<decltype(u)>::Tag::field>(value)
 
+#define UNION_MAKE(u, field, value) u::make<u::Tag::field>(value)
+
 namespace aidl_utils {
 
 /**
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
index 493d1ee..ec8abd7 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
@@ -16,12 +16,27 @@
 
 #include <cstdint>
 #include <cstring>
+#include <optional>
 #define LOG_TAG "EffectConversionHelperAidl"
 //#define LOG_NDEBUG 0
 
 #include <error/expected_utils.h>
 #include <media/audiohal/AudioEffectUuid.h>
-#include <system/audio_effects/audio_effects_utils.h>
+#include <system/audio_effects/effect_aec.h>
+#include <system/audio_effects/effect_agc2.h>
+#include <system/audio_effects/effect_bassboost.h>
+#include <system/audio_effects/effect_downmix.h>
+#include <system/audio_effects/effect_dynamicsprocessing.h>
+#include <system/audio_effects/effect_environmentalreverb.h>
+#include <system/audio_effects/effect_equalizer.h>
+#include <system/audio_effects/effect_hapticgenerator.h>
+#include <system/audio_effects/effect_loudnessenhancer.h>
+#include <system/audio_effects/effect_ns.h>
+#include <system/audio_effects/effect_presetreverb.h>
+#include <system/audio_effects/effect_spatializer.h>
+#include <system/audio_effects/effect_virtualizer.h>
+#include <system/audio_effects/effect_visualizer.h>
+
 #include <utils/Log.h>
 
 #include "EffectConversionHelperAidl.h"
@@ -31,10 +46,16 @@
 
 using ::aidl::android::aidl_utils::statusTFromBinderStatus;
 using ::aidl::android::hardware::audio::effect::AcousticEchoCanceler;
+using ::aidl::android::hardware::audio::effect::AutomaticGainControl;
+using ::aidl::android::hardware::audio::effect::BassBoost;
 using ::aidl::android::hardware::audio::effect::CommandId;
+using ::aidl::android::hardware::audio::effect::Descriptor;
+using ::aidl::android::hardware::audio::effect::Downmix;
 using ::aidl::android::hardware::audio::effect::Parameter;
 using ::aidl::android::media::audio::common::AudioDeviceDescription;
 using ::aidl::android::media::audio::common::AudioUuid;
+using android::effect::utils::EffectParamReader;
+using android::effect::utils::EffectParamWriter;
 
 using ::android::status_t;
 
@@ -59,8 +80,26 @@
         EffectConversionHelperAidl::mParameterHandlerMap = {
                 {kAcousticEchoCancelerTypeUUID,
                  {&EffectConversionHelperAidl::setAecParameter,
-                  &EffectConversionHelperAidl::getAecParameter}}};
+                  &EffectConversionHelperAidl::getAecParameter}},
+                {kAutomaticGainControlTypeUUID,
+                 {&EffectConversionHelperAidl::setAgcParameter,
+                  &EffectConversionHelperAidl::getAgcParameter}},
+                {kBassBoostTypeUUID,
+                 {&EffectConversionHelperAidl::setBassBoostParameter,
+                  &EffectConversionHelperAidl::getBassBoostParameter}},
+                {kDownmixTypeUUID,
+                 {&EffectConversionHelperAidl::setDownmixParameter,
+                  &EffectConversionHelperAidl::getDownmixParameter}}};
 
+EffectConversionHelperAidl::EffectConversionHelperAidl(
+        std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+        int32_t sessionId, int32_t ioId,
+        const ::aidl::android::hardware::audio::effect::Descriptor& desc)
+    : mSessionId(sessionId), mIoId(ioId), mDesc(desc), mEffect(std::move(effect)) {
+    mCommon.session = sessionId;
+    mCommon.ioHandle = ioId;
+    mCommon.input = mCommon.output = kDefaultAudioConfig;
+}
 
 status_t EffectConversionHelperAidl::handleCommand(uint32_t cmdCode, uint32_t cmdSize,
                                                    void* pCmdData, uint32_t* replySize,
@@ -80,84 +119,87 @@
         return BAD_VALUE;
     }
 
-    return *(status_t*)pReplyData = OK;
+    return *(status_t*)pReplyData =
+                   statusTFromBinderStatus(mEffect->open(mCommon, std::nullopt, &mOpenReturn));
 }
 
 status_t EffectConversionHelperAidl::handleSetParameter(uint32_t cmdSize, const void* pCmdData,
                                                         uint32_t* replySize, void* pReplyData) {
-    if (cmdSize < kEffectParamSize || !pCmdData || !replySize || *replySize < sizeof(int) ||
-        !pReplyData) {
+    if (cmdSize < sizeof(effect_param_t) || !pCmdData || !replySize ||
+        *replySize < sizeof(int) || !pReplyData) {
         return BAD_VALUE;
     }
 
-    const effect_param_t* param = (effect_param_t*)pCmdData;
-    if (!validateCommandSize(*param, cmdSize)) {
-        ALOGE("%s illegal param %s size %u", __func__, utils::toString(*param).c_str(), cmdSize);
+    auto reader = EffectParamReader(*(effect_param_t*)pCmdData);
+    if (!reader.validateCmdSize(cmdSize)) {
+        ALOGE("%s illegal param %s size %u", __func__, reader.toString().c_str(), cmdSize);
         return BAD_VALUE;
     }
 
-    const auto& handler = mParameterHandlerMap.find(mTypeUuid);
+    const auto& handler = mParameterHandlerMap.find(mDesc.common.id.type);
     if (handler == mParameterHandlerMap.end() || !handler->second.first) {
-        ALOGE("%s handler for uuid %s not found", __func__, mTypeUuid.toString().c_str());
+        ALOGE("%s handler for uuid %s not found", __func__,
+              mDesc.common.id.type.toString().c_str());
         return BAD_VALUE;
     }
     const SetParameter& functor = handler->second.first;
-    return *(status_t*)pReplyData = (this->*functor)(*(const effect_param_t*)param);
+    return *(status_t*)pReplyData = (this->*functor)(reader);
 }
 
 status_t EffectConversionHelperAidl::handleGetParameter(uint32_t cmdSize, const void* pCmdData,
                                                         uint32_t* replySize, void* pReplyData) {
-    if (cmdSize < kEffectParamSize || !pCmdData || !replySize || !pReplyData) {
+    if (cmdSize < sizeof(effect_param_t) || !pCmdData || !replySize || !pReplyData) {
         return BAD_VALUE;
     }
 
-    const effect_param_t* param = (effect_param_t*)pCmdData;
-    if (!validateCommandSize(*param, *replySize)) {
-        ALOGE("%s illegal param %s, replysize %u", __func__, utils::toString(*param).c_str(),
+    const auto reader = EffectParamReader(*(effect_param_t*)pCmdData);
+    if (!reader.validateCmdSize(cmdSize)) {
+        ALOGE("%s illegal param %s, replysize %u", __func__, reader.toString().c_str(),
               *replySize);
         return BAD_VALUE;
     }
 
-    const auto& handler = mParameterHandlerMap.find(mTypeUuid);
+    const auto& handler = mParameterHandlerMap.find(mDesc.common.id.type);
     if (handler == mParameterHandlerMap.end() || !handler->second.second) {
-        ALOGE("%s handler for uuid %s not found", __func__, mTypeUuid.toString().c_str());
+        ALOGE("%s handler for uuid %s not found", __func__,
+              mDesc.common.id.type.toString().c_str());
         return BAD_VALUE;
     }
     const GetParameter& functor = handler->second.second;
-    memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + param->psize);
-    effect_param_t* reply = (effect_param_t *)pReplyData;
-    (this->*functor)(*reply);
-    *replySize = kEffectParamSize + padding(reply->psize) + reply->vsize;
-    return reply->status;
+    memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + reader.getParameterSize());
+    auto writer = EffectParamWriter(*(effect_param_t *)pReplyData);
+    (this->*functor)(writer);
+    *replySize = writer.getTotalSize();
+    return writer.getStatus();
 }
 
 status_t EffectConversionHelperAidl::handleSetConfig(uint32_t cmdSize, const void* pCmdData,
                                                      uint32_t* replySize, void* pReplyData) {
-    if (!replySize || *replySize != sizeof(int) || !pReplyData || cmdSize != kEffectConfigSize) {
+    if (!replySize || *replySize != sizeof(int) || !pReplyData ||
+        cmdSize != sizeof(effect_config_t)) {
         return BAD_VALUE;
     }
 
     const auto& legacyConfig = static_cast<const effect_config_t*>(pCmdData);
     // already open, apply latest settings
-    Parameter::Common common;
-    common.input.base =
+    mCommon.input.base =
             VALUE_OR_RETURN_STATUS(::aidl::android::legacy2aidl_buffer_config_t_AudioConfigBase(
                     legacyConfig->inputCfg, true /* isInput */));
-    common.output.base =
+    mCommon.output.base =
             VALUE_OR_RETURN_STATUS(::aidl::android::legacy2aidl_buffer_config_t_AudioConfigBase(
                     legacyConfig->outputCfg, false /* isInput */));
-    common.session = mSessionId;
-    common.ioHandle = mIoId;
+    mCommon.session = mSessionId;
+    mCommon.ioHandle = mIoId;
     // TODO: add access mode support
     RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
-            mEffect->setParameter(Parameter::make<Parameter::common>(common))));
+            mEffect->setParameter(Parameter::make<Parameter::common>(mCommon))));
     return *static_cast<int32_t*>(pReplyData) = OK;
 }
 
 status_t EffectConversionHelperAidl::handleGetConfig(uint32_t cmdSize __unused,
                                                      const void* pCmdData __unused,
                                                      uint32_t* replySize, void* pReplyData) {
-    if (!replySize || *replySize != kEffectConfigSize || !pReplyData) {
+    if (!replySize || *replySize != sizeof(effect_config_t) || !pReplyData) {
         ALOGE("%s parameter invalid %p %p", __func__, replySize, pReplyData);
         return BAD_VALUE;
     }
@@ -179,43 +221,40 @@
 status_t EffectConversionHelperAidl::handleReset(uint32_t cmdSize __unused,
                                                  const void* pCmdData __unused, uint32_t* replySize,
                                                  void* pReplyData) {
-    if (!replySize || *replySize != kEffectConfigSize || !pReplyData) {
+    if (!replySize || *replySize != sizeof(effect_config_t) || !pReplyData) {
         ALOGE("%s parameter invalid %p %p", __func__, replySize, pReplyData);
         return BAD_VALUE;
     }
 
-    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->command(CommandId::RESET)));
-    return OK;
+    return statusTFromBinderStatus(mEffect->command(CommandId::RESET));
 }
 
 status_t EffectConversionHelperAidl::handleEnable(uint32_t cmdSize __unused,
                                                  const void* pCmdData __unused, uint32_t* replySize,
                                                  void* pReplyData) {
-    if (!replySize || *replySize != kEffectConfigSize || !pReplyData) {
+    if (!replySize || *replySize != sizeof(effect_config_t) || !pReplyData) {
         ALOGE("%s parameter invalid %p %p", __func__, replySize, pReplyData);
         return BAD_VALUE;
     }
 
-    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->command(CommandId::START)));
-    return OK;
+    return statusTFromBinderStatus(mEffect->command(CommandId::START));
 }
 
 status_t EffectConversionHelperAidl::handleDisable(uint32_t cmdSize __unused,
                                                    const void* pCmdData __unused,
                                                    uint32_t* replySize, void* pReplyData) {
-    if (!replySize || *replySize != kEffectConfigSize || !pReplyData) {
+    if (!replySize || *replySize != sizeof(effect_config_t) || !pReplyData) {
         ALOGE("%s parameter invalid %p %p", __func__, replySize, pReplyData);
         return BAD_VALUE;
     }
 
-    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->command(CommandId::STOP)));
-    return OK;
+    return statusTFromBinderStatus(mEffect->command(CommandId::STOP));
 }
 
 status_t EffectConversionHelperAidl::handleSetDevice(uint32_t cmdSize, const void* pCmdData,
                                                      uint32_t* replySize, void* pReplyData) {
-    if (cmdSize != sizeof(uint32_t) || !pCmdData || !replySize || *replySize != kEffectConfigSize ||
-        !pReplyData) {
+    if (cmdSize != sizeof(uint32_t) || !pCmdData || !replySize ||
+        *replySize != sizeof(effect_config_t) || !pReplyData) {
         ALOGE("%s parameter invalid %u %p %p %p", __func__, cmdSize, pCmdData, replySize,
               pReplyData);
         return BAD_VALUE;
@@ -231,7 +270,7 @@
 status_t EffectConversionHelperAidl::handleSetVolume(uint32_t cmdSize, const void* pCmdData,
                                                      uint32_t* replySize, void* pReplyData) {
     if (cmdSize != 2 * sizeof(uint32_t) || !pCmdData || !replySize ||
-        *replySize != kEffectConfigSize || !pReplyData) {
+        *replySize != sizeof(effect_config_t) || !pReplyData) {
         ALOGE("%s parameter invalid %u %p %p %p", __func__, cmdSize, pCmdData, replySize,
               pReplyData);
         return BAD_VALUE;
@@ -246,7 +285,7 @@
 status_t EffectConversionHelperAidl::handleSetOffload(uint32_t cmdSize, const void* pCmdData,
                                                       uint32_t* replySize, void* pReplyData) {
     if (cmdSize < sizeof(effect_offload_param_t) || !pCmdData || !replySize ||
-        *replySize != kEffectConfigSize || !pReplyData) {
+        *replySize != sizeof(effect_config_t) || !pReplyData) {
         ALOGE("%s parameter invalid %u %p %p %p", __func__, cmdSize, pCmdData, replySize,
               pReplyData);
         return BAD_VALUE;
@@ -258,87 +297,270 @@
 status_t EffectConversionHelperAidl::handleFirstPriority(uint32_t cmdSize __unused,
                                                          const void* pCmdData __unused,
                                                          uint32_t* replySize, void* pReplyData) {
-    if (!replySize || *replySize != kEffectConfigSize || !pReplyData) {
+    if (!replySize || *replySize != sizeof(effect_config_t) || !pReplyData) {
         ALOGE("%s parameter invalid %p %p", __func__, replySize, pReplyData);
         return BAD_VALUE;
     }
 
-    // TODO
+    // TODO to be implemented
     return OK;
 }
 
-status_t EffectConversionHelperAidl::setAecParameter(const effect_param_t& param) {
-    const auto psize = sizeof(uint32_t);
-    const auto vsize = sizeof(uint32_t);
-    if (!validatePVsize(param, psize, vsize)) {
+status_t EffectConversionHelperAidl::setAecParameter(EffectParamReader& param) {
+    uint32_t type, value = 0;
+    if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+        OK != param.readFromParameter(&type) ||
+        OK != param.readFromValue(&value)) {
+        ALOGW("%s invalid param %s", __func__, param.toString().c_str());
         return BAD_VALUE;
     }
 
-    const auto& type = *(uint32_t*)param.data;
-    const auto& value = *(uint32_t*)(param.data + psize);
     Parameter aidlParam;
     switch (type) {
         case AEC_PARAM_ECHO_DELAY:
             FALLTHROUGH_INTENDED;
         case AEC_PARAM_PROPERTIES: {
             aidlParam = VALUE_OR_RETURN_STATUS(
-                    aidl::android::legacy2aidl_uint32_echoDelay_Parameter(value));
+                    aidl::android::legacy2aidl_uint32_echoDelay_Parameter_aec(value));
             break;
         }
         case AEC_PARAM_MOBILE_MODE: {
             aidlParam = VALUE_OR_RETURN_STATUS(
-                    aidl::android::legacy2aidl_uint32_mobileMode_Parameter(value));
+                    aidl::android::legacy2aidl_uint32_mobileMode_Parameter_aec(value));
             break;
         }
         default: {
-            ALOGW("%s unknown param %08x value %08x", __func__, type, value);
+            ALOGW("%s unknown param %s", __func__, param.toString().c_str());
             return BAD_VALUE;
         }
     }
 
-    return mEffect->setParameter(aidlParam).getStatus();
+    return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
 }
 
-status_t EffectConversionHelperAidl::getAecParameter(effect_param_t& param) {
-    const auto psize = sizeof(uint32_t);
-    const auto vsize = sizeof(uint32_t);
-    if (!validatePVsize(param, psize, vsize)) {
-        return param.status = BAD_VALUE;
+status_t EffectConversionHelperAidl::getAecParameter(EffectParamWriter& param) {
+    uint32_t type = 0, value = 0;
+    if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+        OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+        param.setStatus(BAD_VALUE);
+        ALOGW("%s invalid param %s", __func__, param.toString().c_str());
+        return BAD_VALUE;
     }
-
-    uint32_t value = 0;
-    status_t status = BAD_VALUE;
-    const auto& type = *(uint32_t*)param.data;
+    Parameter aidlParam;
     switch (type) {
         case AEC_PARAM_ECHO_DELAY:
             FALLTHROUGH_INTENDED;
         case AEC_PARAM_PROPERTIES: {
-            Parameter aidlParam;
-            Parameter::Id id = Parameter::Id::make<Parameter::Id::acousticEchoCancelerTag>(
-                    AcousticEchoCanceler::Id::make<AcousticEchoCanceler::Id::commonTag>(
-                            AcousticEchoCanceler::echoDelayUs));
+            Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(AcousticEchoCanceler,
+                                                          acousticEchoCancelerTag, echoDelayUs);
             RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
             value = VALUE_OR_RETURN_STATUS(
-                    aidl::android::aidl2legacy_Parameter_uint32_echoDelay(aidlParam));
+                    aidl::android::aidl2legacy_Parameter_aec_uint32_echoDelay(aidlParam));
             break;
         }
         case AEC_PARAM_MOBILE_MODE: {
-            Parameter aidlParam;
-            Parameter::Id id = Parameter::Id::make<Parameter::Id::acousticEchoCancelerTag>(
-                    AcousticEchoCanceler::Id::make<AcousticEchoCanceler::Id::commonTag>(
-                            AcousticEchoCanceler::mobileMode));
+            Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(AcousticEchoCanceler,
+                                                          acousticEchoCancelerTag, mobileMode);
             RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
             value = VALUE_OR_RETURN_STATUS(
-                    aidl::android::aidl2legacy_Parameter_uint32_mobileMode(aidlParam));
+                    aidl::android::aidl2legacy_Parameter_aec_uint32_mobileMode(aidlParam));
             break;
         }
         default:
-            ALOGW("%s unknown param %08x", __func__, type);
+            ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+            return BAD_VALUE;
+    }
+    param.writeToValue(&value);
+    return OK;
+}
+
+status_t EffectConversionHelperAidl::setAgcParameter(EffectParamReader& param) {
+    uint32_t type = 0, value = 0;
+    if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+        OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+        ALOGW("%s invalid param %s", __func__, param.toString().c_str());
+        return BAD_VALUE;
+    }
+    Parameter aidlParam;
+    switch (type) {
+        case AGC2_PARAM_FIXED_DIGITAL_GAIN: {
+            aidlParam = VALUE_OR_RETURN_STATUS(
+                    aidl::android::legacy2aidl_uint32_fixedDigitalGain_Parameter_agc(value));
             break;
+        }
+        case AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR: {
+            aidlParam = VALUE_OR_RETURN_STATUS(
+                    aidl::android::legacy2aidl_uint32_levelEstimator_Parameter_agc(value));
+            break;
+        }
+        case AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN: {
+            aidlParam = VALUE_OR_RETURN_STATUS(
+                    aidl::android::legacy2aidl_uint32_saturationMargin_Parameter_agc(value));
+            break;
+        }
+        default: {
+            ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+            return BAD_VALUE;
+        }
     }
 
-    *(uint32_t*)(param.data + psize) = value;
-    return param.status = status;
+    return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+}
+
+status_t EffectConversionHelperAidl::getAgcParameter(EffectParamWriter& param) {
+    uint32_t type = 0, value = 0;
+    if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+        OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+        ALOGW("%s invalid param %s", __func__, param.toString().c_str());
+        return BAD_VALUE;
+    }
+    Parameter aidlParam;
+    switch (type) {
+        case AGC2_PARAM_FIXED_DIGITAL_GAIN: {
+            Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(
+                    AutomaticGainControl, automaticGainControlTag, fixedDigitalGainMb);
+            RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+            value = VALUE_OR_RETURN_STATUS(
+                    aidl::android::aidl2legacy_Parameter_agc_uint32_fixedDigitalGain(aidlParam));
+            break;
+        }
+        case AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR: {
+            Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(AutomaticGainControl,
+                                                          automaticGainControlTag, levelEstimator);
+            RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+            value = VALUE_OR_RETURN_STATUS(
+                    aidl::android::aidl2legacy_Parameter_agc_uint32_levelEstimator(aidlParam));
+            break;
+        }
+        case AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN: {
+            Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(
+                    AutomaticGainControl, automaticGainControlTag, saturationMarginMb);
+            RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+            value = VALUE_OR_RETURN_STATUS(
+                    aidl::android::aidl2legacy_Parameter_agc_uint32_saturationMargin(aidlParam));
+            break;
+        }
+        default: {
+            ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+            return BAD_VALUE;
+        }
+    }
+
+    param.writeToValue(&value);
+    return OK;
+}
+
+status_t EffectConversionHelperAidl::setBassBoostParameter(EffectParamReader& param) {
+    uint32_t type = 0;
+    uint16_t value = 0;
+    if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
+        OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+        ALOGW("%s invalid param %s", __func__, param.toString().c_str());
+        return BAD_VALUE;
+    }
+    Parameter aidlParam;
+    switch (type) {
+        case BASSBOOST_PARAM_STRENGTH: {
+            aidlParam = VALUE_OR_RETURN_STATUS(
+                    aidl::android::legacy2aidl_uint16_strengthPm_Parameter_BassBoost(value));
+            break;
+        }
+        case BASSBOOST_PARAM_STRENGTH_SUPPORTED: {
+            ALOGW("%s set BASSBOOST_PARAM_STRENGTH_SUPPORTED not supported", __func__);
+            return BAD_VALUE;
+        }
+        default: {
+            ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+            return BAD_VALUE;
+        }
+    }
+
+    return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+}
+
+status_t EffectConversionHelperAidl::getBassBoostParameter(EffectParamWriter& param) {
+    uint32_t type = 0, value = 0;
+    if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+        OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+        ALOGW("%s invalid param %s", __func__, param.toString().c_str());
+        param.setStatus(BAD_VALUE);
+        return BAD_VALUE;
+    }
+    Parameter aidlParam;
+    switch (type) {
+        case BASSBOOST_PARAM_STRENGTH: {
+            Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(BassBoost, bassBoostTag, strengthPm);
+            RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+            value = VALUE_OR_RETURN_STATUS(
+                    aidl::android::aidl2legacy_Parameter_BassBoost_uint16_strengthPm(aidlParam));
+            break;
+        }
+        case BASSBOOST_PARAM_STRENGTH_SUPPORTED: {
+            const auto& cap =
+                    VALUE_OR_RETURN_STATUS(aidl::android::UNION_GET(mDesc.capability, bassBoost));
+            value = VALUE_OR_RETURN_STATUS(
+                    aidl::android::convertIntegral<uint32_t>(cap.strengthSupported));
+            break;
+        }
+        default: {
+            ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+            return BAD_VALUE;
+        }
+    }
+
+    param.writeToValue(&value);
+    return OK;
+}
+
+status_t EffectConversionHelperAidl::setDownmixParameter(EffectParamReader& param) {
+    uint32_t type = 0;
+    int16_t value = 0;
+    if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(int16_t)) ||
+        OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+        ALOGW("%s invalid param %s", __func__, param.toString().c_str());
+        return BAD_VALUE;
+    }
+    Parameter aidlParam;
+    switch (type) {
+        case DOWNMIX_PARAM_TYPE: {
+            aidlParam = VALUE_OR_RETURN_STATUS(
+                    aidl::android::legacy2aidl_int16_type_Parameter_Downmix(value));
+            break;
+        }
+        default: {
+            ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+            return BAD_VALUE;
+        }
+    }
+
+    return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+}
+
+status_t EffectConversionHelperAidl::getDownmixParameter(EffectParamWriter& param) {
+    int16_t value = 0;
+    uint32_t type = 0;
+    if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
+        OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+        param.setStatus(BAD_VALUE);
+        return BAD_VALUE;
+    }
+    Parameter aidlParam;
+    switch (type) {
+        case DOWNMIX_PARAM_TYPE: {
+            Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(Downmix, downmixTag, type);
+            RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+            value = VALUE_OR_RETURN_STATUS(
+                    aidl::android::aidl2legacy_Parameter_Downmix_int16_type(aidlParam));
+            break;
+        }
+        default: {
+            ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+            return BAD_VALUE;
+        }
+    }
+
+    param.writeToValue(&value);
+    return OK;
 }
 
 } // namespace effect
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.h b/media/libaudiohal/impl/EffectConversionHelperAidl.h
index 5d7c1d6..35249f5 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.h
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.h
@@ -25,28 +25,17 @@
 
 #include <media/AidlConversionNdk.h>
 #include <system/audio_effect.h>
-#include <system/audio_effects/effect_aec.h>
-#include <system/audio_effects/effect_downmix.h>
-#include <system/audio_effects/effect_dynamicsprocessing.h>
-#include <system/audio_effects/effect_hapticgenerator.h>
-#include <system/audio_effects/effect_ns.h>
-#include <system/audio_effects/effect_visualizer.h>
+#include <system/audio_effects/audio_effects_utils.h>
 
 namespace android {
 namespace effect {
 
-static const size_t kEffectParamSize = sizeof(effect_param_t);
-static const size_t kEffectConfigSize = sizeof(effect_config_t);
-
 class EffectConversionHelperAidl {
   protected:
     EffectConversionHelperAidl(
             std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
-            int32_t sessionId, int32_t ioId, ::aidl::android::media::audio::common::AudioUuid uuid)
-        : mSessionId(sessionId),
-          mIoId(ioId),
-          mTypeUuid(std::move(uuid)),
-          mEffect(std::move(effect)) {}
+            int32_t sessionId, int32_t ioId,
+            const ::aidl::android::hardware::audio::effect::Descriptor& desc);
 
     status_t handleCommand(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData, uint32_t* replySize,
                            void* pReplyData);
@@ -54,9 +43,25 @@
   private:
     const int32_t mSessionId;
     const int32_t mIoId;
+    const ::aidl::android::hardware::audio::effect::Descriptor mDesc;
     ::aidl::android::media::audio::common::AudioUuid mTypeUuid;
     const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> mEffect;
+    ::aidl::android::hardware::audio::effect::IEffect::OpenEffectReturn mOpenReturn;
+    ::aidl::android::hardware::audio::effect::Parameter::Common mCommon;
 
+    const aidl::android::media::audio::common::AudioFormatDescription kDefaultFormatDescription = {
+            .type = aidl::android::media::audio::common::AudioFormatType::PCM,
+            .pcm = aidl::android::media::audio::common::PcmType::FLOAT_32_BIT};
+
+    static constexpr int kDefaultframeCount = 0x100;
+
+    using AudioChannelLayout = aidl::android::media::audio::common::AudioChannelLayout;
+    const aidl::android::media::audio::common::AudioConfig kDefaultAudioConfig = {
+            .base = {.sampleRate = 44100,
+                     .channelMask = AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                             AudioChannelLayout::LAYOUT_STEREO),
+                     .format = kDefaultFormatDescription},
+            .frameCount = kDefaultframeCount};
     // command handler map
     typedef status_t (EffectConversionHelperAidl::*CommandHandler)(uint32_t /* cmdSize */,
                                                                    const void* /* pCmdData */,
@@ -65,23 +70,14 @@
     static const std::map<uint32_t /* effect_command_e */, CommandHandler> mCommandHandlerMap;
 
     // parameter set/get handler map
-    typedef status_t (EffectConversionHelperAidl::*SetParameter)(const effect_param_t& param);
-    typedef status_t (EffectConversionHelperAidl::*GetParameter)(effect_param_t& param);
+    typedef status_t (EffectConversionHelperAidl::*SetParameter)(
+            android::effect::utils::EffectParamReader& param);
+    typedef status_t (EffectConversionHelperAidl::*GetParameter)(
+            android::effect::utils::EffectParamWriter& param);
     static const std::map<::aidl::android::media::audio::common::AudioUuid /* TypeUUID */,
                           std::pair<SetParameter, GetParameter>>
             mParameterHandlerMap;
 
-    // align to 32 bit boundary
-    static constexpr size_t padding(size_t size) {
-        return ((size - 1) / sizeof(int) + 1) * sizeof(int);
-    }
-    static constexpr bool validatePVsize(const effect_param_t& param, size_t p, size_t v) {
-        return padding(param.psize) == p && param.vsize == v;
-    }
-    static constexpr bool validateCommandSize(const effect_param_t& param, size_t size) {
-        return padding(param.psize) + param.vsize + kEffectParamSize <= size;
-    }
-
     status_t handleInit(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
                         void* pReplyData);
     status_t handleSetParameter(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
@@ -107,9 +103,15 @@
     status_t handleFirstPriority(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
                                  void* pReplyData);
 
-    // AEC parameter handler
-    status_t setAecParameter(const effect_param_t& param);
-    status_t getAecParameter(effect_param_t& param);
+    // set/get parameter handler
+    status_t setAecParameter(android::effect::utils::EffectParamReader& param);
+    status_t getAecParameter(android::effect::utils::EffectParamWriter& param);
+    status_t setAgcParameter(android::effect::utils::EffectParamReader& param);
+    status_t getAgcParameter(android::effect::utils::EffectParamWriter& param);
+    status_t setBassBoostParameter(android::effect::utils::EffectParamReader& param);
+    status_t getBassBoostParameter(android::effect::utils::EffectParamWriter& param);
+    status_t setDownmixParameter(android::effect::utils::EffectParamReader& param);
+    status_t getDownmixParameter(android::effect::utils::EffectParamWriter& param);
 };
 
 }  // namespace effect
diff --git a/media/libaudiohal/impl/EffectHalAidl.cpp b/media/libaudiohal/impl/EffectHalAidl.cpp
index 3346459..0c37552 100644
--- a/media/libaudiohal/impl/EffectHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectHalAidl.cpp
@@ -42,21 +42,30 @@
 using ::aidl::android::hardware::audio::effect::CommandId;
 using ::aidl::android::hardware::audio::effect::Descriptor;
 using ::aidl::android::hardware::audio::effect::IEffect;
+using ::aidl::android::hardware::audio::effect::IFactory;
 using ::aidl::android::hardware::audio::effect::Parameter;
 
 namespace android {
 namespace effect {
 
-EffectHalAidl::EffectHalAidl(const std::shared_ptr<IEffect>& effect, uint64_t effectId,
-                             int32_t sessionId, int32_t ioId, const Descriptor& desc)
-    : EffectConversionHelperAidl(effect, sessionId, ioId, desc.common.id.type),
+EffectHalAidl::EffectHalAidl(
+        const std::shared_ptr<::aidl::android::hardware::audio::effect::IFactory>& factory,
+        const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& effect,
+        uint64_t effectId, int32_t sessionId, int32_t ioId,
+        const ::aidl::android::hardware::audio::effect::Descriptor& desc)
+    : EffectConversionHelperAidl(effect, sessionId, ioId, desc),
+      mFactory(factory),
+      mEffect(effect),
       mEffectId(effectId),
       mSessionId(sessionId),
       mIoId(ioId),
-      mEffect(effect),
       mDesc(desc) {}
 
-EffectHalAidl::~EffectHalAidl() {}
+EffectHalAidl::~EffectHalAidl() {
+    if (mFactory) {
+        mFactory->destroyEffect(mEffect);
+    }
+}
 
 status_t EffectHalAidl::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
     if (buffer == nullptr) {
@@ -105,8 +114,7 @@
 }
 
 status_t EffectHalAidl::close() {
-    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->close()));
-    return OK;
+    return statusTFromBinderStatus(mEffect->close());
 }
 
 status_t EffectHalAidl::dump(int fd) {
diff --git a/media/libaudiohal/impl/EffectHalAidl.h b/media/libaudiohal/impl/EffectHalAidl.h
index 1ba262c..6a1ec1c 100644
--- a/media/libaudiohal/impl/EffectHalAidl.h
+++ b/media/libaudiohal/impl/EffectHalAidl.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <aidl/android/hardware/audio/effect/IEffect.h>
+#include <aidl/android/hardware/audio/effect/IFactory.h>
 #include <media/audiohal/EffectHalInterface.h>
 #include <system/audio_effect.h>
 
@@ -64,19 +65,22 @@
   private:
     friend class sp<EffectHalAidl>;
 
+    const std::shared_ptr<::aidl::android::hardware::audio::effect::IFactory> mFactory;
+    const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> mEffect;
     const uint64_t mEffectId;
     const int32_t mSessionId;
     const int32_t mIoId;
-    const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> mEffect;
     const ::aidl::android::hardware::audio::effect::Descriptor mDesc;
 
     sp<EffectBufferHalInterface> mInBuffer, mOutBuffer;
     effect_config_t mConfig;
 
     // Can not be constructed directly by clients.
-    EffectHalAidl(const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& effect,
-                  uint64_t effectId, int32_t sessionId, int32_t ioId,
-                  const ::aidl::android::hardware::audio::effect::Descriptor& desc);
+    EffectHalAidl(
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IFactory>& factory,
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& effect,
+            uint64_t effectId, int32_t sessionId, int32_t ioId,
+            const ::aidl::android::hardware::audio::effect::Descriptor& desc);
     bool setEffectReverse(bool reverse);
 
     // The destructor automatically releases the effect.
diff --git a/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp b/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
index 96ea861..878c19e 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
@@ -134,7 +134,7 @@
         effectId = ++mEffectIdCounter;
     }
 
-    *effect = sp<EffectHalAidl>::make(aidlEffect, effectId, sessionId, ioId, desc);
+    *effect = sp<EffectHalAidl>::make(mFactory, aidlEffect, effectId, sessionId, ioId, desc);
     return OK;
 }
 
diff --git a/media/libaudiohal/tests/EffectsFactoryHalInterface_test.cpp b/media/libaudiohal/tests/EffectsFactoryHalInterface_test.cpp
index 83c7809..c2e2ba7 100644
--- a/media/libaudiohal/tests/EffectsFactoryHalInterface_test.cpp
+++ b/media/libaudiohal/tests/EffectsFactoryHalInterface_test.cpp
@@ -20,11 +20,17 @@
 
 #include <media/audiohal/EffectsFactoryHalInterface.h>
 
+#include <system/audio_effects/audio_effects_utils.h>
+#include <system/audio_effects/effect_aec.h>
+#include <system/audio_effect.h>
+
 #include <gtest/gtest.h>
 #include <utils/RefBase.h>
 
 namespace android {
 
+using effect::utils::EffectParamWriter;
+
 // EffectsFactoryHalInterface
 TEST(libAudioHalTest, createEffectsFactoryHalInterface) {
     ASSERT_NE(nullptr, EffectsFactoryHalInterface::create());
@@ -78,6 +84,81 @@
     EXPECT_NE(0, version.getMajorVersion());
 }
 
+static char testDataBuffer[sizeof(effect_param_t) + 0xff] = {};
+static char testResponseBuffer[sizeof(effect_param_t) + 0xff] = {};
+TEST(libAudioHalTest, agcNotInit) {
+    auto factory = EffectsFactoryHalInterface::create();
+    ASSERT_NE(nullptr, factory);
+
+    std::vector<effect_descriptor_t> descs;
+    EXPECT_EQ(OK, factory->getDescriptors(&FX_IID_AEC_, &descs));
+    for (const auto& desc : descs) {
+        ASSERT_EQ(0, std::memcmp(&desc.type, &FX_IID_AEC_, sizeof(FX_IID_AEC_)));
+        sp<EffectHalInterface> interface;
+        EXPECT_EQ(OK, factory->createEffect(&desc.uuid, 1 /* sessionId */, 1 /* ioId */,
+                                            1 /* deviceId */, &interface));
+        EXPECT_NE(nullptr, interface);
+        effect_param_t* param = (effect_param_t*)testDataBuffer;
+        uint32_t type = AEC_PARAM_ECHO_DELAY, value = 0xbead;
+        param->psize = sizeof(type);
+        param->vsize = sizeof(value);
+        //EXPECT_EQ(1, 0) << param->psize << " " << param->vsize;
+        EffectParamWriter writer(*param);
+        EXPECT_EQ(OK, writer.writeToParameter(&type)) << writer.toString();
+        EXPECT_EQ(OK, writer.writeToValue(&value)) << writer.toString();
+        status_t reply = 0;
+        uint32_t replySize = sizeof(reply);
+        EXPECT_NE(OK, interface->command(EFFECT_CMD_SET_PARAM, (uint32_t)writer.getTotalSize(),
+                                         param, &replySize, &reply));
+        EXPECT_EQ(replySize, sizeof(reply));
+        EXPECT_NE(OK, reply);
+    }
+}
+
+// TODO: rethink about this test case to make it general for all types of effects
+TEST(libAudioHalTest, aecInitSetAndGet) {
+    auto factory = EffectsFactoryHalInterface::create();
+    ASSERT_NE(nullptr, factory);
+
+    std::vector<effect_descriptor_t> descs;
+    EXPECT_EQ(OK, factory->getDescriptors(&FX_IID_AEC_, &descs));
+    static constexpr uint32_t delayValue = 0x20;
+    for (const auto& desc : descs) {
+        ASSERT_EQ(0, std::memcmp(&desc.type, &FX_IID_AEC_, sizeof(FX_IID_AEC_)));
+        sp<EffectHalInterface> interface;
+        EXPECT_EQ(OK, factory->createEffect(&desc.uuid, 1 /* sessionId */, 1 /* ioId */,
+                                            1 /* deviceId */, &interface));
+        EXPECT_NE(nullptr, interface);
+        effect_param_t* param = (effect_param_t*)testDataBuffer;
+        uint32_t type = AEC_PARAM_ECHO_DELAY, value = delayValue;
+        param->psize = sizeof(type);
+        param->vsize = sizeof(value);
+        //EXPECT_EQ(1, 0) << param->psize << " " << param->vsize;
+        EffectParamWriter writer(*param);
+        EXPECT_EQ(OK, writer.writeToParameter(&type)) << writer.toString();
+        EXPECT_EQ(OK, writer.writeToValue(&value)) << writer.toString();
+        status_t reply = 0;
+        uint32_t replySize = sizeof(reply);
+        EXPECT_EQ(OK, interface->command(EFFECT_CMD_INIT, 0, nullptr, &replySize, &reply));
+        EXPECT_EQ(OK, interface->command(EFFECT_CMD_SET_PARAM, (uint32_t)writer.getTotalSize(),
+                                         param, &replySize, &reply));
+        EXPECT_EQ(replySize, sizeof(reply));
+        EXPECT_EQ(OK, reply);
+
+        effect_param_t* responseParam = (effect_param_t*)testResponseBuffer;
+        param->psize = sizeof(type);
+        param->vsize = sizeof(value);
+        EffectParamWriter response(*param);
+        EXPECT_EQ(OK, response.writeToParameter(&type)) << response.toString();
+        replySize = response.getTotalSize();
+        EXPECT_EQ(OK, interface->command(EFFECT_CMD_GET_PARAM, (uint32_t)writer.getTotalSize(),
+                                         param, &replySize, responseParam));
+        EXPECT_EQ(replySize, response.getTotalSize());
+        EXPECT_EQ(OK, response.readFromValue(&value));
+        EXPECT_EQ(delayValue, value);
+    }
+}
+
 // TODO: b/263986405 Add multi-thread testing
 
 } // namespace android
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index c0e612d..9837574 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3535,9 +3535,9 @@
             if (result != OK) return result;
 
 #ifdef FLOAT_EFFECT_CHAIN
-            buffer = halInBuffer->audioBuffer()->f32;
+            buffer = halInBuffer ? halInBuffer->audioBuffer()->f32 : buffer;
 #else
-            buffer = halInBuffer->audioBuffer()->s16;
+            buffer = halInBuffer ? halInBuffer->audioBuffer()->s16 : buffer;
 #endif
             ALOGV("addEffectChain_l() creating new input buffer %p session %d",
                     buffer, session);
@@ -3566,7 +3566,8 @@
         halOutBuffer = halInBuffer;
         ALOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session);
         if (!audio_is_global_session(session)) {
-            buffer = reinterpret_cast<effect_buffer_t*>(halInBuffer->externalData());
+            buffer = halInBuffer ? reinterpret_cast<effect_buffer_t*>(halInBuffer->externalData())
+                                 : buffer;
             // Only one effect chain can be present in direct output thread and it uses
             // the sink buffer as input
             if (mType != DIRECT) {
@@ -3578,9 +3579,9 @@
                         &halInBuffer);
                 if (result != OK) return result;
 #ifdef FLOAT_EFFECT_CHAIN
-                buffer = halInBuffer->audioBuffer()->f32;
+                buffer = halInBuffer ? halInBuffer->audioBuffer()->f32 : buffer;
 #else
-                buffer = halInBuffer->audioBuffer()->s16;
+                buffer = halInBuffer ? halInBuffer->audioBuffer()->s16 : buffer;
 #endif
                 ALOGV("addEffectChain_l() creating new input buffer %p session %d",
                         buffer, session);