Merge "Camera: Add adb shell cmd to override stream use case"
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index f95d527..fc1780d 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -71,7 +71,7 @@
     mCryptoHalHidl->notifyResolution(width, height);
 }
 
-status_t CryptoHal::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
+DrmStatus CryptoHal::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
     // This requires plugin to be created.
     if (mCryptoHalAidl->initCheck() == OK) return mCryptoHalAidl->setMediaDrmSession(sessionId);
     return mCryptoHalHidl->setMediaDrmSession(sessionId);
diff --git a/drm/libmediadrm/CryptoHalAidl.cpp b/drm/libmediadrm/CryptoHalAidl.cpp
index f01ecb3..c1fd797 100644
--- a/drm/libmediadrm/CryptoHalAidl.cpp
+++ b/drm/libmediadrm/CryptoHalAidl.cpp
@@ -260,7 +260,7 @@
     }
 }
 
-status_t CryptoHalAidl::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
+DrmStatus CryptoHalAidl::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
     Mutex::Autolock autoLock(mLock);
 
     if (mInitCheck != OK) {
diff --git a/drm/libmediadrm/CryptoHalHidl.cpp b/drm/libmediadrm/CryptoHalHidl.cpp
index 55364b5..458a1ae 100644
--- a/drm/libmediadrm/CryptoHalHidl.cpp
+++ b/drm/libmediadrm/CryptoHalHidl.cpp
@@ -386,7 +386,7 @@
     ALOGE_IF(!hResult.isOk(), "notifyResolution txn failed %s", hResult.description().c_str());
 }
 
-status_t CryptoHalHidl::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
+DrmStatus CryptoHalHidl::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
     Mutex::Autolock autoLock(mLock);
 
     if (mInitCheck != OK) {
diff --git a/drm/libmediadrm/include/mediadrm/CryptoHal.h b/drm/libmediadrm/include/mediadrm/CryptoHal.h
index 32a6741..60cbbf8 100644
--- a/drm/libmediadrm/include/mediadrm/CryptoHal.h
+++ b/drm/libmediadrm/include/mediadrm/CryptoHal.h
@@ -38,7 +38,7 @@
     virtual bool requiresSecureDecoderComponent(
             const char *mime) const;
     virtual void notifyResolution(uint32_t width, uint32_t height);
-    virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId);
+    virtual DrmStatus setMediaDrmSession(const Vector<uint8_t> &sessionId);
     virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
             CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
             const drm::V1_0::SharedBuffer &source, size_t offset,
diff --git a/drm/libmediadrm/include/mediadrm/CryptoHalAidl.h b/drm/libmediadrm/include/mediadrm/CryptoHalAidl.h
index 50878a6..eec4585 100644
--- a/drm/libmediadrm/include/mediadrm/CryptoHalAidl.h
+++ b/drm/libmediadrm/include/mediadrm/CryptoHalAidl.h
@@ -49,7 +49,7 @@
     virtual status_t destroyPlugin();
     virtual bool requiresSecureDecoderComponent(const char* mime) const;
     virtual void notifyResolution(uint32_t width, uint32_t height);
-    virtual status_t setMediaDrmSession(const Vector<uint8_t>& sessionId);
+    virtual DrmStatus setMediaDrmSession(const Vector<uint8_t>& sessionId);
     virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16], CryptoPlugin::Mode mode,
                             const CryptoPlugin::Pattern& pattern, const ::SharedBuffer& source,
                             size_t offset, const CryptoPlugin::SubSample* subSamples,
diff --git a/drm/libmediadrm/include/mediadrm/CryptoHalHidl.h b/drm/libmediadrm/include/mediadrm/CryptoHalHidl.h
index 6db1e89..0150d7c 100644
--- a/drm/libmediadrm/include/mediadrm/CryptoHalHidl.h
+++ b/drm/libmediadrm/include/mediadrm/CryptoHalHidl.h
@@ -57,7 +57,7 @@
 
     virtual void notifyResolution(uint32_t width, uint32_t height);
 
-    virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId);
+    virtual DrmStatus setMediaDrmSession(const Vector<uint8_t> &sessionId);
 
     virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
             CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
diff --git a/drm/libmediadrm/include/mediadrm/DrmStatus.h b/drm/libmediadrm/interface/mediadrm/DrmStatus.h
similarity index 100%
rename from drm/libmediadrm/include/mediadrm/DrmStatus.h
rename to drm/libmediadrm/interface/mediadrm/DrmStatus.h
diff --git a/drm/libmediadrm/interface/mediadrm/ICrypto.h b/drm/libmediadrm/interface/mediadrm/ICrypto.h
index 2c4df60..4087186 100644
--- a/drm/libmediadrm/interface/mediadrm/ICrypto.h
+++ b/drm/libmediadrm/interface/mediadrm/ICrypto.h
@@ -17,6 +17,7 @@
 #include <cutils/native_handle.h>
 #include <media/hardware/CryptoAPI.h>
 #include <media/stagefright/foundation/ABase.h>
+#include <mediadrm/DrmStatus.h>
 #include <utils/RefBase.h>
 #include <utils/StrongPointer.h>
 
@@ -65,7 +66,7 @@
 
     virtual void notifyResolution(uint32_t width, uint32_t height) = 0;
 
-    virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId) = 0;
+    virtual DrmStatus setMediaDrmSession(const Vector<uint8_t> &sessionId) = 0;
 
     enum DestinationType {
         kDestinationTypeSharedMemory, // non-secure
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index 42e4717..6dfcc6b 100644
--- a/media/audioaidlconversion/AidlConversionCppNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionCppNdk.cpp
@@ -29,7 +29,7 @@
 #include <media/stagefright/foundation/MediaDefs.h>
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
-// Utilities
+// AIDL CPP/NDK backend to legacy audio data structure conversion utilities.
 
 #if defined(BACKEND_NDK)
 /* AIDL String generated in NDK is different than CPP */
@@ -846,8 +846,8 @@
         case Tag::indexMask:
             // Index masks do not have pre-defined values.
             if (const int bits = aidl.get<Tag::indexMask>();
-                    __builtin_popcount(bits) != 0 &&
-                    __builtin_popcount(bits) <= AUDIO_CHANNEL_COUNT_MAX) {
+                __builtin_popcount(bits) != 0 &&
+                __builtin_popcount(bits) <= (int)AUDIO_CHANNEL_COUNT_MAX) {
                 return audio_channel_mask_from_representation_and_bits(
                         AUDIO_CHANNEL_REPRESENTATION_INDEX, bits);
             } else {
@@ -1123,7 +1123,7 @@
     for (size_t i = 0; i < numValues; ++i) {
         legacy.values[i] = VALUE_OR_RETURN(convertIntegral<int>(aidl.values[i]));
     }
-    legacy.ramp_duration_ms = VALUE_OR_RETURN(convertIntegral<unsigned int>(aidl.rampDurationMs));
+    legacy.ramp_duration_ms = VALUE_OR_RETURN(convertIntegral<int>(aidl.rampDurationMs));
     return legacy;
 }
 
@@ -1167,6 +1167,10 @@
             return AUDIO_INPUT_FLAG_DIRECT;
         case AudioInputFlags::ULTRASOUND:
             return AUDIO_INPUT_FLAG_ULTRASOUND;
+        case AudioInputFlags::HOTWORD_TAP:
+            return AUDIO_INPUT_FLAG_HOTWORD_TAP;
+        case AudioInputFlags::HW_LOOKBACK:
+            return AUDIO_INPUT_FLAG_HW_LOOKBACK;
     }
     return unexpected(BAD_VALUE);
 }
@@ -1194,6 +1198,10 @@
             return AudioInputFlags::DIRECT;
         case AUDIO_INPUT_FLAG_ULTRASOUND:
             return AudioInputFlags::ULTRASOUND;
+        case AUDIO_INPUT_FLAG_HOTWORD_TAP:
+            return AudioInputFlags::HOTWORD_TAP;
+        case AUDIO_INPUT_FLAG_HW_LOOKBACK:
+            return AudioInputFlags::HW_LOOKBACK;
     }
     return unexpected(BAD_VALUE);
 }
@@ -1710,12 +1718,12 @@
     legacy.format = base.format;
     legacy.stream_type = VALUE_OR_RETURN(
             aidl2legacy_AudioStreamType_audio_stream_type_t(aidl.streamType));
-    legacy.bit_rate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.bitRatePerSecond));
+    legacy.bit_rate = VALUE_OR_RETURN(convertIntegral<int32_t>(aidl.bitRatePerSecond));
     legacy.duration_us = VALUE_OR_RETURN(convertIntegral<int64_t>(aidl.durationUs));
     legacy.has_video = aidl.hasVideo;
     legacy.is_streaming = aidl.isStreaming;
-    legacy.bit_width = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.bitWidth));
-    legacy.offload_buffer_size = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.offloadBufferSize));
+    legacy.bit_width = VALUE_OR_RETURN(convertIntegral<int32_t>(aidl.bitWidth));
+    legacy.offload_buffer_size = VALUE_OR_RETURN(convertIntegral<int32_t>(aidl.offloadBufferSize));
     legacy.usage = VALUE_OR_RETURN(aidl2legacy_AudioUsage_audio_usage_t(aidl.usage));
     legacy.encapsulation_mode = VALUE_OR_RETURN(
             aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t(aidl.encapsulationMode));
@@ -1789,7 +1797,7 @@
 ConversionResult<audio_config_base_t>
 aidl2legacy_AudioConfigBase_audio_config_base_t(const AudioConfigBase& aidl, bool isInput) {
     audio_config_base_t legacy;
-    legacy.sample_rate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.sampleRate));
+    legacy.sample_rate = VALUE_OR_RETURN(convertIntegral<int>(aidl.sampleRate));
     legacy.channel_mask = VALUE_OR_RETURN(
             aidl2legacy_AudioChannelLayout_audio_channel_mask_t(aidl.channelMask, isInput));
     legacy.format = VALUE_OR_RETURN(aidl2legacy_AudioFormatDescription_audio_format_t(aidl.format));
@@ -2271,4 +2279,4 @@
 
 #if defined(BACKEND_NDK)
 }  // aidl
-#endif
\ No newline at end of file
+#endif
diff --git a/media/audioaidlconversion/AidlConversionNdk.cpp b/media/audioaidlconversion/AidlConversionNdk.cpp
new file mode 100644
index 0000000..a3e39c7
--- /dev/null
+++ b/media/audioaidlconversion/AidlConversionNdk.cpp
@@ -0,0 +1,259 @@
+/*
+ * 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 <utility>
+
+#define LOG_TAG "AidlConversionNdk"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <media/AidlConversionCppNdk.h>
+#include <media/AidlConversionNdk.h>
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// AIDL NDK backend to legacy audio data structure conversion utilities.
+
+namespace aidl {
+namespace android {
+
+using ::aidl::android::hardware::audio::effect::Descriptor;
+using ::aidl::android::hardware::audio::effect::Flags;
+
+using ::android::BAD_VALUE;
+using ::android::base::unexpected;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Converters
+
+ConversionResult<uint32_t> aidl2legacy_Flags_Type_uint32(Flags::Type type) {
+    switch (type) {
+        case Flags::Type::INSERT:
+            return EFFECT_FLAG_TYPE_INSERT;
+        case Flags::Type::AUXILIARY:
+            return EFFECT_FLAG_TYPE_AUXILIARY;
+        case Flags::Type::REPLACE:
+            return EFFECT_FLAG_TYPE_REPLACE;
+        case Flags::Type::PRE_PROC:
+            return EFFECT_FLAG_TYPE_PRE_PROC;
+        case Flags::Type::POST_PROC:
+            return EFFECT_FLAG_TYPE_POST_PROC;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<uint32_t> aidl2legacy_Flags_Insert_uint32(Flags::Insert insert) {
+    switch (insert) {
+        case Flags::Insert::ANY:
+            return EFFECT_FLAG_INSERT_ANY;
+        case Flags::Insert::FIRST:
+            return EFFECT_FLAG_INSERT_FIRST;
+        case Flags::Insert::LAST:
+            return EFFECT_FLAG_INSERT_LAST;
+        case Flags::Insert::EXCLUSIVE:
+            return EFFECT_FLAG_INSERT_EXCLUSIVE;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<uint32_t> aidl2legacy_Flags_Volume_uint32(Flags::Volume volume) {
+    switch (volume) {
+        case Flags::Volume::NONE:
+            return 0;
+        case Flags::Volume::CTRL:
+            return EFFECT_FLAG_VOLUME_CTRL;
+        case Flags::Volume::IND:
+            return EFFECT_FLAG_VOLUME_IND;
+        case Flags::Volume::MONITOR:
+            return EFFECT_FLAG_VOLUME_MONITOR;
+    }
+    return unexpected(BAD_VALUE);
+}
+ConversionResult<uint32_t> aidl2legacy_Flags_HardwareAccelerator_uint32(
+        Flags::HardwareAccelerator hwAcceleratorMode) {
+    switch (hwAcceleratorMode) {
+        case Flags::HardwareAccelerator::NONE:
+            return 0;
+        case Flags::HardwareAccelerator::SIMPLE:
+            return EFFECT_FLAG_HW_ACC_SIMPLE;
+        case Flags::HardwareAccelerator::TUNNEL:
+            return EFFECT_FLAG_HW_ACC_TUNNEL;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<uint32_t> aidl2legacy_Flags_uint32(Flags aidl) {
+    uint32_t legacy = 0;
+    legacy |= VALUE_OR_RETURN(aidl2legacy_Flags_Type_uint32(aidl.type));
+    legacy |= VALUE_OR_RETURN(aidl2legacy_Flags_Insert_uint32(aidl.insert));
+    legacy |= VALUE_OR_RETURN(aidl2legacy_Flags_Volume_uint32(aidl.volume));
+    legacy |= VALUE_OR_RETURN(aidl2legacy_Flags_HardwareAccelerator_uint32(aidl.hwAcceleratorMode));
+
+    if (aidl.offloadIndication) {
+        legacy |= EFFECT_FLAG_OFFLOAD_SUPPORTED;
+    }
+    if (aidl.deviceIndication) {
+        legacy |= EFFECT_FLAG_DEVICE_IND;
+    }
+    if (aidl.audioModeIndication) {
+        legacy |= EFFECT_FLAG_AUDIO_MODE_IND;
+    }
+    if (aidl.audioSourceIndication) {
+        legacy |= EFFECT_FLAG_AUDIO_SOURCE_IND;
+    }
+    if (aidl.noProcessing) {
+        legacy |= EFFECT_FLAG_NO_PROCESS;
+    }
+    return legacy;
+}
+
+ConversionResult<Flags::Type> legacy2aidl_uint32_Flags_Type(uint32_t legacy) {
+    switch (legacy & EFFECT_FLAG_TYPE_MASK) {
+        case EFFECT_FLAG_TYPE_INSERT:
+            return Flags::Type::INSERT;
+        case EFFECT_FLAG_TYPE_AUXILIARY:
+            return Flags::Type::AUXILIARY;
+        case EFFECT_FLAG_TYPE_REPLACE:
+            return Flags::Type::REPLACE;
+        case EFFECT_FLAG_TYPE_PRE_PROC:
+            return Flags::Type::PRE_PROC;
+        case EFFECT_FLAG_TYPE_POST_PROC:
+            return Flags::Type::POST_PROC;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<Flags::Insert> legacy2aidl_uint32_Flags_Insert(uint32_t legacy) {
+    switch (legacy & EFFECT_FLAG_INSERT_MASK) {
+        case EFFECT_FLAG_INSERT_ANY:
+            return Flags::Insert::ANY;
+        case EFFECT_FLAG_INSERT_FIRST:
+            return Flags::Insert::FIRST;
+        case EFFECT_FLAG_INSERT_LAST:
+            return Flags::Insert::LAST;
+        case EFFECT_FLAG_INSERT_EXCLUSIVE:
+            return Flags::Insert::EXCLUSIVE;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<Flags::Volume> legacy2aidl_uint32_Flags_Volume(uint32_t legacy) {
+    switch (legacy & EFFECT_FLAG_VOLUME_MASK) {
+        case EFFECT_FLAG_VOLUME_IND:
+            return Flags::Volume::IND;
+        case EFFECT_FLAG_VOLUME_MONITOR:
+            return Flags::Volume::MONITOR;
+        case EFFECT_FLAG_VOLUME_NONE:
+            return Flags::Volume::NONE;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<Flags::HardwareAccelerator> legacy2aidl_uint32_Flags_HardwareAccelerator(
+        uint32_t legacy) {
+    switch (legacy & EFFECT_FLAG_HW_ACC_MASK) {
+        case EFFECT_FLAG_HW_ACC_SIMPLE:
+            return Flags::HardwareAccelerator::SIMPLE;
+        case EFFECT_FLAG_HW_ACC_TUNNEL:
+            return Flags::HardwareAccelerator::TUNNEL;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<Flags> legacy2aidl_uint32_Flags(uint32_t legacy) {
+    Flags aidl;
+
+    aidl.type = VALUE_OR_RETURN(legacy2aidl_uint32_Flags_Type(legacy));
+    aidl.insert = VALUE_OR_RETURN(legacy2aidl_uint32_Flags_Insert(legacy));
+    aidl.volume = VALUE_OR_RETURN(legacy2aidl_uint32_Flags_Volume(legacy));
+    aidl.hwAcceleratorMode = VALUE_OR_RETURN(legacy2aidl_uint32_Flags_HardwareAccelerator(legacy));
+    aidl.offloadIndication = (legacy & EFFECT_FLAG_OFFLOAD_SUPPORTED);
+    aidl.deviceIndication = (legacy & EFFECT_FLAG_DEVICE_IND);
+    aidl.audioModeIndication = (legacy & EFFECT_FLAG_AUDIO_MODE_IND);
+    aidl.audioSourceIndication = (legacy & EFFECT_FLAG_AUDIO_SOURCE_IND);
+    aidl.noProcessing = (legacy & EFFECT_FLAG_NO_PROCESS);
+    return aidl;
+}
+
+ConversionResult<effect_descriptor_t>
+aidl2legacy_Descriptor_effect_descriptor(const Descriptor& aidl) {
+    effect_descriptor_t legacy;
+    legacy.type = VALUE_OR_RETURN(aidl2legacy_AudioUuid_audio_uuid_t(aidl.common.id.type));
+    legacy.uuid = VALUE_OR_RETURN(aidl2legacy_AudioUuid_audio_uuid_t(aidl.common.id.uuid));
+    // legacy descriptor doesn't have proxy information
+    // proxy = VALUE_OR_RETURN(aidl2legacy_AudioUuid_audio_uuid_t(aidl.proxy));
+    legacy.apiVersion = EFFECT_CONTROL_API_VERSION;
+    legacy.flags = VALUE_OR_RETURN(aidl2legacy_Flags_uint32(aidl.common.flags));
+    legacy.cpuLoad = VALUE_OR_RETURN(convertIntegral<uint16_t>(aidl.common.cpuLoad));
+    legacy.memoryUsage = VALUE_OR_RETURN(convertIntegral<uint16_t>(aidl.common.memoryUsage));
+    RETURN_IF_ERROR(aidl2legacy_string(aidl.common.name, legacy.name, sizeof(legacy.name)));
+    RETURN_IF_ERROR(aidl2legacy_string(aidl.common.implementor, legacy.implementor,
+                                        sizeof(legacy.implementor)));
+    return legacy;
+}
+
+ConversionResult<Descriptor>
+legacy2aidl_effect_descriptor_Descriptor(const effect_descriptor_t& legacy) {
+    Descriptor aidl;
+    aidl.common.id.type = VALUE_OR_RETURN(legacy2aidl_audio_uuid_t_AudioUuid(legacy.type));
+    aidl.common.id.uuid = VALUE_OR_RETURN(legacy2aidl_audio_uuid_t_AudioUuid(legacy.uuid));
+    // legacy descriptor doesn't have proxy information
+    // aidl.common.id.proxy
+    aidl.common.flags = VALUE_OR_RETURN(legacy2aidl_uint32_Flags(legacy.flags));
+    aidl.common.cpuLoad = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.cpuLoad));
+    aidl.common.memoryUsage = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.memoryUsage));
+    aidl.common.name = VALUE_OR_RETURN(legacy2aidl_string(legacy.name, sizeof(legacy.name)));
+    aidl.common.implementor =
+            VALUE_OR_RETURN(legacy2aidl_string(legacy.implementor, sizeof(legacy.implementor)));
+    return aidl;
+}
+
+ConversionResult<buffer_config_t> aidl2legacy_AudioConfigBase_buffer_config_t(
+        const media::audio::common::AudioConfigBase& aidl, bool isInput) {
+    buffer_config_t legacy;
+
+    legacy.samplingRate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.sampleRate));
+    legacy.mask |= EFFECT_CONFIG_SMP_RATE;
+
+    legacy.channels = VALUE_OR_RETURN(
+            aidl2legacy_AudioChannelLayout_audio_channel_mask_t(aidl.channelMask, isInput));
+    legacy.mask |= EFFECT_CONFIG_CHANNELS;
+
+    legacy.format = VALUE_OR_RETURN(aidl2legacy_AudioFormatDescription_audio_format_t(aidl.format));
+    legacy.mask |= EFFECT_CONFIG_FORMAT;
+
+    return legacy;
+}
+
+ConversionResult<media::audio::common::AudioConfigBase>
+legacy2aidl_AudioConfigBase_buffer_config_t(const buffer_config_t& legacy, bool isInput) {
+    media::audio::common::AudioConfigBase aidl;
+
+    if (legacy.mask & EFFECT_CONFIG_SMP_RATE) {
+        aidl.sampleRate = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.samplingRate));
+    }
+    if (legacy.mask & EFFECT_CONFIG_CHANNELS) {
+        aidl.channelMask = VALUE_OR_RETURN(legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
+                static_cast<audio_channel_mask_t>(legacy.channels), isInput));
+    }
+    if (legacy.mask & EFFECT_CONFIG_FORMAT) {
+        aidl.format = VALUE_OR_RETURN(legacy2aidl_audio_format_t_AudioFormatDescription(
+                static_cast<audio_format_t>(legacy.format)));
+    }
+    return aidl;
+}
+
+}  // namespace android
+}  // aidl
diff --git a/media/audioaidlconversion/Android.bp b/media/audioaidlconversion/Android.bp
index 4a1df3a..86f455e 100644
--- a/media/audioaidlconversion/Android.bp
+++ b/media/audioaidlconversion/Android.bp
@@ -61,9 +61,9 @@
     host_supported: true,
     vendor_available: true,
     double_loadable: true,
-    min_sdk_version: "29",
     header_libs: [
         "libaudio_system_headers",
+        "libhardware_headers",
     ],
     shared_libs: [
         "libbase",
@@ -102,7 +102,9 @@
  */
 cc_library {
     name: "libaudio_aidl_conversion_common_cpp",
-    srcs: ["AidlConversionCppNdk.cpp"],
+    srcs: [
+        "AidlConversionCppNdk.cpp",
+    ],
     header_libs: [
         "libaudio_aidl_conversion_common_util_cpp",
     ],
@@ -113,6 +115,7 @@
         "audio_aidl_conversion_common_default",
         "latest_android_media_audio_common_types_cpp_export_shared",
     ],
+    min_sdk_version: "29",
 }
 
 /**
@@ -120,7 +123,10 @@
  */
 cc_library {
     name: "libaudio_aidl_conversion_common_ndk",
-    srcs: ["AidlConversionCppNdk.cpp"],
+    srcs: [
+        "AidlConversionCppNdk.cpp",
+        "AidlConversionNdk.cpp",
+    ],
     header_libs: [
         "libaudio_aidl_conversion_common_util_ndk",
     ],
@@ -129,12 +135,16 @@
     ],
     defaults: [
         "audio_aidl_conversion_common_default",
+        "latest_android_hardware_audio_common_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
         "latest_android_media_audio_common_types_ndk_shared",
     ],
     shared_libs: [
         "libbinder_ndk",
+        "libbase",
     ],
     cflags: [
         "-DBACKEND_NDK",
     ],
+    min_sdk_version: "31", //AParcelableHolder has been introduced in 31
 }
diff --git a/media/audioaidlconversion/include/media/AidlConversionNdk.h b/media/audioaidlconversion/include/media/AidlConversionNdk.h
new file mode 100644
index 0000000..a3176f6
--- /dev/null
+++ b/media/audioaidlconversion/include/media/AidlConversionNdk.h
@@ -0,0 +1,68 @@
+/*
+ * 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 <android/binder_auto_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+/**
+ * Can only handle conversion between AIDL (NDK backend) and legacy type.
+ */
+#include <hardware/audio_effect.h>
+#include <media/AidlConversionUtil.h>
+#include <system/audio_effect.h>
+
+#include <aidl/android/hardware/audio/effect/IEffect.h>
+
+namespace aidl {
+namespace android {
+
+ConversionResult<uint32_t> aidl2legacy_Flags_Type_uint32(
+        ::aidl::android::hardware::audio::effect::Flags::Type type);
+ConversionResult<uint32_t> aidl2legacy_Flags_Insert_uint32(
+        ::aidl::android::hardware::audio::effect::Flags::Insert insert);
+ConversionResult<uint32_t> aidl2legacy_Flags_Volume_uint32(
+        ::aidl::android::hardware::audio::effect::Flags::Volume volume);
+ConversionResult<uint32_t> aidl2legacy_Flags_HardwareAccelerator_uint32(
+        ::aidl::android::hardware::audio::effect::Flags::HardwareAccelerator hwAcceleratorMode);
+ConversionResult<uint32_t> aidl2legacy_Flags_uint32(
+        const ::aidl::android::hardware::audio::effect::Flags aidl);
+
+ConversionResult<::aidl::android::hardware::audio::effect::Flags::Type>
+legacy2aidl_uint32_Flags_Type(uint32_t legacy);
+ConversionResult<::aidl::android::hardware::audio::effect::Flags::Insert>
+legacy2aidl_uint32_Flags_Insert(uint32_t legacy);
+ConversionResult<::aidl::android::hardware::audio::effect::Flags::Volume>
+legacy2aidl_uint32_Flags_Volume(uint32_t legacy);
+ConversionResult<::aidl::android::hardware::audio::effect::Flags::HardwareAccelerator>
+legacy2aidl_uint32_Flags_HardwareAccelerator(uint32_t legacy);
+ConversionResult<::aidl::android::hardware::audio::effect::Flags> legacy2aidl_uint32_Flags(
+        uint32_t hal);
+
+ConversionResult<effect_descriptor_t> aidl2legacy_Descriptor_effect_descriptor(
+        const ::aidl::android::hardware::audio::effect::Descriptor& aidl);
+ConversionResult<::aidl::android::hardware::audio::effect::Descriptor>
+legacy2aidl_effect_descriptor_Descriptor(const effect_descriptor_t& hal);
+
+ConversionResult<buffer_config_t> aidl2legacy_AudioConfigBase_buffer_config_t(
+        const media::audio::common::AudioConfigBase& aidl, bool isInput);
+ConversionResult<media::audio::common::AudioConfigBase> legacy2aidl_AudioConfigBase_buffer_config_t(
+        const buffer_config_t& legacy, bool isInput);
+
+}  // namespace android
+}  // namespace aidl
diff --git a/media/audioaidlconversion/include/media/AidlConversionUtil.h b/media/audioaidlconversion/include/media/AidlConversionUtil.h
index 95daa4a..28c7522 100644
--- a/media/audioaidlconversion/include/media/AidlConversionUtil.h
+++ b/media/audioaidlconversion/include/media/AidlConversionUtil.h
@@ -25,7 +25,9 @@
 #include <error/Result.h>
 
 #if defined(BACKEND_NDK)
+#include <android/binder_enums.h>
 #include <android/binder_status.h>
+
 namespace aidl {
 #else
 #include <binder/Enums.h>
diff --git a/media/audioserver/main_audioserver.cpp b/media/audioserver/main_audioserver.cpp
index e3db5b4..1e3bfe0 100644
--- a/media/audioserver/main_audioserver.cpp
+++ b/media/audioserver/main_audioserver.cpp
@@ -50,6 +50,8 @@
 
 int main(int argc __unused, char **argv)
 {
+    ALOGD("%s: starting", __func__);
+    const auto startTime = std::chrono::steady_clock::now();
     // TODO: update with refined parameters
     limitProcessMemory(
         "audio.maxmem", /* "ro.audio.maxmem", property that defines limit */
@@ -144,11 +146,36 @@
             setpgid(0, 0);                      // but if I die first, don't kill my parent
         }
         android::hardware::configureRpcThreadpool(4, false /*callerWillJoin*/);
-        sp<ProcessState> proc(ProcessState::self());
+
+        // Ensure threads for possible callbacks.  Note that get_audio_flinger() does
+        // this automatically when called from AudioPolicy, but we do this anyways here.
+        ProcessState::self()->startThreadPool();
+
+        // Instantiating AudioFlinger (making it public, e.g. through ::initialize())
+        // and then instantiating AudioPolicy (and making it public)
+        // leads to situations where AudioFlinger is accessed remotely before
+        // AudioPolicy is initialized.  Not only might this
+        // cause inaccurate results, but if AudioPolicy has slow audio HAL
+        // initialization, it can cause a TimeCheck abort to occur on an AudioFlinger
+        // call which tries to access AudioPolicy.
+        //
+        // We create AudioFlinger and AudioPolicy locally then make it public to ServiceManager.
+        // This requires both AudioFlinger and AudioPolicy to be in-proc.
+        //
+        const auto af = sp<AudioFlinger>::make();
+        const auto afAdapter = sp<AudioFlingerServerAdapter>::make(af);
+        ALOGD("%s: AudioFlinger created", __func__);
+        ALOGW_IF(AudioSystem::setLocalAudioFlinger(af) != OK,
+                "%s: AudioSystem already has an AudioFlinger instance!", __func__);
+        const auto aps = sp<AudioPolicyService>::make();
+        ALOGD("%s: AudioPolicy created", __func__);
+
+        // Add AudioFlinger and AudioPolicy to ServiceManager.
         sp<IServiceManager> sm = defaultServiceManager();
-        ALOGI("ServiceManager: %p", sm.get());
-        AudioFlinger::instantiate();
-        AudioPolicyService::instantiate();
+        sm->addService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME), afAdapter,
+                false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
+        sm->addService(String16(AudioPolicyService::getServiceName()), aps,
+                false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
 
         // AAudioService should only be used in OC-MR1 and later.
         // And only enable the AAudioService if the system MMAP policy explicitly allows it.
@@ -156,7 +183,6 @@
         // If we cannot get audio flinger here, there must be some serious problems. In that case,
         // attempting to call audio flinger on a null pointer could make the process crash
         // and attract attentions.
-        sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
         std::vector<AudioMMapPolicyInfo> policyInfos;
         status_t status = af->getMmapPolicyInfos(
                 AudioMMapPolicyType::DEFAULT, &policyInfos);
@@ -169,11 +195,14 @@
             })) {
             AAudioService::instantiate();
         } else {
-            ALOGD("Do not init aaudio service, status %d, policy info size %zu",
-                  status, policyInfos.size());
+            ALOGD("%s: Do not init aaudio service, status %d, policy info size %zu",
+                  __func__, status, policyInfos.size());
         }
-
-        ProcessState::self()->startThreadPool();
+        const auto endTime = std::chrono::steady_clock::now();
+        using FloatMillis = std::chrono::duration<float, std::milli>;
+        const float timeTaken = std::chrono::duration_cast<FloatMillis>(
+                endTime - startTime).count();
+        ALOGI("%s: initialization done in %.3f ms, joining thread pool", __func__, timeTaken);
         IPCThreadState::self()->joinThreadPool();
     }
 }
diff --git a/media/libaaudio/fuzzer/Android.bp b/media/libaaudio/fuzzer/Android.bp
index f5d2939..3393930 100644
--- a/media/libaaudio/fuzzer/Android.bp
+++ b/media/libaaudio/fuzzer/Android.bp
@@ -39,6 +39,7 @@
         "libaudiomanager",
         "libaudiopolicy",
         "libaudioclient_aidl_conversion",
+        "libaudio_aidl_conversion_common_cpp",
         "libutils",
     ],
     static_libs: [
diff --git a/media/libaaudio/tests/test_attributes.cpp b/media/libaaudio/tests/test_attributes.cpp
index b88d562..e5676a7 100644
--- a/media/libaaudio/tests/test_attributes.cpp
+++ b/media/libaaudio/tests/test_attributes.cpp
@@ -20,6 +20,7 @@
 // "test_aaudio_attributes.cpp". That other file is more current.
 // So these tests could be deleted.
 
+#include <memory>
 #include <stdio.h>
 #include <unistd.h>
 
@@ -40,7 +41,7 @@
                             int privacyMode = DONT_SET,
                             aaudio_direction_t direction = AAUDIO_DIRECTION_OUTPUT) {
 
-    float *buffer = new float[kNumFrames * kChannelCount];
+    std::unique_ptr<float[]> buffer(new float[kNumFrames * kChannelCount]);
 
     AAudioStreamBuilder *aaudioBuilder = nullptr;
     AAudioStream *aaudioStream = nullptr;
@@ -109,16 +110,15 @@
 
     if (direction == AAUDIO_DIRECTION_INPUT) {
         EXPECT_EQ(kNumFrames,
-                  AAudioStream_read(aaudioStream, buffer, kNumFrames, kNanosPerSecond));
+                  AAudioStream_read(aaudioStream, buffer.get(), kNumFrames, kNanosPerSecond));
     } else {
         EXPECT_EQ(kNumFrames,
-                  AAudioStream_write(aaudioStream, buffer, kNumFrames, kNanosPerSecond));
+                  AAudioStream_write(aaudioStream, buffer.get(), kNumFrames, kNanosPerSecond));
     }
 
     EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream));
 
     EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
-    delete[] buffer;
 }
 
 static const aaudio_usage_t sUsages[] = {
diff --git a/media/libaaudio/tests/test_recovery.cpp b/media/libaaudio/tests/test_recovery.cpp
index 6e89f83..11331af 100644
--- a/media/libaaudio/tests/test_recovery.cpp
+++ b/media/libaaudio/tests/test_recovery.cpp
@@ -16,6 +16,7 @@
 
 // Play silence and recover from dead servers or disconnected devices.
 
+#include <memory>
 #include <stdio.h>
 
 #include <aaudio/AAudio.h>
@@ -32,7 +33,6 @@
     int32_t triesLeft = 3;
     int32_t bufferCapacity;
     int32_t framesPerBurst = 0;
-    float *buffer = nullptr;
 
     int32_t actualChannelCount = 0;
     int32_t actualSampleRate = 0;
@@ -83,7 +83,7 @@
         bufferCapacity, framesPerBurst);
 
         int samplesPerBurst = framesPerBurst * actualChannelCount;
-        buffer = new float[samplesPerBurst];
+        std::unique_ptr<float[]> buffer(new float[samplesPerBurst]);
 
         result = AAudioStream_requestStart(aaudioStream);
         if (result != AAUDIO_OK) {
@@ -98,7 +98,7 @@
         int64_t printAt = actualSampleRate;
         while (result == AAUDIO_OK && framesTotal < framesMax) {
             int32_t framesWritten = AAudioStream_write(aaudioStream,
-                                                       buffer, framesPerBurst,
+                                                       buffer.get(), framesPerBurst,
                                                        DEFAULT_TIMEOUT_NANOS);
             if (framesWritten < 0) {
                 result = framesWritten;
@@ -134,6 +134,5 @@
         AAudioStream_close(aaudioStream);
     }
     AAudioStreamBuilder_delete(aaudioBuilder);
-    delete[] buffer;
     printf("          result = %d = %s\n", result, AAudio_convertResultToText(result));
 }
diff --git a/media/libaaudio/tests/test_session_id.cpp b/media/libaaudio/tests/test_session_id.cpp
index 3f7d4fc..5968b5d 100644
--- a/media/libaaudio/tests/test_session_id.cpp
+++ b/media/libaaudio/tests/test_session_id.cpp
@@ -16,6 +16,7 @@
 
 // Test AAudio SessionId, which is used to associate Effects with a stream
 
+#include <memory>
 #include <stdio.h>
 #include <unistd.h>
 
@@ -29,7 +30,7 @@
 // Test AAUDIO_SESSION_ID_NONE default
 static void checkSessionIdNone(aaudio_performance_mode_t perfMode) {
 
-    float *buffer = new float[kNumFrames * kChannelCount];
+    std::unique_ptr<float[]> buffer(new float[kNumFrames * kChannelCount]);
 
     AAudioStreamBuilder *aaudioBuilder = nullptr;
 
@@ -51,12 +52,12 @@
 
     ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream1));
 
-    ASSERT_EQ(kNumFrames, AAudioStream_write(aaudioStream1, buffer, kNumFrames, kNanosPerSecond));
+    ASSERT_EQ(kNumFrames,
+              AAudioStream_write(aaudioStream1, buffer.get(), kNumFrames, kNanosPerSecond));
 
     EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream1));
 
     EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream1));
-    delete[] buffer;
     AAudioStreamBuilder_delete(aaudioBuilder);
 }
 
@@ -72,7 +73,7 @@
 static void checkSessionIdAllocate(aaudio_performance_mode_t perfMode,
                                    aaudio_direction_t direction) {
 
-    float *buffer = new float[kNumFrames * kChannelCount];
+    std::unique_ptr<float[]> buffer(new float[kNumFrames * kChannelCount]);
 
     AAudioStreamBuilder *aaudioBuilder = nullptr;
 
@@ -106,10 +107,10 @@
 
     if (direction == AAUDIO_DIRECTION_INPUT) {
         ASSERT_EQ(kNumFrames, AAudioStream_read(aaudioStream1,
-                                                buffer, kNumFrames, kNanosPerSecond));
+                                                buffer.get(), kNumFrames, kNanosPerSecond));
     } else {
         ASSERT_EQ(kNumFrames, AAudioStream_write(aaudioStream1,
-                                         buffer, kNumFrames, kNanosPerSecond));
+                                         buffer.get(), kNumFrames, kNanosPerSecond));
     }
 
     EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream1));
@@ -135,10 +136,10 @@
 
     if (otherDirection == AAUDIO_DIRECTION_INPUT) {
         ASSERT_EQ(kNumFrames, AAudioStream_read(aaudioStream2,
-                                                 buffer, kNumFrames, kNanosPerSecond));
+                                                 buffer.get(), kNumFrames, kNanosPerSecond));
     } else {
         ASSERT_EQ(kNumFrames, AAudioStream_write(aaudioStream2,
-                                                 buffer, kNumFrames, kNanosPerSecond));
+                                                 buffer.get(), kNumFrames, kNanosPerSecond));
     }
 
     EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream2));
@@ -147,7 +148,6 @@
 
 
     EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream1));
-    delete[] buffer;
     AAudioStreamBuilder_delete(aaudioBuilder);
 }
 
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 9ddae1e..50e9ea7 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -128,6 +128,7 @@
         "audiopolicy-types-aidl-cpp",
         "av-types-aidl-cpp",
         "capture_state_listener-aidl-cpp",
+        "libaudio_aidl_conversion_common_cpp",
         "libaudioclient_aidl_conversion",
         "libaudiofoundation",
         "libaudioutils",
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index ad03711..8b7a63a 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -82,7 +82,7 @@
 // Binder for the AudioFlinger service that's passed to this client process from the system server.
 // This allows specific isolated processes to access the audio system. Currently used only for the
 // HotwordDetectionService.
-sp<IBinder> gAudioFlingerBinder = nullptr;
+static sp<IBinder> gAudioFlingerBinder = nullptr;
 
 void AudioSystem::setAudioFlingerBinder(const sp<IBinder>& audioFlinger) {
     if (audioFlinger->getInterfaceDescriptor() != media::IAudioFlingerService::descriptor) {
@@ -98,6 +98,15 @@
     gAudioFlingerBinder = audioFlinger;
 }
 
+static sp<IAudioFlinger> gLocalAudioFlinger; // set if we are local.
+
+status_t AudioSystem::setLocalAudioFlinger(const sp<IAudioFlinger>& af) {
+    Mutex::Autolock _l(gLock);
+    if (gAudioFlinger != nullptr) return INVALID_OPERATION;
+    gLocalAudioFlinger = af;
+    return OK;
+}
+
 // establish binder interface to AudioFlinger service
 const sp<IAudioFlinger> AudioSystem::get_audio_flinger() {
     sp<IAudioFlinger> af;
@@ -105,7 +114,19 @@
     bool reportNoError = false;
     {
         Mutex::Autolock _l(gLock);
-        if (gAudioFlinger == 0) {
+        if (gAudioFlinger != nullptr) {
+            return gAudioFlinger;
+        }
+
+        if (gAudioFlingerClient == nullptr) {
+            gAudioFlingerClient = sp<AudioFlingerClient>::make();
+        } else {
+            reportNoError = true;
+        }
+
+        if (gLocalAudioFlinger != nullptr) {
+            gAudioFlinger = gLocalAudioFlinger;
+        } else {
             sp<IBinder> binder;
             if (gAudioFlingerBinder != nullptr) {
                 binder = gAudioFlingerBinder;
@@ -113,32 +134,24 @@
                 sp<IServiceManager> sm = defaultServiceManager();
                 do {
                     binder = sm->getService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME));
-                    if (binder != 0)
-                        break;
+                    if (binder != nullptr) break;
                     ALOGW("AudioFlinger not published, waiting...");
                     usleep(500000); // 0.5 s
                 } while (true);
             }
-            if (gAudioFlingerClient == NULL) {
-                gAudioFlingerClient = new AudioFlingerClient();
-            } else {
-                reportNoError = true;
-            }
             binder->linkToDeath(gAudioFlingerClient);
-            gAudioFlinger = new AudioFlingerClientAdapter(
-                    interface_cast<media::IAudioFlingerService>(binder));
-            LOG_ALWAYS_FATAL_IF(gAudioFlinger == 0);
-            afc = gAudioFlingerClient;
-            // Make sure callbacks can be received by gAudioFlingerClient
-            ProcessState::self()->startThreadPool();
+            const auto afs = interface_cast<media::IAudioFlingerService>(binder);
+            LOG_ALWAYS_FATAL_IF(afs == nullptr);
+            gAudioFlinger = sp<AudioFlingerClientAdapter>::make(afs);
         }
+        afc = gAudioFlingerClient;
         af = gAudioFlinger;
+        // Make sure callbacks can be received by gAudioFlingerClient
+        ProcessState::self()->startThreadPool();
     }
-    if (afc != 0) {
-        int64_t token = IPCThreadState::self()->clearCallingIdentity();
-        af->registerClient(afc);
-        IPCThreadState::self()->restoreCallingIdentity(token);
-    }
+    const int64_t token = IPCThreadState::self()->clearCallingIdentity();
+    af->registerClient(afc);
+    IPCThreadState::self()->restoreCallingIdentity(token);
     if (reportNoError) reportError(NO_ERROR);
     return af;
 }
@@ -2223,8 +2236,25 @@
             aps->setDevicesRoleForStrategy(strategyAidl, roleAidl, devicesAidl));
 }
 
+status_t AudioSystem::removeDevicesRoleForStrategy(product_strategy_t strategy,
+                                                   device_role_t role,
+                                                   const AudioDeviceTypeAddrVector& devices) {
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) {
+        return PERMISSION_DENIED;
+    }
+
+    int32_t strategyAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_product_strategy_t_int32_t(strategy));
+    media::DeviceRole roleAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_device_role_t_DeviceRole(role));
+    std::vector<AudioDevice> devicesAidl = VALUE_OR_RETURN_STATUS(
+            convertContainer<std::vector<AudioDevice>>(devices,
+                                                       legacy2aidl_AudioDeviceTypeAddress));
+    return statusTFromBinderStatus(
+            aps->removeDevicesRoleForStrategy(strategyAidl, roleAidl, devicesAidl));
+}
+
 status_t
-AudioSystem::removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role) {
+AudioSystem::clearDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role) {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) {
         return PERMISSION_DENIED;
@@ -2232,7 +2262,7 @@
     int32_t strategyAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_product_strategy_t_int32_t(strategy));
     media::DeviceRole roleAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_device_role_t_DeviceRole(role));
     return statusTFromBinderStatus(
-            aps->removeDevicesRoleForStrategy(strategyAidl, roleAidl));
+            aps->clearDevicesRoleForStrategy(strategyAidl, roleAidl));
 }
 
 status_t AudioSystem::getDevicesForRoleAndStrategy(product_strategy_t strategy,
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
index ec5097a..fa6c733 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
@@ -313,6 +313,15 @@
 
     boolean isUltrasoundSupported();
 
+    /**
+     * Queries if there is hardware support for requesting audio capture content from
+     * the DSP hotword pipeline.
+     *
+     * @param lookbackAudio true if additionally querying for the ability to capture audio
+     *                      from the pipeline prior to capture stream open.
+     */
+    boolean isHotwordStreamSupported(boolean lookbackAudio);
+
     AudioProductStrategy[] listAudioProductStrategies();
     int /* product_strategy_t */ getProductStrategyFromAudioAttributes(
             in AudioAttributesInternal aa, boolean fallbackOnDefault);
@@ -330,7 +339,10 @@
                                    in AudioDevice[] devices);
 
     void removeDevicesRoleForStrategy(int /* product_strategy_t */ strategy,
-                                       DeviceRole role);
+                                      DeviceRole role,
+                                      in AudioDevice[] devices);
+
+    void clearDevicesRoleForStrategy(int /* product_strategy_t */ strategy, DeviceRole role);
 
     AudioDevice[] getDevicesForRoleAndStrategy(int /* product_strategy_t */ strategy,
                                                DeviceRole role);
diff --git a/media/libaudioclient/fuzzer/Android.bp b/media/libaudioclient/fuzzer/Android.bp
index dd3e3ba..b1feb60 100644
--- a/media/libaudioclient/fuzzer/Android.bp
+++ b/media/libaudioclient/fuzzer/Android.bp
@@ -56,6 +56,7 @@
         "av-types-aidl-cpp",
         "capture_state_listener-aidl-cpp",
         "libaudioclient_aidl_conversion",
+        "libaudio_aidl_conversion_common_cpp",
         "libaudioflinger",
         "libaudiofoundation",
         "libaudiomanager",
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index fedf511..23b0340 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -167,6 +167,10 @@
     // HotwordDetectionService.
     static void setAudioFlingerBinder(const sp<IBinder>& audioFlinger);
 
+    // Sets a local AudioFlinger interface to be used by AudioSystem.
+    // This is used by audioserver main() to avoid binder AIDL translation.
+    static status_t setLocalAudioFlinger(const sp<IAudioFlinger>& af);
+
     // helper function to obtain AudioFlinger service handle
     static const sp<IAudioFlinger> get_audio_flinger();
 
@@ -523,7 +527,11 @@
     static status_t setDevicesRoleForStrategy(product_strategy_t strategy,
             device_role_t role, const AudioDeviceTypeAddrVector &devices);
 
-    static status_t removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role);
+    static status_t removeDevicesRoleForStrategy(product_strategy_t strategy,
+            device_role_t role, const AudioDeviceTypeAddrVector &devices);
+
+    static status_t clearDevicesRoleForStrategy(product_strategy_t strategy,
+            device_role_t role);
 
     static status_t getDevicesForRoleAndStrategy(product_strategy_t strategy,
             device_role_t role, AudioDeviceTypeAddrVector &devices);
diff --git a/media/libaudioclient/tests/Android.bp b/media/libaudioclient/tests/Android.bp
index cbcef12..dcb6c25 100644
--- a/media/libaudioclient/tests/Android.bp
+++ b/media/libaudioclient/tests/Android.bp
@@ -110,6 +110,7 @@
         "capture_state_listener-aidl-cpp",
         "framework-permission-aidl-cpp",
         "libaudioclient_aidl_conversion",
+        "libaudio_aidl_conversion_common_cpp",
         "libbase",
         "libbinder",
         "libcgrouprc",
diff --git a/media/libaudioclient/tests/audiosystem_tests.cpp b/media/libaudioclient/tests/audiosystem_tests.cpp
index 3dd2c95..a947105 100644
--- a/media/libaudioclient/tests/audiosystem_tests.cpp
+++ b/media/libaudioclient/tests/audiosystem_tests.cpp
@@ -405,8 +405,8 @@
         EXPECT_EQ(OK, AudioSystem::getDevicesForRoleAndStrategy(mediaStrategy.getId(),
                                                                 DEVICE_ROLE_PREFERRED, devices));
         EXPECT_EQ(devices, outputDevices);
-        EXPECT_EQ(OK, AudioSystem::removeDevicesRoleForStrategy(mediaStrategy.getId(),
-                                                                DEVICE_ROLE_PREFERRED));
+        EXPECT_EQ(OK, AudioSystem::clearDevicesRoleForStrategy(mediaStrategy.getId(),
+                                                               DEVICE_ROLE_PREFERRED));
         EXPECT_EQ(NAME_NOT_FOUND, AudioSystem::getDevicesForRoleAndStrategy(
                                           mediaStrategy.getId(), DEVICE_ROLE_PREFERRED, devices));
     }
diff --git a/media/libaudiofoundation/AudioDeviceTypeAddr.cpp b/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
index 4a7e956..ad39d32 100644
--- a/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
+++ b/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
@@ -150,6 +150,20 @@
     return remainedDevices;
 }
 
+AudioDeviceTypeAddrVector joinDeviceTypeAddrs(
+        const AudioDeviceTypeAddrVector& devices,
+        const AudioDeviceTypeAddrVector& devicesToJoin) {
+    std::set<AudioDeviceTypeAddr> devicesSet(devices.begin(), devices.end());
+    std::set<AudioDeviceTypeAddr> devicesToJoinSet(devicesToJoin.begin(), devicesToJoin.end());
+    AudioDeviceTypeAddrVector joinedDevices;
+
+    std::set_union(devicesSet.begin(), devicesSet.end(),
+                   devicesToJoinSet.begin(), devicesToJoinSet.end(),
+                   std::back_inserter(joinedDevices));
+
+    return joinedDevices;
+}
+
 std::string dumpAudioDeviceTypeAddrVector(const AudioDeviceTypeAddrVector& deviceTypeAddrs,
                                           bool includeSensitiveInfo) {
     std::stringstream stream;
diff --git a/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h b/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
index 11aa222..b2f2bd0 100644
--- a/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
+++ b/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
@@ -84,6 +84,14 @@
         const AudioDeviceTypeAddrVector& devices,
         const AudioDeviceTypeAddrVector& devicesToExclude);
 
+/**
+ * Return a collection of AudioDeviceTypeAddrs that is the union of `devices` and
+ * `devicesToJoin`
+ */
+AudioDeviceTypeAddrVector joinDeviceTypeAddrs(
+        const AudioDeviceTypeAddrVector& devices,
+        const AudioDeviceTypeAddrVector& devicesToJoin);
+
 std::string dumpAudioDeviceTypeAddrVector(const AudioDeviceTypeAddrVector& deviceTypeAddrs,
                                           bool includeSensitiveInfo=false);
 
diff --git a/media/libaudiohal/Android.bp b/media/libaudiohal/Android.bp
index 320c639..f47dd0b 100644
--- a/media/libaudiohal/Android.bp
+++ b/media/libaudiohal/Android.bp
@@ -43,6 +43,7 @@
     header_libs: [
         "libaudiohal_headers",
         "libbase_headers",
+        "liberror_headers",
         "libmediautils_headers",
     ]
 }
@@ -74,8 +75,4 @@
     name: "libaudiohal_headers",
 
     export_include_dirs: ["include"],
-
-    // This is needed because the stream interface includes media/MicrophoneInfo.h
-    header_libs: ["av-headers"],
-    export_header_lib_headers: ["av-headers"],
 }
diff --git a/media/libaudiohal/FactoryHal.cpp b/media/libaudiohal/FactoryHal.cpp
index 16d591c..84ac64c 100644
--- a/media/libaudiohal/FactoryHal.cpp
+++ b/media/libaudiohal/FactoryHal.cpp
@@ -141,7 +141,7 @@
     auto halType = version.getType();
     if (halType == AudioHalVersionInfo::Type::AIDL) {
         return hasAidlHalService(interface, version);
-    } else if (version.getType() == AudioHalVersionInfo::Type::HIDL) {
+    } else if (halType == AudioHalVersionInfo::Type::HIDL) {
         return hasHidlHalService(interface, version);
     } else {
         ALOGE("HalType not supported %s", version.toString().c_str());
@@ -164,9 +164,9 @@
     auto siblingInterfaceMap = isDevice ? sEffectsHALInterfaces : sDevicesHALInterfaces;
     auto ifaceVersionIt = findMostRecentVersion(interfaceMap);
     auto siblingVersionIt = findMostRecentVersion(siblingInterfaceMap);
-    if (ifaceVersionIt != sAudioHALVersions.end() &&
-        siblingVersionIt != sAudioHALVersions.end() &&
-        // same major version
+    if (ifaceVersionIt != sAudioHALVersions.end() && siblingVersionIt != sAudioHALVersions.end() &&
+        // same HAL type (HIDL/AIDL) and same major version
+        ifaceVersionIt->getType() == siblingVersionIt->getType() &&
         ifaceVersionIt->getMajorVersion() == siblingVersionIt->getMajorVersion()) {
         void* rawInterface;
         if (createHalService(std::max(*ifaceVersionIt, *siblingVersionIt), isDevice,
diff --git a/media/libaudiohal/impl/Android.bp b/media/libaudiohal/impl/Android.bp
index bb5601f..d151817 100644
--- a/media/libaudiohal/impl/Android.bp
+++ b/media/libaudiohal/impl/Android.bp
@@ -241,15 +241,34 @@
         "libaudiohal_default",
         "latest_android_hardware_audio_common_ndk_shared",
         "latest_android_hardware_audio_core_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_static",
+        "latest_android_media_audio_common_types_ndk_shared",
     ],
     srcs: [
         "DevicesFactoryHalEntry.cpp",
         "DevicesFactoryHalAidl.cpp",
+        "EffectBufferHalAidl.cpp",
+        "EffectHalAidl.cpp",
         "EffectsFactoryHalAidl.cpp",
         "EffectsFactoryHalEntry.cpp",
     ],
+    static_libs: [
+        "android.hardware.common-V2-ndk",
+        "android.hardware.common.fmq-V1-ndk",
+    ],
     shared_libs: [
         "libbinder_ndk",
-    ]
+        "libaudio_aidl_conversion_common_ndk",
+    ],
+    header_libs: [
+        "libaudio_aidl_conversion_common_util_ndk",
+        "libaudio_system_headers",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-Wthread-safety",
+        "-DBACKEND_NDK",
+    ],
 }
\ No newline at end of file
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
new file mode 100644
index 0000000..d85d960
--- /dev/null
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "DeviceHalAidl"
+
+#include "DeviceHalAidl.h"
+
+status_t DeviceHalAidl::getSupportedDevices(uint32_t* devices) {
+    ALOGE("%s not implemented yet devices %p", __func__, devices);
+    return OK;
+}
+
+status_t DeviceHalAidl::initCheck() {
+    ALOGE("%s not implemented yet", __func__);
+    return OK;
+}
+
+status_t DeviceHalAidl::setVoiceVolume(float volume) {
+    mVoiceVolume = volume;
+    ALOGE("%s not implemented yet %f", __func__, volume);
+    return OK;
+}
+
+status_t DeviceHalAidl::setMasterVolume(float volume) {
+    mMasterVolume = volume;
+    ALOGE("%s not implemented yet %f", __func__, volume);
+    return OK;
+}
+
+status_t DeviceHalAidl::getMasterVolume(float *volume) {
+    *volume = mMasterVolume;
+    ALOGE("%s not implemented yet %f", __func__, *volume);
+    return OK;
+}
+
+status_t DeviceHalAidl::setMode(audio_mode_t mode) {
+    ALOGE("%s not implemented yet %u", __func__, mode);
+    return OK;
+}
+
+status_t DeviceHalAidl::setMicMute(bool state) {
+    mMicMute = state;
+    ALOGE("%s not implemented yet %d", __func__, state);
+    return OK;
+}
+status_t DeviceHalAidl::getMicMute(bool *state) {
+    *state = mMicMute;
+    ALOGE("%s not implemented yet %d", __func__, *state);
+    return OK;
+}
+status_t DeviceHalAidl::setMasterMute(bool state) {
+    mMasterMute = state;
+    ALOGE("%s not implemented yet %d", __func__, state);
+    return OK;
+}
+status_t DeviceHalAidl::getMasterMute(bool *state) {
+    *state = mMasterMute;
+    ALOGE("%s not implemented yet %d", __func__, *state);
+    return OK;
+}
+
+status_t DeviceHalAidl::setParameters(const String8& kvPairs) {
+    ALOGE("%s not implemented yet %s", __func__, kvPairs.c_str());
+    return OK;
+}
+
+status_t DeviceHalAidl::getParameters(const String8& keys, String8 *values) {
+    ALOGE("%s not implemented yet %s %s", __func__, keys.c_str(), values->c_str());
+    return OK;
+}
+
+status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
+    ALOGE("%s not implemented yet %p %zu", __func__, config, *size);
+    return OK;
+}
+
+status_t DeviceHalAidl::openOutputStream(audio_io_handle_t handle, audio_devices_t devices,
+                                         audio_output_flags_t flags, struct audio_config* config,
+                                         const char* address,
+                                         sp<StreamOutHalInterface>* outStream) {
+    ALOGE("%s not implemented yet %d %u %u %p %s %p", __func__, handle, devices, flags, config,
+          address, outStream);
+    return OK;
+}
+
+status_t DeviceHalAidl::openInputStream(audio_io_handle_t handle, audio_devices_t devices,
+                                        struct audio_config* config, audio_input_flags_t flags,
+                                        const char* address, audio_source_t source,
+                                        audio_devices_t outputDevice,
+                                        const char* outputDeviceAddress,
+                                        sp<StreamInHalInterface>* inStream) {
+    ALOGE("%s not implemented yet %d %u %u %u %p %s %s %p %d", __func__, handle, devices,
+          outputDevice, flags, config, address, outputDeviceAddress, inStream, source);
+    return OK;
+}
+
+status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
+    *supportsPatches = true;
+    return OK;
+}
+
+status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
+                                         const struct audio_port_config* sources,
+                                         unsigned int num_sinks,
+                                         const struct audio_port_config* sinks,
+                                         audio_patch_handle_t* patch) {
+    ALOGE("%s not implemented yet %d %p %d %p %p", __func__, num_sources, sources, num_sinks,
+            sinks, patch);
+    return OK;
+}
+
+status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
+    ALOGE("%s not implemented yet patch %d", __func__, patch);
+    return OK;
+}
+
+status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
+    ALOGE("%s not implemented yet config %p", __func__, config);
+    return OK;
+}
+
+status_t DeviceHalAidl::getMicrophones(
+        std::vector<audio_microphone_characteristic_t>* microphones) {
+    ALOGE("%s not implemented yet microphones %p", __func__, microphones);
+    return OK;
+}
+
+status_t DeviceHalAidl::addDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) {
+    if (!effect) {
+        return BAD_VALUE;
+    }
+    ALOGE("%s not implemented yet device %d", __func__, device);
+    return OK;
+}
+status_t DeviceHalAidl::removeDeviceEffect(audio_port_handle_t device,
+                            sp<EffectHalInterface> effect) {
+    if (!effect) {
+        return BAD_VALUE;
+    }
+    ALOGE("%s not implemented yet device %d", __func__, device);
+    return OK;
+}
+
+status_t DeviceHalAidl::getMmapPolicyInfos(
+        media::audio::common::AudioMMapPolicyType policyType __unused,
+        std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos __unused) {
+    ALOGE("%s not implemented yet", __func__);
+    return OK;
+}
+
+int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
+    ALOGE("%s not implemented yet", __func__);
+    return OK;
+}
+
+int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
+    ALOGE("%s not implemented yet", __func__);
+    return OK;
+}
+
+error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
+    ALOGE("%s not implemented yet", __func__);
+    return base::unexpected(INVALID_OPERATION);
+}
+
+status_t DeviceHalAidl::dump(int __unused, const Vector<String16>& __unused) {
+    ALOGE("%s not implemented yet", __func__);
+    return OK;
+};
+
+int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports __unused) override {
+    ALOGE("%s not implemented yet", __func__);
+    return INVALID_OPERATION;
+}
diff --git a/media/libaudiohal/impl/DeviceHalAidl.h b/media/libaudiohal/impl/DeviceHalAidl.h
new file mode 100644
index 0000000..5e8a8dd
--- /dev/null
+++ b/media/libaudiohal/impl/DeviceHalAidl.h
@@ -0,0 +1,130 @@
+/*
+ * 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 <media/audiohal/DeviceHalInterface.h>
+#include <media/audiohal/EffectHalInterface.h>
+
+#include <aidl/android/hardware/audio/core/BpModule.h>
+
+namespace android {
+
+class DeviceHalAidl : public DeviceHalInterface {
+  public:
+    // Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t.
+    status_t getSupportedDevices(uint32_t *devices) override;
+
+    // Check to see if the audio hardware interface has been initialized.
+    status_t initCheck() override;
+
+    // Set the audio volume of a voice call. Range is between 0.0 and 1.0.
+    status_t setVoiceVolume(float volume) override;
+
+    // Set the audio volume for all audio activities other than voice call.
+    status_t setMasterVolume(float volume) override;
+
+    // Get the current master volume value for the HAL.
+    status_t getMasterVolume(float *volume) override;
+
+    // Called when the audio mode changes.
+    status_t setMode(audio_mode_t mode) override;
+
+    // Muting control.
+    status_t setMicMute(bool state) override;
+
+    status_t getMicMute(bool* state) override;
+
+    status_t setMasterMute(bool state) override;
+
+    status_t getMasterMute(bool *state) override;
+
+    // Set global audio parameters.
+    status_t setParameters(const String8& kvPairs) override;
+
+    // Get global audio parameters.
+    status_t getParameters(const String8& keys, String8 *values) override;
+
+    // Returns audio input buffer size according to parameters passed.
+    status_t getInputBufferSize(const struct audio_config* config, size_t* size) override;
+
+    // Creates and opens the audio hardware output stream. The stream is closed
+    // by releasing all references to the returned object.
+    status_t openOutputStream(audio_io_handle_t handle, audio_devices_t devices,
+                              audio_output_flags_t flags, struct audio_config* config,
+                              const char* address, sp<StreamOutHalInterface>* outStream) override;
+
+    // Creates and opens the audio hardware input stream. The stream is closed
+    // by releasing all references to the returned object.
+    status_t openInputStream(audio_io_handle_t handle, audio_devices_t devices,
+                             struct audio_config* config, audio_input_flags_t flags,
+                             const char* address, audio_source_t source,
+                             audio_devices_t outputDevice, const char* outputDeviceAddress,
+                             sp<StreamInHalInterface>* inStream) override;
+
+    // Returns whether createAudioPatch and releaseAudioPatch operations are supported.
+    status_t supportsAudioPatches(bool* supportsPatches) override;
+
+    // Creates an audio patch between several source and sink ports.
+    status_t createAudioPatch(unsigned int num_sources, const struct audio_port_config* sources,
+                              unsigned int num_sinks, const struct audio_port_config* sinks,
+                              audio_patch_handle_t* patch) override;
+
+    // Releases an audio patch.
+    status_t releaseAudioPatch(audio_patch_handle_t patch) override;
+
+    // Set audio port configuration.
+    status_t setAudioPortConfig(const struct audio_port_config* config) override;
+
+    // List microphones
+    status_t getMicrophones(std::vector<audio_microphone_characteristic_t>* microphones);
+
+    status_t addDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
+
+    status_t removeDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
+
+    status_t getMmapPolicyInfos(media::audio::common::AudioMMapPolicyType policyType __unused,
+                                std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos
+                                        __unused) override;
+
+    int32_t getAAudioMixerBurstCount() override;
+
+    int32_t getAAudioHardwareBurstMinUsec() override;
+
+    error::Result<audio_hw_sync_t> getHwAvSync() override;
+
+    status_t dump(int __unused, const Vector<String16>& __unused) override;
+
+    int32_t supportsBluetoothVariableLatency(bool* supports __unused) override;
+
+  private:
+    friend class DevicesFactoryHalAidl;
+    const std::shared_ptr<::aidl::android::hardware::audio::core::IModule> mCore;
+    float mMasterVolume = 0.0f;
+    float mVoiceVolume = 0.0f;
+    bool mMasterMute = false;
+    bool mMicMute = false;
+
+    // Can not be constructed directly by clients.
+    explicit DeviceHalAidl(
+            const std::shared_ptr<::aidl::android::hardware::audio::core::IModule>& core)
+        : mCore(core) {}
+
+    // The destructor automatically closes the device.
+    ~DeviceHalAidl();
+};
+
+} // namespace android
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index 0cdf621..be063ab 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -459,12 +459,13 @@
 
 #if MAJOR_VERSION == 2
 status_t DeviceHalHidl::getMicrophones(
-        std::vector<media::MicrophoneInfo> *microphonesInfo __unused) {
+        std::vector<audio_microphone_characteristic_t> *microphonesInfo __unused) {
     if (mDevice == 0) return NO_INIT;
     return INVALID_OPERATION;
 }
 #elif MAJOR_VERSION >= 4
-status_t DeviceHalHidl::getMicrophones(std::vector<media::MicrophoneInfo> *microphonesInfo) {
+status_t DeviceHalHidl::getMicrophones(
+        std::vector<audio_microphone_characteristic_t> *microphonesInfo) {
     TIME_CHECK();
     if (mDevice == 0) return NO_INIT;
     Result retval;
@@ -475,8 +476,7 @@
             audio_microphone_characteristic_t dst;
             //convert
             (void)CoreUtils::microphoneInfoToHal(micArrayHal[k], &dst);
-            media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
-            microphonesInfo->push_back(microphone);
+            microphonesInfo->push_back(dst);
         }
     });
     return processReturn("getMicrophones", ret, retval);
diff --git a/media/libaudiohal/impl/DeviceHalHidl.h b/media/libaudiohal/impl/DeviceHalHidl.h
index 3e33609..052eb65 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.h
+++ b/media/libaudiohal/impl/DeviceHalHidl.h
@@ -30,87 +30,74 @@
 {
   public:
     // Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t.
-    virtual status_t getSupportedDevices(uint32_t *devices);
+    status_t getSupportedDevices(uint32_t *devices) override;
 
     // Check to see if the audio hardware interface has been initialized.
-    virtual status_t initCheck();
+    status_t initCheck() override;
 
     // Set the audio volume of a voice call. Range is between 0.0 and 1.0.
-    virtual status_t setVoiceVolume(float volume);
+    status_t setVoiceVolume(float volume) override;
 
     // Set the audio volume for all audio activities other than voice call.
-    virtual status_t setMasterVolume(float volume);
+    status_t setMasterVolume(float volume) override;
 
     // Get the current master volume value for the HAL.
-    virtual status_t getMasterVolume(float *volume);
+    status_t getMasterVolume(float *volume) override;
 
     // Called when the audio mode changes.
-    virtual status_t setMode(audio_mode_t mode);
+    status_t setMode(audio_mode_t mode) override;
 
     // Muting control.
-    virtual status_t setMicMute(bool state);
-    virtual status_t getMicMute(bool *state);
-    virtual status_t setMasterMute(bool state);
-    virtual status_t getMasterMute(bool *state);
+    status_t setMicMute(bool state) override;
+    status_t getMicMute(bool *state) override;
+    status_t setMasterMute(bool state) override;
+    status_t getMasterMute(bool *state) override;
 
     // Set global audio parameters.
-    virtual status_t setParameters(const String8& kvPairs);
+    status_t setParameters(const String8& kvPairs) override;
 
     // Get global audio parameters.
-    virtual status_t getParameters(const String8& keys, String8 *values);
+    status_t getParameters(const String8& keys, String8 *values) override;
 
     // Returns audio input buffer size according to parameters passed.
-    virtual status_t getInputBufferSize(const struct audio_config *config,
-            size_t *size);
+    status_t getInputBufferSize(const struct audio_config* config, size_t* size) override;
 
     // Creates and opens the audio hardware output stream. The stream is closed
     // by releasing all references to the returned object.
-    virtual status_t openOutputStream(
-            audio_io_handle_t handle,
-            audio_devices_t devices,
-            audio_output_flags_t flags,
-            struct audio_config *config,
-            const char *address,
-            sp<StreamOutHalInterface> *outStream);
+    status_t openOutputStream(audio_io_handle_t handle, audio_devices_t devices,
+                              audio_output_flags_t flags, struct audio_config* config,
+                              const char* address, sp<StreamOutHalInterface>* outStream) override;
 
     // Creates and opens the audio hardware input stream. The stream is closed
     // by releasing all references to the returned object.
-    virtual status_t openInputStream(
-            audio_io_handle_t handle,
-            audio_devices_t devices,
-            struct audio_config *config,
-            audio_input_flags_t flags,
-            const char *address,
-            audio_source_t source,
-            audio_devices_t outputDevice,
-            const char *outputDeviceAddress,
-            sp<StreamInHalInterface> *inStream);
+    status_t openInputStream(audio_io_handle_t handle, audio_devices_t devices,
+                             struct audio_config* config, audio_input_flags_t flags,
+                             const char* address, audio_source_t source,
+                             audio_devices_t outputDevice, const char* outputDeviceAddress,
+                             sp<StreamInHalInterface>* inStream) override;
 
     // Returns whether createAudioPatch and releaseAudioPatch operations are supported.
-    virtual status_t supportsAudioPatches(bool *supportsPatches);
+    status_t supportsAudioPatches(bool* supportsPatches) override;
 
     // Creates an audio patch between several source and sink ports.
-    virtual status_t createAudioPatch(
-            unsigned int num_sources,
-            const struct audio_port_config *sources,
-            unsigned int num_sinks,
-            const struct audio_port_config *sinks,
-            audio_patch_handle_t *patch);
+    status_t createAudioPatch(unsigned int num_sources, const struct audio_port_config* sources,
+                              unsigned int num_sinks, const struct audio_port_config* sinks,
+                              audio_patch_handle_t* patch) override;
 
     // Releases an audio patch.
-    virtual status_t releaseAudioPatch(audio_patch_handle_t patch);
+    status_t releaseAudioPatch(audio_patch_handle_t patch) override;
 
     // Fills the list of supported attributes for a given audio port.
-    virtual status_t getAudioPort(struct audio_port *port);
+    status_t getAudioPort(struct audio_port *port) override;
 
     // Fills the list of supported attributes for a given audio port.
-    virtual status_t getAudioPort(struct audio_port_v7 *port);
+    status_t getAudioPort(struct audio_port_v7 *port) override;
 
     // Set audio port configuration.
-    virtual status_t setAudioPortConfig(const struct audio_port_config *config);
+    status_t setAudioPortConfig(const struct audio_port_config *config) override;
 
     // List microphones
-    virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones);
+    status_t getMicrophones(std::vector<audio_microphone_characteristic_t>* microphones) override;
 
     status_t addDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
     status_t removeDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
diff --git a/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp b/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp
index 29fb558..b9ca164 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp
@@ -17,18 +17,22 @@
 #define LOG_TAG "DevicesFactoryHalAidl"
 //#define LOG_NDEBUG 0
 
+#include <aidl/android/hardware/audio/core/IModule.h>
 #include <android/binder_manager.h>
+#include <memory>
 #include <utils/Log.h>
 
+#include "DeviceHalAidl.h"
 #include "DevicesFactoryHalAidl.h"
 
+using namespace ::aidl::android::hardware::audio::core;
 using ::android::detail::AudioHalVersionInfo;
 
 namespace android {
 
-DevicesFactoryHalAidl::DevicesFactoryHalAidl(std::shared_ptr<IConfig> iconfig) {
+DevicesFactoryHalAidl::DevicesFactoryHalAidl(std::shared_ptr<IConfig> iconfig)
+    : mIConfig(std::move(iconfig)) {
     ALOG_ASSERT(iconfig != nullptr, "Provided default IConfig service is NULL");
-    mIConfig = std::move(iconfig);
 }
 
 void DevicesFactoryHalAidl::onFirstRef() {
@@ -41,8 +45,18 @@
     if (name == nullptr || device == nullptr) {
         return BAD_VALUE;
     }
-    ALOGE("%s not implemented yet", __func__);
+    ALOGE("%s not implemented yet %s", __func__, name);
     return INVALID_OPERATION;
+
+    // TODO: only support primary now ("default" means "primary")
+    if (strcmp(name, "primary") != 0) {
+        auto serviceName = std::string() + IModule::descriptor + "/default";
+        auto service = IModule::fromBinder(
+                ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
+        ALOGW("%s fromBinder %s %s", __func__, IModule::descriptor, service ? "succ" : "fail");
+        *device = new DeviceHalAidl(service);
+    }
+    return OK;
 }
 
 status_t DevicesFactoryHalAidl::getHalPids(std::vector<pid_t> *pids) {
@@ -76,9 +90,14 @@
 
 // Main entry-point to the shared library.
 extern "C" __attribute__((visibility("default"))) void* createIDevicesFactoryImpl() {
+    auto serviceName = std::string(IConfig::descriptor) + "/default";
     auto service = IConfig::fromBinder(
-            ndk::SpAIBinder(AServiceManager_waitForService(IConfig::descriptor)));
-    return service ? new DevicesFactoryHalAidl(service) : nullptr;
+            ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
+    if (!service) {
+        ALOGE("%s binder service %s not exist", __func__, serviceName.c_str());
+        return nullptr;
+    }
+    return new DevicesFactoryHalAidl(service);
 }
 
 } // namespace android
diff --git a/media/libaudiohal/impl/DevicesFactoryHalAidl.h b/media/libaudiohal/impl/DevicesFactoryHalAidl.h
index f4812af..71138a0 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalAidl.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalAidl.h
@@ -20,14 +20,13 @@
 #include <media/audiohal/DevicesFactoryHalInterface.h>
 #include <utils/RefBase.h>
 
-using namespace ::aidl::android::hardware::audio::core;
-
 namespace android {
 
 class DevicesFactoryHalAidl : public DevicesFactoryHalInterface
 {
   public:
-    explicit DevicesFactoryHalAidl(std::shared_ptr<IConfig> iConfig);
+    explicit DevicesFactoryHalAidl(
+            std::shared_ptr<::aidl::android::hardware::audio::core::IConfig> iConfig);
     void onFirstRef() override;
 
     // Opens a device with the specified name. To close the device, it is
@@ -41,8 +40,8 @@
     android::detail::AudioHalVersionInfo getHalVersion() const override;
 
   private:
-    std::shared_ptr<IConfig> mIConfig;
-    virtual ~DevicesFactoryHalAidl() = default;
+    const std::shared_ptr<::aidl::android::hardware::audio::core::IConfig> mIConfig;
+    ~DevicesFactoryHalAidl() = default;
 };
 
 } // namespace android
diff --git a/media/libaudiohal/impl/EffectBufferHalAidl.cpp b/media/libaudiohal/impl/EffectBufferHalAidl.cpp
new file mode 100644
index 0000000..5af8e24
--- /dev/null
+++ b/media/libaudiohal/impl/EffectBufferHalAidl.cpp
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "EffectBufferHalAidl"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+
+#include "EffectBufferHalAidl.h"
+
+namespace android {
+namespace effect {
+
+// static
+status_t EffectBufferHalAidl::allocate(size_t size, sp<EffectBufferHalInterface>* buffer) {
+    ALOGE("%s not implemented yet %zu %p", __func__, size, buffer);
+    return mirror(nullptr, size, buffer);
+}
+
+status_t EffectBufferHalAidl::mirror(void* external, size_t size,
+                                     sp<EffectBufferHalInterface>* buffer) {
+    // buffer->setExternalData(external);
+    ALOGW("%s not implemented yet %p %zu %p", __func__, external, size, buffer);
+    return OK;
+}
+
+EffectBufferHalAidl::EffectBufferHalAidl(size_t size)
+    : mBufferSize(size),
+      mFrameCountChanged(false),
+      mExternalData(nullptr),
+      mAudioBuffer{0, {nullptr}} {
+}
+
+EffectBufferHalAidl::~EffectBufferHalAidl() {
+}
+
+status_t EffectBufferHalAidl::init() {
+    ALOGW("%s not implemented yet", __func__);
+    return OK;
+}
+
+audio_buffer_t* EffectBufferHalAidl::audioBuffer() {
+    return &mAudioBuffer;
+}
+
+void* EffectBufferHalAidl::externalData() const {
+    return mExternalData;
+}
+
+void EffectBufferHalAidl::setFrameCount(size_t frameCount) {
+    mAudioBuffer.frameCount = frameCount;
+    mFrameCountChanged = true;
+}
+
+bool EffectBufferHalAidl::checkFrameCountChange() {
+    bool result = mFrameCountChanged;
+    mFrameCountChanged = false;
+    return result;
+}
+
+void EffectBufferHalAidl::setExternalData(void* external) {
+    mExternalData = external;
+}
+
+void EffectBufferHalAidl::update() {
+    ALOGW("%s not implemented yet", __func__);
+}
+
+void EffectBufferHalAidl::commit() {
+    ALOGW("%s not implemented yet", __func__);
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/EffectBufferHalAidl.h b/media/libaudiohal/impl/EffectBufferHalAidl.h
new file mode 100644
index 0000000..f488708
--- /dev/null
+++ b/media/libaudiohal/impl/EffectBufferHalAidl.h
@@ -0,0 +1,61 @@
+/*
+ * 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 <media/audiohal/EffectBufferHalInterface.h>
+#include <system/audio_effect.h>
+
+namespace android {
+namespace effect {
+
+class EffectBufferHalAidl : public EffectBufferHalInterface {
+  public:
+    static status_t allocate(size_t size, sp<EffectBufferHalInterface>* buffer);
+    static status_t mirror(void* external, size_t size, sp<EffectBufferHalInterface>* buffer);
+
+    audio_buffer_t* audioBuffer() override;
+    void* externalData() const override;
+
+    size_t getSize() const override { return mBufferSize; }
+
+    void setExternalData(void* external) override;
+    void setFrameCount(size_t frameCount) override;
+    bool checkFrameCountChange() override;
+
+    void update() override;
+    void commit() override;
+    void update(size_t size) override;
+    void commit(size_t size) override;
+
+  private:
+    friend class EffectBufferHalInterface;
+
+    const size_t mBufferSize;
+    bool mFrameCountChanged;
+    void* mExternalData;
+    audio_buffer_t mAudioBuffer;
+
+    // Can not be constructed directly by clients.
+    explicit EffectBufferHalAidl(size_t size);
+
+    ~EffectBufferHalAidl();
+
+    status_t init();
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/EffectHalAidl.cpp b/media/libaudiohal/impl/EffectHalAidl.cpp
new file mode 100644
index 0000000..31c5ca5
--- /dev/null
+++ b/media/libaudiohal/impl/EffectHalAidl.cpp
@@ -0,0 +1,234 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "EffectHalAidl"
+//#define LOG_NDEBUG 0
+
+#include <media/AidlConversionCppNdk.h>
+#include <media/AidlConversionNdk.h>
+#include <media/audiohal/AudioHalUtils.h>
+#include <media/EffectsFactoryApi.h>
+#include <mediautils/TimeCheck.h>
+#include <utils/Log.h>
+
+#include "EffectHalAidl.h"
+
+#include <system/audio.h>
+
+#include <aidl/android/hardware/audio/effect/IEffect.h>
+
+using ::aidl::android::hardware::audio::effect::CommandId;
+using ::aidl::android::hardware::audio::effect::Descriptor;
+using ::aidl::android::hardware::audio::effect::IEffect;
+using ::aidl::android::hardware::audio::effect::State;
+using ::aidl::android::hardware::audio::effect::Parameter;
+
+namespace android {
+namespace effect {
+
+EffectHalAidl::EffectHalAidl(const std::shared_ptr<IEffect>& effect, uint64_t effectId,
+                             int32_t sessionId, int32_t ioId)
+    : mEffectId(effectId), mSessionId(sessionId), mIoId(ioId), mEffect(effect) {}
+
+EffectHalAidl::~EffectHalAidl() {}
+
+status_t EffectHalAidl::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
+    if (buffer == nullptr) {
+        return BAD_VALUE;
+    }
+    ALOGW("%s not implemented yet", __func__);
+    return OK;
+}
+
+status_t EffectHalAidl::setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
+    if (buffer == nullptr) {
+        return BAD_VALUE;
+    }
+    ALOGW("%s not implemented yet", __func__);
+    return OK;
+}
+
+status_t EffectHalAidl::process() {
+    ALOGW("%s not implemented yet", __func__);
+    // write to input FMQ here?
+    return OK;
+}
+
+// TODO: no one using, maybe deprecate this interface
+status_t EffectHalAidl::processReverse() {
+    ALOGW("%s not implemented yet", __func__);
+    return OK;
+}
+
+status_t EffectHalAidl::handleSetConfig(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData,
+                                        uint32_t* replySize, void* pReplyData) {
+    if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) || replySize == NULL ||
+        *replySize != sizeof(int32_t) || pReplyData == NULL) {
+        ALOGE("%s parameter error code %u", __func__, cmdCode);
+        return BAD_VALUE;
+    }
+
+    *static_cast<int32_t*>(pReplyData) = FAILED_TRANSACTION;
+    memcpy(&mConfig, pCmdData, cmdSize);
+
+    State state;
+    RETURN_IF_BINDER_FAIL(mEffect->getState(&state));
+    // effect not open yet, save settings locally
+    if (state != State::INIT) {
+        effect_config_t* legacyConfig = static_cast<effect_config_t*>(pCmdData);
+        // already open, apply latest settings
+        Parameter aidlParam;
+        Parameter::Common aidlCommon;
+        aidlCommon.input.base =
+                VALUE_OR_RETURN_STATUS(::aidl::android::legacy2aidl_AudioConfigBase_buffer_config_t(
+                        legacyConfig->inputCfg, true /* isInput */));
+        aidlCommon.output.base =
+                VALUE_OR_RETURN_STATUS(::aidl::android::legacy2aidl_AudioConfigBase_buffer_config_t(
+                        legacyConfig->outputCfg, false /* isInput */));
+        aidlCommon.session = mSessionId;
+        aidlCommon.ioHandle = mIoId;
+        Parameter::Id id;
+        id.set<Parameter::Id::commonTag>(Parameter::common);
+        aidlParam.set<Parameter::common>(aidlCommon);
+        RETURN_IF_BINDER_FAIL(mEffect->setParameter(aidlParam));
+    }
+    *(int*)pReplyData = 0;
+    *static_cast<int32_t*>(pReplyData) = OK;
+    return OK;
+}
+
+status_t EffectHalAidl::handleGetConfig(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData,
+                                        uint32_t* replySize, void* pReplyData) {
+    if (pCmdData == NULL || cmdSize == 0 || replySize == NULL ||
+        *replySize != sizeof(effect_config_t) || pReplyData == NULL) {
+        ALOGE("%s parameter error with cmdCode %d", __func__, cmdCode);
+        return BAD_VALUE;
+    }
+
+    *(effect_config_t*)pReplyData = mConfig;
+    return OK;
+}
+
+status_t EffectHalAidl::handleSetParameter(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData,
+                                           uint32_t* replySize, void* pReplyData) {
+    ALOGW("%s not implemented yet", __func__);
+    if (pCmdData == NULL || cmdSize == 0 || replySize == NULL ||
+        *replySize != sizeof(effect_config_t) || pReplyData == NULL) {
+        ALOGE("%s parameter error with cmdCode %d", __func__, cmdCode);
+        return BAD_VALUE;
+    }
+    return OK;
+}
+
+status_t EffectHalAidl::handleGetParameter(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData,
+                                           uint32_t* replySize, void* pReplyData) {
+    ALOGW("%s not implemented yet", __func__);
+    if (pCmdData == NULL || cmdSize == 0 || replySize == NULL ||
+        *replySize != sizeof(effect_config_t) || pReplyData == NULL) {
+        ALOGE("%s parameter error with cmdCode %d", __func__, cmdCode);
+        return BAD_VALUE;
+    }
+    return OK;
+}
+
+status_t EffectHalAidl::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData,
+                                uint32_t* replySize, void* pReplyData) {
+    ALOGW("%s code %d not implemented yet", __func__, cmdCode);
+    ::ndk::ScopedAStatus status;
+    switch (cmdCode) {
+        case EFFECT_CMD_INIT: {
+            // open with default effect_config_t (convert to Parameter.Common)
+            IEffect::OpenEffectReturn ret;
+            Parameter::Common common;
+            RETURN_IF_BINDER_FAIL(mEffect->open(common, std::nullopt, &ret));
+            return OK;
+        }
+        case EFFECT_CMD_SET_CONFIG:
+            return handleSetConfig(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
+        case EFFECT_CMD_GET_CONFIG:
+            return handleGetConfig(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
+        case EFFECT_CMD_RESET:
+            return mEffect->command(CommandId::RESET).getStatus();
+        case EFFECT_CMD_ENABLE:
+            return mEffect->command(CommandId::START).getStatus();
+        case EFFECT_CMD_DISABLE:
+            return mEffect->command(CommandId::STOP).getStatus();
+        case EFFECT_CMD_SET_PARAM:
+            return handleSetParameter(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
+        case EFFECT_CMD_SET_PARAM_DEFERRED:
+        case EFFECT_CMD_SET_PARAM_COMMIT:
+            // TODO
+            return OK;
+        case EFFECT_CMD_GET_PARAM:
+            return handleGetParameter(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
+        case EFFECT_CMD_SET_DEVICE:
+            return OK;
+        case EFFECT_CMD_SET_VOLUME:
+            return OK;
+        case EFFECT_CMD_SET_AUDIO_MODE:
+            return OK;
+        case EFFECT_CMD_SET_CONFIG_REVERSE:
+            return OK;
+        case EFFECT_CMD_SET_INPUT_DEVICE:
+            return OK;
+        case EFFECT_CMD_GET_CONFIG_REVERSE:
+            return OK;
+        case EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS:
+            return OK;
+        case EFFECT_CMD_GET_FEATURE_CONFIG:
+            return OK;
+        case EFFECT_CMD_SET_FEATURE_CONFIG:
+            return OK;
+        case EFFECT_CMD_SET_AUDIO_SOURCE:
+            return OK;
+        case EFFECT_CMD_OFFLOAD:
+            return OK;
+        case EFFECT_CMD_DUMP:
+            return OK;
+        case EFFECT_CMD_FIRST_PROPRIETARY:
+            return OK;
+        default:
+            return INVALID_OPERATION;
+    }
+    return INVALID_OPERATION;
+}
+
+status_t EffectHalAidl::getDescriptor(effect_descriptor_t* pDescriptor) {
+    ALOGW("%s %p", __func__, pDescriptor);
+    if (pDescriptor == nullptr) {
+        return BAD_VALUE;
+    }
+    Descriptor aidlDesc;
+    RETURN_IF_BINDER_FAIL(mEffect->getDescriptor(&aidlDesc));
+
+    *pDescriptor = VALUE_OR_RETURN_STATUS(
+            ::aidl::android::aidl2legacy_Descriptor_effect_descriptor(aidlDesc));
+    return OK;
+}
+
+status_t EffectHalAidl::close() {
+    auto ret = mEffect->close();
+    ALOGI("%s %s", __func__, ret.getMessage());
+    return ret.getStatus();
+}
+
+status_t EffectHalAidl::dump(int fd) {
+    ALOGW("%s not implemented yet, fd %d", __func__, fd);
+    return OK;
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/EffectHalAidl.h b/media/libaudiohal/impl/EffectHalAidl.h
new file mode 100644
index 0000000..76bb240
--- /dev/null
+++ b/media/libaudiohal/impl/EffectHalAidl.h
@@ -0,0 +1,86 @@
+/*
+ * 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 <aidl/android/hardware/audio/effect/IEffect.h>
+#include <media/audiohal/EffectHalInterface.h>
+#include <system/audio_effect.h>
+
+namespace android {
+namespace effect {
+
+class EffectHalAidl : public EffectHalInterface {
+  public:
+    // Set the input buffer.
+    status_t setInBuffer(const sp<EffectBufferHalInterface>& buffer) override;
+
+    // Set the output buffer.
+    status_t setOutBuffer(const sp<EffectBufferHalInterface>& buffer) override;
+
+    // Effect process function.
+    status_t process() override;
+
+    // Process reverse stream function. This function is used to pass
+    // a reference stream to the effect engine.
+    status_t processReverse() override;
+
+    // Send a command and receive a response to/from effect engine.
+    status_t command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData, uint32_t* replySize,
+                     void* pReplyData) override;
+
+    // Returns the effect descriptor.
+    status_t getDescriptor(effect_descriptor_t *pDescriptor) override;
+
+    // Free resources on the remote side.
+    status_t close() override;
+
+    // Whether it's a local implementation.
+    bool isLocal() const override { return false; }
+
+    status_t dump(int fd) override;
+
+    uint64_t effectId() const override { return mEffectId; }
+
+  private:
+    friend class EffectsFactoryHalAidl;
+
+    const uint64_t mEffectId;
+    const int32_t mSessionId;
+    const int32_t mIoId;
+    sp<EffectBufferHalInterface> mInBuffer, mOutBuffer;
+    effect_config_t mConfig;
+    std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> mEffect;
+
+    // Can not be constructed directly by clients.
+    EffectHalAidl(const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& effect,
+                  uint64_t effectId, int32_t sessionId, int32_t ioId);
+
+    status_t handleSetConfig(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData,
+                             uint32_t* replySize, void* pReplyData);
+    status_t handleGetConfig(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData,
+                             uint32_t* replySize, void* pReplyData);
+    status_t handleSetParameter(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData,
+                                uint32_t* replySize, void* pReplyData);
+    status_t handleGetParameter(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData,
+                                uint32_t* replySize, void* pReplyData);
+
+    // The destructor automatically releases the effect.
+    virtual ~EffectHalAidl();
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp b/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
index 7aec859..0039c86 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
@@ -14,69 +14,122 @@
  * limitations under the License.
  */
 
-#include <random>
+#include <algorithm>
+#include <cstdint>
+#include <memory>
 #define LOG_TAG "EffectsFactoryHalAidl"
 //#define LOG_NDEBUG 0
 
 #include <aidl/android/hardware/audio/effect/IFactory.h>
 #include <android/binder_manager.h>
+#include <media/AidlConversionCppNdk.h>
+#include <media/AidlConversionNdk.h>
+#include <media/audiohal/AudioHalUtils.h>
 #include <utils/Log.h>
 
+#include "EffectBufferHalAidl.h"
+#include "EffectHalAidl.h"
 #include "EffectsFactoryHalAidl.h"
 
 using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::media::audio::common::AudioUuid;
 using android::detail::AudioHalVersionInfo;
 
 namespace android {
 namespace effect {
 
-EffectsFactoryHalAidl::EffectsFactoryHalAidl(std::shared_ptr<IFactory> effectsFactory) {
+EffectsFactoryHalAidl::EffectsFactoryHalAidl(std::shared_ptr<IFactory> effectsFactory)
+    : mFactory(effectsFactory),
+      mHalVersion(AudioHalVersionInfo(AudioHalVersionInfo::Type::AIDL, [this]() {
+          int32_t majorVersion = 0;
+          return (mFactory && mFactory->getInterfaceVersion(&majorVersion).isOk()) ? majorVersion
+                                                                                   : 0;
+      }())) {
     ALOG_ASSERT(effectsFactory != nullptr, "Provided IEffectsFactory service is NULL");
-    mEffectsFactory = effectsFactory;
 }
 
 status_t EffectsFactoryHalAidl::queryNumberEffects(uint32_t *pNumEffects) {
     if (pNumEffects == nullptr) {
         return BAD_VALUE;
     }
-    ALOGE("%s not implemented yet", __func__);
-    return INVALID_OPERATION;
+
+    {
+        std::lock_guard lg(mLock);
+        RETURN_IF_NOT_OK(queryEffectList_l());
+        *pNumEffects = mDescList->size();
+    }
+    ALOGI("%s %d", __func__, *pNumEffects);
+    return OK;
 }
 
 status_t EffectsFactoryHalAidl::getDescriptor(uint32_t index, effect_descriptor_t* pDescriptor) {
-    if (index < 0 || pDescriptor == nullptr) {
+    if (pDescriptor == nullptr) {
         return BAD_VALUE;
     }
-    ALOGE("%s not implemented yet", __func__);
-    return INVALID_OPERATION;
+
+    std::lock_guard lg(mLock);
+    RETURN_IF_NOT_OK(queryEffectList_l());
+
+    auto listSize = mDescList->size();
+    if (index >= listSize) {
+        ALOGE("%s index %d exceed size DescList %zd", __func__, index, listSize);
+        return INVALID_OPERATION;
+    }
+
+    *pDescriptor = VALUE_OR_RETURN_STATUS(
+            ::aidl::android::aidl2legacy_Descriptor_effect_descriptor(mDescList->at(index)));
+    return OK;
 }
 
-status_t EffectsFactoryHalAidl::getDescriptor(const effect_uuid_t* pEffectUuid,
+status_t EffectsFactoryHalAidl::getDescriptor(const effect_uuid_t* halUuid,
                                               effect_descriptor_t* pDescriptor) {
-    if (pEffectUuid == nullptr || pDescriptor == nullptr) {
+    if (halUuid == nullptr || pDescriptor == nullptr) {
         return BAD_VALUE;
     }
-    ALOGE("%s not implemented yet", __func__);
-    return INVALID_OPERATION;
+
+    AudioUuid uuid =
+            VALUE_OR_RETURN_STATUS(::aidl::android::legacy2aidl_audio_uuid_t_AudioUuid(*halUuid));
+    std::lock_guard lg(mLock);
+    return getHalDescriptorWithImplUuid_l(uuid, pDescriptor);
 }
 
-status_t EffectsFactoryHalAidl::getDescriptors(const effect_uuid_t* pEffectType,
+status_t EffectsFactoryHalAidl::getDescriptors(const effect_uuid_t* halType,
                                                std::vector<effect_descriptor_t>* descriptors) {
-    if (pEffectType == nullptr || descriptors == nullptr) {
+    if (halType == nullptr || descriptors == nullptr) {
         return BAD_VALUE;
     }
-    ALOGE("%s not implemented yet", __func__);
-    return INVALID_OPERATION;
+
+    AudioUuid type =
+            VALUE_OR_RETURN_STATUS(::aidl::android::legacy2aidl_audio_uuid_t_AudioUuid(*halType));
+    std::lock_guard lg(mLock);
+    return getHalDescriptorWithTypeUuid_l(type, descriptors);
 }
 
-status_t EffectsFactoryHalAidl::createEffect(const effect_uuid_t* pEffectUuid, int32_t sessionId,
+status_t EffectsFactoryHalAidl::createEffect(const effect_uuid_t* uuid, int32_t sessionId,
                                              int32_t ioId, int32_t deviceId __unused,
                                              sp<EffectHalInterface>* effect) {
-    if (pEffectUuid == nullptr || effect == nullptr) {
+    if (uuid == nullptr || effect == nullptr) {
         return BAD_VALUE;
     }
-    ALOGE("%s not implemented yet %d %d", __func__, sessionId, ioId);
-    return INVALID_OPERATION;
+    ALOGI("%s session %d ioId %d", __func__, sessionId, ioId);
+
+    AudioUuid aidlUuid =
+            VALUE_OR_RETURN_STATUS(::aidl::android::legacy2aidl_audio_uuid_t_AudioUuid(*uuid));
+    std::shared_ptr<IEffect> aidlEffect;
+    ndk::ScopedAStatus status = mFactory->createEffect(aidlUuid, &aidlEffect);
+    if (!status.isOk() || aidlEffect == nullptr) {
+        ALOGE("%s IFactory::createFactory failed %s UUID %s", __func__,
+              status.getDescription().c_str(), aidlUuid.toString().c_str());
+        return INVALID_OPERATION;
+    }
+    uint64_t effectId;
+    {
+        std::lock_guard lg(mLock);
+        effectId = ++mEffectIdCounter;
+    }
+
+    *effect = new EffectHalAidl(aidlEffect, effectId, sessionId, ioId);
+    return OK;
 }
 
 status_t EffectsFactoryHalAidl::dumpEffects(int fd) {
@@ -85,33 +138,77 @@
 }
 
 status_t EffectsFactoryHalAidl::allocateBuffer(size_t size, sp<EffectBufferHalInterface>* buffer) {
-    if (size <= 0 || buffer == nullptr) {
-        return BAD_VALUE;
-    }
-    ALOGE("%s not implemented yet", __func__);
-    return INVALID_OPERATION;
+    ALOGI("%s size %zu buffer %p", __func__, size, buffer);
+    // Buffer doesn't allocated here for AIDL, instead each effect open will return I/O data FMQ.
+    return EffectBufferHalAidl::allocate(size, buffer);
 }
 
 status_t EffectsFactoryHalAidl::mirrorBuffer(void* external, size_t size,
                                              sp<EffectBufferHalInterface>* buffer) {
-    if (external == nullptr || size <= 0 || buffer == nullptr) {
-        return BAD_VALUE;
-    }
-    ALOGE("%s not implemented yet", __func__);
-    return INVALID_OPERATION;
+    ALOGI("%s extern %p size %zu buffer %p", __func__, external, size, buffer);
+    // TODO: implement with FMQ
+    return EffectBufferHalAidl::mirror(external, size, buffer);
 }
 
 AudioHalVersionInfo EffectsFactoryHalAidl::getHalVersion() const {
-    int32_t versionNumber = 0;
-    if (mEffectsFactory) {
-        if (!mEffectsFactory->getInterfaceVersion(&versionNumber).isOk()) {
-            ALOGE("%s getInterfaceVersion failed", __func__);
-        } else {
-            ALOGI("%s getInterfaceVersion %d", __func__, versionNumber);
+    return mHalVersion;
+}
+
+status_t EffectsFactoryHalAidl::queryEffectList_l() {
+    if (!mDescList) {
+        std::vector<Descriptor> list;
+        auto status = mFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &list);
+        if (!status.isOk()) {
+            ALOGE("%s IFactory::queryEffects failed %s", __func__, status.getDescription().c_str());
+            return status.getStatus();
         }
+
+        mDescList = std::make_unique<std::vector<Descriptor>>(list);
     }
-    // AIDL does not have minor version, fill 0 for all versions
-    return AudioHalVersionInfo(AudioHalVersionInfo::Type::AIDL, versionNumber);
+    return OK;
+}
+
+status_t EffectsFactoryHalAidl::getHalDescriptorWithImplUuid_l(const AudioUuid& uuid,
+                                                               effect_descriptor_t* pDescriptor) {
+    if (pDescriptor == nullptr) {
+        return BAD_VALUE;
+    }
+    if (!mDescList) {
+        RETURN_IF_NOT_OK(queryEffectList_l());
+    }
+
+    auto matchIt = std::find_if(mDescList->begin(), mDescList->end(),
+                                 [&](const auto& desc) { return desc.common.id.uuid == uuid; });
+    if (matchIt == mDescList->end()) {
+        ALOGE("%s UUID %s not found", __func__, uuid.toString().c_str());
+        return BAD_VALUE;
+    }
+
+    *pDescriptor = VALUE_OR_RETURN_STATUS(
+            ::aidl::android::aidl2legacy_Descriptor_effect_descriptor(*matchIt));
+    return OK;
+}
+
+status_t EffectsFactoryHalAidl::getHalDescriptorWithTypeUuid_l(
+        const AudioUuid& type, std::vector<effect_descriptor_t>* descriptors) {
+    if (descriptors == nullptr) {
+        return BAD_VALUE;
+    }
+    if (!mDescList) {
+        RETURN_IF_NOT_OK(queryEffectList_l());
+    }
+    std::vector<Descriptor> result;
+    std::copy_if(mDescList->begin(), mDescList->end(), std::back_inserter(result),
+                 [&](auto& desc) { return desc.common.id.type == type; });
+    if (result.size() == 0) {
+        ALOGE("%s type UUID %s not found", __func__, type.toString().c_str());
+        return BAD_VALUE;
+    }
+
+    *descriptors = VALUE_OR_RETURN_STATUS(
+            aidl::android::convertContainer<std::vector<effect_descriptor_t>>(
+                    result, ::aidl::android::aidl2legacy_Descriptor_effect_descriptor));
+    return OK;
 }
 
 } // namespace effect
@@ -120,9 +217,14 @@
 // exports from a static library are optimized out unless actually used by
 // the shared library. See EffectsFactoryHalEntry.cpp.
 extern "C" void* createIEffectsFactoryImpl() {
-    auto factory = IFactory::fromBinder(
-            ndk::SpAIBinder(AServiceManager_waitForService(IFactory::descriptor)));
-    return factory ? new effect::EffectsFactoryHalAidl(factory) : nullptr;
+    auto serviceName = std::string(IFactory::descriptor) + "/default";
+    auto service = IFactory::fromBinder(
+            ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
+    if (!service) {
+        ALOGE("%s binder service %s not exist", __func__, serviceName.c_str());
+        return nullptr;
+    }
+    return new effect::EffectsFactoryHalAidl(service);
 }
 
 } // namespace android
diff --git a/media/libaudiohal/impl/EffectsFactoryHalAidl.h b/media/libaudiohal/impl/EffectsFactoryHalAidl.h
index d6b5684..1e85da9 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalAidl.h
+++ b/media/libaudiohal/impl/EffectsFactoryHalAidl.h
@@ -16,7 +16,13 @@
 
 #pragma once
 
+#include <cstddef>
+#include <memory>
+#include <mutex>
+
+#include <android-base/thread_annotations.h>
 #include <media/audiohal/EffectsFactoryHalInterface.h>
+#include <system/thread_defs.h>
 
 namespace android {
 namespace effect {
@@ -40,8 +46,8 @@
                             std::vector<effect_descriptor_t>* descriptors) override;
 
     // Creates an effect engine of the specified type.
-    // To release the effect engine, it is necessary to release references
-    // to the returned effect object.
+    // To release the effect engine, it is necessary to release references to the returned effect
+    // object.
     status_t createEffect(const effect_uuid_t* pEffectUuid, int32_t sessionId, int32_t ioId,
                           int32_t deviceId, sp<EffectHalInterface>* effect) override;
 
@@ -51,11 +57,23 @@
     status_t mirrorBuffer(void* external, size_t size,
                           sp<EffectBufferHalInterface>* buffer) override;
 
-    android::detail::AudioHalVersionInfo getHalVersion() const override;
+    detail::AudioHalVersionInfo getHalVersion() const override;
 
   private:
-    std::shared_ptr<IFactory> mEffectsFactory;
+    std::mutex mLock;
+    const std::shared_ptr<IFactory> mFactory;
+    uint64_t mEffectIdCounter GUARDED_BY(mLock) = 0; // Align with HIDL (0 is INVALID_ID)
+    std::unique_ptr<std::vector<Descriptor>> mDescList GUARDED_BY(mLock) = nullptr;
+    const detail::AudioHalVersionInfo mHalVersion;
+
     virtual ~EffectsFactoryHalAidl() = default;
+    status_t queryEffectList_l() REQUIRES(mLock);
+    status_t getHalDescriptorWithImplUuid_l(
+            const aidl::android::media::audio::common::AudioUuid& uuid,
+            effect_descriptor_t* pDescriptor) REQUIRES(mLock);
+    status_t getHalDescriptorWithTypeUuid_l(
+            const aidl::android::media::audio::common::AudioUuid& type,
+            std::vector<effect_descriptor_t>* descriptors) REQUIRES(mLock);
 };
 
 } // namespace effect
diff --git a/media/libaudiohal/include/media/audiohal/AudioHalUtils.h b/media/libaudiohal/include/media/audiohal/AudioHalUtils.h
new file mode 100644
index 0000000..4862cba
--- /dev/null
+++ b/media/libaudiohal/include/media/audiohal/AudioHalUtils.h
@@ -0,0 +1,35 @@
+/*
+ * 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
+
+#define RETURN_IF_BINDER_FAIL(expr)                                              \
+    do {                                                                         \
+        const ::ndk::ScopedAStatus _temp_status_ = (expr);                       \
+        if (!_temp_status_.isOk()) {                                             \
+            ALOGE("%s:%d return with expr %s msg %s", __func__, __LINE__, #expr, \
+                  _temp_status_.getMessage());                                   \
+            return _temp_status_.getStatus();                                    \
+        }                                                                        \
+    } while (false)
+
+#define RETURN_IF_NOT_OK(statement) \
+    do {                            \
+        auto tmp = (statement);     \
+        if (tmp != OK) {            \
+            return tmp;             \
+        }                           \
+    } while (false)
diff --git a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
index 3858607..2c8219e 100644
--- a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
@@ -21,7 +21,6 @@
 #include <android/media/audio/common/AudioMMapPolicyType.h>
 #include <error/Result.h>
 #include <media/audiohal/EffectHalInterface.h>
-#include <media/MicrophoneInfo.h>
 #include <system/audio.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
@@ -107,16 +106,23 @@
     virtual status_t releaseAudioPatch(audio_patch_handle_t patch) = 0;
 
     // Fills the list of supported attributes for a given audio port.
-    virtual status_t getAudioPort(struct audio_port *port) = 0;
+    virtual status_t getAudioPort(struct audio_port* port) {
+        ALOGE("%s override me port %p", __func__, port);
+        return OK;
+    }
 
     // Fills the list of supported attributes for a given audio port.
-    virtual status_t getAudioPort(struct audio_port_v7 *port) = 0;
+    virtual status_t getAudioPort(struct audio_port_v7 *port) {
+        ALOGE("%s override me port %p", __func__, port);
+        return OK;
+    }
 
     // Set audio port configuration.
     virtual status_t setAudioPortConfig(const struct audio_port_config *config) = 0;
 
     // List microphones
-    virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones) = 0;
+    virtual status_t getMicrophones(
+            std::vector<audio_microphone_characteristic_t>* microphones) = 0;
 
     virtual status_t addDeviceEffect(
             audio_port_handle_t device, sp<EffectHalInterface> effect) = 0;
@@ -125,13 +131,16 @@
 
     virtual status_t getMmapPolicyInfos(
             media::audio::common::AudioMMapPolicyType policyType,
-            std::vector<media::audio::common::AudioMMapPolicyInfo> *policyInfos)  = 0;
+            std::vector<media::audio::common::AudioMMapPolicyInfo> *policyInfos) = 0;
     virtual int32_t getAAudioMixerBurstCount() = 0;
     virtual int32_t getAAudioHardwareBurstMinUsec() = 0;
     virtual int32_t supportsBluetoothVariableLatency(bool* supports) = 0;
 
     // Update the connection status of an external device.
-    virtual status_t setConnectedState(const struct audio_port_v7 *port, bool connected) = 0;
+    virtual status_t setConnectedState(const struct audio_port_v7* port, bool connected) {
+        ALOGE("%s override me port %p connected %d", __func__, port, connected);
+        return OK;
+    }
 
     virtual error::Result<audio_hw_sync_t> getHwAvSync() = 0;
 
diff --git a/media/libaudiohal/tests/Android.bp b/media/libaudiohal/tests/Android.bp
new file mode 100644
index 0000000..e20f74c
--- /dev/null
+++ b/media/libaudiohal/tests/Android.bp
@@ -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.
+
+// Headers module is in frameworks/av/Android.bp because modules are not allowed
+// to refer to headers in parent directories and the headers live in
+// frameworks/av/include.
+
+package {
+    default_applicable_licenses: ["frameworks_av_license"],
+}
+
+cc_test {
+    name: "EffectsFactoryHalInterfaceTest",
+    test_suites: ["device-tests"],
+
+    srcs: [
+        "EffectsFactoryHalInterface_test.cpp",
+    ],
+
+    defaults: [
+        "latest_android_media_audio_common_types_cpp_shared",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-Wthread-safety",
+    ],
+
+    shared_libs: [
+        "audioclient-types-aidl-cpp",
+        "libaudiohal",
+        "libutils",
+    ],
+
+    header_libs: [
+        "libaudiohal_headers",
+    ],
+}
diff --git a/media/libaudiohal/tests/EffectsFactoryHalInterface_test.cpp b/media/libaudiohal/tests/EffectsFactoryHalInterface_test.cpp
new file mode 100644
index 0000000..83c7809
--- /dev/null
+++ b/media/libaudiohal/tests/EffectsFactoryHalInterface_test.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright 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.
+ */
+
+//#define LOG_NDEBUG 0
+#include <cstdint>
+#define LOG_TAG "EffectsFactoryHalInterfaceTest"
+
+#include <media/audiohal/EffectsFactoryHalInterface.h>
+
+#include <gtest/gtest.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+// EffectsFactoryHalInterface
+TEST(libAudioHalTest, createEffectsFactoryHalInterface) {
+    ASSERT_NE(nullptr, EffectsFactoryHalInterface::create());
+}
+
+TEST(libAudioHalTest, queryNumberEffects) {
+    auto factory = EffectsFactoryHalInterface::create();
+    ASSERT_NE(nullptr, factory);
+
+    uint32_t numEffects = 0;
+    EXPECT_EQ(OK, factory->queryNumberEffects(&numEffects));
+    EXPECT_NE(0ul, numEffects);
+}
+
+TEST(libAudioHalTest, getDescriptorByNumber) {
+    auto factory = EffectsFactoryHalInterface::create();
+    ASSERT_NE(nullptr, factory);
+
+    uint32_t numEffects = 0;
+    EXPECT_EQ(OK, factory->queryNumberEffects(&numEffects));
+    EXPECT_NE(0ul, numEffects);
+
+    effect_descriptor_t desc;
+    for (uint32_t i = 0; i < numEffects; i++) {
+        EXPECT_EQ(OK, factory->getDescriptor(i, &desc));
+    }
+}
+
+TEST(libAudioHalTest, createEffect) {
+    auto factory = EffectsFactoryHalInterface::create();
+    ASSERT_NE(nullptr, factory);
+
+    uint32_t numEffects = 0;
+    EXPECT_EQ(OK, factory->queryNumberEffects(&numEffects));
+    EXPECT_NE(0ul, numEffects);
+
+    effect_descriptor_t desc;
+    for (uint32_t i = 0; i < numEffects; i++) {
+        sp<EffectHalInterface> interface;
+        EXPECT_EQ(OK, factory->getDescriptor(i, &desc));
+        EXPECT_EQ(OK, factory->createEffect(&desc.uuid, 1 /* sessionId */, 1 /* ioId */,
+                                            1 /* deviceId */, &interface));
+    }
+}
+
+TEST(libAudioHalTest, getHalVersion) {
+    auto factory = EffectsFactoryHalInterface::create();
+    ASSERT_NE(nullptr, factory);
+
+    auto version = factory->getHalVersion();
+    EXPECT_NE(0, version.getMajorVersion());
+}
+
+// TODO: b/263986405 Add multi-thread testing
+
+} // namespace android
diff --git a/media/libeffects/dynamicsproc/Android.bp b/media/libeffects/dynamicsproc/Android.bp
index 84131a4..f655c4f 100644
--- a/media/libeffects/dynamicsproc/Android.bp
+++ b/media/libeffects/dynamicsproc/Android.bp
@@ -32,34 +32,68 @@
     ],
 }
 
+cc_defaults {
+    name : "dynamicsprocessingdefaults",
+    srcs: [
+        "dsp/DPBase.cpp",
+        "dsp/DPFrequency.cpp",
+    ],
+
+    shared_libs: [
+        "libaudioutils",
+        "libbase",
+        "liblog",
+        "libutils",
+    ],
+    header_libs: [
+        "libaudioeffects",
+        "libeigen",
+    ],
+    cflags: [
+        "-Wthread-safety",
+        "-Wall",
+        "-Werror",
+    ],
+}
+
 cc_library_shared {
     name: "libdynproc",
 
     vendor: true,
 
+    defaults: [
+        "dynamicsprocessingdefaults",
+    ],
+
     srcs: [
         "EffectDynamicsProcessing.cpp",
-        "dsp/DPBase.cpp",
-        "dsp/DPFrequency.cpp",
     ],
 
     cflags: [
         "-O2",
         "-fvisibility=hidden",
-
-        "-Wall",
-        "-Werror",
-    ],
-
-    shared_libs: [
-        "libcutils",
-        "liblog",
     ],
 
     relative_install_path: "soundfx",
+}
 
-    header_libs: [
-        "libaudioeffects",
-        "libeigen",
+cc_library_shared {
+    name: "libdynamicsprocessingaidl",
+
+    srcs: [
+        "aidl/DynamicsProcessing.cpp",
+        "aidl/DynamicsProcessingContext.cpp",
+        ":effectCommonFile",
+    ],
+
+    defaults: [
+        "aidlaudioservice_defaults",
+        "latest_android_hardware_audio_effect_ndk_shared",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "dynamicsprocessingdefaults",
+    ],
+
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
     ],
 }
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
new file mode 100644
index 0000000..203a27b
--- /dev/null
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
@@ -0,0 +1,313 @@
+/*
+ * 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 "AHAL_DynamicsProcessingLibEffects"
+
+#include <android-base/logging.h>
+
+#include "DynamicsProcessing.h"
+
+#include <dsp/DPBase.h>
+#include <dsp/DPFrequency.h>
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::DynamicsProcessingImpl;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kDynamicsProcessingImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioUuid;
+using aidl::android::media::audio::common::PcmType;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+                                           std::shared_ptr<IEffect>* instanceSpp) {
+    if (!in_impl_uuid || *in_impl_uuid != kDynamicsProcessingImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<DynamicsProcessingImpl>();
+        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 || *in_impl_uuid != kDynamicsProcessingImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    *_aidl_return = DynamicsProcessingImpl::kDescriptor;
+    return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string DynamicsProcessingImpl::kEffectName = "DynamicsProcessing";
+const DynamicsProcessing::Capability DynamicsProcessingImpl::kCapability = {.minCutOffFreq = 220,
+                                                                            .maxCutOffFreq = 20000};
+const Descriptor DynamicsProcessingImpl::kDescriptor = {
+        .common = {.id = {.type = kDynamicsProcessingTypeUUID,
+                          .uuid = kDynamicsProcessingImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::LAST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = DynamicsProcessingImpl::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = Capability::make<Capability::dynamicsProcessing>(
+                DynamicsProcessingImpl::kCapability)};
+
+ndk::ScopedAStatus DynamicsProcessingImpl::open(const Parameter::Common& common,
+                                                const std::optional<Parameter::Specific>& specific,
+                                                OpenEffectReturn* ret) {
+    LOG(DEBUG) << __func__;
+    // effect only support 32bits float
+    RETURN_IF(common.input.base.format.pcm != common.output.base.format.pcm ||
+                      common.input.base.format.pcm != PcmType::FLOAT_32_BIT,
+              EX_ILLEGAL_ARGUMENT, "dataMustBe32BitsFloat");
+    RETURN_OK_IF(mState != State::INIT);
+    auto context = createContext(common);
+    RETURN_IF(!context, EX_NULL_POINTER, "createContextFailed");
+
+    RETURN_IF_ASTATUS_NOT_OK(setParameterCommon(common), "setCommParamErr");
+    if (specific.has_value()) {
+        RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr");
+    } else {
+        Parameter::Specific defaultSpecific =
+                Parameter::Specific::make<Parameter::Specific::dynamicsProcessing>(
+                        DynamicsProcessing::make<DynamicsProcessing::engineArchitecture>(
+                                mContext->getEngineArchitecture()));
+        RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(defaultSpecific), "setDefaultEngineErr");
+    }
+
+    mState = State::IDLE;
+    context->dupeFmq(ret);
+    RETURN_IF(createThread(context, getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
+              "FailedToCreateWorker");
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus DynamicsProcessingImpl::getDescriptor(Descriptor* _aidl_return) {
+    RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus DynamicsProcessingImpl::commandImpl(CommandId command) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    switch (command) {
+        case CommandId::START:
+            mContext->enable();
+            return ndk::ScopedAStatus::ok();
+        case CommandId::STOP:
+            mContext->disable();
+            return ndk::ScopedAStatus::ok();
+        case CommandId::RESET:
+            mContext->disable();
+            mContext->resetBuffer();
+            return ndk::ScopedAStatus::ok();
+        default:
+            // Need this default handling for vendor extendable CommandId::VENDOR_COMMAND_*
+            LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "commandIdNotSupported");
+    }
+}
+
+ndk::ScopedAStatus DynamicsProcessingImpl::setParameterSpecific(
+        const Parameter::Specific& specific) {
+    RETURN_IF(Parameter::Specific::dynamicsProcessing != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+              "EffectNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto& param = specific.get<Parameter::Specific::dynamicsProcessing>();
+    auto tag = param.getTag();
+
+    switch (tag) {
+        case DynamicsProcessing::engineArchitecture: {
+            RETURN_IF(mContext->setEngineArchitecture(
+                              param.get<DynamicsProcessing::engineArchitecture>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setEngineArchitectureFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::preEq: {
+            RETURN_IF(
+                    mContext->setPreEq(param.get<DynamicsProcessing::preEq>()) != RetCode::SUCCESS,
+                    EX_ILLEGAL_ARGUMENT, "setPreEqFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::postEq: {
+            RETURN_IF(mContext->setPostEq(param.get<DynamicsProcessing::postEq>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setPostEqFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::preEqBand: {
+            RETURN_IF(mContext->setPreEqBand(param.get<DynamicsProcessing::preEqBand>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setPreEqBandFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::postEqBand: {
+            RETURN_IF(mContext->setPostEqBand(param.get<DynamicsProcessing::postEqBand>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setPostEqBandFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::mbc: {
+            RETURN_IF(mContext->setMbc(param.get<DynamicsProcessing::mbc>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setMbcFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::mbcBand: {
+            RETURN_IF(mContext->setMbcBand(param.get<DynamicsProcessing::mbcBand>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setMbcBandFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::limiter: {
+            RETURN_IF(mContext->setLimiter(param.get<DynamicsProcessing::limiter>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setLimiterFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::inputGain: {
+            RETURN_IF(mContext->setInputGain(param.get<DynamicsProcessing::inputGain>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setInputGainFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::vendorExtension: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "DPVendorExtensionTagNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus DynamicsProcessingImpl::getParameterSpecific(const Parameter::Id& id,
+                                                                Parameter::Specific* specific) {
+    RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::dynamicsProcessingTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto dpId = id.get<Parameter::Id::dynamicsProcessingTag>();
+    auto dpIdTag = dpId.getTag();
+    switch (dpIdTag) {
+        case DynamicsProcessing::Id::commonTag:
+            return getParameterDynamicsProcessing(dpId.get<DynamicsProcessing::Id::commonTag>(),
+                                                  specific);
+        case DynamicsProcessing::Id::vendorExtensionTag:
+            LOG(ERROR) << __func__ << " unsupported ID: " << toString(dpIdTag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "DPVendorExtensionIdNotSupported");
+    }
+}
+
+ndk::ScopedAStatus DynamicsProcessingImpl::getParameterDynamicsProcessing(
+        const DynamicsProcessing::Tag& tag, Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    switch (tag) {
+        case DynamicsProcessing::engineArchitecture: {
+            specific->set<Parameter::Specific::dynamicsProcessing>(
+                    DynamicsProcessing::make<DynamicsProcessing::engineArchitecture>(
+                            mContext->getEngineArchitecture()));
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::preEq: {
+            specific->set<Parameter::Specific::dynamicsProcessing>(
+                    DynamicsProcessing::make<DynamicsProcessing::preEq>(mContext->getPreEq()));
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::postEq: {
+            specific->set<Parameter::Specific::dynamicsProcessing>(
+                    DynamicsProcessing::make<DynamicsProcessing::postEq>(mContext->getPostEq()));
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::preEqBand: {
+            specific->set<Parameter::Specific::dynamicsProcessing>(
+                    DynamicsProcessing::make<DynamicsProcessing::preEqBand>(
+                            mContext->getPreEqBand()));
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::postEqBand: {
+            specific->set<Parameter::Specific::dynamicsProcessing>(
+                    DynamicsProcessing::make<DynamicsProcessing::postEqBand>(
+                            mContext->getPostEqBand()));
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::mbc: {
+            specific->set<Parameter::Specific::dynamicsProcessing>(
+                    DynamicsProcessing::make<DynamicsProcessing::mbc>(mContext->getMbc()));
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::mbcBand: {
+            specific->set<Parameter::Specific::dynamicsProcessing>(
+                    DynamicsProcessing::make<DynamicsProcessing::mbcBand>(mContext->getMbcBand()));
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::limiter: {
+            specific->set<Parameter::Specific::dynamicsProcessing>(
+                    DynamicsProcessing::make<DynamicsProcessing::limiter>(mContext->getLimiter()));
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::inputGain: {
+            specific->set<Parameter::Specific::dynamicsProcessing>(
+                    DynamicsProcessing::make<DynamicsProcessing::inputGain>(
+                            mContext->getInputGain()));
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::vendorExtension: {
+            LOG(ERROR) << __func__ << " wrong vendor tag in CommonTag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "DPVendorExtensionTagInWrongId");
+        }
+    }
+}
+
+std::shared_ptr<EffectContext> DynamicsProcessingImpl::createContext(
+        const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+        return mContext;
+    }
+
+    mContext = std::make_shared<DynamicsProcessingContext>(1 /* statusFmqDepth */, common);
+    return mContext;
+}
+
+RetCode DynamicsProcessingImpl::releaseContext() {
+    if (mContext) {
+        mContext->disable();
+        mContext->resetBuffer();
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status DynamicsProcessingImpl::effectProcessImpl(float* in, float* out, int samples) {
+    IEffect::Status status = {EX_NULL_POINTER, 0, 0};
+    RETURN_VALUE_IF(!mContext, status, "nullContext");
+    return mContext->lvmProcess(in, out, samples);
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
new file mode 100644
index 0000000..824ebea
--- /dev/null
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
@@ -0,0 +1,60 @@
+/*
+ * 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 "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+#include "DynamicsProcessingContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class DynamicsProcessingImpl final : public EffectImpl {
+  public:
+    static const std::string kEffectName;
+    static const Descriptor kDescriptor;
+    static const DynamicsProcessing::Capability kCapability;
+
+    DynamicsProcessingImpl() { LOG(DEBUG) << __func__; }
+    ~DynamicsProcessingImpl() {
+        cleanUp();
+        LOG(DEBUG) << __func__;
+    }
+
+    ndk::ScopedAStatus open(const Parameter::Common& common,
+                            const std::optional<Parameter::Specific>& specific,
+                            OpenEffectReturn* ret) override;
+    ndk::ScopedAStatus commandImpl(CommandId command) 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;
+    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    RetCode releaseContext() override;
+
+    std::shared_ptr<EffectContext> getContext() override { return mContext; }
+    std::string getEffectName() override { return kEffectName; }
+
+  private:
+    std::shared_ptr<DynamicsProcessingContext> mContext;
+    ndk::ScopedAStatus getParameterDynamicsProcessing(const DynamicsProcessing::Tag& tag,
+                                                      Parameter::Specific* specific);
+};
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
new file mode 100644
index 0000000..57a2be9
--- /dev/null
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
@@ -0,0 +1,580 @@
+/*
+ * 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 "AHAL_DPLibEffectsContext"
+
+#include "DynamicsProcessing.h"
+#include "DynamicsProcessingContext.h"
+
+#include <functional>
+#include <sys/param.h>
+#include <unordered_set>
+
+namespace aidl::android::hardware::audio::effect {
+
+DynamicsProcessingContext::DynamicsProcessingContext(int statusDepth,
+                                                     const Parameter::Common& common)
+    : EffectContext(statusDepth, common) {
+    LOG(DEBUG) << __func__;
+    init();
+}
+
+DynamicsProcessingContext::~DynamicsProcessingContext() {
+    LOG(DEBUG) << __func__;
+}
+
+RetCode DynamicsProcessingContext::enable() {
+    std::lock_guard lg(mMutex);
+    if (mState != DYNAMICS_PROCESSING_STATE_INITIALIZED) {
+        return RetCode::ERROR_EFFECT_LIB_ERROR;
+    }
+    mState = DYNAMICS_PROCESSING_STATE_ACTIVE;
+    return RetCode::SUCCESS;
+}
+
+RetCode DynamicsProcessingContext::disable() {
+    std::lock_guard lg(mMutex);
+    if (mState != DYNAMICS_PROCESSING_STATE_ACTIVE) {
+        return RetCode::ERROR_EFFECT_LIB_ERROR;
+    }
+    mState = DYNAMICS_PROCESSING_STATE_INITIALIZED;
+    return RetCode::SUCCESS;
+}
+
+void DynamicsProcessingContext::reset() {
+    std::lock_guard lg(mMutex);
+    if (mDpFreq != nullptr) {
+        mDpFreq.reset();
+    }
+}
+
+RetCode DynamicsProcessingContext::setCommon(const Parameter::Common& common) {
+    mCommon = common;
+    init();
+    return RetCode::SUCCESS;
+}
+
+void DynamicsProcessingContext::dpSetFreqDomainVariant_l(
+        const DynamicsProcessing::EngineArchitecture& engine) {
+    mDpFreq.reset(new dp_fx::DPFrequency());
+    mDpFreq->init(mChannelCount, engine.preEqStage.inUse, engine.preEqStage.bandCount,
+                  engine.mbcStage.inUse, engine.mbcStage.bandCount, engine.postEqStage.inUse,
+                  engine.postEqStage.bandCount, engine.limiterInUse);
+
+    int32_t sampleRate = mCommon.input.base.sampleRate;
+    int32_t minBlockSize = (int32_t)dp_fx::DPFrequency::getMinBockSize();
+    int32_t block = engine.preferredProcessingDurationMs * sampleRate / 1000.0f;
+    LOG(INFO) << __func__ << " sampleRate " << sampleRate << " block length "
+              << engine.preferredProcessingDurationMs << " ms (" << block << "samples)";
+    if (block < minBlockSize) {
+        block = minBlockSize;
+    } else if (!powerof2(block)) {
+        //find next highest power of 2.
+        block = 1 << (32 - __builtin_clz(block));
+    }
+    mDpFreq->configure(block, block >> 1, sampleRate);
+}
+
+RetCode DynamicsProcessingContext::setEngineArchitecture(
+        const DynamicsProcessing::EngineArchitecture& engineArchitecture) {
+    RETURN_VALUE_IF(!validateEngineConfig(engineArchitecture), RetCode::ERROR_ILLEGAL_PARAMETER,
+                    "illegalEngineConfig");
+
+    std::lock_guard lg(mMutex);
+    if (!mEngineInited || mEngineArchitecture != engineArchitecture) {
+        if (engineArchitecture.resolutionPreference ==
+            DynamicsProcessing::ResolutionPreference::FAVOR_FREQUENCY_RESOLUTION) {
+            dpSetFreqDomainVariant_l(engineArchitecture);
+        } else {
+            LOG(WARNING) << __func__ << toString(engineArchitecture.resolutionPreference)
+                         << " not available now";
+        }
+        mEngineInited = true;
+        mEngineArchitecture = engineArchitecture;
+    }
+    LOG(INFO) << __func__ << engineArchitecture.toString();
+    return RetCode::SUCCESS;
+}
+
+RetCode DynamicsProcessingContext::setPreEq(
+        const std::vector<DynamicsProcessing::ChannelConfig>& channels) {
+    std::lock_guard lg(mMutex);
+    return setDpChannels_l<dp_fx::DPEq>(channels, mEngineArchitecture.preEqStage.inUse,
+                                        StageType::PREEQ);
+}
+
+RetCode DynamicsProcessingContext::setPostEq(
+        const std::vector<DynamicsProcessing::ChannelConfig>& channels) {
+    std::lock_guard lg(mMutex);
+    return setDpChannels_l<dp_fx::DPEq>(channels, mEngineArchitecture.postEqStage.inUse,
+                                        StageType::POSTEQ);
+}
+
+RetCode DynamicsProcessingContext::setMbc(
+        const std::vector<DynamicsProcessing::ChannelConfig>& channels) {
+    std::lock_guard lg(mMutex);
+    return setDpChannels_l<dp_fx::DPMbc>(channels, mEngineArchitecture.mbcStage.inUse,
+                                         StageType::MBC);
+}
+
+RetCode DynamicsProcessingContext::setPreEqBand(
+        const std::vector<DynamicsProcessing::EqBandConfig>& bands) {
+    std::lock_guard lg(mMutex);
+    RETURN_VALUE_IF(!mEngineArchitecture.postEqStage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER,
+                    "postEqNotInUse");
+    return setBands_l<DynamicsProcessing::EqBandConfig>(
+            bands, mEngineArchitecture.preEqStage.bandCount, StageType::PREEQ);
+}
+
+RetCode DynamicsProcessingContext::setPostEqBand(
+        const std::vector<DynamicsProcessing::EqBandConfig>& bands) {
+    std::lock_guard lg(mMutex);
+    RETURN_VALUE_IF(!mEngineArchitecture.postEqStage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER,
+                    "postEqNotInUse");
+    return setBands_l<DynamicsProcessing::EqBandConfig>(
+            bands, mEngineArchitecture.postEqStage.bandCount, StageType::POSTEQ);
+}
+
+RetCode DynamicsProcessingContext::setMbcBand(
+        const std::vector<DynamicsProcessing::MbcBandConfig>& bands) {
+    std::lock_guard lg(mMutex);
+    RETURN_VALUE_IF(!mEngineArchitecture.mbcStage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER,
+                    "mbcNotInUse");
+    return setBands_l<DynamicsProcessing::MbcBandConfig>(
+            bands, mEngineArchitecture.preEqStage.bandCount, StageType::MBC);
+}
+
+RetCode DynamicsProcessingContext::setLimiter(
+        const std::vector<DynamicsProcessing::LimiterConfig>& limiters) {
+    std::lock_guard lg(mMutex);
+    RETURN_VALUE_IF(!mEngineArchitecture.limiterInUse, RetCode::ERROR_ILLEGAL_PARAMETER,
+                    "limiterNotInUse");
+    return setBands_l<DynamicsProcessing::LimiterConfig>(limiters, -1, StageType::LIMITER);
+}
+
+RetCode DynamicsProcessingContext::setInputGain(
+        const std::vector<DynamicsProcessing::InputGain>& inputGains) {
+    std::lock_guard lg(mMutex);
+    return setBands_l<DynamicsProcessing::InputGain>(inputGains, -1, StageType::INPUTGAIN);
+}
+
+DynamicsProcessing::EngineArchitecture DynamicsProcessingContext::getEngineArchitecture() {
+    std::lock_guard lg(mMutex);
+    LOG(INFO) << __func__ << mEngineArchitecture.toString();
+    return mEngineArchitecture;
+}
+
+std::vector<DynamicsProcessing::ChannelConfig> DynamicsProcessingContext::getPreEq() {
+    return getChannelConfig(StageType::PREEQ);
+}
+
+std::vector<DynamicsProcessing::ChannelConfig> DynamicsProcessingContext::getPostEq() {
+    return getChannelConfig(StageType::POSTEQ);
+}
+
+std::vector<DynamicsProcessing::EqBandConfig> DynamicsProcessingContext::getPreEqBand() {
+    return getEqBandConfigs(StageType::PREEQ);
+}
+
+std::vector<DynamicsProcessing::EqBandConfig> DynamicsProcessingContext::getPostEqBand() {
+    return getEqBandConfigs(StageType::POSTEQ);
+}
+
+std::vector<DynamicsProcessing::ChannelConfig> DynamicsProcessingContext::getMbc() {
+    return getChannelConfig(StageType::MBC);
+}
+
+std::vector<DynamicsProcessing::MbcBandConfig> DynamicsProcessingContext::getMbcBand() {
+    std::vector<DynamicsProcessing::MbcBandConfig> bands;
+
+    std::lock_guard lg(mMutex);
+    auto maxBand = mEngineArchitecture.mbcStage.bandCount;
+    for (int32_t ch = 0; ch < mChannelCount; ch++) {
+        auto mbc = getMbc_l(ch);
+        if (!mbc) {
+            continue;
+        }
+        for (int32_t bandId = 0; bandId < maxBand; bandId++) {
+            auto band = mbc->getBand(bandId);
+            if (!band) {
+                continue;
+            }
+            bands.push_back({.channel = ch,
+                             .band = bandId,
+                             .enable = band->isEnabled(),
+                             .cutoffFrequencyHz = band->getCutoffFrequency(),
+                             .attackTimeMs = band->getAttackTime(),
+                             .releaseTimeMs = band->getReleaseTime(),
+                             .ratio = band->getRatio(),
+                             .thresholdDb = band->getThreshold(),
+                             .kneeWidthDb = band->getKneeWidth(),
+                             .noiseGateThresholdDb = band->getNoiseGateThreshold(),
+                             .expanderRatio = band->getExpanderRatio(),
+                             .preGainDb = band->getPreGain(),
+                             .postGainDb = band->getPostGain()});
+        }
+    }
+    return bands;
+}
+
+std::vector<DynamicsProcessing::LimiterConfig> DynamicsProcessingContext::getLimiter() {
+    std::vector<DynamicsProcessing::LimiterConfig> ret;
+
+    std::lock_guard lg(mMutex);
+    for (int32_t ch = 0; ch < mChannelCount; ch++) {
+        auto limiter = getLimiter_l(ch);
+        if (!limiter) {
+            continue;
+        }
+        ret.push_back({.channel = ch,
+                       .enable = limiter->isEnabled(),
+                       .linkGroup = static_cast<int32_t>(limiter->getLinkGroup()),
+                       .attackTimeMs = limiter->getAttackTime(),
+                       .releaseTimeMs = limiter->getReleaseTime(),
+                       .ratio = limiter->getRatio(),
+                       .thresholdDb = limiter->getThreshold(),
+                       .postGainDb = limiter->getPostGain()});
+    }
+    return ret;
+}
+
+std::vector<DynamicsProcessing::InputGain> DynamicsProcessingContext::getInputGain() {
+    std::vector<DynamicsProcessing::InputGain> ret;
+
+    std::lock_guard lg(mMutex);
+    for (int32_t ch = 0; ch < mChannelCount; ch++) {
+        auto channel = getChannel_l(ch);
+        if (!channel) {
+            continue;
+        }
+        ret.push_back({.channel = ch, .gainDb = channel->getInputGain()});
+    }
+    return ret;
+}
+
+IEffect::Status DynamicsProcessingContext::lvmProcess(float* in, float* out, int samples) {
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " sample " << 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};
+
+    LOG(DEBUG) << __func__ << " start processing";
+    {
+        std::lock_guard lg(mMutex);
+        RETURN_VALUE_IF(mState != DynamicsProcessingState::DYNAMICS_PROCESSING_STATE_ACTIVE, status,
+                        "notInActiveState");
+        RETURN_VALUE_IF(!mDpFreq, status, "engineNotInited");
+        mDpFreq->processSamples(in, out, samples);
+    }
+    return {STATUS_OK, samples, samples};
+}
+
+void DynamicsProcessingContext::init() {
+    std::lock_guard lg(mMutex);
+    mState = DYNAMICS_PROCESSING_STATE_INITIALIZED;
+    mChannelCount =
+            ::android::hardware::audio::common::getChannelCount(mCommon.input.base.channelMask);
+}
+
+dp_fx::DPChannel* DynamicsProcessingContext::getChannel_l(int channel) {
+    RETURN_VALUE_IF(mDpFreq == nullptr, nullptr, "DPFreqNotInited");
+
+    return mDpFreq->getChannel(channel);
+}
+
+dp_fx::DPEq* DynamicsProcessingContext::getPreEq_l(int ch) {
+    auto channel = getChannel_l(ch);
+    RETURN_VALUE_IF(channel == nullptr, nullptr, "ChannelNotExist");
+
+    return channel->getPreEq();
+}
+
+dp_fx::DPEq* DynamicsProcessingContext::getPostEq_l(int ch) {
+    auto channel = getChannel_l(ch);
+    RETURN_VALUE_IF(channel == nullptr, nullptr, "ChannelNotExist");
+
+    return channel->getPostEq();
+}
+
+dp_fx::DPMbc* DynamicsProcessingContext::getMbc_l(int ch) {
+    auto channel = getChannel_l(ch);
+    RETURN_VALUE_IF(channel == nullptr, nullptr, "ChannelNotExist");
+
+    return channel->getMbc();
+}
+
+dp_fx::DPLimiter* DynamicsProcessingContext::getLimiter_l(int ch) {
+    auto channel = getChannel_l(ch);
+    RETURN_VALUE_IF(channel == nullptr, nullptr, "ChannelNotExist");
+
+    return channel->getLimiter();
+}
+
+dp_fx::DPBandStage* DynamicsProcessingContext::getStageWithType_l(
+        DynamicsProcessingContext::StageType type, int ch) {
+    switch (type) {
+        case StageType::PREEQ: {
+            return getEqWithType_l(type, ch);
+        }
+        case StageType::POSTEQ: {
+            return getEqWithType_l(type, ch);
+        }
+        case StageType::MBC: {
+            return getMbc_l(ch);
+        }
+        case StageType::LIMITER:
+            FALLTHROUGH_INTENDED;
+        case StageType::INPUTGAIN: {
+            return nullptr;
+        }
+    }
+}
+
+dp_fx::DPEq* DynamicsProcessingContext::getEqWithType_l(DynamicsProcessingContext::StageType type,
+                                                        int ch) {
+    switch (type) {
+        case StageType::PREEQ: {
+            return getPreEq_l(ch);
+        }
+        case StageType::POSTEQ: {
+            return getPostEq_l(ch);
+        }
+        case StageType::MBC:
+            FALLTHROUGH_INTENDED;
+        case StageType::LIMITER:
+            FALLTHROUGH_INTENDED;
+        case StageType::INPUTGAIN: {
+            return nullptr;
+        }
+    }
+}
+
+std::vector<DynamicsProcessing::ChannelConfig> DynamicsProcessingContext::getChannelConfig(
+        StageType type) {
+    std::vector<DynamicsProcessing::ChannelConfig> ret;
+
+    std::lock_guard lg(mMutex);
+    for (int32_t ch = 0; ch < mChannelCount; ch++) {
+        auto stage = getStageWithType_l(type, ch);
+        if (!stage) {
+            continue;
+        }
+        ret.push_back({.channel = ch, .enable = stage->isEnabled()});
+    }
+    return ret;
+}
+
+std::vector<DynamicsProcessing::EqBandConfig> DynamicsProcessingContext::getEqBandConfigs(
+        StageType type) {
+    std::vector<DynamicsProcessing::EqBandConfig> eqBands;
+
+    std::lock_guard lg(mMutex);
+    auto maxBand = mEngineArchitecture.preEqStage.bandCount;
+    for (int32_t ch = 0; ch < mChannelCount; ch++) {
+        auto eq = getEqWithType_l(type, ch);
+        if (!eq) {
+            continue;
+        }
+        for (int32_t bandId = 0; bandId < maxBand; bandId++) {
+            auto band = eq->getBand(bandId);
+            if (!band) {
+                continue;
+            }
+            eqBands.push_back({.channel = ch,
+                               .band = bandId,
+                               .enable = band->isEnabled(),
+                               .cutoffFrequencyHz = band->getCutoffFrequency(),
+                               .gainDb = band->getGain()});
+        }
+    }
+    return eqBands;
+}
+
+/**
+ * When StageEnablement is in use, bandCount needs to be positive.
+ */
+bool DynamicsProcessingContext::validateStageEnablement(
+        const DynamicsProcessing::StageEnablement& enablement) {
+    return !enablement.inUse || (enablement.inUse && enablement.bandCount > 0);
+}
+
+bool DynamicsProcessingContext::validateEngineConfig(
+        const DynamicsProcessing::EngineArchitecture& engine) {
+    return engine.preferredProcessingDurationMs >= 0 &&
+           validateStageEnablement(engine.preEqStage) &&
+           validateStageEnablement(engine.postEqStage) && validateStageEnablement(engine.mbcStage);
+}
+
+inline bool DynamicsProcessingContext::validateCutoffFrequency(float freq) {
+    return freq >= DynamicsProcessingImpl::kCapability.minCutOffFreq &&
+            freq <= DynamicsProcessingImpl::kCapability.maxCutOffFreq;
+}
+
+bool DynamicsProcessingContext::validateEqBandConfig(const DynamicsProcessing::EqBandConfig& band,
+                                                     int maxChannel, int maxBand) {
+    return validateChannel(band.channel, maxChannel) && validateBand(band.band, maxBand) &&
+           validateCutoffFrequency(band.cutoffFrequencyHz);
+}
+
+bool DynamicsProcessingContext::validateMbcBandConfig(const DynamicsProcessing::MbcBandConfig& band,
+                                                      int maxChannel, int maxBand) {
+    return validateChannel(band.channel, maxChannel) && validateBand(band.band, maxBand) &&
+           validateCutoffFrequency(band.cutoffFrequencyHz) && validateTime(band.attackTimeMs) &&
+           validateTime(band.releaseTimeMs) && validateRatio(band.ratio) &&
+           validateBandDb(band.thresholdDb) && validateBandDb(band.kneeWidthDb) &&
+           validateBandDb(band.noiseGateThresholdDb) && validateRatio(band.expanderRatio);
+}
+
+bool DynamicsProcessingContext::validateLimiterConfig(
+        const DynamicsProcessing::LimiterConfig& limiter, int maxChannel) {
+    return validateChannel(limiter.channel, maxChannel) && validateTime(limiter.attackTimeMs) &&
+           validateTime(limiter.releaseTimeMs) && validateRatio(limiter.ratio) &&
+           validateBandDb(limiter.thresholdDb);
+}
+
+bool DynamicsProcessingContext::validateInputGainConfig(const DynamicsProcessing::InputGain& gain,
+                                                        int maxChannel) {
+    return validateChannel(gain.channel, maxChannel);
+}
+
+template <typename D>
+RetCode DynamicsProcessingContext::setDpChannels_l(
+        const std::vector<DynamicsProcessing::ChannelConfig>& channels, bool stageInUse,
+        StageType type) {
+    RetCode ret = RetCode::SUCCESS;
+    std::unordered_set<int> channelSet;
+
+    RETURN_VALUE_IF(!stageInUse, RetCode::ERROR_ILLEGAL_PARAMETER, "stageNotInUse");
+    for (auto& it : channels) {
+        if (0 != channelSet.count(it.channel)) {
+            LOG(WARNING) << __func__ << " duplicated channel " << it.channel;
+            ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+        } else {
+            channelSet.insert(it.channel);
+        }
+        if (it.channel < 0 || it.channel >= mChannelCount) {
+            LOG(WARNING) << __func__ << " skip illegal ChannelConfig " << it.toString() << " max "
+                         << mChannelCount;
+            ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+            continue;
+        }
+        auto dp = getStageWithType_l(type, it.channel);
+        if (!dp) {
+            LOG(WARNING) << __func__ << " channel " << it.channel << " not exist";
+            ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+            continue;
+        }
+        if (dp->isEnabled() != it.enable) {
+            LOG(INFO) << __func__ << it.toString();
+            dp->setEnabled(it.enable);
+        }
+    }
+    return ret;
+}
+
+RetCode DynamicsProcessingContext::setDpChannelBand_l(const std::any& anyConfig, StageType type,
+                                                      int maxCh, int maxBand,
+                                                      std::set<std::pair<int, int>>& chBandSet) {
+    RETURN_VALUE_IF(!anyConfig.has_value(), RetCode::ERROR_ILLEGAL_PARAMETER, "bandInvalid");
+    RetCode ret = RetCode::SUCCESS;
+    std::pair<int, int> chBandKey;
+    switch (type) {
+        case StageType::PREEQ:
+            FALLTHROUGH_INTENDED;
+        case StageType::POSTEQ: {
+            dp_fx::DPEq* dp;
+            const auto& config = std::any_cast<DynamicsProcessing::EqBandConfig>(anyConfig);
+            RETURN_VALUE_IF(!validateEqBandConfig(config, maxCh, maxBand),
+                            RetCode::ERROR_ILLEGAL_PARAMETER, "eqBandNotValid");
+            RETURN_VALUE_IF(
+                    nullptr == (dp = getEqWithType_l(type, config.channel)) || !dp->isEnabled(),
+                    RetCode::ERROR_ILLEGAL_PARAMETER, "dpEqNotExist");
+            dp_fx::DPEqBand band;
+            band.init(config.enable, config.cutoffFrequencyHz, config.gainDb);
+            dp->setBand(config.band, band);
+            chBandKey = {config.channel, config.band};
+            break;
+        }
+        case StageType::MBC: {
+            dp_fx::DPMbc* dp;
+            const auto& config = std::any_cast<DynamicsProcessing::MbcBandConfig>(anyConfig);
+            RETURN_VALUE_IF(!validateMbcBandConfig(config, maxCh, maxBand),
+                            RetCode::ERROR_ILLEGAL_PARAMETER, "mbcBandNotValid");
+            RETURN_VALUE_IF(nullptr == (dp = getMbc_l(config.channel)) || !dp->isEnabled(),
+                            RetCode::ERROR_ILLEGAL_PARAMETER, "dpMbcNotExist");
+            dp_fx::DPMbcBand band;
+            band.init(config.enable, config.cutoffFrequencyHz, config.attackTimeMs,
+                      config.releaseTimeMs, config.ratio, config.thresholdDb, config.kneeWidthDb,
+                      config.noiseGateThresholdDb, config.expanderRatio, config.preGainDb,
+                      config.postGainDb);
+            dp->setBand(config.band, band);
+            chBandKey = {config.channel, config.band};
+            break;
+        }
+        case StageType::LIMITER: {
+            dp_fx::DPChannel* dp;
+            const auto& config = std::any_cast<DynamicsProcessing::LimiterConfig>(anyConfig);
+            RETURN_VALUE_IF(!validateLimiterConfig(config, maxCh),
+                            RetCode::ERROR_ILLEGAL_PARAMETER, "limiterBandNotValid");
+            RETURN_VALUE_IF(nullptr == (dp = getChannel_l(config.channel)),
+                            RetCode::ERROR_ILLEGAL_PARAMETER, "dpChNotExist");
+            dp_fx::DPLimiter limiter;
+            limiter.init(mEngineArchitecture.limiterInUse, config.enable, config.linkGroup,
+                         config.attackTimeMs, config.releaseTimeMs, config.ratio,
+                         config.thresholdDb, config.postGainDb);
+            dp->setLimiter(limiter);
+            chBandKey = {config.channel, 0};
+            break;
+        }
+        case StageType::INPUTGAIN: {
+            dp_fx::DPChannel* dp;
+            const auto& config = std::any_cast<DynamicsProcessing::InputGain>(anyConfig);
+            RETURN_VALUE_IF(!validateInputGainConfig(config, maxCh),
+                            RetCode::ERROR_ILLEGAL_PARAMETER, "inputGainNotValid");
+            RETURN_VALUE_IF(nullptr == (dp = getChannel_l(config.channel)),
+                            RetCode::ERROR_ILLEGAL_PARAMETER, "dpChNotExist");
+            dp->setInputGain(config.gainDb);
+            chBandKey = {config.channel, 0};
+            break;
+        }
+    }
+    RETURN_VALUE_IF(0 != chBandSet.count(chBandKey), RetCode::ERROR_ILLEGAL_PARAMETER,
+                    "duplicatedBand");
+    chBandSet.insert(chBandKey);
+    return ret;
+}
+
+template <typename T /* BandConfig */>
+RetCode DynamicsProcessingContext::setBands_l(
+        const std::vector<T>& bands, int maxBand, StageType type) {
+    RetCode ret = RetCode::SUCCESS;
+    std::set<std::pair<int /* channel */, int /* band */>> bandSet;
+
+    for (const auto& it : bands) {
+        if (RetCode::SUCCESS !=
+            setDpChannelBand_l(std::make_any<T>(it), type, mChannelCount, maxBand, bandSet)) {
+            LOG(WARNING) << __func__ << " skipping band " << it.toString();
+            ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+            continue;
+        }
+        LOG(INFO) << __func__ << it.toString();
+    }
+    return ret;
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h
new file mode 100644
index 0000000..8be784e
--- /dev/null
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h
@@ -0,0 +1,130 @@
+/*
+ * 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/thread_annotations.h>
+#include <audio_effects/effect_dynamicsprocessing.h>
+
+#include "effect-impl/EffectContext.h"
+
+#include <any>
+#include <cstddef>
+#include <dsp/DPBase.h>
+#include <dsp/DPFrequency.h>
+
+namespace aidl::android::hardware::audio::effect {
+
+enum DynamicsProcessingState {
+    DYNAMICS_PROCESSING_STATE_UNINITIALIZED,
+    DYNAMICS_PROCESSING_STATE_INITIALIZED,
+    DYNAMICS_PROCESSING_STATE_ACTIVE,
+};
+
+class DynamicsProcessingContext final : public EffectContext {
+  public:
+    DynamicsProcessingContext(int statusDepth, const Parameter::Common& common);
+    ~DynamicsProcessingContext();
+
+    RetCode enable();
+    RetCode disable();
+    void reset();
+
+    // override EffectContext::setCommon to update mChannelCount
+    RetCode setCommon(const Parameter::Common& common) override;
+
+    RetCode setEngineArchitecture(const DynamicsProcessing::EngineArchitecture& engineArchitecture);
+    RetCode setPreEq(const std::vector<DynamicsProcessing::ChannelConfig>& eqChannels);
+    RetCode setPostEq(const std::vector<DynamicsProcessing::ChannelConfig>& eqChannels);
+    RetCode setPreEqBand(const std::vector<DynamicsProcessing::EqBandConfig>& eqBands);
+    RetCode setPostEqBand(const std::vector<DynamicsProcessing::EqBandConfig>& eqBands);
+    RetCode setMbc(const std::vector<DynamicsProcessing::ChannelConfig>& mbcChannels);
+    RetCode setMbcBand(const std::vector<DynamicsProcessing::MbcBandConfig>& eqBands);
+    RetCode setLimiter(const std::vector<DynamicsProcessing::LimiterConfig>& limiters);
+    RetCode setInputGain(const std::vector<DynamicsProcessing::InputGain>& gain);
+
+    DynamicsProcessing::EngineArchitecture getEngineArchitecture();
+    std::vector<DynamicsProcessing::ChannelConfig> getPreEq();
+    std::vector<DynamicsProcessing::ChannelConfig> getPostEq();
+    std::vector<DynamicsProcessing::EqBandConfig> getPreEqBand();
+    std::vector<DynamicsProcessing::EqBandConfig> getPostEqBand();
+    std::vector<DynamicsProcessing::ChannelConfig> getMbc();
+    std::vector<DynamicsProcessing::MbcBandConfig> getMbcBand();
+    std::vector<DynamicsProcessing::LimiterConfig> getLimiter();
+    std::vector<DynamicsProcessing::InputGain> getInputGain();
+
+    IEffect::Status lvmProcess(float* in, float* out, int samples);
+
+  private:
+    static constexpr float kPreferredProcessingDurationMs = 10.0f;
+    static constexpr int kBandCount = 5;
+    std::mutex mMutex;
+    size_t mChannelCount GUARDED_BY(mMutex) = 0;
+    DynamicsProcessingState mState GUARDED_BY(mMutex) = DYNAMICS_PROCESSING_STATE_UNINITIALIZED;
+    std::unique_ptr<dp_fx::DPFrequency> mDpFreq GUARDED_BY(mMutex) = nullptr;
+    bool mEngineInited GUARDED_BY(mMutex) = false;
+    DynamicsProcessing::EngineArchitecture mEngineArchitecture GUARDED_BY(mMutex) = {
+            .resolutionPreference =
+                    DynamicsProcessing::ResolutionPreference::FAVOR_FREQUENCY_RESOLUTION,
+            .preferredProcessingDurationMs = kPreferredProcessingDurationMs,
+            .preEqStage = {.inUse = true, .bandCount = kBandCount},
+            .postEqStage = {.inUse = true, .bandCount = kBandCount},
+            .mbcStage = {.inUse = true, .bandCount = kBandCount},
+            .limiterInUse = true,
+    };
+
+    enum class StageType { PREEQ, POSTEQ, MBC, LIMITER, INPUTGAIN };
+
+    void init();
+
+    void dpSetFreqDomainVariant_l(const DynamicsProcessing::EngineArchitecture& engine)
+            REQUIRES(mMutex);
+    dp_fx::DPChannel* getChannel_l(int ch) REQUIRES(mMutex);
+    dp_fx::DPEq* getPreEq_l(int ch) REQUIRES(mMutex);
+    dp_fx::DPEq* getPostEq_l(int ch) REQUIRES(mMutex);
+    dp_fx::DPMbc* getMbc_l(int ch) REQUIRES(mMutex);
+    dp_fx::DPLimiter* getLimiter_l(int ch) REQUIRES(mMutex);
+    dp_fx::DPBandStage* getStageWithType_l(StageType type, int ch) REQUIRES(mMutex);
+    dp_fx::DPEq* getEqWithType_l(StageType type, int ch) REQUIRES(mMutex);
+    template <typename D>
+    RetCode setDpChannels_l(const std::vector<DynamicsProcessing::ChannelConfig>& channels,
+                            bool stageInUse, StageType type) REQUIRES(mMutex);
+    template <typename T /* BandConfig */>
+    RetCode setBands_l(const std::vector<T>& bands, int maxBand, StageType type) REQUIRES(mMutex);
+    RetCode setDpChannelBand_l(const std::any& anyConfig, StageType type, int maxCh, int maxBand,
+                               std::set<std::pair<int, int>>& chBandSet) REQUIRES(mMutex);
+
+    std::vector<DynamicsProcessing::EqBandConfig> getEqBandConfigs(StageType type);
+    std::vector<DynamicsProcessing::ChannelConfig> getChannelConfig(StageType type);
+
+    bool validateStageEnablement(const DynamicsProcessing::StageEnablement& enablement);
+    bool validateEngineConfig(const DynamicsProcessing::EngineArchitecture& engine);
+    bool validateEqBandConfig(const DynamicsProcessing::EqBandConfig& band, int maxChannel,
+                              int maxBand);
+    bool validateMbcBandConfig(const DynamicsProcessing::MbcBandConfig& band, int maxChannel,
+                               int maxBand);
+    bool validateLimiterConfig(const DynamicsProcessing::LimiterConfig& limiter, int maxChannel);
+    bool validateInputGainConfig(const DynamicsProcessing::InputGain& gain, int maxChannel);
+
+    inline bool validateCutoffFrequency(float freq);
+    inline bool validateChannel(int ch, int maxCh) { return ch >= 0 && ch < maxCh; }
+    inline bool validateBand(int band, int maxBand) { return band >= 0 && band < maxBand; }
+    inline bool validateTime(int time) { return time >= 0; }
+    inline bool validateRatio(int ratio) { return ratio >= 0; }
+    inline bool validateBandDb(int db) { return db <= 0; }
+};
+
+}  // namespace aidl::android::hardware::audio::effect
\ No newline at end of file
diff --git a/media/libeffects/hapticgenerator/Android.bp b/media/libeffects/hapticgenerator/Android.bp
index ba511fe..07ba492 100644
--- a/media/libeffects/hapticgenerator/Android.bp
+++ b/media/libeffects/hapticgenerator/Android.bp
@@ -22,6 +22,23 @@
     default_applicable_licenses: ["frameworks_av_license"],
 }
 
+cc_defaults {
+    name : "hapticgeneratordefaults",
+    srcs: [
+        "Processors.cpp",
+    ],
+    shared_libs: [
+        "libaudioutils",
+        "libbase",
+        "liblog",
+        "libutils",
+        "libvibratorutils",
+    ],
+    header_libs: [
+        "libaudioeffects",
+    ],
+}
+
 cc_library_shared {
     name: "libhapticgenerator",
 
@@ -29,7 +46,10 @@
 
     srcs: [
         "EffectHapticGenerator.cpp",
-        "Processors.cpp",
+    ],
+
+    defaults: [
+        "hapticgeneratordefaults",
     ],
 
     cflags: [
@@ -43,17 +63,30 @@
         "-fvisibility=hidden",
     ],
 
-    shared_libs: [
-        "libaudioutils",
-        "libbase",
-        "liblog",
-        "libutils",
-        "libvibratorutils",
+    relative_install_path: "soundfx",
+}
+
+cc_library_shared {
+    name: "libhapticgeneratoraidl",
+
+    srcs: [
+        "aidl/EffectHapticGenerator.cpp",
+        "aidl/HapticGeneratorContext.cpp",
+        ":effectCommonFile",
     ],
 
-    relative_install_path: "soundfx",
+    defaults: [
+        "aidlaudioservice_defaults",
+        "latest_android_hardware_audio_effect_ndk_shared",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "hapticgeneratordefaults",
+    ],
 
-    header_libs: [
-        "libaudioeffects",
+    cflags: [
+        "-Wthread-safety",
+    ],
+
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
     ],
 }
diff --git a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
new file mode 100644
index 0000000..7e22482
--- /dev/null
+++ b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "AHAL_HapticGeneratorImpl"
+
+#include "EffectHapticGenerator.h"
+
+#include <android-base/logging.h>
+#include <audio_effects/effect_hapticgenerator.h>
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::HapticGeneratorImpl;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kHapticGeneratorImplUUID;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+                                           std::shared_ptr<IEffect>* instanceSpp) {
+    if (!in_impl_uuid || *in_impl_uuid != kHapticGeneratorImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<HapticGeneratorImpl>();
+        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 || *in_impl_uuid != kHapticGeneratorImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    *_aidl_return = HapticGeneratorImpl::kDescriptor;
+    return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string HapticGeneratorImpl::kEffectName = "Haptic Generator";
+const Descriptor HapticGeneratorImpl::kDescriptor = {
+        .common = {.id = {.type = kHapticGeneratorTypeUUID,
+                          .uuid = kHapticGeneratorImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT, .insert = Flags::Insert::FIRST},
+                   .name = HapticGeneratorImpl::kEffectName,
+                   .implementor = "The Android Open Source Project"}};
+
+ndk::ScopedAStatus HapticGeneratorImpl::getDescriptor(Descriptor* _aidl_return) {
+    RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus HapticGeneratorImpl::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->reset();
+            break;
+        default:
+            LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "commandIdNotSupported");
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus HapticGeneratorImpl::setParameterSpecific(const Parameter::Specific& specific) {
+    RETURN_IF(Parameter::Specific::hapticGenerator != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+              "EffectNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto& hgParam = specific.get<Parameter::Specific::hapticGenerator>();
+    auto tag = hgParam.getTag();
+
+    switch (tag) {
+        case HapticGenerator::hapticScales: {
+            RETURN_IF(mContext->setHgHapticScales(hgParam.get<HapticGenerator::hapticScales>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setHapticScaleFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case HapticGenerator::vibratorInfo: {
+            RETURN_IF(mContext->setHgVibratorInformation(
+                              hgParam.get<HapticGenerator::vibratorInfo>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setVibratorInfoFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "HapticGeneratorTagNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus HapticGeneratorImpl::getParameterSpecific(const Parameter::Id& id,
+                                                             Parameter::Specific* specific) {
+    RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::hapticGeneratorTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto hgId = id.get<Parameter::Id::hapticGeneratorTag>();
+    auto hgIdTag = hgId.getTag();
+    switch (hgIdTag) {
+        case HapticGenerator::Id::commonTag:
+            return getParameterHapticGenerator(hgId.get<HapticGenerator::Id::commonTag>(),
+                                               specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(hgIdTag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "HapticGeneratorTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus HapticGeneratorImpl::getParameterHapticGenerator(const HapticGenerator::Tag& tag,
+                                                                    Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    HapticGenerator hgParam;
+    switch (tag) {
+        case HapticGenerator::hapticScales: {
+            hgParam.set<HapticGenerator::hapticScales>(mContext->getHgHapticScales());
+            break;
+        }
+        case HapticGenerator::vibratorInfo: {
+            hgParam.set<HapticGenerator::vibratorInfo>(mContext->getHgVibratorInformation());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "HapticGeneratorTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::hapticGenerator>(hgParam);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> HapticGeneratorImpl::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+        return mContext;
+    }
+
+    mContext = std::make_shared<HapticGeneratorContext>(1 /* statusFmqDepth */, common);
+    return mContext;
+}
+
+RetCode HapticGeneratorImpl::releaseContext() {
+    if (mContext) {
+        mContext->reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status HapticGeneratorImpl::effectProcessImpl(float* in, float* out, int samples) {
+    IEffect::Status status = {EX_NULL_POINTER, 0, 0};
+    RETURN_VALUE_IF(!mContext, status, "nullContext");
+    return mContext->lvmProcess(in, out, samples);
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h
new file mode 100644
index 0000000..02ca392
--- /dev/null
+++ b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h
@@ -0,0 +1,55 @@
+/*
+ * 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 <aidl/android/hardware/audio/effect/BnEffect.h>
+
+#include "HapticGeneratorContext.h"
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class HapticGeneratorImpl final : public EffectImpl {
+  public:
+    static const std::string kEffectName;
+    static const Descriptor kDescriptor;
+    HapticGeneratorImpl() { LOG(DEBUG) << __func__; }
+    ~HapticGeneratorImpl() {
+        cleanUp();
+        LOG(DEBUG) << __func__;
+    }
+
+    ndk::ScopedAStatus commandImpl(CommandId command) 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;
+    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    RetCode releaseContext() override;
+
+    std::shared_ptr<EffectContext> getContext() override { return mContext; }
+    std::string getEffectName() override { return kEffectName; }
+
+  private:
+    std::shared_ptr<HapticGeneratorContext> mContext;
+    ndk::ScopedAStatus getParameterHapticGenerator(const HapticGenerator::Tag& tag,
+                                                   Parameter::Specific* specific);
+};
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
new file mode 100644
index 0000000..64f51c3
--- /dev/null
+++ b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
@@ -0,0 +1,346 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "AHAL_HapticGeneratorContext"
+
+#include <Utils.h>
+#include <android-base/parsedouble.h>
+#include <android-base/properties.h>
+
+#include "HapticGeneratorContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+HapticGeneratorContext::HapticGeneratorContext(int statusDepth, const Parameter::Common& common)
+    : EffectContext(statusDepth, common) {
+    LOG(DEBUG) << __func__;
+    mState = HAPTIC_GENERATOR_STATE_UNINITIALIZED;
+    mSampleRate = common.input.base.sampleRate;
+    mFrameCount = common.input.frameCount;
+    init_params(common.input.base.channelMask, common.output.base.channelMask);
+}
+
+HapticGeneratorContext::~HapticGeneratorContext() {
+    LOG(DEBUG) << __func__;
+    mState = HAPTIC_GENERATOR_STATE_UNINITIALIZED;
+}
+
+RetCode HapticGeneratorContext::enable() {
+    if (mState != HAPTIC_GENERATOR_STATE_INITIALIZED) {
+        return RetCode::ERROR_EFFECT_LIB_ERROR;
+    }
+    mState = HAPTIC_GENERATOR_STATE_ACTIVE;
+    return RetCode::SUCCESS;
+}
+
+RetCode HapticGeneratorContext::disable() {
+    if (mState != HAPTIC_GENERATOR_STATE_ACTIVE) {
+        return RetCode::ERROR_EFFECT_LIB_ERROR;
+    }
+    mState = HAPTIC_GENERATOR_STATE_INITIALIZED;
+    return RetCode::SUCCESS;
+}
+
+void HapticGeneratorContext::reset() {
+    for (auto& filter : mProcessorsRecord.filters) {
+        filter->clear();
+    }
+    for (auto& slowEnv : mProcessorsRecord.slowEnvs) {
+        slowEnv->clear();
+    }
+    for (auto& distortion : mProcessorsRecord.distortions) {
+        distortion->clear();
+    }
+}
+
+RetCode HapticGeneratorContext::setHgHapticScales(
+        const std::vector<HapticGenerator::HapticScale> hapticScales) {
+    std::lock_guard lg(mMutex);
+    for (auto hapticScale : hapticScales) {
+        mParams.mHapticScales.insert_or_assign(hapticScale.id, hapticScale.scale);
+    }
+    mParams.mMaxVibratorScale = HapticGenerator::VibratorScale::MUTE;
+    for (const auto& [id, vibratorScale] : mParams.mHapticScales) {
+        mParams.mMaxVibratorScale = std::max(mParams.mMaxVibratorScale, vibratorScale);
+    }
+    return RetCode::SUCCESS;
+}
+
+HapticGenerator::VibratorInformation HapticGeneratorContext::getHgVibratorInformation() {
+    std::lock_guard lg(mMutex);
+    return mParams.mVibratorInfo;
+}
+
+std::vector<HapticGenerator::HapticScale> HapticGeneratorContext::getHgHapticScales() {
+    std::vector<HapticGenerator::HapticScale> result;
+    std::lock_guard lg(mMutex);
+    for (const auto& [id, vibratorScale] : mParams.mHapticScales) {
+        result.push_back({id, vibratorScale});
+    }
+    return result;
+}
+
+RetCode HapticGeneratorContext::setHgVibratorInformation(
+        const HapticGenerator::VibratorInformation& vibratorInfo) {
+    {
+        std::lock_guard lg(mMutex);
+        mParams.mVibratorInfo = vibratorInfo;
+
+        if (mProcessorsRecord.bpf != nullptr) {
+            mProcessorsRecord.bpf->setCoefficients(
+                    ::android::audio_effect::haptic_generator::bpfCoefs(
+                            mParams.mVibratorInfo.resonantFrequencyHz, DEFAULT_BPF_Q, mSampleRate));
+        }
+        if (mProcessorsRecord.bsf != nullptr) {
+            mProcessorsRecord.bsf->setCoefficients(
+                    ::android::audio_effect::haptic_generator::bsfCoefs(
+                            mParams.mVibratorInfo.resonantFrequencyHz,
+                            mParams.mVibratorInfo.qFactor, mParams.mVibratorInfo.qFactor / 2.0f,
+                            mSampleRate));
+        }
+    }
+    configure();
+    return RetCode::SUCCESS;
+}
+
+IEffect::Status HapticGeneratorContext::lvmProcess(float* in, float* out, int samples) {
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " sample " << 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};
+    RETURN_VALUE_IF(getInputFrameSize() != getOutputFrameSize(), status, "FrameSizeMismatch");
+    auto frameSize = getInputFrameSize();
+    RETURN_VALUE_IF(0 == frameSize, status, "zeroFrameSize");
+
+    LOG(DEBUG) << __func__ << " start processing";
+    // The audio data must not be modified but just written to
+    // output buffer according the access mode.
+    bool accumulate = false;
+    if (in != out) {
+        for (int i = 0; i < samples; i++) {
+            if (accumulate) {
+                out[i] += in[i];
+            } else {
+                out[i] = in[i];
+            }
+        }
+    }
+
+    if (mState != HAPTIC_GENERATOR_STATE_ACTIVE) {
+        return status;
+    }
+
+    std::lock_guard lg(mMutex);
+    if (mParams.mMaxVibratorScale == HapticGenerator::VibratorScale::MUTE) {
+        // Haptic channels are muted, not need to generate haptic data.
+        return {STATUS_OK, samples, samples};
+    }
+
+    // Resize buffer if the haptic sample count is greater than buffer size.
+    size_t hapticSampleCount = mFrameCount * mParams.mHapticChannelCount;
+    if (hapticSampleCount > mInputBuffer.size()) {
+        // The inputBuffer and outputBuffer must have the same size, which must be at least
+        // the haptic sample count.
+        mInputBuffer.resize(hapticSampleCount);
+        mOutputBuffer.resize(hapticSampleCount);
+    }
+
+    // Construct input buffer according to haptic channel source
+    for (size_t i = 0; i < mFrameCount; ++i) {
+        for (size_t j = 0; j < mParams.mHapticChannelCount; ++j) {
+            mInputBuffer[i * mParams.mHapticChannelCount + j] =
+                    in[i * mParams.mAudioChannelCount + mParams.mHapticChannelSource[j]];
+        }
+    }
+
+    float* hapticOutBuffer =
+            runProcessingChain(mInputBuffer.data(), mOutputBuffer.data(), mFrameCount);
+    ::android::os::scaleHapticData(
+            hapticOutBuffer, hapticSampleCount,
+            static_cast<::android::os::HapticScale>(mParams.mMaxVibratorScale),
+            mParams.mVibratorInfo.qFactor);
+
+    // For haptic data, the haptic playback thread will copy the data from effect input
+    // buffer, which contains haptic data at the end of the buffer, directly to sink buffer.
+    // In that case, copy haptic data to input buffer instead of output buffer.
+    // Note: this may not work with rpc/binder calls
+    int offset = samples;
+    for (int i = 0; i < hapticSampleCount; ++i) {
+        in[samples + i] = hapticOutBuffer[i];
+    }
+    return {STATUS_OK, samples, static_cast<int32_t>(samples + hapticSampleCount)};
+}
+
+void HapticGeneratorContext::init_params(media::audio::common::AudioChannelLayout inputChMask,
+                                         media::audio::common::AudioChannelLayout outputChMask) {
+    std::lock_guard lg(mMutex);
+    mParams.mMaxVibratorScale = HapticGenerator::VibratorScale::MUTE;
+    mParams.mVibratorInfo.resonantFrequencyHz = DEFAULT_RESONANT_FREQUENCY;
+    mParams.mVibratorInfo.qFactor = DEFAULT_BSF_ZERO_Q;
+
+    mParams.mAudioChannelCount = ::android::hardware::audio::common::getChannelCount(
+            inputChMask, ~media::audio::common::AudioChannelLayout::LAYOUT_HAPTIC_AB);
+    mParams.mHapticChannelCount = ::android::hardware::audio::common::getChannelCount(
+            outputChMask, media::audio::common::AudioChannelLayout::LAYOUT_HAPTIC_AB);
+    LOG_ALWAYS_FATAL_IF(mParams.mHapticChannelCount > 2, "haptic channel count is too large");
+    for (size_t i = 0; i < mParams.mHapticChannelCount; ++i) {
+        // By default, use the first audio channel to generate haptic channels.
+        mParams.mHapticChannelSource[i] = 0;
+    }
+
+    mState = HAPTIC_GENERATOR_STATE_INITIALIZED;
+}
+
+float HapticGeneratorContext::getDistortionOutputGain() {
+    float distortionOutputGain = getFloatProperty(
+            "vendor.audio.hapticgenerator.distortion.output.gain", DEFAULT_DISTORTION_OUTPUT_GAIN);
+    LOG(DEBUG) << "Using distortion output gain as " << distortionOutputGain;
+    return distortionOutputGain;
+}
+
+float HapticGeneratorContext::getFloatProperty(const std::string& key, float defaultValue) {
+    float result;
+    std::string value = ::android::base::GetProperty(key, "");
+    if (!value.empty() && ::android::base::ParseFloat(value, &result)) {
+        return result;
+    }
+    return defaultValue;
+}
+
+void HapticGeneratorContext::addBiquadFilter(std::shared_ptr<HapticBiquadFilter> filter) {
+    // The process chain captures the shared pointer of the filter in lambda.
+    // The process record will keep a shared pointer to the filter so that it is possible to
+    // access the filter outside of the process chain.
+    mProcessorsRecord.filters.push_back(filter);
+    mProcessingChain.push_back([filter](float* out, const float* in, size_t frameCount) {
+        filter->process(out, in, frameCount);
+    });
+}
+
+/**
+ * Build haptic generator processing chain.
+ */
+void HapticGeneratorContext::buildProcessingChain() {
+    std::lock_guard lg(mMutex);
+    const size_t channelCount = mParams.mHapticChannelCount;
+    float highPassCornerFrequency = 50.0f;
+    auto hpf = ::android::audio_effect::haptic_generator::createHPF2(highPassCornerFrequency,
+                                                                     mSampleRate, channelCount);
+    addBiquadFilter(hpf);
+    float lowPassCornerFrequency = 9000.0f;
+    auto lpf = ::android::audio_effect::haptic_generator::createLPF2(lowPassCornerFrequency,
+                                                                     mSampleRate, channelCount);
+    addBiquadFilter(lpf);
+
+    auto ramp = std::make_shared<::android::audio_effect::haptic_generator::Ramp>(
+            channelCount);  // ramp = half-wave rectifier.
+    // The process chain captures the shared pointer of the ramp in lambda. It will be the only
+    // reference to the ramp.
+    // The process record will keep a weak pointer to the ramp so that it is possible to access
+    // the ramp outside of the process chain.
+    mProcessorsRecord.ramps.push_back(ramp);
+    mProcessingChain.push_back([ramp](float* out, const float* in, size_t frameCount) {
+        ramp->process(out, in, frameCount);
+    });
+
+    highPassCornerFrequency = 60.0f;
+    hpf = ::android::audio_effect::haptic_generator::createHPF2(highPassCornerFrequency,
+                                                                mSampleRate, channelCount);
+    addBiquadFilter(hpf);
+    lowPassCornerFrequency = 700.0f;
+    lpf = ::android::audio_effect::haptic_generator::createLPF2(lowPassCornerFrequency, mSampleRate,
+                                                                channelCount);
+    addBiquadFilter(lpf);
+
+    lowPassCornerFrequency = 400.0f;
+    lpf = ::android::audio_effect::haptic_generator::createLPF2(lowPassCornerFrequency, mSampleRate,
+                                                                channelCount);
+    addBiquadFilter(lpf);
+    lowPassCornerFrequency = 500.0f;
+    lpf = ::android::audio_effect::haptic_generator::createLPF2(lowPassCornerFrequency, mSampleRate,
+                                                                channelCount);
+    addBiquadFilter(lpf);
+
+    auto bpf = ::android::audio_effect::haptic_generator::createBPF(
+            mParams.mVibratorInfo.resonantFrequencyHz, DEFAULT_BPF_Q, mSampleRate, channelCount);
+    mProcessorsRecord.bpf = bpf;
+    addBiquadFilter(bpf);
+
+    float normalizationPower = DEFAULT_SLOW_ENV_NORMALIZATION_POWER;
+    // The process chain captures the shared pointer of the slow envelope in lambda. It will
+    // be the only reference to the slow envelope.
+    // The process record will keep a weak pointer to the slow envelope so that it is possible
+    // to access the slow envelope outside of the process chain.
+    // SlowEnvelope = partial normalizer, or AGC.
+    auto slowEnv = std::make_shared<::android::audio_effect::haptic_generator::SlowEnvelope>(
+            5.0f /*envCornerFrequency*/, mSampleRate, normalizationPower, 0.01f /*envOffset*/,
+            channelCount);
+    mProcessorsRecord.slowEnvs.push_back(slowEnv);
+    mProcessingChain.push_back([slowEnv](float* out, const float* in, size_t frameCount) {
+        slowEnv->process(out, in, frameCount);
+    });
+
+    auto bsf = ::android::audio_effect::haptic_generator::createBSF(
+            mParams.mVibratorInfo.resonantFrequencyHz, mParams.mVibratorInfo.qFactor,
+            mParams.mVibratorInfo.qFactor / 2.0f, mSampleRate, channelCount);
+    mProcessorsRecord.bsf = bsf;
+    addBiquadFilter(bsf);
+
+    // The process chain captures the shared pointer of the Distortion in lambda. It will
+    // be the only reference to the Distortion.
+    // The process record will keep a weak pointer to the Distortion so that it is possible
+    // to access the Distortion outside of the process chain.
+    auto distortion = std::make_shared<::android::audio_effect::haptic_generator::Distortion>(
+            DEFAULT_DISTORTION_CORNER_FREQUENCY, mSampleRate, DEFAULT_DISTORTION_INPUT_GAIN,
+            DEFAULT_DISTORTION_CUBE_THRESHOLD, getDistortionOutputGain(), channelCount);
+    mProcessorsRecord.distortions.push_back(distortion);
+    mProcessingChain.push_back([distortion](float* out, const float* in, size_t frameCount) {
+        distortion->process(out, in, frameCount);
+    });
+}
+
+void HapticGeneratorContext::configure() {
+    mProcessingChain.clear();
+    mProcessorsRecord.filters.clear();
+    mProcessorsRecord.ramps.clear();
+    mProcessorsRecord.slowEnvs.clear();
+    mProcessorsRecord.distortions.clear();
+
+    buildProcessingChain();
+}
+
+/**
+ * Run the processing chain to generate haptic data from audio data
+ *
+ * @param buf1 a buffer contains raw audio data
+ * @param buf2 a buffer that is large enough to keep all the data
+ * @param frameCount frame count of the data
+ *
+ * @return a pointer to the output buffer
+ */
+float* HapticGeneratorContext::runProcessingChain(float* buf1, float* buf2, size_t frameCount) {
+    float* in = buf1;
+    float* out = buf2;
+    for (const auto processingFunc : mProcessingChain) {
+        processingFunc(out, in, frameCount);
+        std::swap(in, out);
+    }
+    return in;
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.h b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.h
new file mode 100644
index 0000000..dc43feb
--- /dev/null
+++ b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.h
@@ -0,0 +1,124 @@
+/*
+ * 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 <android-base/thread_annotations.h>
+#include <vibrator/ExternalVibrationUtils.h>
+#include <map>
+
+#include "Processors.h"
+#include "effect-impl/EffectContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+enum HapticGeneratorState {
+    HAPTIC_GENERATOR_STATE_UNINITIALIZED,
+    HAPTIC_GENERATOR_STATE_INITIALIZED,
+    HAPTIC_GENERATOR_STATE_ACTIVE,
+};
+
+struct HapticGeneratorParam {
+    // The audio channels used to generate haptic channels. The first channel will be used to
+    // generate HAPTIC_A, The second channel will be used to generate HAPTIC_B.
+    // The value will be offset of audio channel
+    int mHapticChannelSource[2];
+
+    int mHapticChannelCount;
+    int mAudioChannelCount;
+
+    HapticGenerator::HapticScale mHapticScale;
+    std::map<int, HapticGenerator::VibratorScale> mHapticScales;
+    // max intensity will be used to scale haptic data.
+    HapticGenerator::VibratorScale mMaxVibratorScale;
+
+    HapticGenerator::VibratorInformation mVibratorInfo;
+};
+
+// A structure to keep all shared pointers for all processors in HapticGenerator.
+struct HapticGeneratorProcessorsRecord {
+    std::vector<std::shared_ptr<HapticBiquadFilter>> filters;
+    std::vector<std::shared_ptr<::android::audio_effect::haptic_generator::Ramp>> ramps;
+    std::vector<std::shared_ptr<::android::audio_effect::haptic_generator::SlowEnvelope>> slowEnvs;
+    std::vector<std::shared_ptr<::android::audio_effect::haptic_generator::Distortion>> distortions;
+
+    // Cache band-pass filter and band-stop filter for updating parameters
+    // according to vibrator info
+    std::shared_ptr<HapticBiquadFilter> bpf;
+    std::shared_ptr<HapticBiquadFilter> bsf;
+};
+
+class HapticGeneratorContext final : public EffectContext {
+  public:
+    HapticGeneratorContext(int statusDepth, const Parameter::Common& common);
+    ~HapticGeneratorContext();
+    RetCode enable();
+    RetCode disable();
+    void reset();
+
+    RetCode setHgHapticScales(const std::vector<HapticGenerator::HapticScale> hapticScales);
+    std::vector<HapticGenerator::HapticScale> getHgHapticScales();
+
+    RetCode setHgVibratorInformation(const HapticGenerator::VibratorInformation& vibratorInfo);
+    HapticGenerator::VibratorInformation getHgVibratorInformation();
+
+    IEffect::Status lvmProcess(float* in, float* out, int samples);
+
+  private:
+    static constexpr float DEFAULT_RESONANT_FREQUENCY = 150.0f;
+    static constexpr float DEFAULT_BSF_ZERO_Q = 8.0f;
+    static constexpr float DEFAULT_BSF_POLE_Q = 4.0f;
+    static constexpr float DEFAULT_DISTORTION_OUTPUT_GAIN = 1.5f;
+    static constexpr float DEFAULT_BPF_Q = 1.0f;
+    static constexpr float DEFAULT_SLOW_ENV_NORMALIZATION_POWER = -0.8f;
+    static constexpr float DEFAULT_DISTORTION_CORNER_FREQUENCY = 300.0f;
+    static constexpr float DEFAULT_DISTORTION_INPUT_GAIN = 0.3f;
+    static constexpr float DEFAULT_DISTORTION_CUBE_THRESHOLD = 0.1f;
+
+    std::mutex mMutex;
+    HapticGeneratorState mState;
+    HapticGeneratorParam mParams GUARDED_BY(mMutex);
+    int mSampleRate;
+    int mFrameCount = 0;
+
+    // A cache for all shared pointers of the HapticGenerator
+    struct HapticGeneratorProcessorsRecord mProcessorsRecord;
+
+    // Using a vector of functions to record the processing chain for haptic-generating algorithm.
+    // The three parameters of the processing functions are pointer to output buffer, pointer to
+    // input buffer and frame count.
+    std::vector<std::function<void(float*, const float*, size_t)>> mProcessingChain;
+
+    // inputBuffer is where to keep input buffer for the generating algorithm. It will be
+    // constructed according to hapticChannelSource.
+    std::vector<float> mInputBuffer;
+
+    // outputBuffer is a buffer having the same length as inputBuffer. It can be used as
+    // intermediate buffer in the generating algorithm.
+    std::vector<float> mOutputBuffer;
+
+    void init_params(media::audio::common::AudioChannelLayout inputChMask,
+                     media::audio::common::AudioChannelLayout outputChMask);
+    void configure();
+
+    float getDistortionOutputGain();
+    float getFloatProperty(const std::string& key, float defaultValue);
+    void addBiquadFilter(std::shared_ptr<HapticBiquadFilter> filter);
+    void buildProcessingChain();
+    float* runProcessingChain(float* buf1, float* buf2, size_t frameCount);
+};
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
index 1bcde74..3aee721 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
@@ -96,8 +96,11 @@
             mSamplesToExitCountVirt = (mSamplesPerSecond * 0.1);
             tempDisabled = mVirtualizerTempDisabled;
             break;
-        default:
-            // Add handling for other effects
+        case lvm::BundleEffectType::VOLUME:
+            LOG(DEBUG) << __func__ << " enable bundle VOL";
+            if ((mEffectInDrain & (1 << int(lvm::BundleEffectType::VOLUME))) == 0)
+                mNumberEffectsEnabled++;
+            mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::VOLUME));
             break;
     }
     mEnabled = true;
@@ -123,8 +126,8 @@
                 LOG(DEBUG) << __func__ << " enable bundle VR";
                 params.VirtualizerOperatingMode = LVM_MODE_ON;
                 break;
-            default:
-                // Add handling for other effects
+            case lvm::BundleEffectType::VOLUME:
+                LOG(DEBUG) << __func__ << " enable bundle VOL";
                 break;
         }
         RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, &params),
@@ -148,8 +151,9 @@
             LOG(DEBUG) << __func__ << " disable bundle VR";
             mEffectInDrain |= 1 << int(lvm::BundleEffectType::VIRTUALIZER);
             break;
-        default:
-            // Add handling for other effects
+        case lvm::BundleEffectType::VOLUME:
+            LOG(DEBUG) << __func__ << " disable bundle VOL";
+            mEffectInDrain |= 1 << int(lvm::BundleEffectType::VOLUME);
             break;
     }
     mEnabled = false;
@@ -175,8 +179,8 @@
                 LOG(DEBUG) << __func__ << " disable bundle VR";
                 params.VirtualizerOperatingMode = LVM_MODE_OFF;
                 break;
-            default:
-                // Add handling for other effects
+            case lvm::BundleEffectType::VOLUME:
+                LOG(DEBUG) << __func__ << " disable bundle VOL";
                 break;
         }
         RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, &params),
@@ -255,15 +259,15 @@
 
         // roundoff
         int maxLevelRound = (int)(totalEnergyEstimation + 0.99);
-        if (maxLevelRound + mLevelSaved > 0) {
-            gainCorrection = maxLevelRound + mLevelSaved;
+        if (maxLevelRound + mVolume > 0) {
+            gainCorrection = maxLevelRound + mVolume;
         }
 
-        params.VC_EffectLevel = mLevelSaved - gainCorrection;
+        params.VC_EffectLevel = mVolume - gainCorrection;
         if (params.VC_EffectLevel < -96) {
             params.VC_EffectLevel = -96;
         }
-        LOG(INFO) << "\tVol: " << mLevelSaved << ", GainCorrection: " << gainCorrection
+        LOG(INFO) << "\tVol: " << mVolume << ", GainCorrection: " << gainCorrection
                   << ", Actual vol: " << params.VC_EffectLevel;
 
         /* Activate the initial settings */
@@ -395,8 +399,7 @@
     int rightdB = VolToDb(volume.right);
     int maxdB = std::max(leftdB, rightdB);
     int pandB = rightdB - leftdB;
-    // TODO: add volume effect implementation here:
-    // android::VolumeSetVolumeLevel(pContext, (int16_t)(maxdB * 100));
+    setVolumeLevel(maxdB * 100);
     LOG(DEBUG) << __func__ << " pandB: " << pandB << " maxdB " << maxdB;
 
     {
@@ -495,8 +498,7 @@
 }
 
 RetCode BundleContext::setBassBoostStrength(int strength) {
-    if (strength < BassBoost::MIN_PER_MILLE_STRENGTH ||
-        strength > BassBoost::MAX_PER_MILLE_STRENGTH) {
+    if (strength < 0 || strength > lvm::kBassBoostCap.maxStrengthPm) {
         LOG(ERROR) << __func__ << " invalid strength: " << strength;
         return RetCode::ERROR_ILLEGAL_PARAMETER;
     }
@@ -519,9 +521,37 @@
     return limitLevel();
 }
 
+RetCode BundleContext::setVolumeLevel(int level) {
+    if (level < lvm::kVolumeCap.minLevelDb || level > lvm::kVolumeCap.maxLevelDb) {
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+
+    if (mMuteEnabled) {
+        mLevelSaved = level / 100;
+    } else {
+        mVolume = level / 100;
+    }
+    LOG(INFO) << __func__ << " success with level " << level;
+    return limitLevel();
+}
+
+int BundleContext::getVolumeLevel() const {
+    return (mMuteEnabled ? mLevelSaved * 100 : mVolume * 100);
+}
+
+RetCode BundleContext::setVolumeMute(bool mute) {
+    mMuteEnabled = mute;
+    if (mMuteEnabled) {
+        mLevelSaved = mVolume;
+        mVolume = -96;
+    } else {
+        mVolume = mLevelSaved;
+    }
+    return limitLevel();
+}
+
 RetCode BundleContext::setVirtualizerStrength(int strength) {
-    if (strength < Virtualizer::MIN_PER_MILLE_STRENGTH ||
-        strength > Virtualizer::MAX_PER_MILLE_STRENGTH) {
+    if (strength < 0 || strength > lvm::kVirtualizerCap.maxStrengthPm) {
         return RetCode::ERROR_ILLEGAL_PARAMETER;
     }
 
@@ -662,6 +692,11 @@
             --mNumberEffectsEnabled;
             mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::VIRTUALIZER));
         }
+        if ((undrainedEffects & 1 << int(lvm::BundleEffectType::VOLUME)) != 0) {
+            LOG(DEBUG) << "Draining VOLUME";
+            --mNumberEffectsEnabled;
+            mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::VOLUME));
+        }
     }
     mEffectProcessCalled |= 1 << int(mType);
     if (!mEnabled) {
@@ -705,8 +740,13 @@
                     LOG(DEBUG) << "Effect_process() this is the last frame for VIRTUALIZER";
                 }
                 break;
-            default:
-                // Add handling for other effects
+            case lvm::BundleEffectType::VOLUME:
+                isDataAvailable = false;
+                if ((mEffectInDrain & 1 << int(lvm::BundleEffectType::VOLUME)) != 0) {
+                    mNumberEffectsEnabled--;
+                    mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::VOLUME));
+                }
+                LOG(DEBUG) << "Effect_process() LVM_VOLUME Effect is not enabled";
                 break;
         }
     }
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
index 116ae6f..be723f7 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
@@ -71,6 +71,12 @@
     RetCode setBassBoostStrength(int strength);
     int getBassBoostStrength() const { return mBassStrengthSaved; }
 
+    RetCode setVolumeLevel(int level);
+    int getVolumeLevel() const;
+
+    RetCode setVolumeMute(bool mute);
+    int getVolumeMute() const { return mMuteEnabled; }
+
     RetCode setVirtualizerStrength(int strength);
     int getVirtualizerStrength() const { return mVirtStrengthSaved; }
 
@@ -106,7 +112,7 @@
     int mEffectProcessCalled = 0;
     int mNumberEffectsEnabled = 0;
     int mNumberEffectsCalled = 0;
-    bool mFirstVolume = false;
+    bool mFirstVolume = true;
     // Bass
     bool mBassTempDisabled = false;
     int mBassStrengthSaved = 0;
@@ -118,6 +124,7 @@
     bool mVirtualizerTempDisabled = false;
     // Volume
     int mLevelSaved = 0; /* for when mute is set, level must be saved */
+    int mVolume = 0;
     bool mMuteEnabled = false; /* Must store as mute = -96dB level */
 
     void initControlParameter(LVM_ControlParams_t& params) const;
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
index 95a0dab..1996240 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
@@ -85,7 +85,8 @@
 
 static const bool mStrengthSupported = true;
 
-static const BassBoost::Capability kBassBoostCap = {.strengthSupported = mStrengthSupported};
+static const BassBoost::Capability kBassBoostCap = {.maxStrengthPm = 1000,
+                                                    .strengthSupported = mStrengthSupported};
 
 static const std::string kBassBoostEffectName = "Dynamic Bass Boost";
 
@@ -103,7 +104,8 @@
                    .implementor = "NXP Software Ltd."},
         .capability = Capability::make<Capability::bassBoost>(kBassBoostCap)};
 
-static const Virtualizer::Capability kVirtualizerCap = {.strengthSupported = mStrengthSupported};
+static const Virtualizer::Capability kVirtualizerCap = {.maxStrengthPm = 1000,
+                                                        .strengthSupported = mStrengthSupported};
 
 static const std::string kVirtualizerEffectName = "Virtualizer";
 
@@ -112,7 +114,7 @@
                           .uuid = kVirtualizerBundleImplUUID,
                           .proxy = kVirtualizerProxyUUID},
                    .flags = {.type = Flags::Type::INSERT,
-                             .insert = Flags::Insert::FIRST,
+                             .insert = Flags::Insert::LAST,
                              .volume = Flags::Volume::CTRL,
                              .deviceIndication = true},
                    .cpuLoad = VIRTUALIZER_CUP_LOAD_ARM9E,
@@ -121,8 +123,22 @@
                    .implementor = "NXP Software Ltd."},
         .capability = Capability::make<Capability::virtualizer>(kVirtualizerCap)};
 
-// TODO: add descriptors for other bundle effect types here.
-static const Descriptor kVolumeDesc;
+static const Volume::Capability kVolumeCap = {.minLevelDb = -9600, .maxLevelDb = 0};
+
+static const std::string kVolumeEffectName = "Volume";
+
+static const Descriptor kVolumeDesc = {
+        .common = {.id = {.type = kVolumeTypeUUID,
+                          .uuid = kVolumeBundleImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::LAST,
+                             .volume = Flags::Volume::CTRL},
+                   .cpuLoad = VOLUME_CUP_LOAD_ARM9E,
+                   .memoryUsage = BUNDLE_MEM_USAGE,
+                   .name = kVolumeEffectName,
+                   .implementor = "NXP Software Ltd."},
+        .capability = Capability::make<Capability::volume>(kVolumeCap)};
 
 /* The following tables have been computed using the actual levels measured by the output of
  * white noise or pink noise (IEC268-1) for the EQ and BassBoost Effects. These are estimates of
diff --git a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
index b435ab4..81b8aca 100644
--- a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
@@ -35,12 +35,13 @@
 using aidl::android::hardware::audio::effect::kBassBoostBundleImplUUID;
 using aidl::android::hardware::audio::effect::kEqualizerBundleImplUUID;
 using aidl::android::hardware::audio::effect::kVirtualizerBundleImplUUID;
+using aidl::android::hardware::audio::effect::kVolumeBundleImplUUID;
 using aidl::android::hardware::audio::effect::State;
 using aidl::android::media::audio::common::AudioUuid;
 
 bool isUuidSupported(const AudioUuid* uuid) {
     return (*uuid == kEqualizerBundleImplUUID || *uuid == kBassBoostBundleImplUUID ||
-            *uuid == kVirtualizerBundleImplUUID);
+            *uuid == kVirtualizerBundleImplUUID || *uuid == kVolumeBundleImplUUID);
 }
 
 extern "C" binder_exception_t createEffect(const AudioUuid* uuid,
@@ -70,6 +71,8 @@
         *_aidl_return = aidl::android::hardware::audio::effect::lvm:: kBassBoostDesc;
     } else if (*in_impl_uuid == kVirtualizerBundleImplUUID) {
         *_aidl_return = aidl::android::hardware::audio::effect::lvm::kVirtualizerDesc;
+    } else if (*in_impl_uuid == kVolumeBundleImplUUID) {
+        *_aidl_return = aidl::android::hardware::audio::effect::lvm::kVolumeDesc;
     }
     return EX_NONE;
 }
@@ -90,9 +93,12 @@
         mType = lvm::BundleEffectType::VIRTUALIZER;
         mDescriptor = &lvm::kVirtualizerDesc;
         mEffectName = &lvm::kVirtualizerEffectName;
+    } else if (uuid == kVolumeBundleImplUUID) {
+        mType = lvm::BundleEffectType::VOLUME;
+        mDescriptor = &lvm::kVolumeDesc;
+        mEffectName = &lvm::kVolumeEffectName;
     } else {
-        // TODO: add other bundle effect types here.
-        LOG(ERROR) << __func__ << uuid.toString() << " not supported yet!";
+        LOG(ERROR) << __func__ << uuid.toString() << " not supported!";
     }
 }
 
@@ -156,6 +162,8 @@
             return setParameterBassBoost(specific);
         case Parameter::Specific::virtualizer:
             return setParameterVirtualizer(specific);
+        case Parameter::Specific::volume:
+            return setParameterVolume(specific);
         default:
             LOG(ERROR) << __func__ << " unsupported tag " << toString(tag);
             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
@@ -217,6 +225,26 @@
     }
 }
 
+ndk::ScopedAStatus EffectBundleAidl::setParameterVolume(const Parameter::Specific& specific) {
+    auto& vol = specific.get<Parameter::Specific::volume>();
+    auto volTag = vol.getTag();
+    switch (volTag) {
+        case Volume::levelDb: {
+            RETURN_IF(mContext->setVolumeLevel(vol.get<Volume::levelDb>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setLevelFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case Volume::mute:
+            RETURN_IF(mContext->setVolumeMute(vol.get<Volume::mute>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setMuteFailed");
+            return ndk::ScopedAStatus::ok();
+        default:
+            LOG(ERROR) << __func__ << " unsupported parameter " << specific.toString();
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "volTagNotSupported");
+    }
+}
+
 ndk::ScopedAStatus EffectBundleAidl::getParameterSpecific(const Parameter::Id& id,
                                                           Parameter::Specific* specific) {
     RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
@@ -229,6 +257,8 @@
             return getParameterBassBoost(id.get<Parameter::Id::bassBoostTag>(), specific);
         case Parameter::Id::virtualizerTag:
             return getParameterVirtualizer(id.get<Parameter::Id::virtualizerTag>(), specific);
+        case Parameter::Id::volumeTag:
+            return getParameterVolume(id.get<Parameter::Id::volumeTag>(), specific);
         default:
             LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
@@ -288,6 +318,34 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus EffectBundleAidl::getParameterVolume(const Volume::Id& id,
+                                                        Parameter::Specific* specific) {
+    RETURN_IF(id.getTag() != Volume::Id::commonTag, EX_ILLEGAL_ARGUMENT, "VolumeTagNotSupported");
+
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    Volume volParam;
+
+    auto tag = id.get<Volume::Id::commonTag>();
+    switch (tag) {
+        case Volume::levelDb: {
+            volParam.set<Volume::levelDb>(mContext->getVolumeLevel());
+            break;
+        }
+        case Volume::mute: {
+            volParam.set<Volume::mute>(mContext->getVolumeMute());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " not handled tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VolumeTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::volume>(volParam);
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus EffectBundleAidl::getParameterVirtualizer(const Virtualizer::Id& id,
                                                              Parameter::Specific* specific) {
     RETURN_IF(id.getTag() != Virtualizer::Id::commonTag, EX_ILLEGAL_ARGUMENT,
diff --git a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
index ebf100a..0330e5a 100644
--- a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
+++ b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
@@ -67,6 +67,8 @@
     ndk::ScopedAStatus setParameterEqualizer(const Parameter::Specific& specific);
     ndk::ScopedAStatus getParameterEqualizer(const Equalizer::Id& id,
                                              Parameter::Specific* specific);
+    ndk::ScopedAStatus setParameterVolume(const Parameter::Specific& specific);
+    ndk::ScopedAStatus getParameterVolume(const Volume::Id& id, Parameter::Specific* specific);
     ndk::ScopedAStatus setParameterVirtualizer(const Parameter::Specific& specific);
     ndk::ScopedAStatus getParameterVirtualizer(const Virtualizer::Id& id,
                                                Parameter::Specific* specific);
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index 61a2bf5..59f1fc3 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -102,7 +102,8 @@
     uint32_t state;                // current state (enum preproc_session_state)
     int id;                        // audio session ID
     int io;                        // handle of input stream this session is on
-    webrtc::AudioProcessing* apm;  // handle on webRTC audio processing module (APM)
+    rtc::scoped_refptr<webrtc::AudioProcessing>
+            apm;  // handle on webRTC audio processing module (APM)
     // Audio Processing module builder
     webrtc::AudioProcessingBuilder ap_builder;
     // frameCount represents the size of the buffers used for processing, and must represent 10ms.
@@ -260,9 +261,6 @@
     ALOGV("Agc2Init");
     effect->session->config = effect->session->apm->GetConfig();
     effect->session->config.gain_controller2.fixed_digital.gain_db = 0.f;
-    effect->session->config.gain_controller2.adaptive_digital.level_estimator =
-            effect->session->config.gain_controller2.kRms;
-    effect->session->config.gain_controller2.adaptive_digital.extra_saturation_margin_db = 2.f;
     effect->session->apm->ApplyConfig(effect->session->config);
     return 0;
 }
@@ -332,24 +330,19 @@
             ALOGV("Agc2GetParameter() target level %f dB", *(float*)pValue);
             break;
         case AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR:
-            *(uint32_t*)pValue = (uint32_t)(
-                    effect->session->config.gain_controller2.adaptive_digital.level_estimator);
-            ALOGV("Agc2GetParameter() level estimator %d",
-                  *(webrtc::AudioProcessing::Config::GainController2::LevelEstimator*)pValue);
+            // WebRTC only supports RMS level estimator now
+            *(uint32_t*)pValue = (uint32_t)(0);
+            ALOGV("Agc2GetParameter() level estimator RMS");
             break;
         case AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN:
-            *(float*)pValue = (float)(effect->session->config.gain_controller2.adaptive_digital
-                                              .extra_saturation_margin_db);
+            *(float*)pValue = (float)(2.0);
             ALOGV("Agc2GetParameter() extra saturation margin %f dB", *(float*)pValue);
             break;
         case AGC2_PARAM_PROPERTIES:
             pProperties->fixedDigitalGain =
                     (float)(effect->session->config.gain_controller2.fixed_digital.gain_db);
-            pProperties->level_estimator = (uint32_t)(
-                    effect->session->config.gain_controller2.adaptive_digital.level_estimator);
-            pProperties->extraSaturationMargin =
-                    (float)(effect->session->config.gain_controller2.adaptive_digital
-                                    .extra_saturation_margin_db);
+            pProperties->level_estimator = 0;
+            pProperties->extraSaturationMargin = 2.0;
             break;
         default:
             ALOGW("Agc2GetParameter() unknown param %d", param);
@@ -438,16 +431,19 @@
             effect->session->config.gain_controller2.fixed_digital.gain_db = valueFloat;
             break;
         case AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR:
-            ALOGV("Agc2SetParameter() level estimator %d",
-                  *(webrtc::AudioProcessing::Config::GainController2::LevelEstimator*)pValue);
-            effect->session->config.gain_controller2.adaptive_digital.level_estimator =
-                    (*(webrtc::AudioProcessing::Config::GainController2::LevelEstimator*)pValue);
+            ALOGV("Agc2SetParameter() level estimator %d", *(uint32_t*)pValue);
+            if (*(uint32_t*)pValue != 0) {
+              // only RMS is supported
+              status = -EINVAL;
+            }
             break;
         case AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN:
             valueFloat = (float)(*(int32_t*)pValue);
             ALOGV("Agc2SetParameter() extra saturation margin %f dB", valueFloat);
-            effect->session->config.gain_controller2.adaptive_digital.extra_saturation_margin_db =
-                    valueFloat;
+            if (valueFloat != 2.0) {
+              // extra_staturation_margin_db is no longer configurable in webrtc
+              status = -EINVAL;
+            }
             break;
         case AGC2_PARAM_PROPERTIES:
             ALOGV("Agc2SetParameter() properties gain %f, level %d margin %f",
@@ -455,11 +451,9 @@
                   pProperties->extraSaturationMargin);
             effect->session->config.gain_controller2.fixed_digital.gain_db =
                     pProperties->fixedDigitalGain;
-            effect->session->config.gain_controller2.adaptive_digital.level_estimator =
-                    (webrtc::AudioProcessing::Config::GainController2::LevelEstimator)
-                            pProperties->level_estimator;
-            effect->session->config.gain_controller2.adaptive_digital.extra_saturation_margin_db =
-                    pProperties->extraSaturationMargin;
+            if (pProperties->level_estimator != 0 || pProperties->extraSaturationMargin != 2.0) {
+              status = -EINVAL;
+            }
             break;
         default:
             ALOGW("Agc2SetParameter() unknown param %08x value %08x", param, *(uint32_t*)pValue);
@@ -879,8 +873,8 @@
 
 error:
     if (session->createdMsk == 0) {
-        delete session->apm;
-        session->apm = NULL;
+        // Scoped_refptr will handle reference counting here
+        session->apm = nullptr;
     }
     return status;
 }
@@ -889,8 +883,8 @@
     ALOGW_IF(Effect_Release(fx) != 0, " Effect_Release() failed for proc ID %d", fx->procId);
     session->createdMsk &= ~(1 << fx->procId);
     if (session->createdMsk == 0) {
-        delete session->apm;
-        session->apm = NULL;
+        // Scoped_refptr will handle reference counting here
+        session->apm = nullptr;
         session->id = 0;
     }
 
diff --git a/media/libeffects/preprocessing/tests/EffectPreprocessingTest.cpp b/media/libeffects/preprocessing/tests/EffectPreprocessingTest.cpp
index 07006a1..8fdb864 100644
--- a/media/libeffects/preprocessing/tests/EffectPreprocessingTest.cpp
+++ b/media/libeffects/preprocessing/tests/EffectPreprocessingTest.cpp
@@ -143,10 +143,6 @@
         const AGC2Params* agc2Params = &params->agc2Params;
         ASSERT_NO_FATAL_FAILURE(
                 effect.setParam(AGC2_PARAM_FIXED_DIGITAL_GAIN, agc2Params->fixedDigitalGain));
-        ASSERT_NO_FATAL_FAILURE(effect.setParam(AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR,
-                                                agc2Params->adaptDigiLevelEstimator));
-        ASSERT_NO_FATAL_FAILURE(effect.setParam(AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN,
-                                                agc2Params->extraSaturationMargin));
     } else if (isAECEffect(uuid)) {
         const AECParams* aecParams = &params->aecParams;
         ASSERT_NO_FATAL_FAILURE(effect.setParam(AEC_PARAM_ECHO_DELAY, aecParams->echoDelay));
diff --git a/media/libeffects/preprocessing/tests/PreProcessingTest.cpp b/media/libeffects/preprocessing/tests/PreProcessingTest.cpp
index 3bd93f8..03400d7 100644
--- a/media/libeffects/preprocessing/tests/PreProcessingTest.cpp
+++ b/media/libeffects/preprocessing/tests/PreProcessingTest.cpp
@@ -400,20 +400,6 @@
             ALOGE("Invalid AGC2 Fixed Digital Gain. Error %d\n", status);
             return EXIT_FAILURE;
         }
-        if (int status = preProcSetConfigParam(AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR,
-                                               (uint32_t)preProcCfgParams.agc2Level,
-                                               effectHandle[PREPROC_AGC2]);
-            status != 0) {
-            ALOGE("Invalid AGC2 Level Estimator. Error %d\n", status);
-            return EXIT_FAILURE;
-        }
-        if (int status = preProcSetConfigParam(AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN,
-                                               (float)preProcCfgParams.agc2SaturationMargin,
-                                               effectHandle[PREPROC_AGC2]);
-            status != 0) {
-            ALOGE("Invalid AGC2 Saturation Margin. Error %d\n", status);
-            return EXIT_FAILURE;
-        }
     }
     if (effectEn[PREPROC_NS]) {
         if (int status = preProcSetConfigParam(NS_PARAM_LEVEL, (uint32_t)preProcCfgParams.nsLevel,
diff --git a/media/libeffects/visualizer/Android.bp b/media/libeffects/visualizer/Android.bp
index 8dd6789..fb9d7b7 100644
--- a/media/libeffects/visualizer/Android.bp
+++ b/media/libeffects/visualizer/Android.bp
@@ -18,34 +18,59 @@
     ],
 }
 
-cc_library_shared {
-    name: "libvisualizer",
-
+cc_defaults {
+    name: "visualizer_defaults",
     vendor: true,
-
-    srcs: [
-        "EffectVisualizer.cpp",
-    ],
-
     cflags: [
-        "-O2",
-        "-fvisibility=hidden",
-
-        "-DBUILD_FLOAT",
+        "-DBUILD_FLOAT", // TODO: remove BUILD_FLOAT and SUPPORT_MC in lvm libs
         "-DSUPPORT_MC",
-
         "-Wall",
         "-Werror",
     ],
-
     shared_libs: [
         "liblog",
     ],
-
-    relative_install_path: "soundfx",
-
     header_libs: [
         "libaudioeffects",
         "libaudioutils_headers",
     ],
 }
+
+cc_library_shared {
+    name: "libvisualizer",
+    defaults: [
+        "visualizer_defaults",
+    ],
+    srcs: [
+        "EffectVisualizer.cpp",
+    ],
+    relative_install_path: "soundfx",
+    cflags: [
+        "-O2",
+        "-fvisibility=hidden",
+    ],
+}
+
+cc_library_shared {
+    name: "libvisualizeraidl",
+    srcs: [
+        "aidl/Visualizer.cpp",
+        "aidl/VisualizerContext.cpp",
+        ":effectCommonFile",
+    ],
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+        "latest_android_hardware_audio_effect_ndk_shared",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "visualizer_defaults",
+    ],
+    cflags: [
+        "-Wthread-safety",
+    ],
+    shared_libs: [
+        "libcutils",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/media/libeffects/visualizer/aidl/Visualizer.cpp b/media/libeffects/visualizer/aidl/Visualizer.cpp
new file mode 100644
index 0000000..28a7287
--- /dev/null
+++ b/media/libeffects/visualizer/aidl/Visualizer.cpp
@@ -0,0 +1,258 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "AHAL_VisualizerLibEffects"
+
+#include <android-base/logging.h>
+#include "Visualizer.h"
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::VisualizerImpl;
+using aidl::android::hardware::audio::effect::kVisualizerImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+                                           std::shared_ptr<IEffect>* instanceSpp) {
+    if (!in_impl_uuid || *in_impl_uuid != kVisualizerImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<VisualizerImpl>();
+        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 || *in_impl_uuid != kVisualizerImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    *_aidl_return = VisualizerImpl::kDescriptor;
+    return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string VisualizerImpl::kEffectName = "Visualizer";
+const Visualizer::Capability VisualizerImpl::kCapability = {
+        .maxLatencyMs = VisualizerContext::kMaxLatencyMs,
+        .captureSampleRange = {.min = 0, .max = VisualizerContext::kMaxCaptureBufSize}};
+const Descriptor VisualizerImpl::kDescriptor = {
+        .common = {.id = {.type = kVisualizerTypeUUID,
+                          .uuid = kVisualizerImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::LAST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = VisualizerImpl::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = Capability::make<Capability::visualizer>(VisualizerImpl::kCapability)};
+
+ndk::ScopedAStatus VisualizerImpl::getDescriptor(Descriptor* _aidl_return) {
+    RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VisualizerImpl::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();
+}
+
+ndk::ScopedAStatus VisualizerImpl::setOnlyParameter(
+        const Visualizer::SetOnlyParameters& param) {
+    auto tag = param.getTag();
+    switch (tag) {
+        case Visualizer::SetOnlyParameters::latencyMs: {
+            RETURN_IF(mContext->setDownstreamLatency(
+                              param.get<Visualizer::SetOnlyParameters::latencyMs>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setLatencyFailed");
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "setOnlyParameterTagNotSupported");
+        }
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VisualizerImpl::setParameterSpecific(const Parameter::Specific& specific) {
+    RETURN_IF(Parameter::Specific::visualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+              "EffectNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto& param = specific.get<Parameter::Specific::visualizer>();
+    const auto tag = param.getTag();
+    switch (tag) {
+        case Visualizer::captureSamples: {
+            RETURN_IF(mContext->setCaptureSamples(param.get<Visualizer::captureSamples>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setCaptureSizeFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case Visualizer::scalingMode: {
+            RETURN_IF(mContext->setScalingMode(param.get<Visualizer::scalingMode>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setScalingModeFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case Visualizer::measurementMode: {
+            RETURN_IF(mContext->setMeasurementMode(param.get<Visualizer::measurementMode>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setMeasurementModeFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case Visualizer::setOnlyParameters: {
+            return setOnlyParameter(param.get<Visualizer::setOnlyParameters>());
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "VisualizerTagNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus VisualizerImpl::getOnlyParameter(const Visualizer::GetOnlyParameters::Tag tag,
+                                                    Parameter::Specific* specific) {
+    Visualizer visualizer;
+    Visualizer::GetOnlyParameters param;
+    switch (tag) {
+        case Visualizer::GetOnlyParameters::measurement: {
+            param.set<Visualizer::GetOnlyParameters::measurement>(mContext->getMeasure());
+            break;
+        }
+        case Visualizer::GetOnlyParameters::captureSampleBuffer: {
+            param.set<Visualizer::GetOnlyParameters::captureSampleBuffer>(mContext->capture());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "setOnlyParameterTagNotSupported");
+        }
+    }
+    visualizer.set<Visualizer::getOnlyParameters>(param);
+    specific->set<Parameter::Specific::visualizer>(visualizer);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VisualizerImpl::getParameterSpecific(const Parameter::Id& id,
+                                                        Parameter::Specific* specific) {
+    RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::visualizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto specificId = id.get<Parameter::Id::visualizerTag>();
+    auto specificTag = specificId.getTag();
+    switch (specificTag) {
+        case Visualizer::Id::commonTag: {
+            return getParameterVisualizer(specificId.get<Visualizer::Id::commonTag>(), specific);
+        }
+        case Visualizer::Id::getOnlyParamTag: {
+            return getOnlyParameter(specificId.get<Visualizer::Id::getOnlyParamTag>(), specific);
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(specificTag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VisualizerTagNotSupported");
+        }
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VisualizerImpl::getParameterVisualizer(const Visualizer::Tag& tag,
+                                                          Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    Visualizer param;
+    switch (tag) {
+        case Visualizer::captureSamples: {
+            param.set<Visualizer::captureSamples>(mContext->getCaptureSamples());
+            break;
+        }
+        case Visualizer::scalingMode: {
+            param.set<Visualizer::scalingMode>(mContext->getScalingMode());
+            break;
+        }
+        case Visualizer::measurementMode: {
+            param.set<Visualizer::measurementMode>(mContext->getMeasurementMode());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "VisualizerTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::visualizer>(param);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> VisualizerImpl::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+        return mContext;
+    }
+
+    mContext = std::make_shared<VisualizerContext>(1 /* statusFmqDepth */, common);
+    mContext->initParams(common);
+    return mContext;
+}
+
+RetCode VisualizerImpl::releaseContext() {
+    if (mContext) {
+        mContext->disable();
+        mContext->resetBuffer();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status VisualizerImpl::effectProcessImpl(float* in, float* out, int samples) {
+    IEffect::Status status = {EX_NULL_POINTER, 0, 0};
+    RETURN_VALUE_IF(!mContext, status, "nullContext");
+    return mContext->process(in, out, samples);
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/visualizer/aidl/Visualizer.h b/media/libeffects/visualizer/aidl/Visualizer.h
new file mode 100644
index 0000000..5908d9a
--- /dev/null
+++ b/media/libeffects/visualizer/aidl/Visualizer.h
@@ -0,0 +1,60 @@
+/*
+ * 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 <aidl/android/hardware/audio/effect/BnEffect.h>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+#include "VisualizerContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class VisualizerImpl final : public EffectImpl {
+  public:
+    static const std::string kEffectName;
+    static const Visualizer::Capability kCapability;
+    static const Descriptor kDescriptor;
+    VisualizerImpl() { LOG(DEBUG) << __func__; }
+    ~VisualizerImpl() {
+        cleanUp();
+        LOG(DEBUG) << __func__;
+    }
+
+    ndk::ScopedAStatus commandImpl(CommandId command) 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;
+    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    RetCode releaseContext() override;
+
+    std::shared_ptr<EffectContext> getContext() override { return mContext; }
+    std::string getEffectName() override { return kEffectName; }
+
+  private:
+    std::shared_ptr<VisualizerContext> mContext;
+    ndk::ScopedAStatus getParameterVisualizer(const Visualizer::Tag& tag,
+                                                    Parameter::Specific* specific);
+    ndk::ScopedAStatus setOnlyParameter(const Visualizer::SetOnlyParameters& param);
+    ndk::ScopedAStatus getOnlyParameter(const Visualizer::GetOnlyParameters::Tag tag,
+                                        Parameter::Specific* specific);
+};
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/visualizer/aidl/VisualizerContext.cpp b/media/libeffects/visualizer/aidl/VisualizerContext.cpp
new file mode 100644
index 0000000..1965e0e
--- /dev/null
+++ b/media/libeffects/visualizer/aidl/VisualizerContext.cpp
@@ -0,0 +1,331 @@
+/*
+ * 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 "VisualizerContext.h"
+
+#include <algorithm>
+#include <android/binder_status.h>
+#include <audio_utils/primitives.h>
+#include <math.h>
+#include <system/audio.h>
+#include <time.h>
+#include <Utils.h>
+
+#ifndef BUILD_FLOAT
+        #error AIDL Visualizer only support float 32bits, make sure add cflags -DBUILD_FLOAT,
+#endif
+
+using android::hardware::audio::common::getChannelCount;
+
+namespace aidl::android::hardware::audio::effect {
+
+VisualizerContext::VisualizerContext(int statusDepth, const Parameter::Common& common)
+    : EffectContext(statusDepth, common) {
+}
+
+VisualizerContext::~VisualizerContext() {
+    std::lock_guard lg(mMutex);
+    LOG(DEBUG) << __func__;
+    mState = State::UNINITIALIZED;
+}
+
+RetCode VisualizerContext::initParams(const Parameter::Common& common) {
+    std::lock_guard lg(mMutex);
+    LOG(DEBUG) << __func__;
+    if (common.input != common.output) {
+        LOG(ERROR) << __func__ << " mismatch input: " << common.input.toString()
+                   << " and output: " << common.output.toString();
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+
+    mState = State::INITIALIZED;
+    auto channelCount = getChannelCount(common.input.base.channelMask);
+#ifdef SUPPORT_MC
+    if (channelCount < 1 || channelCount > FCC_LIMIT) return RetCode::ERROR_ILLEGAL_PARAMETER;
+#else
+    if (channelCount != FCC_2) return RetCode::ERROR_ILLEGAL_PARAMETER;
+#endif
+    mChannelCount = channelCount;
+    mCommon = common;
+    return RetCode::SUCCESS;
+}
+
+RetCode VisualizerContext::enable() {
+    std::lock_guard lg(mMutex);
+    if (mState != State::INITIALIZED) {
+        return RetCode::ERROR_EFFECT_LIB_ERROR;
+    }
+    mState = State::ACTIVE;
+    return RetCode::SUCCESS;
+}
+
+RetCode VisualizerContext::disable() {
+    std::lock_guard lg(mMutex);
+    if (mState != State::ACTIVE) {
+        return RetCode::ERROR_EFFECT_LIB_ERROR;
+    }
+    mState = State::INITIALIZED;
+    return RetCode::SUCCESS;
+}
+
+void VisualizerContext::reset() {
+    std::lock_guard lg(mMutex);
+    std::fill_n(mCaptureBuf.begin(), kMaxCaptureBufSize, 0x80);
+}
+
+RetCode VisualizerContext::setCaptureSamples(int samples) {
+    std::lock_guard lg(mMutex);
+    if (samples < 0 || (unsigned)samples > kMaxCaptureBufSize) {
+        LOG(ERROR) << __func__ << " captureSamples " << samples << " exceed valid range: 0 - "
+                   << kMaxCaptureBufSize;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    mCaptureSamples = samples;
+    return RetCode::SUCCESS;
+}
+int VisualizerContext::getCaptureSamples() {
+    std::lock_guard lg(mMutex);
+    return mCaptureSamples;
+}
+
+RetCode VisualizerContext::setMeasurementMode(Visualizer::MeasurementMode mode) {
+    std::lock_guard lg(mMutex);
+    mMeasurementMode = mode;
+    return RetCode::SUCCESS;
+}
+Visualizer::MeasurementMode VisualizerContext::getMeasurementMode() {
+    std::lock_guard lg(mMutex);
+    return mMeasurementMode;
+}
+
+RetCode VisualizerContext::setScalingMode(Visualizer::ScalingMode mode) {
+    std::lock_guard lg(mMutex);
+    mScalingMode = mode;
+    return RetCode::SUCCESS;
+}
+Visualizer::ScalingMode VisualizerContext::getScalingMode() {
+    std::lock_guard lg(mMutex);
+    return mScalingMode;
+}
+
+RetCode VisualizerContext::setDownstreamLatency(int latency) {
+    if (latency < 0 || (unsigned)latency > kMaxLatencyMs) {
+        LOG(ERROR) << __func__ << " latency " << latency << " exceed valid range: 0 - "
+                   << kMaxLatencyMs;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    std::lock_guard lg(mMutex);
+    mDownstreamLatency = latency;
+    return RetCode::SUCCESS;
+}
+
+uint32_t VisualizerContext::getDeltaTimeMsFromUpdatedTime_l() {
+    uint32_t deltaMs = 0;
+    if (mBufferUpdateTime.tv_sec != 0) {
+        struct timespec ts;
+        if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+            time_t secs = ts.tv_sec - mBufferUpdateTime.tv_sec;
+            long nsec = ts.tv_nsec - mBufferUpdateTime.tv_nsec;
+            if (nsec < 0) {
+                --secs;
+                nsec += 1000000000;
+            }
+            deltaMs = secs * 1000 + nsec / 1000000;
+        }
+    }
+    return deltaMs;
+}
+
+Visualizer::GetOnlyParameters::Measurement VisualizerContext::getMeasure() {
+    uint16_t peakU16 = 0;
+    float sumRmsSquared = 0.0f;
+    uint8_t nbValidMeasurements = 0;
+
+    {
+        std::lock_guard lg(mMutex);
+        // reset measurements if last measurement was too long ago (which implies stored
+        // measurements aren't relevant anymore and shouldn't bias the new one)
+        const uint32_t delayMs = getDeltaTimeMsFromUpdatedTime_l();
+        if (delayMs > kDiscardMeasurementsTimeMs) {
+            LOG(INFO) << __func__ << " Discarding " << delayMs << " ms old measurements";
+            for (uint32_t i = 0; i < mMeasurementWindowSizeInBuffers; i++) {
+                mPastMeasurements[i].mIsValid = false;
+                mPastMeasurements[i].mPeakU16 = 0;
+                mPastMeasurements[i].mRmsSquared = 0;
+            }
+            mMeasurementBufferIdx = 0;
+        } else {
+            // only use actual measurements, otherwise the first RMS measure happening before
+            // MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS have been played will always be artificially
+            // low
+            for (uint32_t i = 0; i < mMeasurementWindowSizeInBuffers; i++) {
+                if (mPastMeasurements[i].mIsValid) {
+                    if (mPastMeasurements[i].mPeakU16 > peakU16) {
+                        peakU16 = mPastMeasurements[i].mPeakU16;
+                    }
+                    sumRmsSquared += mPastMeasurements[i].mRmsSquared;
+                    nbValidMeasurements++;
+                }
+            }
+        }
+    }
+
+    float rms = nbValidMeasurements == 0 ? 0.0f : sqrtf(sumRmsSquared / nbValidMeasurements);
+    Visualizer::GetOnlyParameters::Measurement measure;
+    // convert from I16 sample values to mB and write results
+    measure.rms = (rms < 0.000016f) ? -9600 : (int32_t)(2000 * log10(rms / 32767.0f));
+    measure.peak = (peakU16 == 0) ? -9600 : (int32_t)(2000 * log10(peakU16 / 32767.0f));
+    LOG(INFO) << __func__ << " peak " << peakU16 << " (" << measure.peak << "mB), rms " << rms
+              << " (" << measure.rms << "mB)";
+    return measure;
+}
+
+std::vector<uint8_t> VisualizerContext::capture() {
+    std::vector<uint8_t> result;
+    std::lock_guard lg(mMutex);
+    RETURN_VALUE_IF(mState != State::ACTIVE, result, "illegalState");
+    const uint32_t deltaMs = getDeltaTimeMsFromUpdatedTime_l();
+
+    // if audio framework has stopped playing audio although the effect is still active we must
+    // clear the capture buffer to return silence
+    if ((mLastCaptureIdx == mCaptureIdx) && (mBufferUpdateTime.tv_sec != 0) &&
+        (deltaMs > kMaxStallTimeMs)) {
+        LOG(INFO) << __func__ << " capture going to idle";
+        mBufferUpdateTime.tv_sec = 0;
+        return result;
+    }
+    int32_t latencyMs = mDownstreamLatency;
+    latencyMs -= deltaMs;
+    if (latencyMs < 0) {
+        latencyMs = 0;
+    }
+    uint32_t deltaSamples = mCaptureSamples + mCommon.input.base.sampleRate * latencyMs / 1000;
+
+    // large sample rate, latency, or capture size, could cause overflow.
+    // do not offset more than the size of buffer.
+    if (deltaSamples > kMaxCaptureBufSize) {
+        android_errorWriteLog(0x534e4554, "31781965");
+        deltaSamples = kMaxCaptureBufSize;
+    }
+
+    int32_t capturePoint;
+    //capturePoint = (int32_t)mCaptureIdx - deltaSamples;
+    __builtin_sub_overflow((int32_t) mCaptureIdx, deltaSamples, &capturePoint);
+    // a negative capturePoint means we wrap the buffer.
+    if (capturePoint < 0) {
+        uint32_t size = -capturePoint;
+        if (size > mCaptureSamples) {
+            size = mCaptureSamples;
+        }
+        result.insert(result.end(), &mCaptureBuf[kMaxCaptureBufSize + capturePoint],
+                        &mCaptureBuf[kMaxCaptureBufSize + capturePoint + size]);
+        mCaptureSamples -= size;
+        capturePoint = 0;
+    }
+    result.insert(result.end(), &mCaptureBuf[capturePoint],
+                    &mCaptureBuf[capturePoint + mCaptureSamples]);
+    mLastCaptureIdx = mCaptureIdx;
+    return result;
+}
+
+IEffect::Status VisualizerContext::process(float* in, float* out, int samples) {
+    IEffect::Status result = {STATUS_NOT_ENOUGH_DATA, 0, 0};
+    RETURN_VALUE_IF(in == nullptr || out == nullptr || samples == 0, result, "dataBufferError");
+
+    std::lock_guard lg(mMutex);
+    result.status = STATUS_INVALID_OPERATION;
+    RETURN_VALUE_IF(mState != State::ACTIVE, result, "stateNotActive");
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " sample " << samples;
+    // perform measurements if needed
+    if (mMeasurementMode == Visualizer::MeasurementMode::PEAK_RMS) {
+        // find the peak and RMS squared for the new buffer
+        float rmsSqAcc = 0;
+        float maxSample = 0.f;
+        for (size_t inIdx = 0; inIdx < (unsigned)samples; ++inIdx) {
+            maxSample = fmax(maxSample, fabs(in[inIdx]));
+            rmsSqAcc += in[inIdx] * in[inIdx];
+        }
+        maxSample *= 1 << 15; // scale to int16_t, with exactly 1 << 15 representing positive num.
+        rmsSqAcc *= 1 << 30; // scale to int16_t * 2
+        mPastMeasurements[mMeasurementBufferIdx] = {
+                .mPeakU16 = (uint16_t)maxSample,
+                .mRmsSquared = rmsSqAcc / samples,
+                .mIsValid = true };
+        if (++mMeasurementBufferIdx >= mMeasurementWindowSizeInBuffers) {
+            mMeasurementBufferIdx = 0;
+        }
+    }
+
+    float fscale;  // multiplicative scale
+    if (mScalingMode == Visualizer::ScalingMode::NORMALIZED) {
+        // derive capture scaling factor from peak value in current buffer
+        // this gives more interesting captures for display.
+        float maxSample = 0.f;
+        for (size_t inIdx = 0; inIdx < (unsigned)samples; ) {
+            // we reconstruct the actual summed value to ensure proper normalization
+            // for multichannel outputs (channels > 2 may often be 0).
+            float smp = 0.f;
+            for (int i = 0; i < mChannelCount; ++i) {
+                smp += in[inIdx++];
+            }
+            maxSample = fmax(maxSample, fabs(smp));
+        }
+        if (maxSample > 0.f) {
+            fscale = 0.99f / maxSample;
+            int exp; // unused
+            const float significand = frexp(fscale, &exp);
+            if (significand == 0.5f) {
+                fscale *= 255.f / 256.f; // avoid returning unaltered PCM signal
+            }
+        } else {
+            // scale doesn't matter, the values are all 0.
+            fscale = 1.f;
+        }
+    } else {
+        assert(mScalingMode == Visualizer::ScalingMode::AS_PLAYED);
+        // Note: if channels are uncorrelated, 1/sqrt(N) could be used at the risk of clipping.
+        fscale = 1.f / mChannelCount;  // account for summing all the channels together.
+    }
+
+    uint32_t captIdx;
+    uint32_t inIdx;
+    for (inIdx = 0, captIdx = mCaptureIdx; inIdx < (unsigned)samples; captIdx++) {
+        // wrap
+        if (captIdx >= kMaxCaptureBufSize) {
+            captIdx = 0;
+        }
+
+        float smp = 0.f;
+        for (uint32_t i = 0; i < mChannelCount; ++i) {
+            smp += in[inIdx++];
+        }
+        mCaptureBuf[captIdx] = clamp8_from_float(smp * fscale);
+    }
+
+    // the following two should really be atomic, though it probably doesn't
+    // matter much for visualization purposes
+    mCaptureIdx = captIdx;
+    // update last buffer update time stamp
+    if (clock_gettime(CLOCK_MONOTONIC, &mBufferUpdateTime) < 0) {
+        mBufferUpdateTime.tv_sec = 0;
+    }
+
+    // TODO: handle access_mode
+    memcpy(out, in, samples * sizeof(float));
+    return {STATUS_OK, samples, samples};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/visualizer/aidl/VisualizerContext.h b/media/libeffects/visualizer/aidl/VisualizerContext.h
new file mode 100644
index 0000000..bfda0b9
--- /dev/null
+++ b/media/libeffects/visualizer/aidl/VisualizerContext.h
@@ -0,0 +1,101 @@
+/*
+ * 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 <android-base/thread_annotations.h>
+#include <audio_effects/effect_dynamicsprocessing.h>
+
+#include "effect-impl/EffectContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class VisualizerContext final : public EffectContext {
+  public:
+    static const uint32_t kMaxCaptureBufSize = 65536;
+    static const uint32_t kMaxLatencyMs = 3000;  // 3 seconds of latency for audio pipeline
+
+    VisualizerContext(int statusDepth, const Parameter::Common& common);
+    ~VisualizerContext();
+
+    RetCode initParams(const Parameter::Common& common);
+
+    RetCode enable();
+    RetCode disable();
+    // keep all parameters and reset buffer.
+    void reset();
+
+    RetCode setCaptureSamples(int captureSize);
+    int getCaptureSamples();
+    RetCode setMeasurementMode(Visualizer::MeasurementMode mode);
+    Visualizer::MeasurementMode getMeasurementMode();
+    RetCode setScalingMode(Visualizer::ScalingMode mode);
+    Visualizer::ScalingMode getScalingMode();
+    RetCode setDownstreamLatency(int latency);
+
+    IEffect::Status process(float* in, float* out, int samples);
+    // Gets the current measurements, measured by process() and consumed by getParameter()
+    Visualizer::GetOnlyParameters::Measurement getMeasure();
+    // Gets the latest PCM capture, data captured by process() and consumed by getParameter()
+    std::vector<uint8_t> capture();
+
+    struct BufferStats {
+        bool mIsValid;
+        uint16_t mPeakU16; // the positive peak of the absolute value of the samples in a buffer
+        float mRmsSquared; // the average square of the samples in a buffer
+    };
+
+    enum State {
+        UNINITIALIZED,
+        INITIALIZED,
+        ACTIVE,
+    };
+
+  private:
+    // maximum time since last capture buffer update before resetting capture buffer. This means
+    // that the framework has stopped playing audio and we must start returning silence
+    static const uint32_t kMaxStallTimeMs = 1000;
+    // discard measurements older than this number of ms
+    static const uint32_t kDiscardMeasurementsTimeMs = 2000;
+    // maximum number of buffers for which we keep track of the measurements
+    // note: buffer index is stored in uint8_t
+    static const uint32_t kMeasurementWindowMaxSizeInBuffers = 25;
+
+    // serialize process() and parameter setting
+    std::mutex mMutex;
+    Parameter::Common mCommon GUARDED_BY(mMutex);
+    State mState GUARDED_BY(mMutex) = State::UNINITIALIZED;
+    uint32_t mCaptureIdx GUARDED_BY(mMutex) = 0;
+    uint32_t mLastCaptureIdx GUARDED_BY(mMutex) = 0;
+    Visualizer::ScalingMode mScalingMode GUARDED_BY(mMutex) = Visualizer::ScalingMode::NORMALIZED;
+    struct timespec mBufferUpdateTime GUARDED_BY(mMutex);
+    // capture buf with 8 bits PCM
+    std::array<uint8_t, kMaxCaptureBufSize> mCaptureBuf GUARDED_BY(mMutex);
+    uint32_t mDownstreamLatency GUARDED_BY(mMutex) = 0;
+    uint32_t mCaptureSamples GUARDED_BY(mMutex) = kMaxCaptureBufSize;
+
+    // to avoid recomputing it every time a buffer is processed
+    uint8_t mChannelCount GUARDED_BY(mMutex) = 0;
+    Visualizer::MeasurementMode mMeasurementMode GUARDED_BY(mMutex) =
+            Visualizer::MeasurementMode::NONE;
+    uint8_t mMeasurementWindowSizeInBuffers = kMeasurementWindowMaxSizeInBuffers;
+    uint8_t mMeasurementBufferIdx GUARDED_BY(mMutex) = 0;
+    std::array<BufferStats, kMeasurementWindowMaxSizeInBuffers> mPastMeasurements;
+    void init_params();
+
+    uint32_t getDeltaTimeMsFromUpdatedTime_l() REQUIRES(mMutex);
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libstagefright/OggWriter.cpp b/media/libstagefright/OggWriter.cpp
index d2a65d0..cff37a3 100644
--- a/media/libstagefright/OggWriter.cpp
+++ b/media/libstagefright/OggWriter.cpp
@@ -96,6 +96,7 @@
         return ERROR_UNSUPPORTED;
     }
 
+    // NOLINTNEXTLINE(clang-analyzer-unix.MallocSizeof)
     mOs = (OggStreamState*) malloc(sizeof(ogg_stream_state));
     if (ogg_stream_init((ogg_stream_state*)mOs, rand()) == -1) {
         ALOGE("ogg stream init failed");
diff --git a/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp b/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp
index 51e8d7a..15f043a 100644
--- a/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp
+++ b/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp
@@ -25,6 +25,7 @@
 
 static constexpr int kMaxOperations = 50;
 static constexpr int kMaxStringLen = 256;
+static constexpr int kMaxSpaces = 1000;
 
 using android::content::AttributionSourceState;
 
@@ -35,7 +36,9 @@
             pm.allowPlaybackCapture(uid);
         },
         [](FuzzedDataProvider* data_provider, android::MediaPackageManager pm) -> void {
-            int spaces = data_provider->ConsumeIntegral<int>();
+           /* The large value of spaces was taking time in file write operation.
+            * Limited spaces values in range to avoid timeout.*/
+            int spaces = data_provider->ConsumeIntegralInRange<int>(0, kMaxSpaces);
 
             // Dump everything into /dev/null
             int fd = open("/dev/null", O_WRONLY);
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index d930fb5..f8d7c70 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -2863,14 +2863,15 @@
     status_t status = INVALID_OPERATION;
 
     for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
-        std::vector<media::MicrophoneInfo> mics;
+        std::vector<audio_microphone_characteristic_t> mics;
         AudioHwDevice *dev = mAudioHwDevs.valueAt(i);
         mHardwareStatus = AUDIO_HW_GET_MICROPHONES;
         status_t devStatus = dev->hwDevice()->getMicrophones(&mics);
         mHardwareStatus = AUDIO_HW_IDLE;
         if (devStatus == NO_ERROR) {
-            microphones->insert(microphones->begin(), mics.begin(), mics.end());
             // report success if at least one HW module supports the function.
+            std::transform(mics.begin(), mics.end(), std::back_inserter(*microphones),
+                           [](auto& mic) { return media::MicrophoneInfo(mic); });
             status = NO_ERROR;
         }
     }
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 173f0c9..100d8c7 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -140,6 +140,7 @@
 
 class AudioFlinger : public AudioFlingerServerAdapter::Delegate
 {
+    friend class sp<AudioFlinger>;
 public:
     static void instantiate() ANDROID_API;
 
diff --git a/services/audioflinger/MelReporter.cpp b/services/audioflinger/MelReporter.cpp
index b185959..5ac7cde 100644
--- a/services/audioflinger/MelReporter.cpp
+++ b/services/audioflinger/MelReporter.cpp
@@ -25,7 +25,7 @@
 #include <android/binder_manager.h>
 #include <utils/Log.h>
 
-using aidl::android::hardware::audio::core::ISoundDose;
+using aidl::android::hardware::audio::core::sounddose::ISoundDose;
 using aidl::android::hardware::audio::sounddose::ISoundDoseFactory;
 
 namespace android {
@@ -60,8 +60,6 @@
         return false;
     }
 
-    std::lock_guard _l(mLock);
-    mUseHalSoundDoseInterface = true;
     stopInternalMelComputation();
     return true;
 }
@@ -77,12 +75,6 @@
     }
 
     mSoundDoseManager->setHalSoundDoseInterface(nullptr);
-
-    for (const auto& activePatches : mActiveMelPatches) {
-        for (const auto& deviceId : activePatches.second.deviceHandles) {
-            startMelComputationForNewPatch(activePatches.second.streamHandle, deviceId);
-        }
-    }
 }
 
 void AudioFlinger::MelReporter::onFirstRef() {
@@ -205,16 +197,9 @@
 
 void AudioFlinger::MelReporter::stopInternalMelComputation() {
     ALOGV("%s", __func__);
-    std::unordered_map<audio_patch_handle_t, ActiveMelPatch> activePatchesCopy;
-    {
-        std::lock_guard _l(mLock);
-        activePatchesCopy = mActiveMelPatches;
-        mActiveMelPatches.clear();
-    }
-
-    for (const auto& activePatch : activePatchesCopy) {
-        stopInternalMelComputationForStream(activePatch.second.streamHandle);
-    }
+    std::lock_guard _l(mLock);
+    mActiveMelPatches.clear();
+    mUseHalSoundDoseInterface = true;
 }
 
 void AudioFlinger::MelReporter::stopInternalMelComputationForStream(audio_io_handle_t streamId) {
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 3dcf932..f850ede 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2089,8 +2089,7 @@
         mHwSupportsPause(false), mHwPaused(false), mFlushPending(false),
         mLeftVolFloat(-1.0), mRightVolFloat(-1.0),
         mDownStreamPatch{},
-        mIsTimestampAdvancing(kMinimumTimeBetweenTimestampChecksNs),
-        mBluetoothLatencyModesEnabled(true)
+        mIsTimestampAdvancing(kMinimumTimeBetweenTimestampChecksNs)
 {
     snprintf(mThreadName, kThreadNameLength, "AudioOut_%X", id);
     mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName);
@@ -2971,7 +2970,14 @@
 void AudioFlinger::PlaybackThread::onCodecFormatChanged(
         const std::basic_string<uint8_t>& metadataBs)
 {
-    std::thread([this, metadataBs]() {
+    wp<AudioFlinger::PlaybackThread> weakPointerThis = this;
+    std::thread([this, metadataBs, weakPointerThis]() {
+            sp<AudioFlinger::PlaybackThread> playbackThread = weakPointerThis.promote();
+            if (playbackThread == nullptr) {
+                ALOGW("PlaybackThread was destroyed, skip codec format change event");
+                return;
+            }
+
             audio_utils::metadata::Data metadata =
                     audio_utils::metadata::dataFromByteString(metadataBs);
             if (metadata.empty()) {
@@ -4693,6 +4699,8 @@
     } else {
         status = PlaybackThread::createAudioPatch_l(patch, handle);
     }
+
+    updateHalSupportedLatencyModes_l();
     return status;
 }
 
@@ -4844,6 +4852,7 @@
     :   PlaybackThread(audioFlinger, output, id, type, systemReady, mixerConfig),
         // mAudioMixer below
         // mFastMixer below
+        mBluetoothLatencyModesEnabled(false),
         mFastMixerFutex(0),
         mMasterMono(false)
         // mOutputSink below
@@ -5059,6 +5068,21 @@
     delete mAudioMixer;
 }
 
+void AudioFlinger::MixerThread::onFirstRef() {
+    PlaybackThread::onFirstRef();
+
+    Mutex::Autolock _l(mLock);
+    if (mOutput != nullptr && mOutput->stream != nullptr) {
+        status_t status = mOutput->stream->setLatencyModeCallback(this);
+        if (status != INVALID_OPERATION) {
+            updateHalSupportedLatencyModes_l();
+        }
+        // Default to enabled if the HAL supports it. This can be changed by Audioflinger after
+        // the thread construction according to AudioFlinger::mBluetoothLatencyModesEnabled
+        mBluetoothLatencyModesEnabled.store(
+                mOutput->audioHwDev->supportsBluetoothVariableLatency());
+    }
+}
 
 uint32_t AudioFlinger::MixerThread::correctLatency_l(uint32_t latency) const
 {
@@ -6268,6 +6292,100 @@
     maxPeriod = seconds(mNormalFrameCount) / mSampleRate * 15;
 }
 
+void AudioFlinger::MixerThread::onHalLatencyModesChanged_l() {
+    mAudioFlinger->onSupportedLatencyModesChanged(mId, mSupportedLatencyModes);
+}
+
+void AudioFlinger::MixerThread::setHalLatencyMode_l() {
+    // Only handle latency mode if:
+    // - mBluetoothLatencyModesEnabled is true
+    // - the HAL supports latency modes
+    // - the selected device is Bluetooth LE or A2DP
+    if (!mBluetoothLatencyModesEnabled.load() || mSupportedLatencyModes.empty()) {
+        return;
+    }
+    if (mOutDeviceTypeAddrs.size() != 1
+            || !(audio_is_a2dp_out_device(mOutDeviceTypeAddrs[0].mType)
+                 || audio_is_ble_out_device(mOutDeviceTypeAddrs[0].mType))) {
+        return;
+    }
+
+    audio_latency_mode_t latencyMode = AUDIO_LATENCY_MODE_FREE;
+    if (mSupportedLatencyModes.size() == 1) {
+        // If the HAL only support one latency mode currently, confirm the choice
+        latencyMode = mSupportedLatencyModes[0];
+    } else if (mSupportedLatencyModes.size() > 1) {
+        // Request low latency if:
+        // - At least one active track is either:
+        //   - a fast track with gaming usage or
+        //   - a track with acessibility usage
+        for (const auto& track : mActiveTracks) {
+            if ((track->isFastTrack() && track->attributes().usage == AUDIO_USAGE_GAME)
+                    || track->attributes().usage == AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY) {
+                latencyMode = AUDIO_LATENCY_MODE_LOW;
+                break;
+            }
+        }
+    }
+
+    if (latencyMode != mSetLatencyMode) {
+        status_t status = mOutput->stream->setLatencyMode(latencyMode);
+        ALOGD("%s: thread(%d) setLatencyMode(%s) returned %d",
+                __func__, mId, toString(latencyMode).c_str(), status);
+        if (status == NO_ERROR) {
+            mSetLatencyMode = latencyMode;
+        }
+    }
+}
+
+void AudioFlinger::MixerThread::updateHalSupportedLatencyModes_l() {
+
+    if (mOutput == nullptr || mOutput->stream == nullptr) {
+        return;
+    }
+    std::vector<audio_latency_mode_t> latencyModes;
+    const status_t status = mOutput->stream->getRecommendedLatencyModes(&latencyModes);
+    if (status != NO_ERROR) {
+        latencyModes.clear();
+    }
+    if (latencyModes != mSupportedLatencyModes) {
+        ALOGD("%s: thread(%d) status %d supported latency modes: %s",
+            __func__, mId, status, toString(latencyModes).c_str());
+        mSupportedLatencyModes.swap(latencyModes);
+        sendHalLatencyModesChangedEvent_l();
+    }
+}
+
+status_t AudioFlinger::MixerThread::getSupportedLatencyModes(
+        std::vector<audio_latency_mode_t>* modes) {
+    if (modes == nullptr) {
+        return BAD_VALUE;
+    }
+    Mutex::Autolock _l(mLock);
+    *modes = mSupportedLatencyModes;
+    return NO_ERROR;
+}
+
+void AudioFlinger::MixerThread::onRecommendedLatencyModeChanged(
+        std::vector<audio_latency_mode_t> modes) {
+    Mutex::Autolock _l(mLock);
+    if (modes != mSupportedLatencyModes) {
+        ALOGD("%s: thread(%d) supported latency modes: %s",
+            __func__, mId, toString(modes).c_str());
+        mSupportedLatencyModes.swap(modes);
+        sendHalLatencyModesChangedEvent_l();
+    }
+}
+
+status_t AudioFlinger::MixerThread::setBluetoothVariableLatencyEnabled(bool enabled) {
+    if (mOutput == nullptr || mOutput->audioHwDev == nullptr
+            || !mOutput->audioHwDev->supportsBluetoothVariableLatency()) {
+        return INVALID_OPERATION;
+    }
+    mBluetoothLatencyModesEnabled.store(enabled);
+    return NO_ERROR;
+}
+
 // ----------------------------------------------------------------------------
 
 AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
@@ -7499,13 +7617,7 @@
 }
 
 void AudioFlinger::SpatializerThread::onFirstRef() {
-    PlaybackThread::onFirstRef();
-
-    Mutex::Autolock _l(mLock);
-    status_t status = mOutput->stream->setLatencyModeCallback(this);
-    if (status != INVALID_OPERATION) {
-        updateHalSupportedLatencyModes_l();
-    }
+    MixerThread::onFirstRef();
 
     const pid_t tid = getTid();
     if (tid == -1) {
@@ -7519,32 +7631,6 @@
     }
 }
 
-status_t AudioFlinger::SpatializerThread::createAudioPatch_l(const struct audio_patch *patch,
-                                                          audio_patch_handle_t *handle)
-{
-    status_t status = MixerThread::createAudioPatch_l(patch, handle);
-    updateHalSupportedLatencyModes_l();
-    return status;
-}
-
-void AudioFlinger::SpatializerThread::updateHalSupportedLatencyModes_l() {
-    std::vector<audio_latency_mode_t> latencyModes;
-    const status_t status = mOutput->stream->getRecommendedLatencyModes(&latencyModes);
-    if (status != NO_ERROR) {
-        latencyModes.clear();
-    }
-    if (latencyModes != mSupportedLatencyModes) {
-        ALOGD("%s: thread(%d) status %d supported latency modes: %s",
-            __func__, mId, status, toString(latencyModes).c_str());
-        mSupportedLatencyModes.swap(latencyModes);
-        sendHalLatencyModesChangedEvent_l();
-    }
-}
-
-void AudioFlinger::SpatializerThread::onHalLatencyModesChanged_l() {
-    mAudioFlinger->onSupportedLatencyModesChanged(mId, mSupportedLatencyModes);
-}
-
 void AudioFlinger::SpatializerThread::setHalLatencyMode_l() {
     // if mSupportedLatencyModes is empty, the HAL stream does not support
     // latency mode control and we can exit.
@@ -7592,25 +7678,6 @@
     return NO_ERROR;
 }
 
-status_t AudioFlinger::SpatializerThread::getSupportedLatencyModes(
-        std::vector<audio_latency_mode_t>* modes) {
-    if (modes == nullptr) {
-        return BAD_VALUE;
-    }
-    Mutex::Autolock _l(mLock);
-    *modes = mSupportedLatencyModes;
-    return NO_ERROR;
-}
-
-status_t AudioFlinger::PlaybackThread::setBluetoothVariableLatencyEnabled(bool enabled) {
-    if (mOutput == nullptr || mOutput->audioHwDev == nullptr
-            || !mOutput->audioHwDev->supportsBluetoothVariableLatency()) {
-        return INVALID_OPERATION;
-    }
-    mBluetoothLatencyModesEnabled.store(enabled);
-    return NO_ERROR;
-}
-
 void AudioFlinger::SpatializerThread::checkOutputStageEffects()
 {
     bool hasVirtualizer = false;
@@ -7663,17 +7730,6 @@
     }
 }
 
-void AudioFlinger::SpatializerThread::onRecommendedLatencyModeChanged(
-        std::vector<audio_latency_mode_t> modes) {
-    Mutex::Autolock _l(mLock);
-    if (modes != mSupportedLatencyModes) {
-        ALOGD("%s: thread(%d) supported latency modes: %s",
-            __func__, mId, toString(modes).c_str());
-        mSupportedLatencyModes.swap(modes);
-        sendHalLatencyModesChangedEvent_l();
-    }
-}
-
 // ----------------------------------------------------------------------------
 //      Record
 // ----------------------------------------------------------------------------
@@ -7745,10 +7801,11 @@
         ALOGV("%p kUseFastCapture = Always, initFastCapture = true", this);
         break;
     case FastCapture_Static:
-        initFastCapture = (mFrameCount * 1000) / mSampleRate < kMinNormalCaptureBufferSizeMs;
-        ALOGV("%p kUseFastCapture = Static, (%lld * 1000) / %u vs %u, initFastCapture = %d",
-                this, (long long)mFrameCount, mSampleRate, kMinNormalCaptureBufferSizeMs,
-                initFastCapture);
+        initFastCapture = !mIsMsdDevice // Disable fast capture for MSD BUS devices.
+                && (mFrameCount * 1000) / mSampleRate < kMinNormalCaptureBufferSizeMs;
+        ALOGV("%p kUseFastCapture = Static, (%lld * 1000) / %u vs %u, initFastCapture = %d "
+                "mIsMsdDevice = %d", this, (long long)mFrameCount, mSampleRate,
+                kMinNormalCaptureBufferSizeMs, initFastCapture, mIsMsdDevice);
         break;
     // case FastCapture_Dynamic:
     }
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 1f0f13a..4ab4557 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -376,8 +376,6 @@
     virtual     void        toAudioPortConfig(struct audio_port_config *config) = 0;
 
     virtual     void        resizeInputBuffer_l(int32_t maxSharedAudioHistoryMs);
-    virtual     void        onHalLatencyModesChanged_l() {}
-
 
                 // see note at declaration of mStandby, mOutDevice and mInDevice
                 bool        standby() const { return mStandby; }
@@ -625,6 +623,8 @@
 
                 product_strategy_t getStrategyForStream(audio_stream_type_t stream) const;
 
+    virtual     void        onHalLatencyModesChanged_l() {}
+
     virtual     void        dumpInternals_l(int fd __unused, const Vector<String16>& args __unused)
                             { }
     virtual     void        dumpTracks_l(int fd __unused, const Vector<String16>& args __unused) { }
@@ -1102,7 +1102,9 @@
                     return INVALID_OPERATION;
                 }
 
-    virtual     status_t setBluetoothVariableLatencyEnabled(bool enabled);
+    virtual     status_t setBluetoothVariableLatencyEnabled(bool enabled __unused) {
+                    return INVALID_OPERATION;
+                }
 
                 void startMelComputation(const sp<audio_utils::MelProcessor>& processor);
                 void stopMelComputation();
@@ -1462,12 +1464,10 @@
     virtual     void flushHw_l() {
                     mIsTimestampAdvancing.clear();
                 }
-
-        // Bluetooth Variable latency control logic is enabled or disabled for this thread
-        std::atomic_bool mBluetoothLatencyModesEnabled;
 };
 
-class MixerThread : public PlaybackThread {
+class MixerThread : public PlaybackThread,
+                    public StreamOutHalInterfaceLatencyModeCallback  {
 public:
     MixerThread(const sp<AudioFlinger>& audioFlinger,
                 AudioStreamOut* output,
@@ -1477,6 +1477,13 @@
                 audio_config_base_t *mixerConfig = nullptr);
     virtual             ~MixerThread();
 
+    // RefBase
+    virtual     void        onFirstRef();
+
+                // StreamOutHalInterfaceLatencyModeCallback
+                void        onRecommendedLatencyModeChanged(
+                                    std::vector<audio_latency_mode_t> modes) override;
+
     // Thread virtuals
 
     virtual     bool        checkForNewParameter_l(const String8& keyValuePair,
@@ -1513,6 +1520,17 @@
     virtual     status_t    releaseAudioPatch_l(const audio_patch_handle_t handle);
 
                 AudioMixer* mAudioMixer;    // normal mixer
+
+            // Support low latency mode by default as unless explicitly indicated by the audio HAL
+            // we assume the audio path is compatible with the head tracking latency requirements
+            std::vector<audio_latency_mode_t> mSupportedLatencyModes = {AUDIO_LATENCY_MODE_LOW};
+            // default to invalid value to force first update to the audio HAL
+            audio_latency_mode_t mSetLatencyMode =
+                    (audio_latency_mode_t)AUDIO_LATENCY_MODE_INVALID;
+
+            // Bluetooth Variable latency control logic is enabled or disabled for this thread
+            std::atomic_bool mBluetoothLatencyModesEnabled;
+
 private:
                 // one-time initialization, no locks required
                 sp<FastMixer>     mFastMixer;     // non-0 if there is also a fast mixer
@@ -1546,6 +1564,11 @@
                                 return INVALID_OPERATION;
                             }
 
+                status_t    getSupportedLatencyModes(
+                                    std::vector<audio_latency_mode_t>* modes) override;
+
+                status_t    setBluetoothVariableLatencyEnabled(bool enabled) override;
+
 protected:
     virtual     void       setMasterMono_l(bool mono) {
                                mMasterMono.store(mono);
@@ -1564,6 +1587,10 @@
                                    mFastMixer->setMasterBalance(balance);
                                }
                            }
+
+                void       updateHalSupportedLatencyModes_l();
+                void       onHalLatencyModesChanged_l() override;
+                void       setHalLatencyMode_l() override;
 };
 
 class DirectOutputThread : public PlaybackThread {
@@ -1767,8 +1794,7 @@
     }
 };
 
-class SpatializerThread : public MixerThread,
-        public StreamOutHalInterfaceLatencyModeCallback {
+class SpatializerThread : public MixerThread {
 public:
     SpatializerThread(const sp<AudioFlinger>& audioFlinger,
                            AudioStreamOut* output,
@@ -1779,32 +1805,16 @@
 
             bool hasFastMixer() const override { return false; }
 
-            status_t    createAudioPatch_l(const struct audio_patch *patch,
-                                   audio_patch_handle_t *handle) override;
-
             // RefBase
             virtual void        onFirstRef();
 
-            // StreamOutHalInterfaceLatencyModeCallback
-            void onRecommendedLatencyModeChanged(std::vector<audio_latency_mode_t> modes) override;
-
             status_t setRequestedLatencyMode(audio_latency_mode_t mode) override;
-            status_t getSupportedLatencyModes(std::vector<audio_latency_mode_t>* modes) override;
 
 protected:
             void checkOutputStageEffects() override;
-            void onHalLatencyModesChanged_l() override;
             void setHalLatencyMode_l() override;
 
 private:
-            void updateHalSupportedLatencyModes_l();
-
-            // Support low latency mode by default as unless explicitly indicated by the audio HAL
-            // we assume the audio path is compatible with the head tracking latency requirements
-            std::vector<audio_latency_mode_t> mSupportedLatencyModes = {AUDIO_LATENCY_MODE_LOW};
-            // default to invalid value to force first update to the audio HAL
-            audio_latency_mode_t mSetLatencyMode =
-                    (audio_latency_mode_t)AUDIO_LATENCY_MODE_INVALID;
             // Do not request a specific mode by default
             audio_latency_mode_t mRequestedLatencyMode = AUDIO_LATENCY_MODE_FREE;
 
diff --git a/services/audioflinger/sounddose/SoundDoseManager.h b/services/audioflinger/sounddose/SoundDoseManager.h
index b10874f..db87ad8 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.h
+++ b/services/audioflinger/sounddose/SoundDoseManager.h
@@ -17,7 +17,7 @@
 
 #pragma once
 
-#include <aidl/android/hardware/audio/core/ISoundDose.h>
+#include <aidl/android/hardware/audio/core/sounddose/ISoundDose.h>
 #include <aidl/android/media/audio/common/AudioDevice.h>
 #include <android/media/BnSoundDose.h>
 #include <android/media/ISoundDoseCallback.h>
@@ -30,7 +30,7 @@
 
 namespace android {
 
-using aidl::android::hardware::audio::core::ISoundDose;
+using aidl::android::hardware::audio::core::sounddose::ISoundDose;
 
 class SoundDoseManager : public audio_utils::MelProcessor::MelCallback {
 public:
diff --git a/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp b/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
index ba2edcf..4b1edf3 100644
--- a/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
+++ b/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
@@ -17,7 +17,7 @@
 // #define LOG_NDEBUG 0
 #define LOG_TAG "SoundDoseManager_tests"
 
-#include <aidl/android/hardware/audio/core/BnSoundDose.h>
+#include <aidl/android/hardware/audio/core/sounddose/BnSoundDose.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
@@ -26,7 +26,7 @@
 namespace android {
 namespace {
 
-using aidl::android::hardware::audio::core::BnSoundDose;
+using aidl::android::hardware::audio::core::sounddose::BnSoundDose;
 using aidl::android::media::audio::common::AudioDevice;
 using aidl::android::media::audio::common::AudioDeviceAddress;
 
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 520bad2..8f9c60b 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -300,6 +300,8 @@
 
     virtual bool     isUltrasoundSupported() = 0;
 
+    virtual bool     isHotwordStreamSupported(bool lookbackAudio) = 0;
+
     virtual status_t getHwOffloadFormatsSupportedForBluetoothMedia(
                 audio_devices_t device, std::vector<audio_format_t> *formats) = 0;
 
@@ -323,8 +325,11 @@
                                                const AudioDeviceTypeAddrVector &devices) = 0;
 
     virtual status_t removeDevicesRoleForStrategy(product_strategy_t strategy,
-                                                  device_role_t role) = 0;
+                                                  device_role_t role,
+                                                  const AudioDeviceTypeAddrVector &devices) = 0;
 
+    virtual status_t clearDevicesRoleForStrategy(product_strategy_t strategy,
+                                                     device_role_t role) = 0;
 
     virtual status_t getDevicesForRoleAndStrategy(product_strategy_t strategy,
                                                   device_role_t role,
diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h
index 7d21ae0..8cfa592 100644
--- a/services/audiopolicy/engine/common/include/EngineBase.h
+++ b/services/audiopolicy/engine/common/include/EngineBase.h
@@ -105,7 +105,10 @@
     status_t setDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
             const AudioDeviceTypeAddrVector &devices) override;
 
-    status_t removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role) override;
+    status_t removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
+            const AudioDeviceTypeAddrVector &devices) override;
+
+    status_t clearDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role) override;
 
     status_t getDevicesForRoleAndStrategy(product_strategy_t strategy, device_role_t role,
             AudioDeviceTypeAddrVector &devices) const override;
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 9b78758..8015ae0 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -369,13 +369,11 @@
     }
 
     switch (role) {
-    case DEVICE_ROLE_PREFERRED:
-    case DEVICE_ROLE_DISABLED: {
+    case DEVICE_ROLE_PREFERRED: {
         tDevicesRoleMap[std::make_pair(t, role)] = devices;
         // The preferred devices and disabled devices are mutually exclusive. Once a device is added
         // the a list, it must be removed from the other one.
-        const device_role_t roleToRemove = role == DEVICE_ROLE_PREFERRED ? DEVICE_ROLE_DISABLED
-                                                                         : DEVICE_ROLE_PREFERRED;
+        const device_role_t roleToRemove = DEVICE_ROLE_DISABLED;
         auto it = tDevicesRoleMap.find(std::make_pair(t, roleToRemove));
         if (it != tDevicesRoleMap.end()) {
             it->second = excludeDeviceTypeAddrsFrom(it->second, devices);
@@ -384,6 +382,25 @@
             }
         }
     } break;
+    case DEVICE_ROLE_DISABLED: {
+        auto it = tDevicesRoleMap.find(std::make_pair(t, role));
+        if (it != tDevicesRoleMap.end()) {
+            it->second = joinDeviceTypeAddrs(it->second, devices);
+        } else {
+            tDevicesRoleMap[std::make_pair(t, role)] = devices;
+        }
+
+        // The preferred devices and disabled devices are mutually exclusive. Once a device is added
+        // the a list, it must be removed from the other one.
+        const device_role_t roleToRemove = DEVICE_ROLE_PREFERRED;
+        it = tDevicesRoleMap.find(std::make_pair(t, roleToRemove));
+        if (it != tDevicesRoleMap.end()) {
+            it->second = excludeDeviceTypeAddrsFrom(it->second, devices);
+            if (it->second.empty()) {
+                tDevicesRoleMap.erase(it);
+            }
+        }
+    } break;
     case DEVICE_ROLE_NONE:
         // Intentionally fall-through as it is no need to set device role as none for a strategy.
     default:
@@ -394,6 +411,36 @@
 }
 
 template <typename T>
+status_t removeDevicesRoleForT(
+        std::map<std::pair<T, device_role_t>, AudioDeviceTypeAddrVector>& tDevicesRoleMap,
+        T t, device_role_t role, const AudioDeviceTypeAddrVector &devices,
+        const std::string& logStr, std::function<bool(T)> p) {
+    if (!p(t)) {
+        ALOGE("%s invalid %s %u", __func__, logStr.c_str(), t);
+        return BAD_VALUE;
+    }
+
+    switch (role) {
+    case DEVICE_ROLE_PREFERRED:
+    case DEVICE_ROLE_DISABLED: {
+        auto it = tDevicesRoleMap.find(std::make_pair(t, role));
+        if (it != tDevicesRoleMap.end()) {
+            it->second = excludeDeviceTypeAddrsFrom(it->second, devices);
+            if (it->second.empty()) {
+                tDevicesRoleMap.erase(it);
+            }
+        }
+    } break;
+    case DEVICE_ROLE_NONE:
+        // Intentionally fall-through as it is not needed to set device role as none for a strategy.
+    default:
+        ALOGE("%s invalid role %d", __func__, role);
+        return BAD_VALUE;
+    }
+    return NO_ERROR;
+}
+
+template <typename T>
 status_t removeAllDevicesRoleForT(
         std::map<std::pair<T, device_role_t>, AudioDeviceTypeAddrVector>& tDevicesRoleMap,
         T t, device_role_t role, const std::string& logStr, std::function<bool(T)> p) {
@@ -462,7 +509,18 @@
             mProductStrategyDeviceRoleMap, strategy, role, devices, "strategy" /*logStr*/, p);
 }
 
-status_t EngineBase::removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role)
+status_t EngineBase::removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
+            const AudioDeviceTypeAddrVector &devices)
+{
+    std::function<bool(product_strategy_t)> p = [this](product_strategy_t strategy) {
+        return mProductStrategies.find(strategy) != mProductStrategies.end();
+    };
+    return removeDevicesRoleForT(
+            mProductStrategyDeviceRoleMap, strategy, role, devices, "strategy" /*logStr*/, p);
+}
+
+status_t EngineBase::clearDevicesRoleForStrategy(product_strategy_t strategy,
+            device_role_t role)
 {
     std::function<bool(product_strategy_t)> p = [this](product_strategy_t strategy) {
         return mProductStrategies.find(strategy) != mProductStrategies.end();
diff --git a/services/audiopolicy/engine/interface/EngineInterface.h b/services/audiopolicy/engine/interface/EngineInterface.h
index 70d25fc..b8e35ed 100644
--- a/services/audiopolicy/engine/interface/EngineInterface.h
+++ b/services/audiopolicy/engine/interface/EngineInterface.h
@@ -326,10 +326,22 @@
      * for the given strategy
      * @param strategy the audio strategy whose routing will be affected
      * @param role the role of the devices for strategy
+     * @param devices the audio devices to be removed
      * @return BAD_VALUE if the strategy or role is invalid,
      *     or NO_ERROR if the devices for this role was removed
      */
-    virtual status_t removeDevicesRoleForStrategy(product_strategy_t strategy,
+    virtual status_t removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
+            const AudioDeviceTypeAddrVector &devices) = 0;
+
+    /**
+     * @brief clearDevicesRoleForStrategy removes the role of all devices previously set
+     * for the given strategy
+     * @param strategy the audio strategy whose routing will be affected
+     * @param role the role of the devices for strategy
+     * @return BAD_VALUE if the strategy or role is invalid,
+     *     or NO_ERROR if the devices for this role was removed
+     */
+    virtual status_t clearDevicesRoleForStrategy(product_strategy_t strategy,
             device_role_t role) = 0;
 
     /**
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index f99f76e..0f2b34e 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -34,6 +34,7 @@
 #include <map>
 #include <math.h>
 #include <set>
+#include <type_traits>
 #include <unordered_set>
 #include <vector>
 
@@ -3875,14 +3876,47 @@
     }
 }
 
-status_t AudioPolicyManager::removeDevicesRoleForStrategy(product_strategy_t strategy,
-                                                          device_role_t role)
+status_t
+AudioPolicyManager::removeDevicesRoleForStrategy(product_strategy_t strategy,
+                                                 device_role_t role,
+                                                 const AudioDeviceTypeAddrVector &devices) {
+    ALOGV("%s() strategy=%d role=%d %s", __func__, strategy, role,
+            dumpAudioDeviceTypeAddrVector(devices).c_str());
+
+    if (!areAllDevicesSupported(devices, audio_is_output_device, __func__)) {
+        return BAD_VALUE;
+    }
+    status_t status = mEngine->removeDevicesRoleForStrategy(strategy, role, devices);
+    if (status != NO_ERROR) {
+        ALOGW("Engine could not remove devices %s for strategy %d role %d",
+                dumpAudioDeviceTypeAddrVector(devices).c_str(), strategy, role);
+        return status;
+    }
+
+    checkForDeviceAndOutputChanges();
+
+    bool forceVolumeReeval = false;
+    // TODO(b/263479999): workaround for truncated touch sounds
+    // to be removed when the problem is handled by system UI
+    uint32_t delayMs = 0;
+    if (strategy == mCommunnicationStrategy) {
+        forceVolumeReeval = true;
+        delayMs = TOUCH_SOUND_FIXED_DELAY_MS;
+        updateInputRouting();
+    }
+    updateCallAndOutputRouting(forceVolumeReeval, delayMs);
+
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::clearDevicesRoleForStrategy(product_strategy_t strategy,
+                                                         device_role_t role)
 {
     ALOGV("%s() strategy=%d role=%d", __func__, strategy, role);
 
-    status_t status = mEngine->removeDevicesRoleForStrategy(strategy, role);
+    status_t status = mEngine->clearDevicesRoleForStrategy(strategy, role);
     if (status != NO_ERROR) {
-        ALOGV("Engine could not remove preferred device for strategy %d status %d",
+        ALOGV("Engine could not remove device role for strategy %d status %d",
                 strategy, status);
         return status;
     }
@@ -5653,6 +5687,21 @@
     return false;
 }
 
+bool AudioPolicyManager::isHotwordStreamSupported(bool lookbackAudio)
+{
+    const auto mask = AUDIO_INPUT_FLAG_HOTWORD_TAP |
+        (lookbackAudio ? AUDIO_INPUT_FLAG_HW_LOOKBACK : 0);
+    for (const auto& hwModule : mHwModules) {
+        const InputProfileCollection &inputProfiles = hwModule->getInputProfiles();
+        for (const auto &inputProfile : inputProfiles) {
+            if ((inputProfile->getFlags() & mask) == mask) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
 bool AudioPolicyManager::isCallScreenModeSupported()
 {
     return getConfig().isCallScreenModeSupported();
@@ -7406,8 +7455,11 @@
     // TODO: perhaps isCompatibleProfile should return a "matching" score so we can return
     // the best matching profile, not the first one.
 
-    const audio_input_flags_t mustMatchFlag = AUDIO_INPUT_FLAG_MMAP_NOIRQ;
-    const audio_input_flags_t oriFlags = flags;
+    using underlying_input_flag_t = std::underlying_type_t<audio_input_flags_t>;
+    const underlying_input_flag_t mustMatchFlag = AUDIO_INPUT_FLAG_MMAP_NOIRQ |
+                         AUDIO_INPUT_FLAG_HOTWORD_TAP | AUDIO_INPUT_FLAG_HW_LOOKBACK;
+
+    const underlying_input_flag_t oriFlags = flags;
 
     for (;;) {
         sp<IOProfile> firstInexact = nullptr;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 885f7c6..3bbcf69 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -299,8 +299,11 @@
                                                    const AudioDeviceTypeAddrVector &devices);
 
         virtual status_t removeDevicesRoleForStrategy(product_strategy_t strategy,
-                                                      device_role_t role);
+                                                      device_role_t role,
+                                                      const AudioDeviceTypeAddrVector &devices);
 
+        virtual status_t clearDevicesRoleForStrategy(product_strategy_t strategy,
+                                                     device_role_t role);
 
         virtual status_t getDevicesForRoleAndStrategy(product_strategy_t strategy,
                                                       device_role_t role,
@@ -352,6 +355,8 @@
 
         virtual bool isUltrasoundSupported();
 
+        bool isHotwordStreamSupported(bool lookbackAudio) override;
+
         virtual status_t listAudioProductStrategies(AudioProductStrategyVector &strategies)
         {
             return mEngine->listAudioProductStrategies(strategies);
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 5c32209..1774600 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -667,7 +667,9 @@
         return binderStatusFromStatusT(PERMISSION_DENIED);
     }
 
-    if (((flags & AUDIO_INPUT_FLAG_HW_HOTWORD) != 0)
+    if (((flags & (AUDIO_INPUT_FLAG_HW_HOTWORD |
+                        AUDIO_INPUT_FLAG_HOTWORD_TAP |
+                        AUDIO_INPUT_FLAG_HW_LOOKBACK)) != 0)
             && !canCaptureHotword) {
         ALOGE("%s: permission denied: hotword mode not allowed"
               " for uid %d pid %d", __func__, attributionSource.uid, attributionSource.pid);
@@ -2043,6 +2045,17 @@
     return Status::ok();
 }
 
+Status AudioPolicyService::isHotwordStreamSupported(bool lookbackAudio, bool* _aidl_return)
+{
+    if (mAudioPolicyManager == nullptr) {
+        return binderStatusFromStatusT(NO_INIT);
+    }
+    Mutex::Autolock _l(mLock);
+    AutoCallerClear acc;
+    *_aidl_return = mAudioPolicyManager->isHotwordStreamSupported(lookbackAudio);
+    return Status::ok();
+}
+
 Status AudioPolicyService::listAudioProductStrategies(
         std::vector<media::AudioProductStrategy>* _aidl_return) {
     AudioProductStrategyVector strategies;
@@ -2154,8 +2167,31 @@
     return binderStatusFromStatusT(status);
 }
 
-Status AudioPolicyService::removeDevicesRoleForStrategy(int32_t strategyAidl,
-                                                        media::DeviceRole roleAidl) {
+Status AudioPolicyService::removeDevicesRoleForStrategy(
+        int32_t strategyAidl,
+        media::DeviceRole roleAidl,
+        const std::vector<AudioDevice>& devicesAidl) {
+    product_strategy_t strategy = VALUE_OR_RETURN_BINDER_STATUS(
+            aidl2legacy_int32_t_product_strategy_t(strategyAidl));
+    device_role_t role = VALUE_OR_RETURN_BINDER_STATUS(
+            aidl2legacy_DeviceRole_device_role_t(roleAidl));
+    AudioDeviceTypeAddrVector devices = VALUE_OR_RETURN_BINDER_STATUS(
+            convertContainer<AudioDeviceTypeAddrVector>(devicesAidl,
+                                                        aidl2legacy_AudioDeviceTypeAddress));
+
+    if (mAudioPolicyManager == NULL) {
+        return binderStatusFromStatusT(NO_INIT);
+    }
+    Mutex::Autolock _l(mLock);
+    status_t status = mAudioPolicyManager->removeDevicesRoleForStrategy(strategy, role, devices);
+    if (status == NO_ERROR) {
+       onCheckSpatializer_l();
+    }
+    return binderStatusFromStatusT(status);
+}
+
+Status AudioPolicyService::clearDevicesRoleForStrategy(int32_t strategyAidl,
+                                                           media::DeviceRole roleAidl) {
      product_strategy_t strategy = VALUE_OR_RETURN_BINDER_STATUS(
             aidl2legacy_int32_t_product_strategy_t(strategyAidl));
     device_role_t role = VALUE_OR_RETURN_BINDER_STATUS(
@@ -2164,7 +2200,7 @@
         return binderStatusFromStatusT(NO_INIT);
     }
     Mutex::Autolock _l(mLock);
-    status_t status = mAudioPolicyManager->removeDevicesRoleForStrategy(strategy, role);
+    status_t status = mAudioPolicyManager->clearDevicesRoleForStrategy(strategy, role);
     if (status == NO_ERROR) {
        onCheckSpatializer_l();
     }
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 2be5121..974ae38 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -137,6 +137,7 @@
 BINDER_METHOD_ENTRY(setCurrentImeUid) \
 BINDER_METHOD_ENTRY(isHapticPlaybackSupported) \
 BINDER_METHOD_ENTRY(isUltrasoundSupported) \
+BINDER_METHOD_ENTRY(isHotwordStreamSupported) \
 BINDER_METHOD_ENTRY(listAudioProductStrategies) \
 BINDER_METHOD_ENTRY(getProductStrategyFromAudioAttributes) \
 BINDER_METHOD_ENTRY(listAudioVolumeGroups) \
@@ -145,6 +146,7 @@
 BINDER_METHOD_ENTRY(isCallScreenModeSupported) \
 BINDER_METHOD_ENTRY(setDevicesRoleForStrategy) \
 BINDER_METHOD_ENTRY(removeDevicesRoleForStrategy) \
+BINDER_METHOD_ENTRY(clearDevicesRoleForStrategy) \
 BINDER_METHOD_ENTRY(getDevicesForRoleAndStrategy) \
 BINDER_METHOD_ENTRY(setDevicesRoleForCapturePreset) \
 BINDER_METHOD_ENTRY(addDevicesRoleForCapturePreset) \
@@ -1313,11 +1315,13 @@
         case TRANSACTION_getVolumeGroupFromAudioAttributes:
         case TRANSACTION_acquireSoundTriggerSession:
         case TRANSACTION_releaseSoundTriggerSession:
+        case TRANSACTION_isHotwordStreamSupported:
         case TRANSACTION_setRttEnabled:
         case TRANSACTION_isCallScreenModeSupported:
         case TRANSACTION_setDevicesRoleForStrategy:
         case TRANSACTION_setSupportedSystemUsages:
         case TRANSACTION_removeDevicesRoleForStrategy:
+        case TRANSACTION_clearDevicesRoleForStrategy:
         case TRANSACTION_getDevicesForRoleAndStrategy:
         case TRANSACTION_getDevicesForAttributes:
         case TRANSACTION_setAllowedCapturePolicy:
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 50f2180..31d5249 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -70,7 +70,7 @@
     public IBinder::DeathRecipient,
     public SpatializerPolicyCallback
 {
-    friend class BinderService<AudioPolicyService>;
+    friend class sp<AudioPolicyService>;
 
 public:
     // for BinderService
@@ -223,6 +223,7 @@
     binder::Status setCurrentImeUid(int32_t uid) override;
     binder::Status isHapticPlaybackSupported(bool* _aidl_return) override;
     binder::Status isUltrasoundSupported(bool* _aidl_return) override;
+    binder::Status isHotwordStreamSupported(bool lookbackAudio, bool* _aidl_return) override;
     binder::Status listAudioProductStrategies(
             std::vector<media::AudioProductStrategy>* _aidl_return) override;
     binder::Status getProductStrategyFromAudioAttributes(const media::AudioAttributesInternal& aa,
@@ -238,7 +239,12 @@
     binder::Status setDevicesRoleForStrategy(
             int32_t strategy, media::DeviceRole role,
             const std::vector<AudioDevice>& devices) override;
-    binder::Status removeDevicesRoleForStrategy(int32_t strategy, media::DeviceRole role) override;
+    binder::Status removeDevicesRoleForStrategy(
+            int32_t strategy, media::DeviceRole role,
+            const std::vector<AudioDevice>& devices) override;
+    binder::Status clearDevicesRoleForStrategy(
+            int32_t strategy,
+            media::DeviceRole role) override;
     binder::Status getDevicesForRoleAndStrategy(
             int32_t strategy, media::DeviceRole role,
             std::vector<AudioDevice>* _aidl_return) override;
diff --git a/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp b/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp
index fb8979d..9857fd8 100644
--- a/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp
@@ -285,22 +285,37 @@
     }
 
     size_t actualJpegRSize = 0;
-    if (mSupportInternalJpeg) {
-        recoverymap::jpegr_uncompressed_struct p010;
-        recoverymap::jpegr_compressed_struct jpeg;
-        recoverymap::jpegr_compressed_struct jpegR;
+    recoverymap::jpegr_uncompressed_struct p010;
+    recoverymap::jpegr_compressed_struct jpegR;
+    recoverymap::RecoveryMap recoveryMap;
 
-        p010.height = inputFrame.p010Buffer.height;
-        p010.width = inputFrame.p010Buffer.width;
-        p010.colorGamut = recoverymap::jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
-        size_t yChannelSizeInByte = p010.width * p010.height * 2;
-        size_t uvChannelSizeInByte = p010.width * p010.height;
-        p010.data = new uint8_t[yChannelSizeInByte + uvChannelSizeInByte];
-        std::unique_ptr<uint8_t[]> p010_data;
-        p010_data.reset(reinterpret_cast<uint8_t*>(p010.data));
-        memcpy((uint8_t*)p010.data, inputFrame.p010Buffer.data, yChannelSizeInByte);
-        memcpy((uint8_t*)p010.data + yChannelSizeInByte, inputFrame.p010Buffer.dataCb,
-               uvChannelSizeInByte);
+    p010.height = inputFrame.p010Buffer.height;
+    p010.width = inputFrame.p010Buffer.width;
+    p010.colorGamut = recoverymap::jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
+    size_t yChannelSizeInByte = p010.width * p010.height * 2;
+    size_t uvChannelSizeInByte = p010.width * p010.height;
+    p010.data = new uint8_t[yChannelSizeInByte + uvChannelSizeInByte];
+    std::unique_ptr<uint8_t[]> p010_data;
+    p010_data.reset(reinterpret_cast<uint8_t*>(p010.data));
+    memcpy((uint8_t*)p010.data, inputFrame.p010Buffer.data, yChannelSizeInByte);
+    memcpy((uint8_t*)p010.data + yChannelSizeInByte, inputFrame.p010Buffer.dataCb,
+           uvChannelSizeInByte);
+
+    jpegR.data = dstBuffer;
+    jpegR.maxLength = maxJpegRBufferSize;
+
+    recoverymap::jpegr_transfer_function transferFunction;
+    switch (mP010DynamicRange) {
+        case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10:
+        case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS:
+            transferFunction = recoverymap::jpegr_transfer_function::JPEGR_TF_PQ;
+            break;
+        default:
+            transferFunction = recoverymap::jpegr_transfer_function::JPEGR_TF_HLG;
+    }
+
+    if (mSupportInternalJpeg) {
+        recoverymap::jpegr_compressed_struct jpeg;
 
         jpeg.data = inputFrame.jpegBuffer.data;
         jpeg.length = android::camera2::JpegProcessor::findJpegSize(inputFrame.jpegBuffer.data,
@@ -317,28 +332,7 @@
             jpeg.colorGamut = recoverymap::jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
         }
 
-        recoverymap::jpegr_transfer_function transferFunction;
-        switch (mP010DynamicRange) {
-            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10:
-            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS:
-                transferFunction = recoverymap::jpegr_transfer_function::JPEGR_TF_PQ;
-                break;
-            default:
-                transferFunction = recoverymap::jpegr_transfer_function::JPEGR_TF_HLG;
-        }
-
-        jpegR.data = dstBuffer;
-        jpegR.maxLength = maxJpegRBufferSize;
-
-        recoverymap::RecoveryMap recoveryMap;
         res = recoveryMap.encodeJPEGR(&p010, &jpeg, transferFunction, &jpegR);
-        if (res != OK) {
-            ALOGE("%s: Error trying to encode JPEG/R: %s (%d)", __FUNCTION__, strerror(-res), res);
-            return res;
-        }
-
-        actualJpegRSize = jpegR.length;
-        p010_data.release();
     } else {
         const uint8_t* exifBuffer = nullptr;
         size_t exifBufferSize = 0;
@@ -352,8 +346,22 @@
         } else {
             ALOGE("%s: Unable to generate App1 buffer", __FUNCTION__);
         }
+
+        recoverymap::jpegr_exif_struct exif;
+        exif.data = reinterpret_cast<void*>(const_cast<uint8_t*>(exifBuffer));
+        exif.length = exifBufferSize;
+
+        res = recoveryMap.encodeJPEGR(&p010, transferFunction, &jpegR, jpegQuality, &exif);
     }
 
+    if (res != OK) {
+        ALOGE("%s: Error trying to encode JPEG/R: %s (%d)", __FUNCTION__, strerror(-res), res);
+        return res;
+    }
+
+    actualJpegRSize = jpegR.length;
+    p010_data.release();
+
     size_t finalJpegRSize = actualJpegRSize + sizeof(CameraBlob);
     if (finalJpegRSize > maxJpegRBufferSize) {
         ALOGE("%s: Final jpeg buffer not large enough for the jpeg blob header", __FUNCTION__);
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 5b8e3a1..927dc47 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -1153,14 +1153,6 @@
         return OK;
     }
 
-    if (!isConcurrentDynamicRangeCaptureSupported(c,
-                ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10,
-                ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD)) {
-        // Advertise Jpeg/R only in case 10 and 8-bit concurrent capture is supported.
-        // This can be removed when 10-bit to 8-bit tonemapping is available.
-        return OK;
-    }
-
     getSupportedSizes(c, scalerSizesTag,
             static_cast<android_pixel_format_t>(HAL_PIXEL_FORMAT_BLOB), &supportedBlobSizes);
     getSupportedSizes(c, scalerSizesTag,