AIDL effect: Add Equalizer parameters implementation and vts

Bug: 238913361
Test: atest VtsHalAudioEffectTargetTest
atest VtsHalAudioEffectFactoryTargetTest
atest VtsHalEqualizerTargetTest

Change-Id: I94b2283ca2aa0e45715e1c9ac3ea6ad809ec2a2c
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 2baaad9..e64b90c 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -116,6 +116,6 @@
 cc_library_headers {
     name: "libaudioaidl_headers",
     export_include_dirs: ["include"],
-    vendor: true,
+    vendor_available: true,
     host_supported: true,
 }
diff --git a/audio/aidl/default/EffectThread.cpp b/audio/aidl/default/EffectThread.cpp
index 0ad9a14..80f120b 100644
--- a/audio/aidl/default/EffectThread.cpp
+++ b/audio/aidl/default/EffectThread.cpp
@@ -28,11 +28,11 @@
 }
 
 EffectThread::~EffectThread() {
-    destroy();
+    destroyThread();
     LOG(DEBUG) << __func__ << " done";
 };
 
-RetCode EffectThread::create(const std::string& name, const int priority) {
+RetCode EffectThread::createThread(const std::string& name, const int priority) {
     if (mThread.joinable()) {
         LOG(WARNING) << __func__ << " thread already created, no-op";
         return RetCode::SUCCESS;
@@ -44,7 +44,7 @@
     return RetCode::SUCCESS;
 }
 
-RetCode EffectThread::destroy() {
+RetCode EffectThread::destroyThread() {
     {
         std::lock_guard lg(mMutex);
         mStop = mExit = true;
@@ -58,10 +58,10 @@
     return RetCode::SUCCESS;
 }
 
-RetCode EffectThread::start() {
+RetCode EffectThread::startThread() {
     if (!mThread.joinable()) {
         LOG(ERROR) << __func__ << " thread already destroyed";
-        return RetCode::ERROR;
+        return RetCode::ERROR_THREAD;
     }
 
     {
@@ -78,10 +78,10 @@
     return RetCode::SUCCESS;
 }
 
-RetCode EffectThread::stop() {
+RetCode EffectThread::stopThread() {
     if (!mThread.joinable()) {
         LOG(ERROR) << __func__ << " thread already destroyed";
-        return RetCode::ERROR;
+        return RetCode::ERROR_THREAD;
     }
 
     {
@@ -117,15 +117,4 @@
     }
 }
 
-std::string toString(RetCode& code) {
-    switch (code) {
-        case RetCode::SUCCESS:
-            return "SUCCESS";
-        case RetCode::ERROR:
-            return "ERROR";
-        default:
-            return "EnumError";
-    }
-}
-
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/equalizer/Equalizer.cpp b/audio/aidl/default/equalizer/Equalizer.cpp
index 2e4e538..43fa206 100644
--- a/audio/aidl/default/equalizer/Equalizer.cpp
+++ b/audio/aidl/default/equalizer/Equalizer.cpp
@@ -16,10 +16,12 @@
 
 #define LOG_TAG "AHAL_EqualizerSw"
 #include <Utils.h>
-#include <android-base/logging.h>
+#include <algorithm>
 #include <unordered_set>
 
-#include "effect-impl/EffectUUID.h"
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
 #include "equalizer-impl/EqualizerSw.h"
 
 using android::hardware::audio::common::getFrameSizeInBytes;
@@ -68,20 +70,26 @@
     auto& output = common.output;
     size_t inputFrameSize = getFrameSizeInBytes(input.base.format, input.base.channelMask);
     size_t outputFrameSize = getFrameSizeInBytes(output.base.format, output.base.channelMask);
-    if (!createFmq(1, input.frameCount * inputFrameSize, output.frameCount * outputFrameSize,
-                   _aidl_return)) {
+    mContext = std::make_shared<EqualizerSwContext>(1, input.frameCount * inputFrameSize,
+                                                    output.frameCount * outputFrameSize);
+    if (!mContext) {
+        LOG(ERROR) << __func__ << " created EqualizerSwContext failed";
         return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_UNSUPPORTED_OPERATION,
                                                                 "FailedToCreateFmq");
     }
+    setContext(mContext);
 
     // create the worker thread
-    if (RetCode::SUCCESS != mWorker->create(LOG_TAG)) {
+    if (RetCode::SUCCESS != createThread(LOG_TAG)) {
         LOG(ERROR) << __func__ << " created worker thread failed";
-        destroyFmq();
+        mContext.reset();
         return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_UNSUPPORTED_OPERATION,
-                                                                "FailedToCreateFmq");
+                                                                "FailedToCreateWorker");
     }
 
+    _aidl_return->statusMQ = mContext->getStatusFmq()->dupeDesc();
+    _aidl_return->inputDataMQ = mContext->getInputDataFmq()->dupeDesc();
+    _aidl_return->outputDataMQ = mContext->getOutputDataFmq()->dupeDesc();
     mState = State::IDLE;
     return ndk::ScopedAStatus::ok();
 }
@@ -98,8 +106,9 @@
 
     // stop the worker thread
     mState = State::INIT;
-    mWorker->destroy();
-    destroyFmq();
+    destroyThread();
+    mContext.reset();
+
     LOG(DEBUG) << __func__;
     return ndk::ScopedAStatus::ok();
 }
@@ -121,19 +130,19 @@
         case CommandId::START:
             // start processing.
             mState = State::PROCESSING;
-            mWorker->start();
+            startThread();
             LOG(DEBUG) << __func__ << " state: " << toString(mState);
             return ndk::ScopedAStatus::ok();
         case CommandId::STOP:
             // stop processing.
             mState = State::IDLE;
-            mWorker->stop();
+            stopThread();
             LOG(DEBUG) << __func__ << " state: " << toString(mState);
             return ndk::ScopedAStatus::ok();
         case CommandId::RESET:
             // TODO: reset buffer status.
             mState = State::IDLE;
-            mWorker->stop();
+            stopThread();
             LOG(DEBUG) << __func__ << " state: " << toString(mState);
             return ndk::ScopedAStatus::ok();
         default:
@@ -173,23 +182,27 @@
             LOG(DEBUG) << __func__ << " get: " << _aidl_return->toString();
             return ndk::ScopedAStatus::ok();
         }
-        case Parameter::Id::specificTag: {
-            auto& id = in_paramId.get<Parameter::Id::specificTag>();
-            if (id != Parameter::Specific::equalizer) {
-                LOG(ERROR) << " unsupported parameter Id: " << in_paramId.toString();
-                return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
-                        EX_ILLEGAL_ARGUMENT, "Parameter::IdNotSupported");
-            }
+        case Parameter::Id::specificId: {
+            auto& id = in_paramId.get<Parameter::Id::specificId>();
             Parameter::Specific specific;
-            specific.set<Parameter::Specific::equalizer>(mEqualizerParam);
+            ndk::ScopedAStatus status = getSpecificParameter(id, &specific);
+            if (!status.isOk()) {
+                LOG(ERROR) << __func__
+                           << " getSpecificParameter error: " << status.getDescription();
+                return status;
+            }
             _aidl_return->set<Parameter::specific>(specific);
             LOG(DEBUG) << __func__ << _aidl_return->toString();
             return ndk::ScopedAStatus::ok();
         }
-        default:
-            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
-                                                                    "Parameter::IdNotSupported");
+        case Parameter::Id::vendorTag: {
+            LOG(DEBUG) << __func__ << " noop for vendor tag now";
+            return ndk::ScopedAStatus::ok();
+        }
     }
+    LOG(ERROR) << " unsupported tag: " << toString(tag);
+    return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                            "Parameter:IdNotSupported");
 }
 
 ndk::ScopedAStatus EqualizerSw::getState(State* _aidl_return) {
@@ -198,35 +211,12 @@
 }
 
 /// Private methods.
-bool EqualizerSw::createFmq(int statusDepth, int inBufferSize, int outBufferSize,
-                            OpenEffectReturn* ret) {
-    mStatusMQ = std::make_unique<StatusMQ>(statusDepth, true /*configureEventFlagWord*/);
-    mInputMQ = std::make_unique<DataMQ>(inBufferSize);
-    mOutputMQ = std::make_unique<DataMQ>(outBufferSize);
-
-    if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) {
-        LOG(ERROR) << __func__ << " created invalid FMQ";
-        return false;
-    }
-    ret->statusMQ = mStatusMQ->dupeDesc();
-    ret->inputDataMQ = mInputMQ->dupeDesc();
-    ret->outputDataMQ = mOutputMQ->dupeDesc();
-    return true;
-}
-
-void EqualizerSw::destroyFmq() {
-    mStatusMQ.reset(nullptr);
-    mInputMQ.reset(nullptr);
-    mOutputMQ.reset(nullptr);
-}
-
 ndk::ScopedAStatus EqualizerSw::setCommonParameter(const Parameter::Common& common) {
     mCommonParam = common;
     LOG(DEBUG) << __func__ << " set: " << mCommonParam.toString();
     return ndk::ScopedAStatus::ok();
 }
 
-// TODO: implementation need change to save all parameters.
 ndk::ScopedAStatus EqualizerSw::setSpecificParameter(const Parameter::Specific& specific) {
     if (Parameter::Specific::equalizer != specific.getTag()) {
         LOG(ERROR) << " unsupported effect: " << specific.toString();
@@ -234,9 +224,76 @@
                                                                 "EffectNotSupported");
     }
 
-    mEqualizerParam = specific.get<Parameter::Specific::equalizer>();
-    LOG(DEBUG) << __func__ << mEqualizerParam.toString();
-    return ndk::ScopedAStatus::ok();
+    auto& eqParam = specific.get<Parameter::Specific::equalizer>();
+    auto tag = eqParam.getTag();
+    switch (tag) {
+        case Equalizer::bandLevels: {
+            auto& bandLevels = eqParam.get<Equalizer::bandLevels>();
+            const auto& [minItem, maxItem] = std::minmax_element(
+                    bandLevels.begin(), bandLevels.end(),
+                    [](const auto& a, const auto& b) { return a.index < b.index; });
+            if (bandLevels.size() >= NUM_OF_BANDS || minItem->index < 0 ||
+                maxItem->index >= NUM_OF_BANDS) {
+                LOG(ERROR) << " bandLevels " << bandLevels.size() << "minIndex " << minItem->index
+                           << "maxIndex " << maxItem->index << " illegal ";
+                return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                        "ExceedMaxBandNum");
+            }
+            mBandLevels = bandLevels;
+            return ndk::ScopedAStatus::ok();
+        }
+        case Equalizer::preset: {
+            int preset = eqParam.get<Equalizer::preset>();
+            if (preset < 0 || preset >= NUM_OF_PRESETS) {
+                LOG(ERROR) << " preset: " << preset << " invalid";
+                return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                        "ExceedMaxBandNum");
+            }
+            mPreset = preset;
+            LOG(DEBUG) << __func__ << " preset set to " << mPreset;
+            return ndk::ScopedAStatus::ok();
+        }
+        case Equalizer::vendor: {
+            LOG(DEBUG) << __func__ << " noop for vendor tag now";
+            return ndk::ScopedAStatus::ok();
+        }
+    }
+
+    LOG(ERROR) << __func__ << " unsupported eq param tag: " << toString(tag);
+    return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                            "ParamNotSupported");
+}
+
+ndk::ScopedAStatus EqualizerSw::getSpecificParameter(Parameter::Specific::Id id,
+                                                     Parameter::Specific* specific) {
+    Equalizer eqParam;
+    auto tag = id.getTag();
+    if (tag != Parameter::Specific::Id::equalizerTag) {
+        LOG(ERROR) << " invalid tag: " << toString(tag);
+        return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                "UnsupportedTag");
+    }
+    auto eqTag = id.get<Parameter::Specific::Id::equalizerTag>();
+    switch (eqTag) {
+        case Equalizer::bandLevels: {
+            eqParam.set<Equalizer::bandLevels>(mBandLevels);
+            specific->set<Parameter::Specific::equalizer>(eqParam);
+            return ndk::ScopedAStatus::ok();
+        }
+        case Equalizer::preset: {
+            eqParam.set<Equalizer::preset>(mPreset);
+            LOG(DEBUG) << __func__ << " preset " << mPreset;
+            specific->set<Parameter::Specific::equalizer>(eqParam);
+            return ndk::ScopedAStatus::ok();
+        }
+        case Equalizer::vendor: {
+            LOG(DEBUG) << __func__ << " noop for vendor tag now";
+            return ndk::ScopedAStatus::ok();
+        }
+    }
+    LOG(ERROR) << __func__ << " unsupported eq param: " << toString(eqTag);
+    return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                            "ParamNotSupported");
 }
 
 void EqualizerSw::cleanUp() {
@@ -248,9 +305,18 @@
     }
 }
 
-// Processing method running in worker thread.
-void EqualizerSwWorker::process() {
-    // TODO: add EQ processing with FMQ, should wait until data available before data processing.
+IEffect::Status EqualizerSw::status(binder_status_t status, size_t consumed, size_t produced) {
+    IEffect::Status ret;
+    ret.status = status;
+    ret.fmqByteConsumed = consumed;
+    ret.fmqByteProduced = produced;
+    return ret;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status EqualizerSw::effectProcessImpl() {
+    // TODO: get data buffer and process.
+    return status(STATUS_OK, mContext->availableToRead(), mContext->availableToWrite());
 }
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
new file mode 100644
index 0000000..36492ec
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -0,0 +1,65 @@
+/*
+ * 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 <cstdint>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+
+namespace aidl::android::hardware::audio::effect {
+
+class EffectContext {
+  public:
+    typedef ::android::AidlMessageQueue<
+            IEffect::Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+            StatusMQ;
+    typedef ::android::AidlMessageQueue<
+            int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+            DataMQ;
+
+    EffectContext(size_t statusDepth, size_t inBufferSize, size_t outBufferSize) {
+        mStatusMQ = std::make_shared<StatusMQ>(statusDepth, true /*configureEventFlagWord*/);
+        mInputMQ = std::make_shared<DataMQ>(inBufferSize);
+        mOutputMQ = std::make_shared<DataMQ>(outBufferSize);
+
+        if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) {
+            LOG(ERROR) << __func__ << " created invalid FMQ";
+        }
+        mWorkBuffer.reserve(std::max(inBufferSize, outBufferSize));
+    };
+
+    std::shared_ptr<StatusMQ> getStatusFmq() { return mStatusMQ; };
+    std::shared_ptr<DataMQ> getInputDataFmq() { return mInputMQ; };
+    std::shared_ptr<DataMQ> getOutputDataFmq() { return mOutputMQ; };
+
+    int8_t* getWorkBuffer() { return static_cast<int8_t*>(mWorkBuffer.data()); };
+    // TODO: update with actual available size
+    size_t availableToRead() { return mWorkBuffer.capacity(); };
+    size_t availableToWrite() { return mWorkBuffer.capacity(); };
+
+  private:
+    std::shared_ptr<StatusMQ> mStatusMQ;
+    std::shared_ptr<DataMQ> mInputMQ;
+    std::shared_ptr<DataMQ> mOutputMQ;
+    // TODO handle effect process input and output
+    // work buffer set by effect instances, the access and update are in same thread
+    std::vector<int8_t> mWorkBuffer;
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectThread.h b/audio/aidl/default/include/effect-impl/EffectThread.h
index e831cea..09a0000 100644
--- a/audio/aidl/default/include/effect-impl/EffectThread.h
+++ b/audio/aidl/default/include/effect-impl/EffectThread.h
@@ -22,12 +22,10 @@
 #include <android-base/thread_annotations.h>
 #include <system/thread_defs.h>
 
+#include "effect-impl/EffectTypes.h"
+
 namespace aidl::android::hardware::audio::effect {
 
-enum class RetCode { SUCCESS, ERROR };
-
-std::string toString(RetCode& code);
-
 class EffectThread {
   public:
     // default priority is same as HIDL: ANDROID_PRIORITY_URGENT_AUDIO
@@ -35,10 +33,11 @@
     virtual ~EffectThread();
 
     // called by effect implementation.
-    RetCode create(const std::string& name, const int priority = ANDROID_PRIORITY_URGENT_AUDIO);
-    RetCode destroy();
-    RetCode start();
-    RetCode stop();
+    RetCode createThread(const std::string& name,
+                         const int priority = ANDROID_PRIORITY_URGENT_AUDIO);
+    RetCode destroyThread();
+    RetCode startThread();
+    RetCode stopThread();
 
     // Will call process() in a loop if the thread is running.
     void threadLoop();
diff --git a/audio/aidl/default/include/effect-impl/EffectTypes.h b/audio/aidl/default/include/effect-impl/EffectTypes.h
new file mode 100644
index 0000000..46cfc0c
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectTypes.h
@@ -0,0 +1,51 @@
+/*
+ * 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 <ostream>
+#include <string>
+
+namespace aidl::android::hardware::audio::effect {
+
+enum class RetCode {
+    SUCCESS,
+    ERROR_ILLEGAL_PARAMETER, /* Illegal parameter */
+    ERROR_THREAD,            /* Effect thread error */
+    ERROR_NULL_POINTER,      /* NULL pointer */
+    ERROR_ALIGNMENT_ERROR,   /* Memory alignment error */
+    ERROR_BLOCK_SIZE_EXCEED  /* Maximum block size exceeded */
+};
+
+inline std::ostream& operator<<(std::ostream& out, const RetCode& code) {
+    switch (code) {
+        case RetCode::SUCCESS:
+            return out << "SUCCESS";
+        case RetCode::ERROR_ILLEGAL_PARAMETER:
+            return out << "ERROR_ILLEGAL_PARAMETER";
+        case RetCode::ERROR_THREAD:
+            return out << "ERROR_THREAD";
+        case RetCode::ERROR_NULL_POINTER:
+            return out << "ERROR_NULL_POINTER";
+        case RetCode::ERROR_ALIGNMENT_ERROR:
+            return out << "ERROR_ALIGNMENT_ERROR";
+        case RetCode::ERROR_BLOCK_SIZE_EXCEED:
+            return out << "ERROR_BLOCK_SIZE_EXCEED";
+    }
+
+    return out << "EnumError: " << code;
+}
+
+}  // 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 99f6c24..48b7137 100644
--- a/audio/aidl/default/include/effect-impl/EffectUUID.h
+++ b/audio/aidl/default/include/effect-impl/EffectUUID.h
@@ -21,6 +21,17 @@
 
 using ::aidl::android::media::audio::common::AudioUuid;
 
+// Null UUID
+static const AudioUuid EffectNullUuid = {static_cast<int32_t>(0xec7178ec),
+                                         0xe5e1,
+                                         0x4432,
+                                         0xa3f4,
+                                         {0x46, 0x57, 0xe6, 0x79, 0x52, 0x10}};
+
+// Zero UUID
+static const AudioUuid EffectZeroUuid = {
+        static_cast<int32_t>(0x0), 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
+
 // Equalizer type UUID.
 static const AudioUuid EqualizerTypeUUID = {static_cast<int32_t>(0x0bed4300),
                                             0xddd6,
diff --git a/audio/aidl/default/include/effect-impl/EffectWorker.h b/audio/aidl/default/include/effect-impl/EffectWorker.h
new file mode 100644
index 0000000..0fe69ff
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectWorker.h
@@ -0,0 +1,74 @@
+/*
+ * 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 <algorithm>
+#include <memory>
+#include <mutex>
+#include <string>
+
+#include "EffectContext.h"
+#include "EffectThread.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+std::string toString(RetCode& code);
+
+class EffectWorker : public EffectThread {
+  public:
+    // set effect context for worker, suppose to only happen once here
+    void setContext(std::shared_ptr<EffectContext> context) {
+        std::call_once(mOnceFlag, [&]() { mContext = context; });
+    };
+
+    // handle FMQ and call effect implemented virtual function
+    void process() override {
+        if (!mContext) {
+            LOG(ERROR) << __func__ << " invalid context!";
+            return;
+        }
+        std::shared_ptr<EffectContext::StatusMQ> statusMQ = mContext->getStatusFmq();
+        std::shared_ptr<EffectContext::DataMQ> inputMQ = mContext->getInputDataFmq();
+        std::shared_ptr<EffectContext::DataMQ> outputMQ = mContext->getOutputDataFmq();
+
+        // Only this worker will read from input data MQ and write to output data MQ.
+        auto readSize = inputMQ->availableToRead(), writeSize = outputMQ->availableToWrite();
+        if (readSize && writeSize) {
+            LOG(DEBUG) << __func__ << " available to read " << readSize << " available to write "
+                       << writeSize;
+            auto buffer = mContext->getWorkBuffer();
+            inputMQ->read(buffer, readSize);
+            IEffect::Status status = effectProcessImpl();
+            writeSize = std::min((int32_t)writeSize, status.fmqByteProduced);
+            outputMQ->write(buffer, writeSize);
+            statusMQ->writeBlocking(&status, 1);
+            LOG(DEBUG) << __func__ << " done processing, effect consumed " << status.fmqByteConsumed
+                       << " produced " << status.fmqByteProduced;
+        } else {
+            // TODO: maybe add some sleep here to avoid busy waiting
+        }
+    }
+
+    // must implement by each effect implementation
+    virtual IEffect::Status effectProcessImpl() = 0;
+
+  private:
+    // make sure the context only set once.
+    std::once_flag mOnceFlag;
+    std::shared_ptr<EffectContext> mContext;
+};
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/equalizer-impl/EqualizerSw.h b/audio/aidl/default/include/equalizer-impl/EqualizerSw.h
index 58ad1de..aa3a727 100644
--- a/audio/aidl/default/include/equalizer-impl/EqualizerSw.h
+++ b/audio/aidl/default/include/equalizer-impl/EqualizerSw.h
@@ -21,20 +21,29 @@
 #include <cstdlib>
 #include <memory>
 
-#include "effect-impl/EffectThread.h"
+#include "effect-impl/EffectContext.h"
+#include "effect-impl/EffectTypes.h"
+#include "effect-impl/EffectUUID.h"
+#include "effect-impl/EffectWorker.h"
 
 namespace aidl::android::hardware::audio::effect {
 
-class EqualizerSwWorker : public EffectThread {
-    // EqualizerSwWorker(const std::string name){EffectThread(name)};
-    void process() override;
+class EqualizerSwContext : public EffectContext {
+  public:
+    EqualizerSwContext(int statusDepth, int inBufferSize, int outBufferSize)
+        : EffectContext(statusDepth, inBufferSize, outBufferSize) {
+        LOG(DEBUG) << __func__;
+    }
+
+  private:
+    // Add equalizer specific context for processing here
 };
 
-class EqualizerSw : public BnEffect {
+class EqualizerSw : public BnEffect, EffectWorker {
   public:
     EqualizerSw() {
-        // create the worker
-        mWorker = std::make_unique<EqualizerSwWorker>();
+        Equalizer::Capability eqCap = {.bandFrequencies = mBandFrequency, .presets = mPresets};
+        mDesc.capability.set<Capability::equalizer>(eqCap);
         LOG(DEBUG) << __func__;
     };
     ~EqualizerSw() {
@@ -52,12 +61,11 @@
     ndk::ScopedAStatus getParameter(const Parameter::Id& in_paramId,
                                     Parameter* _aidl_return) override;
 
+    IEffect::Status effectProcessImpl() override;
+
   private:
-    // effect processing thread.
-    std::unique_ptr<EqualizerSwWorker> mWorker;
     // Effect descriptor.
-    const Descriptor mDesc = {
-            .common = {.id = {.type = EqualizerTypeUUID, .uuid = EqualizerSwImplUUID}}};
+    Descriptor mDesc = {.common = {.id = {.type = EqualizerTypeUUID, .uuid = EqualizerSwImplUUID}}};
 
     // Parameters.
     Parameter::Common mCommonParam;
@@ -66,21 +74,32 @@
     // Instance state INIT by default.
     State mState = State::INIT;
 
-    typedef ::android::AidlMessageQueue<
-            Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
-            StatusMQ;
-    typedef ::android::AidlMessageQueue<
-            int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
-            DataMQ;
+    int mPreset = PRESET_CUSTOM;  // the current preset
+    const std::vector<Equalizer::BandFrequency> mBandFrequency = {{0, 30000, 120000},
+                                                                  {1, 120001, 460000},
+                                                                  {2, 460001, 1800000},
+                                                                  {3, 1800001, 7000000},
+                                                                  {4, 7000001, 20000000}};
+    // preset band level
+    std::vector<Equalizer::BandLevel> mBandLevels = {{0, 3}, {1, 0}, {2, 0}, {3, 0}, {4, 3}};
+    // presets supported by the device
+    const std::vector<Equalizer::Preset> mPresets = {
+            {0, "Normal"},      {1, "Classical"}, {2, "Dance"}, {3, "Flat"}, {4, "Folk"},
+            {5, "Heavy Metal"}, {6, "Hip Hop"},   {7, "Jazz"},  {8, "Pop"},  {9, "Rock"}};
+    static const int NUM_OF_BANDS = 5;
+    static const int NUM_OF_PRESETS = 10;
+    static const int PRESET_CUSTOM = -1;
 
-    std::unique_ptr<StatusMQ> mStatusMQ;
-    std::unique_ptr<DataMQ> mInputMQ;
-    std::unique_ptr<DataMQ> mOutputMQ;
+    // Equalizer worker context
+    std::shared_ptr<EqualizerSwContext> mContext;
 
     ndk::ScopedAStatus setCommonParameter(const Parameter::Common& common_param);
     ndk::ScopedAStatus setSpecificParameter(const Parameter::Specific& specific);
-    bool createFmq(int statusDepth, int inBufferSize, int outBufferSize, OpenEffectReturn* ret);
-    void destroyFmq();
+    ndk::ScopedAStatus getSpecificParameter(Parameter::Specific::Id id,
+                                            Parameter::Specific* specific);
+
     void cleanUp();
+
+    IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index 63fc415..8de1d79 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -60,6 +60,7 @@
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
     ],
+    header_libs: ["libaudioaidl_headers"],
     cflags: [
         "-Wall",
         "-Wextra",
@@ -75,6 +76,7 @@
 cc_test {
     name: "VtsHalAudioEffectTargetTest",
     defaults: [
+        "latest_android_hardware_audio_common_ndk_static",
         "latest_android_media_audio_common_types_ndk_static",
         "VtsHalTargetTestDefaults",
         "use_libaidlvintf_gtest_helper_static",
@@ -84,12 +86,49 @@
     ],
     shared_libs: [
         "libbinder_ndk",
+        "libfmq",
     ],
     static_libs: [
         "android.hardware.audio.effect-V1-ndk",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
+        "libaudioaidlcommon",
     ],
+    header_libs: ["libaudioaidl_headers"],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-Wthread-safety",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+cc_test {
+    name: "VtsHalEqualizerTargetTest",
+    defaults: [
+        "latest_android_hardware_audio_common_ndk_static",
+        "latest_android_media_audio_common_types_ndk_static",
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "VtsHalEqualizerTargetTest.cpp",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libfmq",
+    ],
+    static_libs: [
+        "android.hardware.audio.effect-V1-ndk",
+        "android.hardware.common-V2-ndk",
+        "android.hardware.common.fmq-V1-ndk",
+        "libaudioaidlcommon",
+    ],
+    header_libs: ["libaudioaidl_headers"],
     cflags: [
         "-Wall",
         "-Wextra",
diff --git a/audio/aidl/vts/EffectFactoryHelper.h b/audio/aidl/vts/EffectFactoryHelper.h
index cf94e58..63efae0 100644
--- a/audio/aidl/vts/EffectFactoryHelper.h
+++ b/audio/aidl/vts/EffectFactoryHelper.h
@@ -24,13 +24,14 @@
 #include <android/binder_auto_utils.h>
 
 #include "TestUtils.h"
+#include "effect-impl/EffectUUID.h"
 
 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::Parameter;
 using aidl::android::hardware::audio::effect::Processing;
 using aidl::android::media::audio::common::AudioUuid;
 
@@ -69,7 +70,6 @@
     }
 
     void CreateEffects() {
-        ASSERT_NE(mEffectFactory, nullptr);
         for (const auto& id : mIds) {
             std::shared_ptr<IEffect> effect;
             EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect));
@@ -80,6 +80,26 @@
         }
     }
 
+    void QueryAndCreateEffects(const AudioUuid& type = EffectNullUuid) {
+        std::vector<Descriptor::Identity> ids;
+        ASSERT_NE(mEffectFactory, nullptr);
+
+        if (type == EffectNullUuid) {
+            EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, &ids));
+        } else {
+            EXPECT_IS_OK(mEffectFactory->queryEffects(type, std::nullopt, &ids));
+        }
+        for (const auto& id : ids) {
+            ASSERT_EQ(id.type, type);
+            std::shared_ptr<IEffect> effect;
+            EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect));
+            EXPECT_NE(effect, nullptr) << id.toString();
+            if (effect) {
+                mEffectIdMap[effect] = id;
+            }
+        }
+    }
+
     void CreateEffectsAndExpect(
             const std::vector<std::pair<Descriptor::Identity, binder_exception_t>>& uuid_status) {
         ASSERT_NE(mEffectFactory, nullptr);
@@ -126,8 +146,10 @@
 
     std::shared_ptr<IFactory> GetFactory() { return mEffectFactory; }
     const std::vector<Descriptor::Identity>& GetEffectIds() { return mIds; }
-    const std::vector<Descriptor::Identity>& GetCompleteEffectIdList() { return mCompleteIds; }
-    const std::map<std::shared_ptr<IEffect>, Descriptor::Identity>& GetEffectMap() {
+    const std::vector<Descriptor::Identity>& GetCompleteEffectIdList() const {
+        return mCompleteIds;
+    }
+    const std::map<std::shared_ptr<IEffect>, Descriptor::Identity>& GetEffectMap() const {
         return mEffectIdMap;
     }
     void ClearEffectMap() { mEffectIdMap.clear(); }
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
new file mode 100644
index 0000000..c58ed13
--- /dev/null
+++ b/audio/aidl/vts/EffectHelper.h
@@ -0,0 +1,310 @@
+/*
+ * 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 <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <aidl/android/hardware/audio/effect/IEffect.h>
+#include <aidl/android/hardware/audio/effect/IFactory.h>
+#include <aidl/android/media/audio/common/AudioChannelLayout.h>
+#include <aidl/android/media/audio/common/AudioDeviceType.h>
+#include <android/binder_auto_utils.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "AudioHalBinderServiceUtil.h"
+#include "EffectFactoryHelper.h"
+#include "TestUtils.h"
+
+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 = {
+        .type = AudioFormatType::PCM, .pcm = PcmType::INT_16_BIT, .encoding = ""};
+
+class EffectHelper {
+  public:
+    explicit EffectHelper(const std::string& name) : mFactoryHelper(EffectFactoryHelper(name)) {
+        mFactoryHelper.ConnectToFactoryService();
+    }
+
+    void OpenEffects(const AudioUuid& type = EffectNullUuid) {
+        auto open = [&](const std::shared_ptr<IEffect>& effect) {
+            IEffect::OpenEffectReturn ret;
+            EXPECT_IS_OK(effect->open(mCommon, mSpecific, &ret));
+            EffectParam params;
+            params.statusMQ = std::make_unique<StatusMQ>(ret.statusMQ);
+            params.inputMQ = std::make_unique<DataMQ>(ret.inputDataMQ);
+            params.outputMQ = std::make_unique<DataMQ>(ret.outputDataMQ);
+            mEffectParams.push_back(std::move(params));
+        };
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(open, type));
+    }
+
+    void CloseEffects(const binder_status_t status = EX_NONE) {
+        auto close = [&](const std::shared_ptr<IEffect>& 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));
+    }
+
+    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();
+    }
+
+    void GetEffectDescriptors() {
+        auto get = [&](const std::shared_ptr<IEffect>& effect) {
+            Descriptor desc;
+            EXPECT_IS_OK(effect->getDescriptor(&desc));
+            mEffectDescriptors.push_back(std::move(desc));
+        };
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(get));
+    }
+
+    void CommandEffects(CommandId command) {
+        auto close = [&](const std::shared_ptr<IEffect>& effect) {
+            EXPECT_IS_OK(effect->command(command));
+        };
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(close));
+    }
+
+    void CommandEffectsExpectStatus(CommandId command, const binder_status_t status) {
+        auto func = [&](const std::shared_ptr<IEffect>& effect) {
+            EXPECT_STATUS(status, effect->command(command));
+        };
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
+    }
+
+    void ExpectState(State expected) {
+        auto get = [&](const std::shared_ptr<IEffect>& effect) {
+            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<IEffect>& effect) {
+            Parameter param;
+            param.set<Parameter::common>(mCommon);
+            EXPECT_IS_OK(effect->setParameter(param));
+        };
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
+    }
+
+    void VerifyParameters() {
+        auto func = [&](const std::shared_ptr<IEffect>& effect) {
+            Parameter paramCommonGet = Parameter(), paramCommonExpect = Parameter();
+            Parameter::Id id;
+            id.set<Parameter::Id::commonTag>(0);
+            paramCommonExpect.set<Parameter::common>(mCommon);
+            EXPECT_IS_OK(effect->getParameter(id, &paramCommonGet));
+            EXPECT_EQ(paramCommonExpect, paramCommonGet)
+                    << paramCommonExpect.toString() << " vs " << paramCommonGet.toString();
+        };
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
+    }
+
+    void QueryEffects(const std::optional<AudioUuid>& in_type,
+                      const std::optional<AudioUuid>& in_instance,
+                      std::vector<Descriptor::Identity>* _aidl_return) {
+        mFactoryHelper.QueryEffects(in_type, in_instance, _aidl_return);
+    }
+
+    template <typename Functor>
+    void ForEachEffect(Functor functor, const std::optional<AudioUuid>& 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);
+        }
+    }
+
+    template <typename Functor>
+    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 mWriteMQSize = 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 = -1, 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;
+        input.base.sampleRate = iSampleRate;
+        input.base.channelMask = mInputChannelLayout;
+        input.frameCount = iFrameCount;
+        output.base.sampleRate = oSampleRate;
+        output.base.channelMask = mOutputChannelLayout;
+        output.frameCount = oFrameCount;
+        inputFrameSize = android::hardware::audio::common::getFrameSizeInBytes(
+                input.base.format, input.base.channelMask);
+        outputFrameSize = android::hardware::audio::common::getFrameSizeInBytes(
+                output.base.format, output.base.channelMask);
+    }
+
+    void setSpecific(Parameter::Specific& specific) { mSpecific = specific; }
+
+    // usually this function only call once.
+    void PrepareInputData(size_t s = mWriteMQSize) {
+        size_t maxInputSize = s;
+        for (auto& it : mEffectParams) {
+            auto& mq = it.inputMQ;
+            EXPECT_NE(nullptr, mq);
+            EXPECT_TRUE(mq->isValid());
+            const size_t bytesToWrite = mq->availableToWrite();
+            EXPECT_EQ(inputFrameSize * mCommon.input.frameCount, bytesToWrite);
+            EXPECT_NE(0UL, bytesToWrite);
+            EXPECT_TRUE(s <= bytesToWrite);
+            maxInputSize = std::max(maxInputSize, bytesToWrite);
+        }
+        mInputBuffer.resize(maxInputSize);
+        std::fill(mInputBuffer.begin(), mInputBuffer.end(), 0x5a);
+    }
+
+    void writeToFmq(size_t s = mWriteMQSize) {
+        for (auto& it : mEffectParams) {
+            auto& mq = it.inputMQ;
+            EXPECT_NE(nullptr, mq);
+            const size_t bytesToWrite = mq->availableToWrite();
+            EXPECT_NE(0Ul, bytesToWrite);
+            EXPECT_TRUE(s <= bytesToWrite);
+            EXPECT_TRUE(mq->write(mInputBuffer.data(), s));
+        }
+    }
+
+    void readFromFmq(size_t expectSize = mWriteMQSize) {
+        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(expectSize, (unsigned)status.fmqByteProduced);
+
+            auto& outputMq = it.outputMQ;
+            EXPECT_NE(nullptr, outputMq);
+            EXPECT_EQ(expectSize, outputMq->availableToRead());
+        }
+    }
+
+    void setInputChannelLayout(AudioChannelLayout input) { mInputChannelLayout = input; }
+    void setOutputChannelLayout(AudioChannelLayout output) { mOutputChannelLayout = output; }
+    const std::vector<Descriptor::Identity>& GetCompleteEffectIdList() const {
+        return mFactoryHelper.GetCompleteEffectIdList();
+    }
+    const std::vector<Descriptor>& getDescriptorVec() const { return mEffectDescriptors; }
+
+  private:
+    EffectFactoryHelper mFactoryHelper;
+
+    AudioChannelLayout mInputChannelLayout =
+            AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                    AudioChannelLayout::LAYOUT_STEREO);
+    AudioChannelLayout mOutputChannelLayout =
+            AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                    AudioChannelLayout::LAYOUT_STEREO);
+
+    Parameter::Common mCommon;
+    Parameter::Specific mSpecific;
+
+    size_t inputFrameSize, outputFrameSize;
+    std::vector<int8_t> mInputBuffer;  // reuse same buffer for all effects testing
+
+    typedef ::android::AidlMessageQueue<
+            IEffect::Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+            StatusMQ;
+    typedef ::android::AidlMessageQueue<
+            int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+            DataMQ;
+
+    class EffectParam {
+      public:
+        std::unique_ptr<StatusMQ> statusMQ;
+        std::unique_ptr<DataMQ> inputMQ;
+        std::unique_ptr<DataMQ> outputMQ;
+    };
+    std::vector<EffectParam> mEffectParams;
+    std::vector<Descriptor> mEffectDescriptors;
+};
diff --git a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
index 454ce29..da8ca37 100644
--- a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
@@ -37,6 +37,8 @@
 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::IFactory;
 using aidl::android::hardware::audio::effect::Processing;
 using aidl::android::media::audio::common::AudioUuid;
@@ -50,17 +52,8 @@
 
     EffectFactoryHelper mFactory = EffectFactoryHelper(GetParam());
 
-    // TODO: these UUID can get from config file
-    // ec7178ec-e5e1-4432-a3f4-4657e6795210
-    const AudioUuid nullUuid = {static_cast<int32_t>(0xec7178ec),
-                                0xe5e1,
-                                0x4432,
-                                0xa3f4,
-                                {0x46, 0x57, 0xe6, 0x79, 0x52, 0x10}};
-    const AudioUuid zeroUuid = {
-            static_cast<int32_t>(0x0), 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
-    const Descriptor::Identity nullDesc = {.uuid = nullUuid};
-    const Descriptor::Identity zeroDesc = {.uuid = zeroUuid};
+    const Descriptor::Identity nullDesc = {.uuid = EffectNullUuid};
+    const Descriptor::Identity zeroDesc = {.uuid = EffectZeroUuid};
 };
 
 TEST_P(EffectFactoryTest, SetupAndTearDown) {
@@ -82,20 +75,20 @@
     mFactory.QueryEffects(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, zeroUuid);
-        EXPECT_NE(desc.uuid, zeroUuid);
+        EXPECT_NE(desc.type, EffectNullUuid);
+        EXPECT_NE(desc.uuid, EffectNullUuid);
     }
 }
 
 TEST_P(EffectFactoryTest, QueriedDescriptorNotExistType) {
     std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(nullUuid, std::nullopt, &descriptors);
+    mFactory.QueryEffects(EffectNullUuid, std::nullopt, &descriptors);
     EXPECT_EQ(descriptors.size(), 0UL);
 }
 
 TEST_P(EffectFactoryTest, QueriedDescriptorNotExistInstance) {
     std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(std::nullopt, nullUuid, &descriptors);
+    mFactory.QueryEffects(std::nullopt, EffectNullUuid, &descriptors);
     EXPECT_EQ(descriptors.size(), 0UL);
 }
 
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index 23b20bd..7ed1f01 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "VtsHalAudioEffectTargetTest"
+
 #include <memory>
 #include <string>
 #include <unordered_map>
 #include <unordered_set>
 #include <vector>
 
-#define LOG_TAG "VtsHalAudioEffect"
-
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
 #include <android-base/logging.h>
@@ -30,13 +30,13 @@
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 
+#include <Utils.h>
 #include <aidl/android/hardware/audio/effect/IEffect.h>
 #include <aidl/android/hardware/audio/effect/IFactory.h>
-#include <aidl/android/media/audio/common/AudioChannelLayout.h>
 #include <aidl/android/media/audio/common/AudioDeviceType.h>
 
 #include "AudioHalBinderServiceUtil.h"
-#include "EffectFactoryHelper.h"
+#include "EffectHelper.h"
 #include "TestUtils.h"
 
 using namespace android;
@@ -49,201 +49,72 @@
 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::AudioChannelLayout;
 using aidl::android::media::audio::common::AudioDeviceType;
 
-class AudioEffect : public testing::TestWithParam<std::string> {
+class AudioEffectTest : public testing::TestWithParam<std::string>, public EffectHelper {
   public:
+    AudioEffectTest() : EffectHelper(GetParam()) {}
+
     void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(mFactoryHelper.ConnectToFactoryService());
         CreateEffects();
+        initParamCommonFormat();
         initParamCommon();
-        initParamSpecific();
+        // initParamSpecific();
     }
 
     void TearDown() override {
         CloseEffects();
         DestroyEffects();
     }
-
-    void OpenEffects() {
-        auto open = [&](const std::shared_ptr<IEffect>& effect) {
-            IEffect::OpenEffectReturn ret;
-            EXPECT_IS_OK(effect->open(mCommon, mSpecific, &ret));
-        };
-        EXPECT_NO_FATAL_FAILURE(ForEachEffect(open));
-    }
-
-    void CloseEffects(const binder_status_t status = EX_NONE) {
-        auto close = [&](const std::shared_ptr<IEffect>& 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 DestroyEffects(const binder_status_t status = EX_NONE, const int remaining = 0) {
-        ASSERT_NO_FATAL_FAILURE(mFactoryHelper.DestroyEffects(status, remaining));
-    }
-
-    void GetEffectDescriptors() {
-        auto get = [](const std::shared_ptr<IEffect>& effect) {
-            Descriptor desc;
-            EXPECT_IS_OK(effect->getDescriptor(&desc));
-        };
-        EXPECT_NO_FATAL_FAILURE(ForEachEffect(get));
-    }
-
-    void CommandEffects(CommandId command) {
-        auto close = [&](const std::shared_ptr<IEffect>& effect) {
-            EXPECT_IS_OK(effect->command(command));
-        };
-        EXPECT_NO_FATAL_FAILURE(ForEachEffect(close));
-    }
-
-    void CommandEffectsExpectStatus(CommandId command, const binder_status_t status) {
-        auto func = [&](const std::shared_ptr<IEffect>& effect) {
-            EXPECT_STATUS(status, effect->command(command));
-        };
-        EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
-    }
-
-    void ExpectState(State expected) {
-        auto get = [&](const std::shared_ptr<IEffect>& effect) {
-            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<IEffect>& effect) {
-            Parameter param;
-            param.set<Parameter::common>(mCommon);
-            EXPECT_IS_OK(effect->setParameter(param));
-        };
-        EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
-    }
-
-    void VerifyParameters() {
-        auto func = [&](const std::shared_ptr<IEffect>& effect) {
-            Parameter paramCommonGet = Parameter(), paramCommonExpect = Parameter();
-            Parameter::Id id;
-            id.set<Parameter::Id::commonTag>(0);
-            paramCommonExpect.set<Parameter::common>(mCommon);
-            EXPECT_IS_OK(effect->getParameter(id, &paramCommonGet));
-            EXPECT_EQ(paramCommonExpect, paramCommonGet)
-                    << paramCommonExpect.toString() << " vs " << paramCommonGet.toString();
-        };
-        EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
-    }
-
-    template <typename Functor>
-    void ForEachEffect(Functor functor) {
-        auto effectMap = mFactoryHelper.GetEffectMap();
-        for (const auto& it : effectMap) {
-            SCOPED_TRACE(it.second.toString());
-            functor(it.first);
-        }
-    }
-
-    void initParamCommon(int session = -1, int ioHandle = -1,
-                         AudioDeviceType deviceType = AudioDeviceType::NONE,
-                         int iSampleRate = 48000, int oSampleRate = 48000, long iFrameCount = 0x100,
-                         long oFrameCount = 0x100) {
-        mCommon.session = session;
-        mCommon.ioHandle = ioHandle;
-        mCommon.device.type = deviceType;
-        mCommon.input.base.sampleRate = iSampleRate;
-        mCommon.input.base.channelMask = mInputChannelLayout;
-        mCommon.input.frameCount = iFrameCount;
-        mCommon.output.base.sampleRate = oSampleRate;
-        mCommon.output.base.channelMask = mOutputChannelLayout;
-        mCommon.output.frameCount = oFrameCount;
-    }
-
-    void initParamSpecific(Parameter::Specific::Tag tag = Parameter::Specific::equalizer) {
-        switch (tag) {
-            case Parameter::Specific::equalizer:
-                mSpecific.set<Parameter::Specific::equalizer>();
-                break;
-            default:
-                return;
-        }
-    }
-
-    void setInputChannelLayout(AudioChannelLayout input) { mInputChannelLayout = input; }
-    void setOutputChannelLayout(AudioChannelLayout output) { mOutputChannelLayout = output; }
-
-    EffectFactoryHelper mFactoryHelper = EffectFactoryHelper(GetParam());
-
-  private:
-    AudioChannelLayout mInputChannelLayout =
-            AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
-                    AudioChannelLayout::LAYOUT_STEREO);
-    AudioChannelLayout mOutputChannelLayout =
-            AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
-                    AudioChannelLayout::LAYOUT_STEREO);
-
-    Parameter::Common mCommon;
-    Parameter::Specific mSpecific;
-    static IEffect::OpenEffectReturn mOpenReturn;
 };
 
-TEST_P(AudioEffect, OpenEffectTest) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
+TEST_P(AudioEffectTest, OpenEffectTest) {
+    OpenEffects();
 }
 
-TEST_P(AudioEffect, OpenAndCloseEffect) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+TEST_P(AudioEffectTest, OpenAndCloseEffect) {
+    OpenEffects();
+    CloseEffects();
 }
 
-TEST_P(AudioEffect, CloseUnopenedEffectTest) {
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+TEST_P(AudioEffectTest, CloseUnopenedEffectTest) {
+    CloseEffects();
 }
 
-TEST_P(AudioEffect, DoubleOpenCloseEffects) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+TEST_P(AudioEffectTest, DoubleOpenCloseEffects) {
+    OpenEffects();
+    CloseEffects();
+    OpenEffects();
+    CloseEffects();
 
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    OpenEffects();
+    OpenEffects();
+    CloseEffects();
 
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    OpenEffects();
+    CloseEffects();
+    CloseEffects();
 }
 
-TEST_P(AudioEffect, GetDescriptors) {
-    EXPECT_NO_FATAL_FAILURE(GetEffectDescriptors());
+TEST_P(AudioEffectTest, GetDescriptors) {
+    GetEffectDescriptors();
 }
 
-TEST_P(AudioEffect, DescriptorIdExistAndUnique) {
+TEST_P(AudioEffectTest, DescriptorIdExistAndUnique) {
     auto checker = [&](const std::shared_ptr<IEffect>& effect) {
         Descriptor desc;
         std::vector<Descriptor::Identity> idList;
         EXPECT_IS_OK(effect->getDescriptor(&desc));
-        mFactoryHelper.QueryEffects(desc.common.id.type, desc.common.id.uuid, &idList);
+        QueryEffects(desc.common.id.type, desc.common.id.uuid, &idList);
         EXPECT_EQ(idList.size(), 1UL);
     };
-    EXPECT_NO_FATAL_FAILURE(ForEachEffect(checker));
+    ForEachEffect(checker);
 
     // Check unique with a set
     auto stringHash = [](const Descriptor::Identity& id) {
         return std::hash<std::string>()(id.toString());
     };
-    auto vec = mFactoryHelper.GetCompleteEffectIdList();
+    auto vec = GetCompleteEffectIdList();
     std::unordered_set<Descriptor::Identity, decltype(stringHash)> idSet(0, stringHash);
     for (auto it : vec) {
         EXPECT_EQ(idSet.count(it), 0UL);
@@ -253,218 +124,235 @@
 
 /// State testing.
 // An effect instance is in INIT state by default after it was created.
-TEST_P(AudioEffect, InitStateAfterCreation) {
+TEST_P(AudioEffectTest, InitStateAfterCreation) {
     ExpectState(State::INIT);
 }
 
 // An effect instance transfer to INIT state after it was open successfully with IEffect.open().
-TEST_P(AudioEffect, IdleStateAfterOpen) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
+TEST_P(AudioEffectTest, IdleStateAfterOpen) {
+    OpenEffects();
     ExpectState(State::IDLE);
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    CloseEffects();
 }
 
 // An effect instance is in PROCESSING state after it receive an START command.
-TEST_P(AudioEffect, ProcessingStateAfterStart) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
+TEST_P(AudioEffectTest, ProcessingStateAfterStart) {
+    OpenEffects();
+    CommandEffects(CommandId::START);
     ExpectState(State::PROCESSING);
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    CommandEffects(CommandId::STOP);
+    CloseEffects();
 }
 
 // An effect instance transfer to IDLE state after Command.Id.STOP in PROCESSING state.
-TEST_P(AudioEffect, IdleStateAfterStop) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
+TEST_P(AudioEffectTest, IdleStateAfterStop) {
+    OpenEffects();
+    CommandEffects(CommandId::START);
     ExpectState(State::PROCESSING);
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
+    CommandEffects(CommandId::STOP);
     ExpectState(State::IDLE);
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    CloseEffects();
 }
 
 // An effect instance transfer to IDLE state after Command.Id.RESET in PROCESSING state.
-TEST_P(AudioEffect, IdleStateAfterReset) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
+TEST_P(AudioEffectTest, IdleStateAfterReset) {
+    OpenEffects();
+    CommandEffects(CommandId::START);
     ExpectState(State::PROCESSING);
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::RESET));
+    CommandEffects(CommandId::RESET);
     ExpectState(State::IDLE);
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    CloseEffects();
 }
 
 // An effect instance transfer to INIT if instance receive a close() call.
-TEST_P(AudioEffect, InitStateAfterClose) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
+TEST_P(AudioEffectTest, InitStateAfterClose) {
+    OpenEffects();
+    CommandEffects(CommandId::START);
     ExpectState(State::PROCESSING);
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
+    CommandEffects(CommandId::STOP);
     ExpectState(State::IDLE);
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    CloseEffects();
     ExpectState(State::INIT);
 }
 
 // An effect instance shouldn't accept any command before open.
-TEST_P(AudioEffect, NoCommandAcceptedBeforeOpen) {
+TEST_P(AudioEffectTest, NoCommandAcceptedBeforeOpen) {
     ExpectState(State::INIT);
-    EXPECT_NO_FATAL_FAILURE(CommandEffectsExpectStatus(CommandId::START, EX_ILLEGAL_STATE));
-    EXPECT_NO_FATAL_FAILURE(CommandEffectsExpectStatus(CommandId::STOP, EX_ILLEGAL_STATE));
-    EXPECT_NO_FATAL_FAILURE(CommandEffectsExpectStatus(CommandId::RESET, EX_ILLEGAL_STATE));
+    CommandEffectsExpectStatus(CommandId::START, EX_ILLEGAL_STATE);
+    CommandEffectsExpectStatus(CommandId::STOP, EX_ILLEGAL_STATE);
+    CommandEffectsExpectStatus(CommandId::RESET, EX_ILLEGAL_STATE);
     ExpectState(State::INIT);
 }
 
 // No-op when receive STOP command in IDLE state.
-TEST_P(AudioEffect, StopCommandInIdleStateNoOp) {
+TEST_P(AudioEffectTest, StopCommandInIdleStateNoOp) {
     ExpectState(State::INIT);
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
+    OpenEffects();
     ExpectState(State::IDLE);
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
+    CommandEffects(CommandId::STOP);
     ExpectState(State::IDLE);
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    CloseEffects();
 }
 
 // No-op when receive STOP command in IDLE state.
-TEST_P(AudioEffect, ResetCommandInIdleStateNoOp) {
+TEST_P(AudioEffectTest, ResetCommandInIdleStateNoOp) {
     ExpectState(State::INIT);
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
+    OpenEffects();
     ExpectState(State::IDLE);
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::RESET));
+    CommandEffects(CommandId::RESET);
     ExpectState(State::IDLE);
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    CloseEffects();
 }
 
 // Repeat START and STOP command.
-TEST_P(AudioEffect, RepeatStartAndStop) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
+TEST_P(AudioEffectTest, RepeatStartAndStop) {
+    OpenEffects();
+    CommandEffects(CommandId::START);
     ExpectState(State::PROCESSING);
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
+    CommandEffects(CommandId::STOP);
     ExpectState(State::IDLE);
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
+    CommandEffects(CommandId::START);
     ExpectState(State::PROCESSING);
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
+    CommandEffects(CommandId::STOP);
     ExpectState(State::IDLE);
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    CloseEffects();
 }
 
 // Repeat START and RESET command.
-TEST_P(AudioEffect, RepeatStartAndReset) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
+TEST_P(AudioEffectTest, RepeatStartAndReset) {
+    OpenEffects();
+    CommandEffects(CommandId::START);
     ExpectState(State::PROCESSING);
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::RESET));
+    CommandEffects(CommandId::RESET);
     ExpectState(State::IDLE);
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
+    CommandEffects(CommandId::START);
     ExpectState(State::PROCESSING);
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::RESET));
+    CommandEffects(CommandId::RESET);
     ExpectState(State::IDLE);
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    CloseEffects();
 }
 
 // Repeat START and STOP command, try to close at PROCESSING state.
-TEST_P(AudioEffect, CloseProcessingStateEffects) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
+TEST_P(AudioEffectTest, CloseProcessingStateEffects) {
+    OpenEffects();
+    CommandEffects(CommandId::START);
     ExpectState(State::PROCESSING);
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
+    CommandEffects(CommandId::STOP);
     ExpectState(State::IDLE);
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
+    CommandEffects(CommandId::START);
     ExpectState(State::PROCESSING);
-    EXPECT_NO_FATAL_FAILURE(CloseEffects(EX_ILLEGAL_STATE));
+    CloseEffects(EX_ILLEGAL_STATE);
     // cleanup
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
+    CommandEffects(CommandId::STOP);
     ExpectState(State::IDLE);
 }
 
 // Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
-TEST_P(AudioEffect, DestroyOpenEffects) {
+TEST_P(AudioEffectTest, DestroyOpenEffects) {
     // cleanup all effects.
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
-    ASSERT_NO_FATAL_FAILURE(DestroyEffects());
+    CloseEffects();
+    DestroyEffects();
 
     // open effects, destroy without close, expect to get EX_ILLEGAL_STATE status.
-    EXPECT_NO_FATAL_FAILURE(CreateEffects());
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(DestroyEffects(EX_ILLEGAL_STATE, 1));
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    CreateEffects();
+    OpenEffects();
+    DestroyEffects(EX_ILLEGAL_STATE, 1);
+    CloseEffects();
 }
 
 /// Parameter testing.
 // Verify parameters pass in open can be successfully get.
-TEST_P(AudioEffect, VerifyParametersAfterOpen) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(VerifyParameters());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+TEST_P(AudioEffectTest, VerifyParametersAfterOpen) {
+    OpenEffects();
+    VerifyParameters();
+    CloseEffects();
 }
 
 // Verify parameters pass in set can be successfully get.
-TEST_P(AudioEffect, SetAndGetParameter) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(VerifyParameters());
-    initParamCommon(1 /* session */, 1 /* ioHandle */, AudioDeviceType::IN_DEFAULT /* deviceType */,
-                    44100 /* iSampleRate */, 44100 /* oSampleRate */);
-    EXPECT_NO_FATAL_FAILURE(SetParameter());
-    EXPECT_NO_FATAL_FAILURE(VerifyParameters());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+TEST_P(AudioEffectTest, SetAndGetParameter) {
+    OpenEffects();
+    VerifyParameters();
+    initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
+                    44100 /* oSampleRate */);
+    SetParameter();
+    VerifyParameters();
+    CloseEffects();
 }
 
 // Verify parameters pass in set can be successfully get.
-TEST_P(AudioEffect, SetAndGetParameterInProcessing) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(VerifyParameters());
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
+TEST_P(AudioEffectTest, SetAndGetParameterInProcessing) {
+    OpenEffects();
+    VerifyParameters();
+    CommandEffects(CommandId::START);
     ExpectState(State::PROCESSING);
-    initParamCommon(1 /* session */, 1 /* ioHandle */, AudioDeviceType::IN_DEFAULT /* deviceType */,
-                    44100 /* iSampleRate */, 44100 /* oSampleRate */);
-    EXPECT_NO_FATAL_FAILURE(SetParameter());
-    EXPECT_NO_FATAL_FAILURE(VerifyParameters());
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
+    initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
+                    44100 /* oSampleRate */);
+    SetParameter();
+    VerifyParameters();
+    CommandEffects(CommandId::STOP);
     ExpectState(State::IDLE);
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    CloseEffects();
 }
 
 // Parameters kept after reset.
-TEST_P(AudioEffect, ResetAndVerifyParameter) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(VerifyParameters());
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
+TEST_P(AudioEffectTest, ResetAndVerifyParameter) {
+    OpenEffects();
+    VerifyParameters();
+    CommandEffects(CommandId::START);
     ExpectState(State::PROCESSING);
-    initParamCommon(1 /* session */, 1 /* ioHandle */, AudioDeviceType::IN_DEFAULT /* deviceType */,
-                    44100 /* iSampleRate */, 44100 /* oSampleRate */);
-    EXPECT_NO_FATAL_FAILURE(SetParameter());
-    EXPECT_NO_FATAL_FAILURE(VerifyParameters());
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::RESET));
+    initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
+                    44100 /* oSampleRate */);
+    SetParameter();
+    VerifyParameters();
+    CommandEffects(CommandId::RESET);
     ExpectState(State::IDLE);
-    EXPECT_NO_FATAL_FAILURE(VerifyParameters());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    VerifyParameters();
+    CloseEffects();
 }
 
 // Multiple instances of same implementation running.
-TEST_P(AudioEffect, MultipleInstancesRunning) {
-    EXPECT_NO_FATAL_FAILURE(CreateEffects(3));
+TEST_P(AudioEffectTest, MultipleInstancesRunning) {
+    CreateEffects(3);
     ExpectState(State::INIT);
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
+    OpenEffects();
     ExpectState(State::IDLE);
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
+    CommandEffects(CommandId::START);
     ExpectState(State::PROCESSING);
-    initParamCommon(1 /* session */, 1 /* ioHandle */, AudioDeviceType::IN_DEFAULT /* deviceType */,
-                    44100 /* iSampleRate */, 44100 /* oSampleRate */);
-    EXPECT_NO_FATAL_FAILURE(SetParameter());
-    EXPECT_NO_FATAL_FAILURE(VerifyParameters());
-    EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
+    initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
+                    44100 /* oSampleRate */);
+    SetParameter();
+    VerifyParameters();
+    CommandEffects(CommandId::STOP);
     ExpectState(State::IDLE);
-    EXPECT_NO_FATAL_FAILURE(VerifyParameters());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    VerifyParameters();
+    CloseEffects();
 }
 
-INSTANTIATE_TEST_SUITE_P(AudioEffectTest, AudioEffect,
+// Send data to effects and expect it to consume by check statusMQ.
+TEST_P(AudioEffectTest, ExpectEffectsToConsumeDataInMQ) {
+    OpenEffects();
+    PrepareInputData(mWriteMQSize);
+
+    CommandEffects(CommandId::START);
+    writeToFmq(mWriteMQSize);
+    readFromFmq(mWriteMQSize);
+
+    ExpectState(State::PROCESSING);
+    CommandEffects(CommandId::STOP);
+    // cleanup
+    CommandEffects(CommandId::STOP);
+    ExpectState(State::IDLE);
+    CloseEffects();
+}
+
+INSTANTIATE_TEST_SUITE_P(AudioEffectTestTest, AudioEffectTest,
                          testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
                          android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioEffect);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioEffectTest);
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
-}
\ No newline at end of file
+}
diff --git a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
new file mode 100644
index 0000000..3b9699b
--- /dev/null
+++ b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
@@ -0,0 +1,233 @@
+/*
+ * 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 <algorithm>
+#include <limits>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#define LOG_TAG "VtsHalEqualizerTest"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <gtest/gtest.h>
+
+#include <Utils.h>
+#include <aidl/android/hardware/audio/effect/IEffect.h>
+#include <aidl/android/hardware/audio/effect/IFactory.h>
+#include <aidl/android/media/audio/common/AudioChannelLayout.h>
+#include <aidl/android/media/audio/common/AudioDeviceType.h>
+
+#include "AudioHalBinderServiceUtil.h"
+#include "EffectHelper.h"
+#include "TestUtils.h"
+#include "effect-impl/EffectUUID.h"
+
+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::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEfectTargetTest.
+ */
+using EqualizerParamTestParam = std::tuple<int, int, int>;
+
+class EqualizerParamTest : public ::testing::TestWithParam<EqualizerParamTestParam>,
+                           public EffectHelper {
+  public:
+    EqualizerParamTest()
+        : EffectHelper(android::getAidlHalInstanceNames(IFactory::descriptor)[0]),
+          mParamPresetIndex(std::get<0 /* kPresetIndexRange */>(GetParam())),
+          mParamBandIndex(std::get<1 /* kBandIndexRange */>(GetParam())),
+          mParamBandLevel(std::get<2 /* kBandLevelRange */>(GetParam())) {}
+
+    void SetUp() override {
+        CreateEffectsWithUUID(EqualizerTypeUUID);
+        initParamCommonFormat();
+        initParamCommon();
+        initParamSpecific();
+        OpenEffects(EqualizerTypeUUID);
+        SCOPED_TRACE(testing::Message() << "preset: " << mParamPresetIndex << " bandIdx "
+                                        << mParamBandIndex << " level " << mParamBandLevel);
+    }
+
+    void TearDown() override {
+        CloseEffects();
+        DestroyEffects();
+        CleanUp();
+    }
+
+    const int mParamPresetIndex;
+    const int mParamBandIndex;
+    const int mParamBandLevel;
+
+    void SetAndGetEqualizerParameters() {
+        auto functor = [&](const std::shared_ptr<IEffect>& effect) {
+            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;
+
+                // set
+                Parameter expectParam;
+                Parameter::Specific specific;
+                specific.set<Parameter::Specific::equalizer>(*eq.get());
+                expectParam.set<Parameter::specific>(specific);
+                EXPECT_STATUS(expected, effect->setParameter(expectParam))
+                        << expectParam.toString();
+
+                // get
+                if (expected == EX_NONE) {
+                    Parameter getParam;
+                    Parameter::Specific::Id id;
+                    id.set<Parameter::Specific::Id::equalizerTag>(tag);
+                    // if set success, then get should match
+                    EXPECT_STATUS(expected, effect->getParameter(id, &getParam));
+                    EXPECT_EQ(expectParam, getParam) << "\n"
+                                                     << expectParam.toString() << "\n"
+                                                     << getParam.toString();
+                }
+            }
+        };
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(functor));
+    }
+
+    void addPresetParam(int preset) {
+        Equalizer eq;
+        eq.set<Equalizer::preset>(preset);
+        mTags.push_back({Equalizer::preset, std::make_unique<Equalizer>(std::move(eq))});
+    }
+
+    void addBandLevelsParam(std::vector<Equalizer::BandLevel>& bandLevels) {
+        Equalizer eq;
+        eq.set<Equalizer::bandLevels>(bandLevels);
+        mTags.push_back({Equalizer::bandLevels, std::make_unique<Equalizer>(std::move(eq))});
+    }
+
+    bool isTagInRange(const Equalizer::Tag& tag, const std::unique_ptr<Equalizer>& eq,
+                      const Descriptor& desc) const {
+        std::cout << "xxx" << toString(tag) << " " << desc.toString();
+        const Equalizer::Capability& eqCap = desc.capability.get<Capability::equalizer>();
+        switch (tag) {
+            case Equalizer::preset: {
+                int index = eq->get<Equalizer::preset>();
+                return isPresetIndexInRange(eqCap, index);
+            }
+            case Equalizer::bandLevels: {
+                auto& bandLevel = eq->get<Equalizer::bandLevels>();
+                return isBandIndexInRange(eqCap, bandLevel);
+            }
+            default:
+                return false;
+        }
+        return false;
+    }
+
+    bool isPresetIndexInRange(const Equalizer::Capability& cap, int idx) 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 idx >= min->index && idx <= max->index;
+    }
+
+    bool isBandIndexInRange(const Equalizer::Capability& cap,
+                            const std::vector<Equalizer::BandLevel>& bandLevel) const {
+        for (auto& it : bandLevel) {
+            if (!isBandIndexInRange(cap, it.index)) 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;
+    }
+
+  private:
+    Equalizer::VendorExtension mVendorExtension;
+    std::vector<std::pair<Equalizer::Tag, std::unique_ptr<Equalizer>>> mTags;
+
+    bool validCapabilityTag(Capability& cap) { return cap.getTag() == Capability::equalizer; }
+
+    void initParamSpecific() {
+        Equalizer eq;
+        eq.set<Equalizer::preset>(0);
+        Parameter::Specific specific;
+        specific.set<Parameter::Specific::equalizer>(eq);
+        setSpecific(specific);
+    }
+
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(EqualizerParamTest, SetAndGetPreset) {
+    EXPECT_NO_FATAL_FAILURE(addPresetParam(mParamPresetIndex));
+    SetAndGetEqualizerParameters();
+}
+
+TEST_P(EqualizerParamTest, SetAndGetSingleBand) {
+    Equalizer::BandLevel bandLevel = {mParamBandIndex, mParamBandLevel};
+    std::vector<Equalizer::BandLevel> bandLevels;
+    bandLevels.push_back(bandLevel);
+    EXPECT_NO_FATAL_FAILURE(addBandLevelsParam(bandLevels));
+    SetAndGetEqualizerParameters();
+}
+
+/**
+ Testing preset index range with [-10, 10], assuming the min/max preset index 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<int, int> kPresetIndexRange = {-1, 10};  // valid range [0, 9]
+constexpr std::pair<int, int> kBandIndexRange = {-1, 5};     // valid range [0, 4]
+constexpr std::pair<int, int> kBandLevelRange = {-5, 5};     // needs update with implementation
+
+INSTANTIATE_TEST_SUITE_P(
+        EqualizerTest, EqualizerParamTest,
+        ::testing::Combine(testing::Range(kPresetIndexRange.first, kPresetIndexRange.second),
+                           testing::Range(kBandIndexRange.first, kBandIndexRange.second),
+                           testing::Range(kBandLevelRange.first, kBandLevelRange.second)));
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EqualizerTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}