PreProcessing : Add libeffect pre-processing effects implementation

Bug: 258124419
Test: atest VtsHalAECTargetTest
Test: atest VtsHalAGC1TargetTest
Test: atest VtsHalAGC2TargetTest
Test: atest VtsHalNSTargetTest
Change-Id: Idfecf978b87419f54f1c930434821ba2a348d9dd
diff --git a/media/libeffects/preprocessing/Android.bp b/media/libeffects/preprocessing/Android.bp
index c6e036a..d018c47 100644
--- a/media/libeffects/preprocessing/Android.bp
+++ b/media/libeffects/preprocessing/Android.bp
@@ -58,3 +58,39 @@
         "libwebrtc_absl_headers",
     ],
 }
+
+cc_library_shared {
+    name: "libpreprocessingaidl",
+    srcs: [
+        "aidl/PreProcessingContext.cpp",
+        "aidl/EffectPreProcessing.cpp",
+        ":effectCommonFile",
+    ],
+    defaults: [
+        "aidlaudioservice_defaults",
+        "latest_android_hardware_audio_effect_ndk_shared",
+        "latest_android_media_audio_common_types_ndk_shared",
+    ],
+    local_include_dirs: ["aidl"],
+    shared_libs: [
+        "liblog",
+        "libutils",
+        "libaudioutils",
+    ],
+    static_libs: [
+        "webrtc_audio_processing",
+    ],
+    header_libs: [
+        "libwebrtc_absl_headers",
+        "libaudioeffects",
+        "libhardware_headers",
+    ],
+    cflags: [
+        "-Wthread-safety",
+        "-Wno-unused-parameter",
+    ],
+    relative_install_path: "soundfx",
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp b/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
new file mode 100644
index 0000000..b9df915
--- /dev/null
+++ b/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#define LOG_TAG "EffectPreProcessing"
+#include <algorithm>
+#include <unordered_set>
+
+#include <Utils.h>
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "EffectPreProcessing.h"
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::EffectPreProcessing;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kAcousticEchoCancelerSwImplUUID;
+using aidl::android::hardware::audio::effect::kAutomaticGainControlV1SwImplUUID;
+using aidl::android::hardware::audio::effect::kAutomaticGainControlV2SwImplUUID;
+using aidl::android::hardware::audio::effect::kNoiseSuppressionSwImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioUuid;
+
+bool isPreProcessingUuidSupported(const AudioUuid& uuid) {
+    return (uuid == kAcousticEchoCancelerSwImplUUID || uuid == kAutomaticGainControlV1SwImplUUID ||
+            uuid == kAutomaticGainControlV2SwImplUUID || uuid == kNoiseSuppressionSwImplUUID);
+}
+
+extern "C" binder_exception_t createEffect(const AudioUuid* uuid,
+                                           std::shared_ptr<IEffect>* instanceSpp) {
+    if (!uuid || !isPreProcessingUuidSupported(*uuid)) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<EffectPreProcessing>(*uuid);
+        LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+        return EX_NONE;
+    } else {
+        LOG(ERROR) << __func__ << " invalid input parameter!";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+}
+
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || !isPreProcessingUuidSupported(*in_impl_uuid)) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (*in_impl_uuid == kAcousticEchoCancelerSwImplUUID) {
+        *_aidl_return = aidl::android::hardware::audio::effect::kAcousticEchoCancelerDesc;
+    } else if (*in_impl_uuid == kAutomaticGainControlV1SwImplUUID) {
+        *_aidl_return = aidl::android::hardware::audio::effect::kAutomaticGainControlV1Desc;
+    } else if (*in_impl_uuid == kAutomaticGainControlV2SwImplUUID) {
+        *_aidl_return = aidl::android::hardware::audio::effect::kAutomaticGainControlV2Desc;
+    } else if (*in_impl_uuid == kNoiseSuppressionSwImplUUID) {
+        *_aidl_return = aidl::android::hardware::audio::effect::kNoiseSuppressionDesc;
+    }
+    return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+EffectPreProcessing::EffectPreProcessing(const AudioUuid& uuid) {
+    LOG(DEBUG) << __func__ << uuid.toString();
+    if (uuid == kAcousticEchoCancelerSwImplUUID) {
+        mType = PreProcessingEffectType::ACOUSTIC_ECHO_CANCELLATION;
+        mDescriptor = &kAcousticEchoCancelerDesc;
+        mEffectName = &kAcousticEchoCancelerEffectName;
+    } else if (uuid == kAutomaticGainControlV1SwImplUUID) {
+        mType = PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V1;
+        mDescriptor = &kAutomaticGainControlV1Desc;
+        mEffectName = &kAutomaticGainControlV1EffectName;
+    } else if (uuid == kAutomaticGainControlV2SwImplUUID) {
+        mType = PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V2;
+        mDescriptor = &kAutomaticGainControlV2Desc;
+        mEffectName = &kAutomaticGainControlV2EffectName;
+    } else if (uuid == kNoiseSuppressionSwImplUUID) {
+        mType = PreProcessingEffectType::NOISE_SUPPRESSION;
+        mDescriptor = &kNoiseSuppressionDesc;
+        mEffectName = &kNoiseSuppressionEffectName;
+    } else {
+        LOG(ERROR) << __func__ << uuid.toString() << " not supported!";
+    }
+}
+
+EffectPreProcessing::~EffectPreProcessing() {
+    cleanUp();
+    LOG(DEBUG) << __func__;
+}
+
+ndk::ScopedAStatus EffectPreProcessing::getDescriptor(Descriptor* _aidl_return) {
+    RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
+    LOG(DEBUG) << _aidl_return->toString();
+    *_aidl_return = *mDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectPreProcessing::setParameterSpecific(const Parameter::Specific& specific) {
+    LOG(DEBUG) << __func__ << " specific " << specific.toString();
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto tag = specific.getTag();
+    switch (tag) {
+        case Parameter::Specific::acousticEchoCanceler:
+            return setParameterAcousticEchoCanceler(specific);
+        case Parameter::Specific::automaticGainControlV1:
+            return setParameterAutomaticGainControlV1(specific);
+        case Parameter::Specific::automaticGainControlV2:
+            return setParameterAutomaticGainControlV2(specific);
+        case Parameter::Specific::noiseSuppression:
+            return setParameterNoiseSuppression(specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "specificParamNotSupported");
+    }
+}
+
+ndk::ScopedAStatus EffectPreProcessing::setParameterAcousticEchoCanceler(
+        const Parameter::Specific& specific) {
+    auto& param = specific.get<Parameter::Specific::acousticEchoCanceler>();
+    RETURN_IF(!inRange(param, kAcousticEchoCancelerRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
+    auto tag = param.getTag();
+
+    switch (tag) {
+        case AcousticEchoCanceler::echoDelayUs: {
+            RETURN_IF(mContext->setAcousticEchoCancelerEchoDelay(
+                              param.get<AcousticEchoCanceler::echoDelayUs>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "echoDelayNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case AcousticEchoCanceler::mobileMode: {
+            RETURN_IF(mContext->setAcousticEchoCancelerMobileMode(
+                              param.get<AcousticEchoCanceler::mobileMode>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "SettingMobileModeNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "AcousticEchoCancelerTagNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus EffectPreProcessing::setParameterAutomaticGainControlV1(
+        const Parameter::Specific& specific) {
+    auto& param = specific.get<Parameter::Specific::automaticGainControlV1>();
+    RETURN_IF(!inRange(param, kAutomaticGainControlV1Ranges), EX_ILLEGAL_ARGUMENT, "outOfRange");
+    auto tag = param.getTag();
+
+    switch (tag) {
+        case AutomaticGainControlV1::targetPeakLevelDbFs: {
+            RETURN_IF(mContext->setAutomaticGainControlV1TargetPeakLevel(
+                              param.get<AutomaticGainControlV1::targetPeakLevelDbFs>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "targetPeakLevelNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case AutomaticGainControlV1::maxCompressionGainDb: {
+            RETURN_IF(mContext->setAutomaticGainControlV1MaxCompressionGain(
+                              param.get<AutomaticGainControlV1::maxCompressionGainDb>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "maxCompressionGainNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case AutomaticGainControlV1::enableLimiter: {
+            RETURN_IF(
+                    mContext->setAutomaticGainControlV1EnableLimiter(
+                            param.get<AutomaticGainControlV1::enableLimiter>()) != RetCode::SUCCESS,
+                    EX_ILLEGAL_ARGUMENT, "enableLimiterNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "AutomaticGainControlV1TagNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus EffectPreProcessing::setParameterAutomaticGainControlV2(
+        const Parameter::Specific& specific) {
+    auto& param = specific.get<Parameter::Specific::automaticGainControlV2>();
+    RETURN_IF(!inRange(param, kAutomaticGainControlV2Ranges), EX_ILLEGAL_ARGUMENT, "outOfRange");
+    auto tag = param.getTag();
+
+    switch (tag) {
+        case AutomaticGainControlV2::fixedDigitalGainMb: {
+            RETURN_IF(mContext->setAutomaticGainControlV2DigitalGain(
+                              param.get<AutomaticGainControlV2::fixedDigitalGainMb>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "digitalGainNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case AutomaticGainControlV2::levelEstimator: {
+            RETURN_IF(mContext->setAutomaticGainControlV2LevelEstimator(
+                              param.get<AutomaticGainControlV2::levelEstimator>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "levelEstimatorNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case AutomaticGainControlV2::saturationMarginMb: {
+            RETURN_IF(mContext->setAutomaticGainControlV2SaturationMargin(
+                              param.get<AutomaticGainControlV2::saturationMarginMb>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "saturationMarginNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "AutomaticGainControlV2TagNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus EffectPreProcessing::setParameterNoiseSuppression(
+        const Parameter::Specific& specific) {
+    auto& param = specific.get<Parameter::Specific::noiseSuppression>();
+    auto tag = param.getTag();
+
+    switch (tag) {
+        case NoiseSuppression::level: {
+            RETURN_IF(mContext->setNoiseSuppressionLevel(param.get<NoiseSuppression::level>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "levelNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "NoiseSuppressionTagNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus EffectPreProcessing::getParameterSpecific(const Parameter::Id& id,
+                                                             Parameter::Specific* specific) {
+    RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
+    auto tag = id.getTag();
+
+    switch (tag) {
+        case Parameter::Id::acousticEchoCancelerTag:
+            return getParameterAcousticEchoCanceler(
+                    id.get<Parameter::Id::acousticEchoCancelerTag>(), specific);
+        case Parameter::Id::automaticGainControlV1Tag:
+            return getParameterAutomaticGainControlV1(
+                    id.get<Parameter::Id::automaticGainControlV1Tag>(), specific);
+        case Parameter::Id::automaticGainControlV2Tag:
+            return getParameterAutomaticGainControlV2(
+                    id.get<Parameter::Id::automaticGainControlV2Tag>(), specific);
+        case Parameter::Id::noiseSuppressionTag:
+            return getParameterNoiseSuppression(id.get<Parameter::Id::noiseSuppressionTag>(),
+                                                specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "wrongIdTag");
+    }
+}
+
+ndk::ScopedAStatus EffectPreProcessing::getParameterAcousticEchoCanceler(
+        const AcousticEchoCanceler::Id& id, Parameter::Specific* specific) {
+    RETURN_IF(id.getTag() != AcousticEchoCanceler::Id::commonTag, EX_ILLEGAL_ARGUMENT,
+              "AcousticEchoCancelerTagNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    AcousticEchoCanceler param;
+    auto tag = id.get<AcousticEchoCanceler::Id::commonTag>();
+    switch (tag) {
+        case AcousticEchoCanceler::echoDelayUs: {
+            param.set<AcousticEchoCanceler::echoDelayUs>(
+                    mContext->getAcousticEchoCancelerEchoDelay());
+            break;
+        }
+        case AcousticEchoCanceler::mobileMode: {
+            param.set<AcousticEchoCanceler::mobileMode>(
+                    mContext->getAcousticEchoCancelerMobileMode());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "AcousticEchoCancelerTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::acousticEchoCanceler>(param);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectPreProcessing::getParameterAutomaticGainControlV1(
+        const AutomaticGainControlV1::Id& id, Parameter::Specific* specific) {
+    RETURN_IF(id.getTag() != AutomaticGainControlV1::Id::commonTag, EX_ILLEGAL_ARGUMENT,
+              "AutomaticGainControlV1TagNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    AutomaticGainControlV1 param;
+
+    auto tag = id.get<AutomaticGainControlV1::Id::commonTag>();
+    switch (tag) {
+        case AutomaticGainControlV1::targetPeakLevelDbFs: {
+            param.set<AutomaticGainControlV1::targetPeakLevelDbFs>(
+                    mContext->getAutomaticGainControlV1TargetPeakLevel());
+            break;
+        }
+        case AutomaticGainControlV1::maxCompressionGainDb: {
+            param.set<AutomaticGainControlV1::maxCompressionGainDb>(
+                    mContext->getAutomaticGainControlV1MaxCompressionGain());
+            break;
+        }
+        case AutomaticGainControlV1::enableLimiter: {
+            param.set<AutomaticGainControlV1::enableLimiter>(
+                    mContext->getAutomaticGainControlV1EnableLimiter());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "AutomaticGainControlV1TagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::automaticGainControlV1>(param);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectPreProcessing::getParameterAutomaticGainControlV2(
+        const AutomaticGainControlV2::Id& id, Parameter::Specific* specific) {
+    RETURN_IF(id.getTag() != AutomaticGainControlV2::Id::commonTag, EX_ILLEGAL_ARGUMENT,
+              "AutomaticGainControlV2TagNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    AutomaticGainControlV2 param;
+
+    auto tag = id.get<AutomaticGainControlV2::Id::commonTag>();
+    switch (tag) {
+        case AutomaticGainControlV2::fixedDigitalGainMb: {
+            param.set<AutomaticGainControlV2::fixedDigitalGainMb>(
+                    mContext->getAutomaticGainControlV2DigitalGain());
+            break;
+        }
+        case AutomaticGainControlV2::levelEstimator: {
+            param.set<AutomaticGainControlV2::levelEstimator>(
+                    mContext->getAutomaticGainControlV2LevelEstimator());
+            break;
+        }
+        case AutomaticGainControlV2::saturationMarginMb: {
+            param.set<AutomaticGainControlV2::saturationMarginMb>(
+                    mContext->getAutomaticGainControlV2SaturationMargin());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "AutomaticGainControlV2TagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::automaticGainControlV2>(param);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectPreProcessing::getParameterNoiseSuppression(
+        const NoiseSuppression::Id& id, Parameter::Specific* specific) {
+    RETURN_IF(id.getTag() != NoiseSuppression::Id::commonTag, EX_ILLEGAL_ARGUMENT,
+              "NoiseSuppressionTagNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    NoiseSuppression param;
+
+    auto tag = id.get<NoiseSuppression::Id::commonTag>();
+    switch (tag) {
+        case NoiseSuppression::level: {
+            param.set<NoiseSuppression::level>(mContext->getNoiseSuppressionLevel());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "NoiseSuppressionTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::noiseSuppression>(param);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> EffectPreProcessing::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+    } else {
+        // PreProcessingSession is a singleton
+        mContext = PreProcessingSession::getPreProcessingSession().createSession(
+                mType, 1 /* statusFmqDepth */, common);
+    }
+
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> EffectPreProcessing::getContext() {
+    return mContext;
+}
+
+RetCode EffectPreProcessing::releaseContext() {
+    if (mContext) {
+        PreProcessingSession::getPreProcessingSession().releaseSession(mType,
+                                                                       mContext->getSessionId());
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+ndk::ScopedAStatus EffectPreProcessing::commandImpl(CommandId command) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    switch (command) {
+        case CommandId::START:
+            mContext->enable();
+            break;
+        case CommandId::STOP:
+            mContext->disable();
+            break;
+        case CommandId::RESET:
+            mContext->disable();
+            mContext->resetBuffer();
+            break;
+        default:
+            LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "commandIdNotSupported");
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status EffectPreProcessing::effectProcessImpl(float* in, float* out, int sampleToProcess) {
+    IEffect::Status status = {EX_NULL_POINTER, 0, 0};
+    RETURN_VALUE_IF(!mContext, status, "nullContext");
+    return mContext->lvmProcess(in, out, sampleToProcess);
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/preprocessing/aidl/EffectPreProcessing.h b/media/libeffects/preprocessing/aidl/EffectPreProcessing.h
new file mode 100644
index 0000000..fad848a
--- /dev/null
+++ b/media/libeffects/preprocessing/aidl/EffectPreProcessing.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 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 <aidl/android/hardware/audio/effect/BnEffect.h>
+
+#include "PreProcessingContext.h"
+#include "PreProcessingSession.h"
+#include "effect-impl/EffectImpl.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class EffectPreProcessing final : public EffectImpl {
+  public:
+    explicit EffectPreProcessing(const AudioUuid& uuid);
+    ~EffectPreProcessing() override;
+
+    ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+                                            Parameter::Specific* specific) override;
+
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    std::shared_ptr<EffectContext> getContext() override;
+    RetCode releaseContext() override;
+
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+
+    ndk::ScopedAStatus commandImpl(CommandId command) override;
+
+    std::string getEffectName() override { return *mEffectName; }
+
+  private:
+    std::shared_ptr<PreProcessingContext> mContext;
+    const Descriptor* mDescriptor;
+    const std::string* mEffectName;
+    PreProcessingEffectType mType;
+
+    ndk::ScopedAStatus setParameterAcousticEchoCanceler(const Parameter::Specific& specific);
+    ndk::ScopedAStatus getParameterAcousticEchoCanceler(const AcousticEchoCanceler::Id& id,
+                                                        Parameter::Specific* specific);
+
+    ndk::ScopedAStatus setParameterAutomaticGainControlV1(const Parameter::Specific& specific);
+    ndk::ScopedAStatus getParameterAutomaticGainControlV1(const AutomaticGainControlV1::Id& id,
+                                                          Parameter::Specific* specific);
+
+    ndk::ScopedAStatus setParameterAutomaticGainControlV2(const Parameter::Specific& specific);
+    ndk::ScopedAStatus getParameterAutomaticGainControlV2(const AutomaticGainControlV2::Id& id,
+                                                          Parameter::Specific* specific);
+
+    ndk::ScopedAStatus setParameterNoiseSuppression(const Parameter::Specific& specific);
+    ndk::ScopedAStatus getParameterNoiseSuppression(const NoiseSuppression::Id& id,
+                                                    Parameter::Specific* specific);
+};
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp b/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp
new file mode 100644
index 0000000..104277e
--- /dev/null
+++ b/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstddef>
+#define LOG_TAG "PreProcessingContext"
+#include <Utils.h>
+
+#include "PreProcessingContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+using aidl::android::media::audio::common::AudioDeviceDescription;
+using aidl::android::media::audio::common::AudioDeviceType;
+
+RetCode PreProcessingContext::init(const Parameter::Common& common) {
+    std::lock_guard lg(mMutex);
+    webrtc::AudioProcessingBuilder apBuilder;
+    mAudioProcessingModule = apBuilder.Create();
+    if (mAudioProcessingModule == nullptr) {
+        LOG(ERROR) << "init could not get apm engine";
+        return RetCode::ERROR_EFFECT_LIB_ERROR;
+    }
+
+    updateConfigs(common);
+
+    mEnabledMsk = 0;
+    mProcessedMsk = 0;
+    mRevEnabledMsk = 0;
+    mRevProcessedMsk = 0;
+
+    auto config = mAudioProcessingModule->GetConfig();
+    switch (mType) {
+        case PreProcessingEffectType::ACOUSTIC_ECHO_CANCELLATION:
+            config.echo_canceller.mobile_mode = true;
+            break;
+        case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V1:
+            config.gain_controller1.target_level_dbfs = kAgcDefaultTargetLevel;
+            config.gain_controller1.compression_gain_db = kAgcDefaultCompGain;
+            config.gain_controller1.enable_limiter = kAgcDefaultLimiter;
+            break;
+        case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V2:
+            config.gain_controller2.fixed_digital.gain_db = 0.f;
+            break;
+        case PreProcessingEffectType::NOISE_SUPPRESSION:
+            config.noise_suppression.level = kNsDefaultLevel;
+            break;
+    }
+    mAudioProcessingModule->ApplyConfig(config);
+    mState = PRE_PROC_STATE_INITIALIZED;
+    return RetCode::SUCCESS;
+}
+
+RetCode PreProcessingContext::deInit() {
+    std::lock_guard lg(mMutex);
+    mAudioProcessingModule = nullptr;
+    mState = PRE_PROC_STATE_UNINITIALIZED;
+    return RetCode::SUCCESS;
+}
+
+RetCode PreProcessingContext::enable() {
+    if (mState != PRE_PROC_STATE_INITIALIZED) {
+        return RetCode::ERROR_EFFECT_LIB_ERROR;
+    }
+    int typeMsk = (1 << int(mType));
+    std::lock_guard lg(mMutex);
+    // Check if effect is already enabled.
+    if ((mEnabledMsk & typeMsk) == typeMsk) {
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    mEnabledMsk |= typeMsk;
+    auto config = mAudioProcessingModule->GetConfig();
+    switch (mType) {
+        case PreProcessingEffectType::ACOUSTIC_ECHO_CANCELLATION:
+            config.echo_canceller.enabled = true;
+            // AEC has reverse stream
+            mRevEnabledMsk |= typeMsk;
+            mRevProcessedMsk = 0;
+            break;
+        case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V1:
+            config.gain_controller1.enabled = true;
+            break;
+        case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V2:
+            config.gain_controller2.enabled = true;
+            break;
+        case PreProcessingEffectType::NOISE_SUPPRESSION:
+            config.noise_suppression.enabled = true;
+            break;
+    }
+    mProcessedMsk = 0;
+    mAudioProcessingModule->ApplyConfig(config);
+    mState = PRE_PROC_STATE_ACTIVE;
+    return RetCode::SUCCESS;
+}
+
+RetCode PreProcessingContext::disable() {
+    if (mState != PRE_PROC_STATE_ACTIVE) {
+        return RetCode::ERROR_EFFECT_LIB_ERROR;
+    }
+    int typeMsk = (1 << int(mType));
+    std::lock_guard lg(mMutex);
+    // Check if effect is already disabled.
+    if ((mEnabledMsk & typeMsk) != typeMsk) {
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    mEnabledMsk &= ~typeMsk;
+    auto config = mAudioProcessingModule->GetConfig();
+    switch (mType) {
+        case PreProcessingEffectType::ACOUSTIC_ECHO_CANCELLATION:
+            config.echo_canceller.enabled = false;
+            // AEC has reverse stream
+            mRevEnabledMsk &= ~typeMsk;
+            mRevProcessedMsk = 0;
+            break;
+        case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V1:
+            config.gain_controller1.enabled = false;
+            break;
+        case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V2:
+            config.gain_controller2.enabled = false;
+            break;
+        case PreProcessingEffectType::NOISE_SUPPRESSION:
+            config.noise_suppression.enabled = false;
+            break;
+    }
+    mProcessedMsk = 0;
+    mAudioProcessingModule->ApplyConfig(config);
+    mState = PRE_PROC_STATE_INITIALIZED;
+    return RetCode::SUCCESS;
+}
+
+RetCode PreProcessingContext::setCommon(const Parameter::Common& common) {
+    mCommon = common;
+    updateConfigs(common);
+    return RetCode::SUCCESS;
+}
+
+void PreProcessingContext::updateConfigs(const Parameter::Common& common) {
+    mInputConfig.set_sample_rate_hz(common.input.base.sampleRate);
+    mInputConfig.set_num_channels(
+            ::android::hardware::audio::common::getChannelCount(common.input.base.channelMask));
+    mOutputConfig.set_sample_rate_hz(common.input.base.sampleRate);
+    mOutputConfig.set_num_channels(
+            ::android::hardware::audio::common::getChannelCount(common.output.base.channelMask));
+}
+
+RetCode PreProcessingContext::setAcousticEchoCancelerEchoDelay(int echoDelayUs) {
+    mEchoDelayUs = echoDelayUs;
+    std::lock_guard lg(mMutex);
+    mAudioProcessingModule->set_stream_delay_ms(mEchoDelayUs / 1000);
+    return RetCode::SUCCESS;
+}
+
+int PreProcessingContext::getAcousticEchoCancelerEchoDelay() const {
+    return mEchoDelayUs;
+}
+
+RetCode PreProcessingContext::setAcousticEchoCancelerMobileMode(bool mobileMode) {
+    mMobileMode = mobileMode;
+    std::lock_guard lg(mMutex);
+    auto config = mAudioProcessingModule->GetConfig();
+    config.echo_canceller.mobile_mode = mobileMode;
+    mAudioProcessingModule->ApplyConfig(config);
+    return RetCode::SUCCESS;
+}
+
+bool PreProcessingContext::getAcousticEchoCancelerMobileMode() const {
+    return mMobileMode;
+}
+
+RetCode PreProcessingContext::setAutomaticGainControlV1TargetPeakLevel(int targetPeakLevel) {
+    mTargetPeakLevel = targetPeakLevel;
+    std::lock_guard lg(mMutex);
+    auto config = mAudioProcessingModule->GetConfig();
+    config.gain_controller1.target_level_dbfs = -(mTargetPeakLevel / 100);
+    mAudioProcessingModule->ApplyConfig(config);
+    return RetCode::SUCCESS;
+}
+
+int PreProcessingContext::getAutomaticGainControlV1TargetPeakLevel() const {
+    return mTargetPeakLevel;
+}
+
+RetCode PreProcessingContext::setAutomaticGainControlV1MaxCompressionGain(int maxCompressionGain) {
+    mMaxCompressionGain = maxCompressionGain;
+    std::lock_guard lg(mMutex);
+    auto config = mAudioProcessingModule->GetConfig();
+    config.gain_controller1.compression_gain_db = mMaxCompressionGain / 100;
+    mAudioProcessingModule->ApplyConfig(config);
+    return RetCode::SUCCESS;
+}
+
+int PreProcessingContext::getAutomaticGainControlV1MaxCompressionGain() const {
+    return mMaxCompressionGain;
+}
+
+RetCode PreProcessingContext::setAutomaticGainControlV1EnableLimiter(bool enableLimiter) {
+    mEnableLimiter = enableLimiter;
+    std::lock_guard lg(mMutex);
+    auto config = mAudioProcessingModule->GetConfig();
+    config.gain_controller1.enable_limiter = mEnableLimiter;
+    mAudioProcessingModule->ApplyConfig(config);
+    return RetCode::SUCCESS;
+}
+
+bool PreProcessingContext::getAutomaticGainControlV1EnableLimiter() const {
+    return mEnableLimiter;
+}
+
+RetCode PreProcessingContext::setAutomaticGainControlV2DigitalGain(int gain) {
+    mDigitalGain = gain;
+    std::lock_guard lg(mMutex);
+    auto config = mAudioProcessingModule->GetConfig();
+    config.gain_controller2.fixed_digital.gain_db = mDigitalGain;
+    mAudioProcessingModule->ApplyConfig(config);
+    return RetCode::SUCCESS;
+}
+
+int PreProcessingContext::getAutomaticGainControlV2DigitalGain() const {
+    return mDigitalGain;
+}
+
+RetCode PreProcessingContext::setAutomaticGainControlV2LevelEstimator(
+        AutomaticGainControlV2::LevelEstimator levelEstimator) {
+    mLevelEstimator = levelEstimator;
+    return RetCode::SUCCESS;
+}
+
+AutomaticGainControlV2::LevelEstimator
+PreProcessingContext::getAutomaticGainControlV2LevelEstimator() const {
+    return mLevelEstimator;
+}
+
+RetCode PreProcessingContext::setAutomaticGainControlV2SaturationMargin(int saturationMargin) {
+    mSaturationMargin = saturationMargin;
+    return RetCode::SUCCESS;
+}
+
+int PreProcessingContext::getAutomaticGainControlV2SaturationMargin() const {
+    return mSaturationMargin;
+}
+
+RetCode PreProcessingContext::setNoiseSuppressionLevel(NoiseSuppression::Level level) {
+    mLevel = level;
+    std::lock_guard lg(mMutex);
+    auto config = mAudioProcessingModule->GetConfig();
+    config.noise_suppression.level =
+            (webrtc::AudioProcessing::Config::NoiseSuppression::Level)level;
+    mAudioProcessingModule->ApplyConfig(config);
+    return RetCode::SUCCESS;
+}
+
+NoiseSuppression::Level PreProcessingContext::getNoiseSuppressionLevel() const {
+    return mLevel;
+}
+
+IEffect::Status PreProcessingContext::lvmProcess(float* in, float* out, int samples) {
+    IEffect::Status status = {EX_NULL_POINTER, 0, 0};
+    RETURN_VALUE_IF(!in, status, "nullInput");
+    RETURN_VALUE_IF(!out, status, "nullOutput");
+    status = {EX_ILLEGAL_STATE, 0, 0};
+    int64_t inputFrameCount = getCommon().input.frameCount;
+    int64_t outputFrameCount = getCommon().output.frameCount;
+    RETURN_VALUE_IF(inputFrameCount != outputFrameCount, status, "FrameCountMismatch");
+    RETURN_VALUE_IF(0 == getInputFrameSize(), status, "zeroFrameSize");
+
+    LOG(DEBUG) << __func__ << " start processing";
+    std::lock_guard lg(mMutex);
+
+    mProcessedMsk |= (1 << int(mType));
+
+    // webrtc implementation clear out was_stream_delay_set every time after ProcessStream() call
+    mAudioProcessingModule->set_stream_delay_ms(mEchoDelayUs / 1000);
+
+    if ((mProcessedMsk & mEnabledMsk) == mEnabledMsk) {
+        mProcessedMsk = 0;
+        int processStatus = mAudioProcessingModule->ProcessStream(
+                (const int16_t* const)in, mInputConfig, mOutputConfig, (int16_t* const)out);
+        if (processStatus != 0) {
+            LOG(ERROR) << "Process stream failed with error " << processStatus;
+            return status;
+        }
+    }
+
+    mRevProcessedMsk |= (1 << int(mType));
+
+    if ((mRevProcessedMsk & mRevEnabledMsk) == mRevEnabledMsk) {
+        mRevProcessedMsk = 0;
+        int revProcessStatus = mAudioProcessingModule->ProcessReverseStream(
+                (const int16_t* const)in, mInputConfig, mInputConfig, (int16_t* const)out);
+        if (revProcessStatus != 0) {
+            LOG(ERROR) << "Process reverse stream failed with error " << revProcessStatus;
+            return status;
+        }
+    }
+
+    return {STATUS_OK, samples, samples};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/preprocessing/aidl/PreProcessingContext.h b/media/libeffects/preprocessing/aidl/PreProcessingContext.h
new file mode 100644
index 0000000..9ba1bbe
--- /dev/null
+++ b/media/libeffects/preprocessing/aidl/PreProcessingContext.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2023 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 <android-base/logging.h>
+#include <android-base/thread_annotations.h>
+#include <audio_processing.h>
+#include <unordered_map>
+
+#include "PreProcessingTypes.h"
+#include "effect-impl/EffectContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+enum PreProcEffectState {
+    PRE_PROC_STATE_UNINITIALIZED,
+    PRE_PROC_STATE_INITIALIZED,
+    PRE_PROC_STATE_ACTIVE,
+};
+
+class PreProcessingContext final : public EffectContext {
+  public:
+    PreProcessingContext(int statusDepth, const Parameter::Common& common,
+                         const PreProcessingEffectType& type)
+        : EffectContext(statusDepth, common), mType(type) {
+        LOG(DEBUG) << __func__ << type;
+        mState = PRE_PROC_STATE_UNINITIALIZED;
+    }
+    ~PreProcessingContext() override { LOG(DEBUG) << __func__; }
+
+    RetCode init(const Parameter::Common& common);
+    RetCode deInit();
+
+    PreProcessingEffectType getPreProcessingType() const { return mType; }
+
+    RetCode enable();
+    RetCode disable();
+
+    RetCode setCommon(const Parameter::Common& common) override;
+    void updateConfigs(const Parameter::Common& common);
+
+    RetCode setAcousticEchoCancelerEchoDelay(int echoDelayUs);
+    int getAcousticEchoCancelerEchoDelay() const;
+    RetCode setAcousticEchoCancelerMobileMode(bool mobileMode);
+    bool getAcousticEchoCancelerMobileMode() const;
+
+    RetCode setAutomaticGainControlV1TargetPeakLevel(int targetPeakLevel);
+    int getAutomaticGainControlV1TargetPeakLevel() const;
+    RetCode setAutomaticGainControlV1MaxCompressionGain(int maxCompressionGain);
+    int getAutomaticGainControlV1MaxCompressionGain() const;
+    RetCode setAutomaticGainControlV1EnableLimiter(bool enableLimiter);
+    bool getAutomaticGainControlV1EnableLimiter() const;
+
+    RetCode setAutomaticGainControlV2DigitalGain(int gain);
+    int getAutomaticGainControlV2DigitalGain() const;
+    RetCode setAutomaticGainControlV2LevelEstimator(
+            AutomaticGainControlV2::LevelEstimator levelEstimator);
+    AutomaticGainControlV2::LevelEstimator getAutomaticGainControlV2LevelEstimator() const;
+    RetCode setAutomaticGainControlV2SaturationMargin(int saturationMargin);
+    int getAutomaticGainControlV2SaturationMargin() const;
+
+    RetCode setNoiseSuppressionLevel(NoiseSuppression::Level level);
+    NoiseSuppression::Level getNoiseSuppressionLevel() const;
+
+    IEffect::Status lvmProcess(float* in, float* out, int samples);
+
+  private:
+    static constexpr inline int kAgcDefaultTargetLevel = 3;
+    static constexpr inline int kAgcDefaultCompGain = 9;
+    static constexpr inline bool kAgcDefaultLimiter = true;
+    static constexpr inline webrtc::AudioProcessing::Config::NoiseSuppression::Level
+            kNsDefaultLevel = webrtc::AudioProcessing::Config::NoiseSuppression::kModerate;
+
+    std::mutex mMutex;
+    const PreProcessingEffectType mType;
+    PreProcEffectState mState;  // current state
+
+    // handle on webRTC audio processing module (APM)
+    rtc::scoped_refptr<webrtc::AudioProcessing> mAudioProcessingModule GUARDED_BY(mMutex);
+
+    int mEnabledMsk GUARDED_BY(mMutex);       // bit field containing IDs of enabled pre processors
+    int mProcessedMsk GUARDED_BY(mMutex);     // bit field containing IDs of pre processors already
+                                              // processed in current round
+    int mRevEnabledMsk GUARDED_BY(mMutex);    // bit field containing IDs of enabled pre processors
+                                              // with reverse channel
+    int mRevProcessedMsk GUARDED_BY(mMutex);  // bit field containing IDs of pre processors with
+                                              // reverse channel already processed in current round
+
+    webrtc::StreamConfig mInputConfig;   // input stream configuration
+    webrtc::StreamConfig mOutputConfig;  // output stream configuration
+
+    // Acoustic Echo Canceler
+    int mEchoDelayUs = 0;
+    bool mMobileMode = false;
+
+    // Automatic Gain Control V1
+    int mTargetPeakLevel = 0;
+    int mMaxCompressionGain = 0;
+    bool mEnableLimiter = false;
+
+    // Automatic Gain Control V2
+    int mDigitalGain = 0;
+    AutomaticGainControlV2::LevelEstimator mLevelEstimator =
+            AutomaticGainControlV2::LevelEstimator::RMS;
+    int mSaturationMargin = 2;
+
+    // NoiseSuppression
+    NoiseSuppression::Level mLevel = NoiseSuppression::Level::LOW;
+};
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/preprocessing/aidl/PreProcessingSession.h b/media/libeffects/preprocessing/aidl/PreProcessingSession.h
new file mode 100644
index 0000000..877292f
--- /dev/null
+++ b/media/libeffects/preprocessing/aidl/PreProcessingSession.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2023 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 <unordered_map>
+
+#include <android-base/logging.h>
+#include <android-base/thread_annotations.h>
+
+#include "PreProcessingContext.h"
+#include "PreProcessingTypes.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+/**
+ * @brief Maintain all effect pre-processing sessions.
+ *
+ * Sessions are identified with the session ID, maximum of MAX_BUNDLE_SESSIONS is supported by the
+ * pre-processing implementation.
+ */
+class PreProcessingSession {
+  public:
+    static PreProcessingSession& getPreProcessingSession() {
+        static PreProcessingSession instance;
+        return instance;
+    }
+
+    static bool findPreProcessingTypeInList(
+            std::vector<std::shared_ptr<PreProcessingContext>>& list,
+            const PreProcessingEffectType& type, bool remove = false) {
+        auto itor = std::find_if(list.begin(), list.end(),
+                                 [type](const std::shared_ptr<PreProcessingContext>& bundle) {
+                                     return bundle->getPreProcessingType() == type;
+                                 });
+        if (itor == list.end()) {
+            return false;
+        }
+        if (remove) {
+            (*itor)->deInit();
+            list.erase(itor);
+        }
+        return true;
+    }
+
+    /**
+     * Create a certain type of PreProcessingContext in shared_ptr container, each session must not
+     * have more than one session for each type.
+     */
+    std::shared_ptr<PreProcessingContext> createSession(const PreProcessingEffectType& type,
+                                                        int statusDepth,
+                                                        const Parameter::Common& common) {
+        int sessionId = common.session;
+        LOG(DEBUG) << __func__ << type << " with sessionId " << sessionId;
+        std::lock_guard lg(mMutex);
+        if (mSessionMap.count(sessionId) == 0 && mSessionMap.size() >= MAX_PRE_PROC_SESSIONS) {
+            LOG(ERROR) << __func__ << " exceed max bundle session";
+            return nullptr;
+        }
+
+        if (mSessionMap.count(sessionId)) {
+            if (findPreProcessingTypeInList(mSessionMap[sessionId], type)) {
+                LOG(ERROR) << __func__ << type << " already exist in session " << sessionId;
+                return nullptr;
+            }
+        }
+
+        auto& list = mSessionMap[sessionId];
+        auto context = std::make_shared<PreProcessingContext>(statusDepth, common, type);
+        RETURN_VALUE_IF(!context, nullptr, "failedToCreateContext");
+
+        RetCode ret = context->init(common);
+        if (RetCode::SUCCESS != ret) {
+            LOG(ERROR) << __func__ << " context init ret " << ret;
+            return nullptr;
+        }
+        list.push_back(context);
+        return context;
+    }
+
+    void releaseSession(const PreProcessingEffectType& type, int sessionId) {
+        LOG(DEBUG) << __func__ << type << " sessionId " << sessionId;
+        std::lock_guard lg(mMutex);
+        if (mSessionMap.count(sessionId)) {
+            auto& list = mSessionMap[sessionId];
+            if (!findPreProcessingTypeInList(list, type, true /* remove */)) {
+                LOG(ERROR) << __func__ << " can't find " << type << "in session " << sessionId;
+                return;
+            }
+            if (list.empty()) {
+                mSessionMap.erase(sessionId);
+            }
+        }
+    }
+
+  private:
+    // Lock for mSessionMap access.
+    std::mutex mMutex;
+    // Max session number supported.
+    static constexpr int MAX_PRE_PROC_SESSIONS = 8;
+    std::unordered_map<int /* session ID */, std::vector<std::shared_ptr<PreProcessingContext>>>
+            mSessionMap GUARDED_BY(mMutex);
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/preprocessing/aidl/PreProcessingTypes.h b/media/libeffects/preprocessing/aidl/PreProcessingTypes.h
new file mode 100644
index 0000000..2c880d4
--- /dev/null
+++ b/media/libeffects/preprocessing/aidl/PreProcessingTypes.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2023 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 <aidl/android/hardware/audio/effect/BnEffect.h>
+
+#include <audio_effects/effect_aec.h>
+#include <audio_effects/effect_agc.h>
+#include <audio_effects/effect_agc2.h>
+#include <audio_effects/effect_ns.h>
+
+#include "effect-impl/EffectTypes.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+// Acoustic Echo Cancellation
+static const std::string kAcousticEchoCancelerEffectName = "Acoustic Echo Canceler";
+static const std::vector<Range::AcousticEchoCancelerRange> kAcousticEchoCancelerRanges = {
+        MAKE_RANGE(AcousticEchoCanceler, AcousticEchoCanceler::echoDelayUs, 0, 500)};
+static const Capability kAcousticEchoCancelerCap = {.range = kAcousticEchoCancelerRanges};
+static const Descriptor kAcousticEchoCancelerDesc = {
+        .common = {.id = {.type = kAcousticEchoCancelerTypeUUID,
+                          .uuid = kAcousticEchoCancelerSwImplUUID,
+                          .proxy = kEffectNullUuid},
+                   .flags = {.type = Flags::Type::PRE_PROC, .deviceIndication = true},
+                   .name = kAcousticEchoCancelerEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = kAcousticEchoCancelerCap};
+
+// Automatic Gain Control 1
+static const std::string kAutomaticGainControlV1EffectName = "Automatic Gain Control V1";
+static const std::vector<Range::AutomaticGainControlV1Range> kAutomaticGainControlV1Ranges = {
+        MAKE_RANGE(AutomaticGainControlV1, AutomaticGainControlV1::targetPeakLevelDbFs, -3100, 0),
+        MAKE_RANGE(AutomaticGainControlV1, AutomaticGainControlV1::maxCompressionGainDb, 0, 9000)};
+static const Capability kAutomaticGainControlV1Cap = {.range = kAutomaticGainControlV1Ranges};
+static const Descriptor kAutomaticGainControlV1Desc = {
+        .common = {.id = {.type = kAutomaticGainControlV1TypeUUID,
+                          .uuid = kAutomaticGainControlV1SwImplUUID,
+                          .proxy = kEffectNullUuid},
+                   .flags = {.type = Flags::Type::PRE_PROC, .deviceIndication = true},
+                   .name = kAutomaticGainControlV1EffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = kAutomaticGainControlV1Cap};
+
+// Automatic Gain Control 2
+static const std::string kAutomaticGainControlV2EffectName = "Automatic Gain Control V2";
+const std::vector<Range::AutomaticGainControlV2Range> kAutomaticGainControlV2Ranges = {
+        MAKE_RANGE(AutomaticGainControlV2, AutomaticGainControlV2::fixedDigitalGainMb, 0, 90),
+        // extra_staturation_margin_db is no longer configurable in webrtc
+        MAKE_RANGE(AutomaticGainControlV2, AutomaticGainControlV2::saturationMarginMb, 2, 2),
+        // WebRTC only supports RMS level estimator now
+        MAKE_RANGE(AutomaticGainControlV2, AutomaticGainControlV2::levelEstimator,
+                   AutomaticGainControlV2::LevelEstimator::RMS,
+                   AutomaticGainControlV2::LevelEstimator::RMS)};
+static const Capability kAutomaticGainControlV2Cap = {.range = kAutomaticGainControlV2Ranges};
+static const Descriptor kAutomaticGainControlV2Desc = {
+        .common = {.id = {.type = kAutomaticGainControlV2TypeUUID,
+                          .uuid = kAutomaticGainControlV2SwImplUUID,
+                          .proxy = kEffectNullUuid},
+                   .flags = {.type = Flags::Type::PRE_PROC, .deviceIndication = true},
+                   .name = kAutomaticGainControlV2EffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = kAutomaticGainControlV2Cap};
+
+// Noise suppression
+static const std::string kNoiseSuppressionEffectName = "Noise Suppression";
+static const Descriptor kNoiseSuppressionDesc = {
+        .common = {.id = {.type = kNoiseSuppressionTypeUUID,
+                          .uuid = kNoiseSuppressionSwImplUUID,
+                          .proxy = kEffectNullUuid},
+                   .flags = {.type = Flags::Type::PRE_PROC, .deviceIndication = true},
+                   .name = kNoiseSuppressionEffectName,
+                   .implementor = "The Android Open Source Project"}};
+
+enum class PreProcessingEffectType {
+    ACOUSTIC_ECHO_CANCELLATION,
+    AUTOMATIC_GAIN_CONTROL_V1,
+    AUTOMATIC_GAIN_CONTROL_V2,
+    NOISE_SUPPRESSION,
+};
+
+inline std::ostream& operator<<(std::ostream& out, const PreProcessingEffectType& type) {
+    switch (type) {
+        case PreProcessingEffectType::ACOUSTIC_ECHO_CANCELLATION:
+            return out << kAcousticEchoCancelerEffectName;
+        case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V1:
+            return out << kAutomaticGainControlV1EffectName;
+        case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V2:
+            return out << kAutomaticGainControlV2EffectName;
+        case PreProcessingEffectType::NOISE_SUPPRESSION:
+            return out << kNoiseSuppressionEffectName;
+    }
+    return out << "EnumPreProcessingEffectTypeError";
+}
+
+}  // namespace aidl::android::hardware::audio::effect