Merge "hal: msmsteppe: Update class-H mode for wcd9375 xml files"
diff --git a/configs/msmnile_au/audio_platform_info.xml b/configs/msmnile_au/audio_platform_info.xml
index d6d6deb..d74e1a3 100644
--- a/configs/msmnile_au/audio_platform_info.xml
+++ b/configs/msmnile_au/audio_platform_info.xml
@@ -26,12 +26,12 @@
 <!-- IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                          -->
 <audio_platform_info>
     <acdb_ids>
-        <device name="SND_DEVICE_OUT_HANDSET" acdb_id="41"/>
-        <device name="SND_DEVICE_OUT_SPEAKER" acdb_id="41"/>
-        <device name="SND_DEVICE_OUT_HEADPHONES" acdb_id="41"/>
+        <device name="SND_DEVICE_OUT_HANDSET" acdb_id="60"/>
+        <device name="SND_DEVICE_OUT_SPEAKER" acdb_id="60"/>
+        <device name="SND_DEVICE_OUT_HEADPHONES" acdb_id="60"/>
         <device name="SND_DEVICE_OUT_BT_SCO" acdb_id="94"/>
         <device name="SND_DEVICE_OUT_BT_SCO_WB" acdb_id="94"/>
-        <device name="SND_DEVICE_OUT_BT_A2DP" acdb_id="41"/>
+        <device name="SND_DEVICE_OUT_BT_A2DP" acdb_id="60"/>
         <device name="SND_DEVICE_OUT_VOICE_HANDSET" acdb_id="94"/>
         <device name="SND_DEVICE_OUT_VOICE_SPEAKER" acdb_id="94"/>
         <device name="SND_DEVICE_IN_HANDSET_MIC" acdb_id="11"/>
@@ -96,10 +96,10 @@
         <usecase name="USECASE_AUDIO_PLAYBACK_MMAP" type="out" id="28" />
         <usecase name="USECASE_AUDIO_RECORD_MMAP" type="in" id="28" />
         <usecase name="USECASE_AUDIO_RECORD" type="in" id="0" />
-        <usecase name="USECASE_AUDIO_HFP_SCO" type="in" id="29" />
-        <usecase name="USECASE_AUDIO_HFP_SCO" type="out" id="29" />
-        <usecase name="USECASE_AUDIO_HFP_SCO_WB" type="in" id="29" />
-        <usecase name="USECASE_AUDIO_HFP_SCO_WB" type="out" id="29" />
+        <usecase name="USECASE_AUDIO_HFP_SCO" type="in" id="36" />
+        <usecase name="USECASE_AUDIO_HFP_SCO" type="out" id="36" />
+        <usecase name="USECASE_AUDIO_HFP_SCO_WB" type="in" id="36" />
+        <usecase name="USECASE_AUDIO_HFP_SCO_WB" type="out" id="36" />
     </pcm_ids>
 
     <config_params>
diff --git a/configs/msmnile_au/mixer_paths_adp.xml b/configs/msmnile_au/mixer_paths_adp.xml
index bcea162..e8f2540 100644
--- a/configs/msmnile_au/mixer_paths_adp.xml
+++ b/configs/msmnile_au/mixer_paths_adp.xml
@@ -318,6 +318,10 @@
     <ctl name="SEC_TDM_RX_0 Audio Mixer MultiMedia9" value="0" />
     <ctl name="MultiMedia9 Mixer TERT_TDM_TX_0" value="0" />
 
+    <path name="dummy-hostless">
+        <ctl name="SEC_TDM_RX_7 Port Mixer TERT_TDM_TX_7" value="1" />
+    </path>
+
     <!-- Codec controls -->
     <!-- WSA controls -->
     <ctl name="SpkrLeft COMP Switch" value="0" />
@@ -576,7 +580,7 @@
     </path>
 
     <path name="deep-buffer-playback">
-        <ctl name="TERT_TDM_RX_0 Channels" value="Two" />
+        <ctl name="TERT_TDM_RX_0 Channels" value="Six" />
         <ctl name="TERT_TDM_RX_0 Audio Mixer MultiMedia1" value="1" />
     </path>
 
@@ -639,7 +643,7 @@
     </path>
 
     <path name="low-latency-playback">
-        <ctl name="TERT_TDM_RX_0 Channels" value="Two" />
+        <ctl name="TERT_TDM_RX_0 Channels" value="Six" />
         <ctl name="TERT_TDM_RX_0 Audio Mixer MultiMedia5" value="1" />
     </path>
 
@@ -706,7 +710,7 @@
     </path>
 
     <path name="audio-ull-playback">
-        <ctl name="TERT_TDM_RX_0 Channels" value="Two" />
+        <ctl name="TERT_TDM_RX_0 Channels" value="Six" />
         <ctl name="TERT_TDM_RX_0 Audio Mixer MultiMedia8" value="1" />
     </path>
 
@@ -772,7 +776,7 @@
     </path>
 
     <path name="compress-offload-playback">
-        <ctl name="TERT_TDM_RX_0 Channels" value="Two" />
+        <ctl name="TERT_TDM_RX_0 Channels" value="Six" />
         <ctl name="TERT_TDM_RX_0 Audio Mixer MultiMedia4" value="1" />
     </path>
 
@@ -847,7 +851,7 @@
     </path>
 
     <path name="compress-offload-playback2">
-        <ctl name="TERT_TDM_RX_0 Channels" value="Two" />
+        <ctl name="TERT_TDM_RX_0 Channels" value="Six" />
         <ctl name="TERT_TDM_RX_0 Audio Mixer MultiMedia7" value="1" />
     </path>
 
@@ -914,7 +918,7 @@
     </path>
 
     <path name="compress-offload-playback3">
-        <ctl name="TERT_TDM_RX_0 Channels" value="Two" />
+        <ctl name="TERT_TDM_RX_0 Channels" value="Six" />
         <ctl name="TERT_TDM_RX_0 Audio Mixer MultiMedia10" value="1" />
     </path>
 
@@ -981,7 +985,7 @@
     </path>
 
     <path name="compress-offload-playback4">
-        <ctl name="TERT_TDM_RX_0 Channels" value="Two" />
+        <ctl name="TERT_TDM_RX_0 Channels" value="Six" />
         <ctl name="TERT_TDM_RX_0 Audio Mixer MultiMedia11" value="1" />
     </path>
 
@@ -1049,7 +1053,7 @@
     </path>
 
     <path name="compress-offload-playback5">
-        <ctl name="TERT_TDM_RX_0 Channels" value="Two" />
+        <ctl name="TERT_TDM_RX_0 Channels" value="Six" />
         <ctl name="TERT_TDM_RX_0 Audio Mixer MultiMedia12" value="1" />
     </path>
 
@@ -1116,7 +1120,7 @@
     </path>
 
     <path name="compress-offload-playback6">
-        <ctl name="TERT_TDM_RX_0 Channels" value="Two" />
+        <ctl name="TERT_TDM_RX_0 Channels" value="Six" />
         <ctl name="TERT_TDM_RX_0 Audio Mixer MultiMedia13" value="1" />
     </path>
 
@@ -1183,7 +1187,7 @@
     </path>
 
     <path name="compress-offload-playback7">
-        <ctl name="TERT_TDM_RX_0 Channels" value="Two" />
+        <ctl name="TERT_TDM_RX_0 Channels" value="Six" />
         <ctl name="TERT_TDM_RX_0 Audio Mixer MultiMedia14" value="1" />
     </path>
 
@@ -1250,7 +1254,7 @@
     </path>
 
     <path name="compress-offload-playback8">
-        <ctl name="TERT_TDM_RX_0 Channels" value="Two" />
+        <ctl name="TERT_TDM_RX_0 Channels" value="Six" />
         <ctl name="TERT_TDM_RX_0 Audio Mixer MultiMedia15" value="1" />
     </path>
 
@@ -1317,7 +1321,7 @@
     </path>
 
     <path name="compress-offload-playback9">
-        <ctl name="TERT_TDM_RX_0 Channels" value="Two" />
+        <ctl name="TERT_TDM_RX_0 Channels" value="Six" />
         <ctl name="TERT_TDM_RX_0 Audio Mixer MultiMedia16" value="1" />
     </path>
 
@@ -1753,6 +1757,7 @@
 
     <!-- VoIP Rx settings -->
     <path name="audio-playback-voip">
+        <ctl name="TERT_TDM_RX_0 Channels" value="Six" />
         <ctl name="TERT_TDM_RX_0 Audio Mixer MultiMedia10" value="1" />
     </path>
 
diff --git a/configs/msmnile_au/msmnile_au.mk b/configs/msmnile_au/msmnile_au.mk
index 9b0952b..7abac58 100644
--- a/configs/msmnile_au/msmnile_au.mk
+++ b/configs/msmnile_au/msmnile_au.mk
@@ -70,6 +70,11 @@
 AUDIO_FEATURE_ENABLED_BATTERY_LISTENER := false
 ##AUDIO_FEATURE_FLAGS
 
+AUDIO_FEATURE_ENABLED_EXT_HW_PLUGIN := true
+AUDIO_FEATURE_ENABLED_BUS_ADDRESS := true
+AUDIO_FEATURE_ENABLED_AUDIO_CONTROL_HAL := true
+##AUTOMOTIVE_AUDIO_FEATURE_FLAGS
+
 ifneq ($(strip $(TARGET_USES_RRO)), true)
 #Audio Specific device overlays
 DEVICE_PACKAGE_OVERLAYS += hardware/qcom/audio/configs/common/overlay
@@ -249,14 +254,3 @@
     android.hardware.audio@4.0-impl \
     android.hardware.audio.effect@4.0 \
     android.hardware.audio.effect@4.0-impl
-
-PRODUCT_PROPERTY_OVERRIDES += \
-persist.audio.calfile0=/vendor/etc/acdbdata/adsp_avs_config.acdb\
-persist.audio.calfile1=/vendor/etc/acdbdata/ADP/Bluetooth_cal.acdb\
-persist.audio.calfile2=/vendor/etc/acdbdata/ADP/Codec_cal.acdb\
-persist.audio.calfile3=/vendor/etc/acdbdata/ADP/General_cal.acdb\
-persist.audio.calfile4=/vendor/etc/acdbdata/ADP/Global_cal.acdb\
-persist.audio.calfile5=/vendor/etc/acdbdata/ADP/Handset_cal.acdb\
-persist.audio.calfile6=/vendor/etc/acdbdata/ADP/Hdmi_cal.acdb\
-persist.audio.calfile7=/vendor/etc/acdbdata/ADP/Headset_cal.acdb\
-persist.audio.calfile8=/vendor/etc/acdbdata/ADP/Speaker_cal.acdb
diff --git a/configs/sdm710/mixer_paths_tavil.xml b/configs/sdm710/mixer_paths_tavil.xml
index 319b3ea..ec90fc0 100644
--- a/configs/sdm710/mixer_paths_tavil.xml
+++ b/configs/sdm710/mixer_paths_tavil.xml
@@ -754,6 +754,25 @@
         <ctl name="DISPLAY_PORT Mixer MultiMedia4" value="1" />
     </path>
 
+    <path name="silence-playback">
+        <ctl name="AUDIO_REF_EC_UL1 MUX" value="SLIM_RX" />
+        <ctl name="SLIMBUS_0_RX Audio Mixer MultiMedia9" value="1" />
+    </path>
+
+    <path name="ec-ref-audio-capture">
+        <ctl name="AUDIO_REF_EC_UL1 MUX" value="SLIM_RX" />
+        <ctl name="MultiMedia9 Mixer AFE_LOOPBACK_TX" value="1" />
+    </path>
+
+    <path name="ec-ref-loopback-mono">
+    </path>
+
+    <path name="ec-ref-loopback-stereo">
+    </path>
+
+    <path name="ec-ref-loopback-quad">
+    </path>
+
     <path name="silence-playback display-port">
         <ctl name="DISPLAY_PORT Mixer MultiMedia9" value="1" />
     </path>
diff --git a/configs/sdm710/sdm710.mk b/configs/sdm710/sdm710.mk
index 776c2e1..6db48b6 100644
--- a/configs/sdm710/sdm710.mk
+++ b/configs/sdm710/sdm710.mk
@@ -50,7 +50,7 @@
 AUDIO_FEATURE_ENABLED_FLUENCE := true
 AUDIO_FEATURE_ENABLED_HDMI_EDID := true
 AUDIO_FEATURE_ENABLED_HDMI_PASSTHROUGH := true
-#AUDIO_FEATURE_ENABLED_KEEP_ALIVE := true
+AUDIO_FEATURE_ENABLED_KEEP_ALIVE := true
 AUDIO_FEATURE_ENABLED_DISPLAY_PORT := true
 AUDIO_FEATURE_ENABLED_DS2_DOLBY_DAP := false
 AUDIO_FEATURE_ENABLED_HFP := true
@@ -68,8 +68,13 @@
 BOARD_SUPPORTS_QSTHW_API := true
 AUDIO_FEATURE_ENABLED_RAS := true
 AUDIO_FEATURE_ENABLED_SND_MONITOR := true
+BOARD_SUPPORTS_SOUND_TRIGGER_ARM := true
+AUDIO_FEATURE_ENABLED_FFV := true
+AUDIO_FEATURE_ENABLED_KEEP_ALIVE_ARM_FFV := true
 AUDIO_FEATURE_ENABLED_DLKM := true
 AUDIO_FEATURE_ENABLED_SVA_MULTI_STAGE := true
+BOARD_SUPPORTS_SOUND_TRIGGER_CPU_AFFINITY_SET := true
+BOARD_SUPPORTS_FFV_EC_THREAD_RT_PRIORITY := true
 ##AUDIO_FEATURE_FLAGS
 
 ifneq ($(strip $(TARGET_USES_RRO)), true)
diff --git a/configs/sdm710/sound_trigger_mixer_paths_wcd9340.xml b/configs/sdm710/sound_trigger_mixer_paths_wcd9340.xml
index ffae119..4d1bb31 100644
--- a/configs/sdm710/sound_trigger_mixer_paths_wcd9340.xml
+++ b/configs/sdm710/sound_trigger_mixer_paths_wcd9340.xml
@@ -95,6 +95,7 @@
     <ctl name= "WDMA3 CH2 MUX" value="PORT_0" />
     <ctl name= "WDMA3_ON_OFF Switch" value="0" />
     <ctl name="SLIM_0_TX Channels" value="One" />
+    <ctl name="AUDIO_REF_EC_UL1 MUX" value="None"/>
 
     <path name="listen-voice-wakeup-1">
         <ctl name="SLIMBUS_5_TX LSM Function" value="AUDIO" />
@@ -332,6 +333,44 @@
         <ctl name="DMIC MUX8" value="DMIC0" />
     </path>
 
+    <path name="listen-handset-qmic">
+        <ctl name="AIF1_CAP Mixer SLIM TX5" value="1" />
+        <ctl name="AIF1_CAP Mixer SLIM TX6" value="1" />
+        <ctl name="AIF1_CAP Mixer SLIM TX7" value="1" />
+        <ctl name="AIF1_CAP Mixer SLIM TX8" value="1" />
+        <ctl name="SLIM_0_TX Channels" value="Four" />
+        <ctl name="CDC_IF TX5 MUX" value="DEC5" />
+        <ctl name="ADC MUX5" value="DMIC" />
+        <ctl name="DMIC MUX5" value="DMIC1" />
+        <ctl name="CDC_IF TX6 MUX" value="DEC6" />
+        <ctl name="ADC MUX6" value="DMIC" />
+        <ctl name="DMIC MUX6" value="DMIC5" />
+        <ctl name="CDC_IF TX7 MUX" value="DEC7" />
+        <ctl name="ADC MUX7" value="DMIC" />
+        <ctl name="DMIC MUX7" value="DMIC2" />
+        <ctl name="CDC_IF TX8 MUX" value="DEC8" />
+        <ctl name="ADC MUX8" value="DMIC" />
+        <ctl name="DMIC MUX8" value="DMIC0" />
+    </path>
+
+   <path name="audio-capture">
+      <ctl name="MultiMedia2 Mixer SLIM_0_TX" value="1" />
+   </path>
+
+   <path name="ec-ref-audio-capture">
+      <ctl name="AUDIO_REF_EC_UL1 MUX" value="SLIM_RX" />
+      <ctl name="MultiMedia9 Mixer AFE_LOOPBACK_TX" value="1" />
+   </path>
+
+    <path name="ec-ref-loopback-mono">
+    </path>
+
+    <path name="ec-ref-loopback-stereo">
+    </path>
+
+    <path name="ec-ref-loopback-quad">
+    </path>
+
     <path name="echo-reference">
         <ctl name="AUDIO_REF_EC_UL1 MUX" value="SLIM_RX"/>
         <ctl name="EC Reference Channels" value="Two"/>
diff --git a/configs/sdm710/sound_trigger_platform_info.xml b/configs/sdm710/sound_trigger_platform_info.xml
index 690289b..9604b93 100644
--- a/configs/sdm710/sound_trigger_platform_info.xml
+++ b/configs/sdm710/sound_trigger_platform_info.xml
@@ -53,10 +53,29 @@
         <param DEVICE_HANDSET_QMIC_APE="137" />
         <param DEVICE_HEADSET_MIC_CPE="139" />
         <param DEVICE_HANDSET_DMIC_APE="149" />
+        <param DEVICE_HANDSET_QMIC_ARM="140" />
     </acdb_ids>
     <!-- Multiple sound_model_config tags can be listed, each with unique   -->
     <!-- vendor_uuid. The below tag represents QTI SVA engine sound model   -->
     <!-- configuration. ISV must use their own unique vendor_uuid.          -->
+    <!-- ARM based SVA sound_model_config -->
+    <sound_model_config>
+        <param vendor_uuid="67fabb70-79e8-4e1c-a202-bcb050243a70" />
+        <param execution_type="ARM" />
+        <!-- ec reference loopback params -->
+        <!-- split_ec_ref_data - true if ec ref is packed with mic captured data -->
+        <param split_ec_ref_data="false"/>
+        <param ec_ref_channel_count="2"/>
+
+        <!-- Profile specific data which the algorithm can support -->
+        <param sample_rate="16000" />
+        <param bit_width="16" />
+        <param channel_count="4"/>
+        <!-- adm_cfg_profile should match with the one defined under adm_config -->
+        <!-- Set it to NONE if LSM directly connects to AFE -->
+        <param adm_cfg_profile="DEFAULT" />
+    </sound_model_config>
+    <!-- Sound model config for Hotword !-->
     <sound_model_config>
         <param vendor_uuid="68ab2d40-e860-11e3-95ef-0002a5d5c51b" />
         <param execution_type="WDSP" /> <!-- value: "WDSP" "ADSP" "DYNAMIC" -->
diff --git a/hal/Android.mk b/hal/Android.mk
index 3e75dc1..783c6aa 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -62,6 +62,10 @@
 endif
 endif
 
+ifeq ($(TARGET_BOARD_AUTO),true)
+  LOCAL_CFLAGS += -DPLATFORM_AUTO
+endif
+
 LOCAL_CFLAGS += -Wno-macro-redefined
 
 LOCAL_HEADER_LIBRARIES := libhardware_headers
@@ -440,6 +444,11 @@
     LOCAL_STATIC_LIBRARIES += libprofile_rt
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXT_HW_PLUGIN)),true)
+    LOCAL_CFLAGS += -DEXT_HW_PLUGIN_ENABLED
+    LOCAL_SRC_FILES += audio_extn/ext_hw_plugin.c
+endif
+
 LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM)
 
 LOCAL_MODULE_RELATIVE_PATH := hw
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
old mode 100755
new mode 100644
index 452c9a2..f01bff1
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -954,6 +954,7 @@
        adev->offload_effects_set_parameters(parms);
    audio_extn_set_aptx_dec_bt_addr(adev, parms);
    audio_extn_ffv_set_parameters(adev, parms);
+   audio_extn_ext_hw_plugin_set_parameters(adev->ext_hw_plugin, parms);
 }
 
 void audio_extn_get_parameters(const struct audio_device *adev,
@@ -972,6 +973,7 @@
     audio_extn_sound_trigger_get_parameters(adev, query, reply);
     if (adev->offload_effects_get_parameters != NULL)
         adev->offload_effects_get_parameters(query, reply);
+    audio_extn_ext_hw_plugin_get_parameters(adev->ext_hw_plugin, query, reply);
 
     kv_pairs = str_parms_to_str(reply);
     ALOGD_IF(kv_pairs != NULL, "%s: returns %s", __func__, kv_pairs);
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 7cb6ce5..9047cb3 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -1141,4 +1141,29 @@
 void audio_extn_send_dual_mono_mixing_coefficients(struct stream_out *out);
 #endif
 int audio_extn_utils_get_license_params(const struct audio_device *adev,  struct audio_license_params *lic_params);
+
+#ifndef EXT_HW_PLUGIN_ENABLED
+#define audio_extn_ext_hw_plugin_init(adev)                (0)
+#define audio_extn_ext_hw_plugin_deinit(plugin)              (0)
+#define audio_extn_ext_hw_plugin_usecase_start(plugin, usecase) (0)
+#define audio_extn_ext_hw_plugin_usecase_stop(plugin, usecase) (0)
+#define audio_extn_ext_hw_plugin_set_parameters(plugin, parms) (0)
+#define audio_extn_ext_hw_plugin_get_parameters(plugin, query, reply) (0)
+#define audio_extn_ext_hw_plugin_set_mic_mute(plugin, mute) (0)
+#define audio_extn_ext_hw_plugin_get_mic_mute(plugin, mute) (0)
+#define audio_extn_ext_hw_plugin_set_audio_gain(plugin, usecase, gain) (0)
+#else
+void* audio_extn_ext_hw_plugin_init(struct audio_device *adev);
+int audio_extn_ext_hw_plugin_deinit(void *plugin);
+int audio_extn_ext_hw_plugin_usecase_start(void *plugin, struct audio_usecase *usecase);
+int audio_extn_ext_hw_plugin_usecase_stop(void *plugin, struct audio_usecase *usecase);
+int audio_extn_ext_hw_plugin_set_parameters(void *plugin,
+                                           struct str_parms *parms);
+int audio_extn_ext_hw_plugin_get_parameters(void *plugin,
+                  struct str_parms *query, struct str_parms *reply);
+int audio_extn_ext_hw_plugin_set_mic_mute(void *plugin, bool mute);
+int audio_extn_ext_hw_plugin_get_mic_mute(void *plugin, bool *mute);
+int audio_extn_ext_hw_plugin_set_audio_gain(void *plugin,
+            struct audio_usecase *usecase, uint32_t gain);
+#endif
 #endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/ext_hw_plugin.c b/hal/audio_extn/ext_hw_plugin.c
new file mode 100644
index 0000000..3c9458a
--- /dev/null
+++ b/hal/audio_extn/ext_hw_plugin.c
@@ -0,0 +1,1595 @@
+/* ext_hw_plugin.c
+Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
+
+#define LOG_TAG "audio_ext_hw_plugin"
+#define LOG_NDEBUG 0
+
+#include <errno.h>
+#include <pthread.h>
+#include <dlfcn.h>
+#include <cutils/log.h>
+#include <audio_hw.h>
+#include "audio_extn.h"
+#include "platform_api.h"
+#include "platform.h"
+#include "audio_hal_plugin.h"
+
+
+#ifdef EXT_HW_PLUGIN_ENABLED
+
+typedef int32_t (*audio_hal_plugin_init_t)(void);
+typedef int32_t (*audio_hal_plugin_deinit_t)(void);
+typedef int32_t (*audio_hal_plugin_send_msg_t)(audio_hal_plugin_msg_type_t,
+                                           void *, uint32_t);
+
+struct ext_hw_plugin_data {
+    struct audio_device           *adev;
+    void                          *plugin_handle;
+    audio_hal_plugin_init_t        audio_hal_plugin_init;
+    audio_hal_plugin_deinit_t      audio_hal_plugin_deinit;
+    audio_hal_plugin_send_msg_t    audio_hal_plugin_send_msg;
+    int32_t                        usecase_ref_count[AUDIO_HAL_PLUGIN_USECASE_MAX];
+    snd_device_t                   out_snd_dev[AUDIO_HAL_PLUGIN_USECASE_MAX];
+    snd_device_t                   in_snd_dev[AUDIO_HAL_PLUGIN_USECASE_MAX];
+    bool                           mic_mute;
+};
+
+/* This can be defined in platform specific file or use compile flag */
+#define LIB_PLUGIN_DRIVER "libaudiohalplugin.so"
+
+/* Note: Due to ADP H/W design, SoC TERT/SEC TDM CLK and FSYNC lines are both connected
+ * with CODEC and a single master is needed to provide consistent CLK and FSYNC to slaves,
+ * hence configuring SoC TERT TDM as single master and bring up a dummy hostless from TERT
+ * to SEC to ensure both slave SoC SEC TDM and CODEC are driven upon system boot. */
+static void audio_extn_ext_hw_plugin_enable_adev_hostless(struct audio_device *adev)
+{
+    ALOGI("%s: Enable TERT -> SEC Hostless", __func__);
+
+    char mixer_path[MIXER_PATH_MAX_LENGTH];
+    strlcpy(mixer_path, "dummy-hostless", MIXER_PATH_MAX_LENGTH);
+    ALOGD("%s: apply mixer and update path: %s", __func__, mixer_path);
+    audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+
+    /* TERT TDM TX 7 HOSTLESS to SEC TDM RX 7 HOSTLESS */
+    int pcm_dev_rx = 48, pcm_dev_tx = 49;
+    struct pcm_config pcm_config_lb = {
+        .channels = 1,
+        .rate = 48000,
+        .period_size = 240,
+        .period_count = 2,
+        .format = PCM_FORMAT_S16_LE,
+        .start_threshold = 0,
+        .stop_threshold = INT_MAX,
+        .avail_min = 0,
+    };
+
+    struct pcm *pcm_tx = pcm_open(adev->snd_card,
+                                   pcm_dev_tx,
+                                   PCM_IN, &pcm_config_lb);
+    if (pcm_tx && !pcm_is_ready(pcm_tx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(pcm_tx));
+        return;
+    }
+    struct pcm *pcm_rx = pcm_open(adev->snd_card,
+                                   pcm_dev_rx,
+                                   PCM_OUT, &pcm_config_lb);
+    if (pcm_rx && !pcm_is_ready(pcm_rx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(pcm_rx));
+        return;
+    }
+
+    if (pcm_start(pcm_tx) < 0) {
+        ALOGE("%s: pcm start for pcm tx failed", __func__);
+        return;
+    }
+    if (pcm_start(pcm_rx) < 0) {
+        ALOGE("%s: pcm start for pcm rx failed", __func__);
+        return;
+    }
+}
+
+void* audio_extn_ext_hw_plugin_init(struct audio_device *adev)
+{
+    int32_t ret = 0;
+    struct ext_hw_plugin_data *my_plugin = NULL;
+
+    my_plugin = calloc(1, sizeof(struct ext_hw_plugin_data));
+
+    if (my_plugin == NULL) {
+        ALOGE("[%s] Memory allocation failed for plugin data",__func__);
+        return NULL;
+    }
+
+    my_plugin->adev = adev;
+
+    my_plugin->plugin_handle = dlopen(LIB_PLUGIN_DRIVER, RTLD_NOW);
+    if (my_plugin->plugin_handle == NULL) {
+        ALOGE("%s: DLOPEN failed for %s", __func__, LIB_PLUGIN_DRIVER);
+        goto plugin_init_fail;
+    } else {
+        ALOGV("%s: DLOPEN successful for %s", __func__, LIB_PLUGIN_DRIVER);
+        my_plugin->audio_hal_plugin_init = (audio_hal_plugin_init_t)dlsym(
+            my_plugin->plugin_handle, "audio_hal_plugin_init");
+        if (!my_plugin->audio_hal_plugin_init) {
+            ALOGE("%s: Could not find the symbol audio_hal_plugin_init from %s",
+                  __func__, LIB_PLUGIN_DRIVER);
+            goto plugin_init_fail;
+        }
+
+        my_plugin->audio_hal_plugin_deinit = (audio_hal_plugin_deinit_t)dlsym(
+           my_plugin->plugin_handle, "audio_hal_plugin_deinit");
+        if (!my_plugin->audio_hal_plugin_deinit) {
+            ALOGE("%s: Could not find the symbol audio_hal_plugin_deinit from %s",
+                  __func__, LIB_PLUGIN_DRIVER);
+            goto plugin_init_fail;
+        }
+
+        my_plugin->audio_hal_plugin_send_msg = (audio_hal_plugin_send_msg_t)
+            dlsym(my_plugin->plugin_handle, "audio_hal_plugin_send_msg");
+        if (!my_plugin->audio_hal_plugin_send_msg) {
+            ALOGE("%s: Could not find the symbol audio_hal_plugin_send_msg from %s",
+                  __func__, LIB_PLUGIN_DRIVER);
+            goto plugin_init_fail;
+        }
+
+        ret = my_plugin->audio_hal_plugin_init();
+        if (ret) {
+            ALOGE("%s: audio_hal_plugin_init failed with ret = %d",
+               __func__, ret);
+            goto plugin_init_fail;
+        }
+    }
+
+    audio_extn_ext_hw_plugin_enable_adev_hostless(adev);
+
+    my_plugin->mic_mute = false;
+    return my_plugin;
+
+plugin_init_fail:
+    if (my_plugin->plugin_handle != NULL)
+        dlclose(my_plugin->plugin_handle);
+    free(my_plugin);
+    return NULL;
+}
+
+int32_t audio_extn_ext_hw_plugin_deinit(void *plugin)
+{
+    int32_t ret = 0;
+    struct ext_hw_plugin_data *my_plugin = (struct ext_hw_plugin_data *)plugin;
+
+    if (my_plugin == NULL) {
+        ALOGE("[%s] NULL plugin pointer",__func__);
+        return -EINVAL;
+    }
+
+    if (my_plugin->audio_hal_plugin_deinit) {
+        ret = my_plugin->audio_hal_plugin_deinit();
+        if (ret) {
+            ALOGE("%s: audio_hal_plugin_deinit failed with ret = %d",
+                  __func__, ret);
+        }
+    }
+    if(my_plugin->plugin_handle != NULL)
+        dlclose(my_plugin->plugin_handle);
+
+    free(my_plugin);
+    return ret;
+}
+
+static int32_t ext_hw_plugin_check_plugin_usecase(audio_usecase_t hal_usecase,
+        audio_hal_plugin_usecase_type_t *plugin_usecase)
+{
+    int32_t ret = 0;
+
+    switch(hal_usecase) {
+    case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER:
+    case USECASE_AUDIO_PLAYBACK_LOW_LATENCY:
+    case USECASE_AUDIO_PLAYBACK_MULTI_CH:
+    case USECASE_AUDIO_PLAYBACK_OFFLOAD:
+#ifdef MULTIPLE_OFFLOAD_ENABLED
+    case USECASE_AUDIO_PLAYBACK_OFFLOAD2:
+    case USECASE_AUDIO_PLAYBACK_OFFLOAD3:
+    case USECASE_AUDIO_PLAYBACK_OFFLOAD4:
+    case USECASE_AUDIO_PLAYBACK_OFFLOAD5:
+    case USECASE_AUDIO_PLAYBACK_OFFLOAD6:
+    case USECASE_AUDIO_PLAYBACK_OFFLOAD7:
+    case USECASE_AUDIO_PLAYBACK_OFFLOAD8:
+    case USECASE_AUDIO_PLAYBACK_OFFLOAD9:
+#endif
+    case USECASE_AUDIO_PLAYBACK_ULL:
+        *plugin_usecase = AUDIO_HAL_PLUGIN_USECASE_DEFAULT_PLAYBACK;
+        break;
+    case USECASE_AUDIO_RECORD:
+    case USECASE_AUDIO_RECORD_COMPRESS:
+    case USECASE_AUDIO_RECORD_LOW_LATENCY:
+    case USECASE_AUDIO_RECORD_FM_VIRTUAL:
+        *plugin_usecase = AUDIO_HAL_PLUGIN_USECASE_DEFAULT_CAPTURE;
+        break;
+    case USECASE_AUDIO_HFP_SCO:
+    case USECASE_AUDIO_HFP_SCO_WB:
+        *plugin_usecase = AUDIO_HAL_PLUGIN_USECASE_HFP_VOICE_CALL;
+        break;
+    case USECASE_VOICE_CALL:
+    case USECASE_VOICEMMODE1_CALL:
+        *plugin_usecase = AUDIO_HAL_PLUGIN_USECASE_CS_VOICE_CALL;
+        break;
+    default:
+        ret = -EINVAL;
+    }
+
+    return ret;
+}
+
+int32_t audio_extn_ext_hw_plugin_usecase_start(void *plugin, struct audio_usecase *usecase)
+{
+    int32_t ret = 0;
+    struct ext_hw_plugin_data *my_plugin = (struct ext_hw_plugin_data *)plugin;
+
+    if ((my_plugin == NULL) || (usecase == NULL)) {
+        ALOGE("[%s] NULL input pointer",__func__);
+        return -EINVAL;
+    }
+
+    if (my_plugin->audio_hal_plugin_send_msg) {
+        audio_hal_plugin_msg_type_t msg = AUDIO_HAL_PLUGIN_MSG_CODEC_ENABLE;
+        audio_hal_plugin_codec_enable_t codec_enable;
+
+        ret = ext_hw_plugin_check_plugin_usecase(usecase->id, &codec_enable.usecase);
+        if(ret){
+            ALOGI("%s: enable audio hal plugin skipped for audio usecase %d",
+                    __func__, usecase->id);
+            return 0;
+        }
+
+        if(usecase->id == USECASE_AUDIO_RECORD) {
+            if(usecase->in_snd_device == SND_DEVICE_IN_SPEAKER_QMIC_AEC) {
+              codec_enable.usecase = AUDIO_HAL_PLUGIN_USECASE_EC_CAPTURE;
+            }
+        }
+
+        if(my_plugin->usecase_ref_count[codec_enable.usecase]){
+            ALOGV("%s: plugin usecase %d already enabled",
+                    __func__, codec_enable.usecase);
+            my_plugin->usecase_ref_count[codec_enable.usecase]++;
+            return 0;
+        }
+
+        if ((usecase->type == PCM_CAPTURE) || (usecase->type == VOICE_CALL) ||
+            (usecase->type == VOIP_CALL) || (usecase->type == PCM_HFP_CALL)) {
+            codec_enable.snd_dev = usecase->in_snd_device;
+            /* TODO - below should be related with in_snd_dev */
+            codec_enable.sample_rate = 48000;
+            codec_enable.bit_width = 16;
+            codec_enable.num_chs = 2;
+
+            ALOGD("%s: enable audio hal plugin input, %d, %d, %d, %d, %d",
+                __func__, (int)codec_enable.usecase,
+                (int)codec_enable.snd_dev,
+                (int)codec_enable.sample_rate,
+                (int)codec_enable.bit_width,
+                (int)codec_enable.num_chs);
+            ret = my_plugin->audio_hal_plugin_send_msg(msg,
+                (void*)&codec_enable, sizeof(codec_enable));
+            if (ret) {
+                ALOGE("%s: enable audio hal plugin input failed ret = %d",
+                    __func__, ret);
+                return ret;
+            }
+            my_plugin->in_snd_dev[codec_enable.usecase] = codec_enable.snd_dev;
+
+            if (my_plugin->mic_mute &&
+                codec_enable.usecase == AUDIO_HAL_PLUGIN_USECASE_HFP_VOICE_CALL) {
+                int plugin_ret;
+                audio_hal_plugin_codec_set_pp_mute_t pp_mute;
+
+                pp_mute.usecase = codec_enable.usecase;
+                pp_mute.snd_dev = codec_enable.snd_dev;
+                pp_mute.ch_mask = AUDIO_CHANNEL_IN_ALL;
+                pp_mute.flag = my_plugin->mic_mute;
+
+                ALOGV("%s: sending codec pp mute msg to HAL plugin driver, %d, %d, %x, %d",
+                        __func__, (int)pp_mute.usecase, (int)pp_mute.snd_dev,
+                        (int)pp_mute.ch_mask, (int)pp_mute.flag);
+                plugin_ret = my_plugin->audio_hal_plugin_send_msg(
+                               AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_MUTE, &pp_mute,
+                               sizeof(pp_mute));
+                if (plugin_ret)
+                  ALOGE("%s: Failed to set plugin pp mute err: %d", __func__, plugin_ret);
+            }
+        }
+
+        if ((usecase->type == PCM_CAPTURE) &&
+            (usecase->id ==  USECASE_AUDIO_RECORD) &&
+            (usecase->in_snd_device == SND_DEVICE_IN_SPEAKER_QMIC_AEC)) {
+            audio_hal_plugin_codec_enable_t codec_enable_ec = {0,};
+            codec_enable_ec.snd_dev = usecase->in_snd_device;
+            // TODO - below should be related with in_snd_dev
+            codec_enable_ec.sample_rate = 48000;
+            codec_enable_ec.bit_width = 16;
+            codec_enable_ec.num_chs = 6;
+            codec_enable_ec.usecase = AUDIO_HAL_PLUGIN_USECASE_EC_REF_CAPTURE;
+
+            ALOGD("%s: enable audio hal plugin input for echo reference, %d, %d, %d, %d, %d",
+                __func__, (int)codec_enable_ec.usecase,
+                (int)codec_enable_ec.snd_dev,
+                (int)codec_enable_ec.sample_rate,
+                (int)codec_enable_ec.bit_width,
+                (int)codec_enable_ec.num_chs);
+            ret = my_plugin->audio_hal_plugin_send_msg(msg,
+                (void*)&codec_enable_ec, sizeof(codec_enable_ec));
+            if (ret) {
+                ALOGE("%s: enable audio hal plugin input failed ret = %d",
+                    __func__, ret);
+                return ret;
+            }
+        }
+
+        if ((usecase->type == PCM_PLAYBACK) || (usecase->type == VOICE_CALL) ||
+            (usecase->type == VOIP_CALL) || (usecase->type == PCM_HFP_CALL)) {
+            codec_enable.snd_dev = usecase->out_snd_device;
+            /* TODO - below should be related with out_snd_dev */
+            codec_enable.sample_rate = 48000;
+            codec_enable.bit_width = 24;
+            codec_enable.num_chs = 2;
+
+            ALOGD("%s: enable audio hal plugin output, %d, %d, %d, %d, %d",
+                __func__, (int)codec_enable.usecase,
+                (int)codec_enable.snd_dev,
+                (int)codec_enable.sample_rate,
+                (int)codec_enable.bit_width,
+                (int)codec_enable.num_chs);
+            ret = my_plugin->audio_hal_plugin_send_msg(msg,
+                (void*)&codec_enable, sizeof(codec_enable));
+            if (ret) {
+                ALOGE("%s: enable audio hal plugin output failed ret = %d",
+                    __func__, ret);
+                return ret;
+            }
+            my_plugin->out_snd_dev[codec_enable.usecase] = codec_enable.snd_dev;
+        }
+        my_plugin->usecase_ref_count[codec_enable.usecase]++;
+    }
+
+    ALOGD("%s: finished ext_hw_plugin usecase start", __func__);
+
+    return ret;
+}
+
+int32_t audio_extn_ext_hw_plugin_usecase_stop(void *plugin, struct audio_usecase *usecase)
+{
+    int32_t ret = 0;
+    struct ext_hw_plugin_data *my_plugin = (struct ext_hw_plugin_data *)plugin;
+
+    if ((my_plugin == NULL) || (usecase == NULL)) {
+        ALOGE("[%s] NULL input pointer",__func__);
+        return -EINVAL;
+    }
+    if (my_plugin->audio_hal_plugin_send_msg) {
+        audio_hal_plugin_msg_type_t msg = AUDIO_HAL_PLUGIN_MSG_CODEC_DISABLE;
+        audio_hal_plugin_codec_disable_t codec_disable;
+
+        ret = ext_hw_plugin_check_plugin_usecase(usecase->id, &codec_disable.usecase);
+        if(ret){
+            ALOGI("%s: disable audio hal plugin skipped for audio usecase %d",
+                    __func__, usecase->id);
+            return 0;
+        }
+
+        if((usecase->id == USECASE_AUDIO_RECORD) &&
+           (usecase->in_snd_device == SND_DEVICE_IN_SPEAKER_QMIC_AEC))
+        {
+           codec_disable.usecase = AUDIO_HAL_PLUGIN_USECASE_EC_CAPTURE;
+        }
+        if(my_plugin->usecase_ref_count[codec_disable.usecase] > 1){
+            ALOGI("%s: plugin usecase %d still in use and can not be disabled",
+                    __func__, codec_disable.usecase);
+            my_plugin->usecase_ref_count[codec_disable.usecase]--;
+            return 0;
+        } else if(my_plugin->usecase_ref_count[codec_disable.usecase] < 1){
+            ALOGE("%s: plugin usecase %d not enabled",
+                    __func__, codec_disable.usecase);
+            return -EINVAL;
+        }
+
+        if ((usecase->type == PCM_PLAYBACK) || (usecase->type == VOICE_CALL) ||
+            (usecase->type == VOIP_CALL) || (usecase->type == PCM_HFP_CALL)) {
+            codec_disable.snd_dev = usecase->out_snd_device;
+
+            ALOGD("%s: disable audio hal plugin output, %d, %d",
+                __func__, (int)codec_disable.usecase,
+                (int)codec_disable.snd_dev);
+            ret = my_plugin->audio_hal_plugin_send_msg(msg,
+                (void*)&codec_disable, sizeof(codec_disable));
+            if (ret) {
+                ALOGE("%s: disable audio hal plugin output failed ret = %d",
+                    __func__, ret);
+            }
+            my_plugin->out_snd_dev[codec_disable.usecase] = 0;
+        }
+        if ((usecase->type == PCM_CAPTURE) || (usecase->type == VOICE_CALL) ||
+            (usecase->type == VOIP_CALL) || (usecase->type == PCM_HFP_CALL)) {
+            codec_disable.snd_dev = usecase->in_snd_device;
+
+            ALOGD("%s: disable audio hal plugin input, %d, %d",
+                __func__, (int)codec_disable.usecase,
+                (int)codec_disable.snd_dev);
+            ret = my_plugin->audio_hal_plugin_send_msg(msg,
+                (void*)&codec_disable, sizeof(codec_disable));
+            if (ret) {
+                ALOGE("%s: disable audio hal plugin input failed ret = %d",
+                    __func__, ret);
+            }
+            my_plugin->in_snd_dev[codec_disable.usecase] = 0;
+        }
+
+        if ((usecase->type == PCM_CAPTURE) &&
+            (usecase->id ==  USECASE_AUDIO_RECORD) &&
+            (usecase->in_snd_device == SND_DEVICE_IN_SPEAKER_QMIC_AEC)) {
+            audio_hal_plugin_codec_disable_t codec_disable_ec = {0,};
+            codec_disable_ec.snd_dev = usecase->in_snd_device;
+            codec_disable_ec.usecase = AUDIO_HAL_PLUGIN_USECASE_EC_REF_CAPTURE;
+
+            ALOGD("%s: disable audio hal plugin input for echo reference, %d, %d",
+                __func__, (int)codec_disable_ec.usecase,
+                (int)codec_disable_ec.snd_dev);
+            ret = my_plugin->audio_hal_plugin_send_msg(msg,
+                (void*)&codec_disable_ec, sizeof(codec_disable_ec));
+            if (ret) {
+                ALOGE("%s: disable audio hal plugin input failed ret = %d",
+                    __func__, ret);
+                return ret;
+            }
+        }
+        my_plugin->usecase_ref_count[codec_disable.usecase]--;
+    }
+
+    ALOGD("%s: finished ext_hw_plugin usecase stop", __func__);
+
+    return ret;
+}
+
+static int32_t ext_hw_plugin_string_to_dword(char *string_value, void **dword_ptr,
+        uint32_t dword_len)
+{
+    int32_t ret = 0;
+    uint32_t i,tmp;
+    uint8_t *dptr = NULL;
+    uint8_t *tmpptr = NULL;
+    int32_t dlen;
+    uint32_t *outptr = NULL;
+
+    dlen = strlen(string_value);
+    if (dlen <= 0) {
+        ALOGE("%s: NULL data received", __func__);
+        return -EINVAL;
+    }
+    dptr = (uint8_t*) calloc(dlen, sizeof(uint8_t));
+    if (dptr == NULL) {
+        ALOGE("%s: memory allocation failed", __func__);
+        return -ENOMEM;
+    }
+    dlen = b64decode(string_value, strlen(string_value), dptr);
+    if ((dlen <= 0) || ((uint32_t)dlen != 4*dword_len)){
+        ALOGE("%s: data decoding failed", __func__);
+        ret = -EINVAL;
+        goto done_string_to_dword;
+    }
+
+    outptr = calloc(dword_len, sizeof(uint32_t));
+    if (outptr == NULL) {
+        ALOGE("%s: memory allocation failed", __func__);
+        ret = -ENOMEM;
+        goto done_string_to_dword;
+    }
+
+    for(i=0; i<dword_len; i++) {
+        tmpptr = dptr+4*i;
+        tmp = (uint32_t) *(tmpptr);
+        tmp |= ((uint32_t) *(tmpptr+1))<<8;
+        tmp |= ((uint32_t) *(tmpptr+2))<<16;
+        tmp |= ((uint32_t) *(tmpptr+3))<<24;
+        *(outptr + i) = tmp;
+    }
+    *dword_ptr = (void*)outptr;
+
+done_string_to_dword:
+    if (dptr != NULL)
+        free(dptr);
+
+    return ret;
+}
+
+static int32_t ext_hw_plugin_dword_to_string(uint32_t *dword_ptr, uint32_t dword_len,
+            char **string_ptr)
+{
+    int32_t ret = 0;
+    uint32_t i,tmp;
+    uint8_t *dptr = NULL;
+    uint8_t *tmpptr = NULL;
+    int32_t dlen;
+    char *outptr = NULL;
+
+    dptr = (uint8_t*)calloc(dword_len, sizeof(uint32_t));
+    if(dptr == NULL) {
+        ALOGE("[%s] Memory allocation failed for dword length %d",__func__,dword_len);
+        return -ENOMEM;
+    }
+
+    /* convert dword to byte array */
+    for(i=0; i<dword_len; i++) {
+        tmp = *(dword_ptr + i);
+        tmpptr = dptr+4*i;
+        *tmpptr = (uint8_t) (tmp & 0xFF);
+        *(tmpptr + 1) = (uint8_t) ((tmp>>8) & 0xFF);
+        *(tmpptr + 2) = (uint8_t) ((tmp>>16) & 0xFF);
+        *(tmpptr + 3) = (uint8_t) ((tmp>>24) & 0xFF);
+    }
+
+    /* Allocate memory for encoding */
+    dlen = dword_len * 4;
+    outptr = (char*)calloc((dlen*2), sizeof(char));
+    if(outptr == NULL) {
+        ALOGE("[%s] Memory allocation failed for size %d",
+                    __func__, dlen*2);
+        ret = -ENOMEM;
+        goto done_dword_to_string;
+    }
+
+    ret = b64encode(dptr, dlen, outptr);
+    if(ret < 0) {
+        ALOGE("[%s] failed to convert data to string ret = %d", __func__, ret);
+        free(outptr);
+        ret = -EINVAL;
+        goto done_dword_to_string;
+    }
+    *string_ptr = outptr;
+
+done_dword_to_string:
+    if (dptr != NULL)
+        free(dptr);
+
+    return ret;
+}
+
+
+int32_t audio_extn_ext_hw_plugin_set_parameters(void *plugin, struct str_parms *parms)
+{
+
+    char *value = NULL;
+    int32_t val, len = 0;
+    int32_t ret = 0, err;
+    char *kv_pairs = NULL;
+    struct ext_hw_plugin_data *my_plugin = NULL;
+
+    if (plugin == NULL || parms == NULL) {
+        ALOGE("[%s] received null pointer",__func__);
+        return -EINVAL;
+    }
+
+    my_plugin = (struct ext_hw_plugin_data *)plugin;
+    if (!my_plugin->audio_hal_plugin_send_msg) {
+        ALOGE("%s: NULL audio_hal_plugin_send_msg func ptr", __func__);
+        return -EINVAL;
+    }
+
+    err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_MSG_TYPE, &val);
+    if (err < 0) {
+        ALOGE("%s: Invalid or missing TYPE param for plugin msg", __func__);
+        return -EINVAL;
+    }
+    ALOGD("%s: received plugin msg type (%d)", __func__, val);
+    str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_MSG_TYPE);
+
+    if(val == AUDIO_HAL_PLUGIN_MSG_CODEC_TUNNEL_CMD ||
+        val == AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_EQ) {
+        kv_pairs = str_parms_to_str(parms);
+        len = strlen(kv_pairs);
+        value = (char*)calloc(len, sizeof(char));
+        if (value == NULL) {
+            ret = -ENOMEM;
+            ALOGE("[%s] failed to allocate memory",__func__);
+            goto done;
+        }
+    }
+
+    if (val == AUDIO_HAL_PLUGIN_MSG_CODEC_TUNNEL_CMD) {
+        uint32_t plsize;
+        int32_t *plptr = NULL;
+
+        err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_TUNNEL_SIZE,
+                (int*)&plsize);
+        if ((err < 0) || (!plsize)) {
+            ALOGE("%s: Invalid or missing size param for TUNNEL command", __func__);
+            ret = -EINVAL;
+            goto done;
+        }
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_TUNNEL_SIZE);
+
+        err = str_parms_get_str(parms,
+                AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_TUNNEL_DATA, value, len);
+        if (err < 0) {
+            ALOGE("%s: Invalid or missing band_data for TUNNEL command", __func__);
+            ret = -EINVAL;
+            goto done;
+        }
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_TUNNEL_DATA);
+
+        ret = ext_hw_plugin_string_to_dword(value, (void**)&plptr, plsize);
+        if (ret) {
+            ALOGE("%s: Failed to parse payload for TUNNEL command", __func__);
+            ret = -EINVAL;
+            goto done_tunnel;
+        }
+
+        audio_hal_plugin_msg_type_t msg =
+                AUDIO_HAL_PLUGIN_MSG_CODEC_TUNNEL_CMD;
+
+        ALOGD("%s: sending codec tunnel cmd msg to HAL plugin driver,size = %d",
+                __func__, (int)plsize);
+
+        ret = my_plugin->audio_hal_plugin_send_msg(msg, (void*)plptr, plsize);
+        if (ret) {
+            ALOGE("%s: Failed to send plugin tunnel cmd err: %d", __func__, ret);
+        }
+
+done_tunnel:
+        if (plptr!= NULL)
+            free(plptr);
+    } else {
+        audio_hal_plugin_usecase_type_t use_case;
+        audio_hal_plugin_direction_type_t dir;
+        snd_device_t snd_dev = 0;
+
+        err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_UC,
+                &use_case);
+        if (err < 0) {
+            ALOGE("%s: Invalid or missing usecase param for plugin msg", __func__);
+            ret = -EINVAL;
+            /* TODO: do we need to support no use case in kvpair? */
+            goto done;
+        }
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_UC);
+        if ((use_case < 0) || (use_case >= AUDIO_HAL_PLUGIN_USECASE_MAX)) {
+            ALOGE("%s: Invalid usecase param for plugin msg", __func__);
+            ret = -EINVAL;
+            goto done;
+        }
+
+        if (my_plugin->usecase_ref_count[use_case] == 0) {
+            /* allow param set when usecase not enabled */
+            ALOGI("%s: plugin usecase (%d) is not enabled", __func__, use_case);
+        } else {
+            err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_DIRECTION,
+                    &dir);
+            if (err < 0) {
+                if (my_plugin->out_snd_dev[use_case]) {
+                    snd_dev = my_plugin->out_snd_dev[use_case];
+                } else if (my_plugin->in_snd_dev[use_case]) {
+                    snd_dev = my_plugin->in_snd_dev[use_case];
+                } else {
+                    ALOGE("%s: No valid snd_device found for the usecase (%d)",
+                            __func__, use_case);
+                    ret = -EINVAL;
+                    goto done;
+                }
+            } else {
+                str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_DIRECTION);
+    
+                switch(dir) {
+                case AUDIO_HAL_PLUGIN_DIRECTION_PLAYBACK:
+                {
+                    if (!my_plugin->out_snd_dev[use_case]) {
+                        ALOGE("%s: No valid out_snd_device found for playback (%d)",
+                                __func__, use_case);
+                        ret = -EINVAL;
+                        goto done;
+                    }
+                    snd_dev = my_plugin->out_snd_dev[use_case];
+                    break;
+                }
+                case AUDIO_HAL_PLUGIN_DIRECTION_CAPTURE:
+                {
+                    if (!my_plugin->in_snd_dev[use_case]) {
+                        ALOGE("%s: No valid in_snd_device found for capture (%d)",
+                                __func__, use_case);
+                        ret = -EINVAL;
+                        goto done;
+                    }
+                    snd_dev = my_plugin->in_snd_dev[use_case];
+                    break;
+                }
+                default:
+                    ALOGE("%s: Invalid direction param for plugin msg", __func__);
+                    ret = -EINVAL;
+                    goto done;
+                }
+            }
+        }
+
+        switch(val) {
+        case AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_VOLUME:
+        {
+            audio_hal_plugin_codec_set_pp_vol_t pp_vol;
+            memset(&pp_vol,0,sizeof(pp_vol));
+            err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_CMASK,
+                    (int*)&pp_vol.ch_mask);
+            if ((err < 0)) {
+                /* TODO: properly handle no cmask param from client case */
+                ALOGE("%s: Invalid or missing CMASK param for SET_PP_VOLUME", __func__);
+                ret = -EINVAL;
+                goto done;
+            }
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_CMASK);
+            err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_GAIN,
+                    (int*)&pp_vol.gain);
+            if ((err < 0)) {
+                /* TODO: properly handle no gain param from client case */
+                ALOGE("%s: Invalid or missing GAIN param for SET_PP_VOLUME", __func__);
+                ret = -EINVAL;
+                goto done;
+            }
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_GAIN);
+
+            audio_hal_plugin_msg_type_t msg =
+                    AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_VOLUME;
+            pp_vol.usecase = use_case;
+            pp_vol.snd_dev= snd_dev;
+
+            ALOGD("%s: sending codec pp vol msg to HAL plugin driver, %d, %d, %d, %d",
+                    __func__, (int)pp_vol.usecase, (int)pp_vol.snd_dev,
+                    (int)pp_vol.ch_mask, (int)pp_vol.gain);
+
+            ret = my_plugin->audio_hal_plugin_send_msg(msg, &pp_vol, sizeof(pp_vol));
+            if (ret) {
+                ALOGE("%s: Failed to set plugin pp vol err: %d", __func__, ret);
+            }
+            break;
+        }
+        case AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_MUTE:
+        {
+            int32_t flag;
+            audio_hal_plugin_codec_set_pp_mute_t pp_mute;
+            memset(&pp_mute,0,sizeof(pp_mute));
+            err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_CMASK,
+                    (int*)&pp_mute.ch_mask);
+            if ((err < 0)) {
+                /* TODO: properly handle no cmask param from client case */
+                ALOGE("%s: Invalid or missing CMASK param for SET_PP_MUTE", __func__);
+                ret = -EINVAL;
+                goto done;
+            }
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_CMASK);
+            err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_MUTE_FLAG,
+                    (int*)&flag);
+            if ((err < 0)) {
+                ALOGE("%s: Invalid or missing FLAG param for SET_PP_MUTE", __func__);
+                ret = -EINVAL;
+                goto done;
+            }
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_MUTE_FLAG);
+            pp_mute.flag = (bool)flag;
+
+            audio_hal_plugin_msg_type_t msg =
+                    AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_MUTE;
+            pp_mute.usecase = use_case;
+            pp_mute.snd_dev= snd_dev;
+
+            ALOGD("%s: sending codec pp mute msg to HAL plugin driver, %d, %d, %d, %d",
+                    __func__, (int)pp_mute.usecase, (int)pp_mute.snd_dev,
+                    (int)pp_mute.ch_mask, (int)pp_mute.flag);
+
+            ret = my_plugin->audio_hal_plugin_send_msg(msg, &pp_mute,
+                    sizeof(pp_mute));
+            if (ret) {
+                ALOGE("%s: Failed to set plugin pp vol err: %d", __func__, ret);
+            }
+            break;
+        }
+        case AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_FADE:
+        {
+            audio_hal_plugin_codec_set_pp_fade_t pp_fade;
+            memset(&pp_fade,0,sizeof(pp_fade));
+            err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_FADE,
+                    (int*)&pp_fade.fade);
+            if ((err < 0)) {
+                ALOGE("%s: Invalid or missing FADE param for SET_PP_FADE", __func__);
+                ret = -EINVAL;
+                goto done;
+            }
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_FADE);
+
+            audio_hal_plugin_msg_type_t msg =
+                        AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_FADE;
+            pp_fade.usecase = use_case;
+            pp_fade.snd_dev= snd_dev;
+
+            ALOGD("%s: sending codec pp fade msg to HAL plugin driver, %d, %d, %d",
+                    __func__, (int)pp_fade.usecase, (int)pp_fade.snd_dev,
+                    (int)pp_fade.fade);
+
+            ret = my_plugin->audio_hal_plugin_send_msg(msg, &pp_fade,
+                    sizeof(pp_fade));
+            if (ret) {
+                ALOGE("%s: Failed to set plugin pp fade err: %d", __func__, ret);
+            }
+            break;
+        }
+        case AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_BALANCE:
+        {
+            audio_hal_plugin_codec_set_pp_balance_t pp_balance;
+            memset(&pp_balance,0,sizeof(pp_balance));
+            err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_BALANCE,
+                    (int*)&pp_balance.balance);
+            if ((err < 0)) {
+                ALOGE("%s: Invalid or missing balance param for SET_PP_BALANCE", __func__);
+                ret = -EINVAL;
+                goto done;
+            }
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_BALANCE);
+
+            audio_hal_plugin_msg_type_t msg =
+                    AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_BALANCE;
+            pp_balance.usecase = use_case;
+            pp_balance.snd_dev= snd_dev;
+
+            ALOGD("%s: sending codec pp balance msg to HAL plugin driver, %d, %d, %d",
+                    __func__, (int)pp_balance.usecase, (int)pp_balance.snd_dev,
+                    (int)pp_balance.balance);
+
+            ret = my_plugin->audio_hal_plugin_send_msg(msg, &pp_balance,
+                    sizeof(pp_balance));
+            if (ret) {
+                ALOGE("%s: Failed to set plugin pp balance err: %d", __func__, ret);
+            }
+            break;
+        }
+        case AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_BMT:
+        {
+            int32_t filter_type, enable_flag;
+            audio_hal_plugin_codec_set_pp_bmt_t pp_bmt;
+            memset(&pp_bmt,0,sizeof(pp_bmt));
+            err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_BMT_FTYPE,
+                    (int*)&filter_type);
+            if ((err < 0)) {
+                ALOGE("%s: Invalid or missing filter type param for SET_PP_BMT", __func__);
+                ret = -EINVAL;
+                goto done;
+            }
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_BMT_FTYPE);
+            if ((filter_type <= AUDIO_HAL_PLUGIN_CODEC_PP_FILTER_TYPE_INVALID) &&
+                    (filter_type >= AUDIO_HAL_PLUGIN_CODEC_PP_FILTER_TYPE_MAX)) {
+                ALOGE("%s: Invalid filter type value for SET_PP_BMT", __func__);
+                ret = -EINVAL;
+                goto done;
+            }
+            pp_bmt.filter_type = filter_type;
+            err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_BMT_FLAG,
+                    (int*)&enable_flag);
+            if ((err < 0)) {
+                ALOGE("%s: Invalid or missing enable flag param for SET_PP_BMT", __func__);
+                ret = -EINVAL;
+                goto done;
+            }
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_BMT_FLAG);
+            pp_bmt.enable_flag = (bool)enable_flag;
+            err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_BMT_VAL,
+                    (int*)&pp_bmt.value);
+            if ((err < 0)) {
+                ALOGE("%s: Invalid or missing value param for SET_PP_BMT", __func__);
+                ret = -EINVAL;
+                goto done;
+            }
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_BMT_VAL);
+
+            audio_hal_plugin_msg_type_t msg =
+                    AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_BMT;
+            pp_bmt.usecase = use_case;
+            pp_bmt.snd_dev= snd_dev;
+
+            ALOGD("%s: sending codec pp bmt msg to HAL plugin driver,%d,%d,%d,%d,%d",
+                    __func__, (int)pp_bmt.usecase, (int)pp_bmt.snd_dev,
+                    (int)pp_bmt.filter_type, (int)pp_bmt.enable_flag,
+                    (int)pp_bmt.value);
+
+            ret = my_plugin->audio_hal_plugin_send_msg(msg, &pp_bmt,
+                    sizeof(pp_bmt));
+            if (ret) {
+                ALOGE("%s: Failed to set plugin pp bmt err: %d", __func__, ret);
+            }
+            break;
+        }
+        case AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_EQ:
+        {
+            int32_t enable_flag;
+            audio_hal_plugin_codec_set_pp_eq_t pp_eq;
+            memset(&pp_eq,0,sizeof(pp_eq));
+
+            err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_EQ_FLAG,
+                    (int*)&enable_flag);
+            if (err < 0) {
+                ALOGE("%s: Invalid or missing enable flag param for SET_PP_EQ", __func__);
+                ret = -EINVAL;
+                goto done;
+            }
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_EQ_FLAG);
+            pp_eq.enable_flag = (bool)enable_flag;
+
+            err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_EQ_ID,
+                    (int*)&pp_eq.preset_id);
+            if (err < 0) {
+                ALOGE("%s: Invalid or missing preset_id param for SET_PP_EQ", __func__);
+                ret = -EINVAL;
+                goto done;
+            }
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_EQ_ID);
+            if (pp_eq.preset_id < -1) {
+                ALOGE("%s: Invalid preset_id param for SET_PP_EQ", __func__);
+                ret = -EINVAL;
+                goto done;
+            }
+
+            if (pp_eq.preset_id == -1) {
+                err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_EQ_NUM_BANDS,
+                        (int*)&pp_eq.num_bands);
+                if (err < 0) {
+                    ALOGE("%s: Invalid or missing num_bands param for SET_PP_EQ", __func__);
+                    ret = -EINVAL;
+                    goto done;
+                }
+                str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_EQ_NUM_BANDS);
+                if (!pp_eq.num_bands) {
+                    ALOGE("%s: Invalid num_bands param for SET_PP_EQ", __func__);
+                    ret = -EINVAL;
+                    goto done;
+                }
+
+                err = str_parms_get_str(parms,
+                        AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_EQ_BAND_DATA, value, len);
+                if (err < 0) {
+                    ALOGE("%s: Invalid or missing band_data for SET_PP_EQ", __func__);
+                    ret = -EINVAL;
+                    goto done;
+                }
+                str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_EQ_BAND_DATA);
+
+                ret = ext_hw_plugin_string_to_dword(value, (void**)&pp_eq.bands,
+                        3*pp_eq.num_bands);
+                if (ret) {
+                    ALOGE("%s: Failed to parse band info for SET_PP_EQ", __func__);
+                    ret = -EINVAL;
+                    goto done_eq;
+                }
+            }
+
+            audio_hal_plugin_msg_type_t msg =
+                    AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_EQ;
+            pp_eq.usecase = use_case;
+            pp_eq.snd_dev= snd_dev;
+
+            ALOGD("%s: sending codec pp eq msg to HAL plugin driver,%d,%d,%d,%d,%d",
+                    __func__, (int)pp_eq.usecase, (int)pp_eq.snd_dev,
+                    (int)pp_eq.enable_flag, (int)pp_eq.preset_id,
+                    (int)pp_eq.num_bands);
+
+            ret = my_plugin->audio_hal_plugin_send_msg(msg, &pp_eq, sizeof(pp_eq));
+            if (ret) {
+                ALOGE("%s: Failed to set plugin pp eq err: %d", __func__, ret);
+            }
+
+done_eq:
+            if (pp_eq.bands != NULL)
+                free(pp_eq.bands);
+            break;
+        }
+        default:
+            ALOGE("%s: Invalid plugin message type: %d", __func__, val);
+            ret = -EINVAL;
+        }
+    }
+
+done:
+    ALOGI("%s: exit with code(%d)", __func__, ret);
+    if(kv_pairs != NULL)
+        free(kv_pairs);
+    if(value != NULL)
+        free(value);
+    return ret;
+}
+
+int audio_extn_ext_hw_plugin_get_parameters(void *plugin,
+                  struct str_parms *query, struct str_parms *reply)
+{
+    char *value = NULL;
+    int32_t val, len = 0;;
+    int32_t ret = 0, err;
+    int32_t rbuf_dlen = 0;
+    uint32_t *rbuf_dptr = NULL;
+    char *rparms = NULL;
+    audio_hal_plugin_usecase_type_t use_case = AUDIO_HAL_PLUGIN_USECASE_INVALID;
+    snd_device_t snd_dev = 0;
+    struct ext_hw_plugin_data *my_plugin = NULL;
+    char *kv_pairs = NULL;
+
+    if(plugin == NULL || query == NULL || reply == NULL) {
+        ALOGE("[%s] received null pointer",__func__);
+        return -EINVAL;
+    }
+
+    err = str_parms_get_int(query, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_MSG_TYPE, &val);
+    if (err < 0) {
+        ALOGE("%s: Invalid or missing TYPE param for plugin msg", __func__);
+        return -EINVAL;
+    }
+    ALOGD("%s: received plugin msg type (%d)", __func__, val);
+    str_parms_del(query, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_MSG_TYPE);
+
+    my_plugin = (struct ext_hw_plugin_data *)plugin;
+    if (!my_plugin->audio_hal_plugin_send_msg) {
+        ALOGE("%s: NULL audio_hal_plugin_send_msg func ptr", __func__);
+        ret = -EINVAL;
+        goto done_get_param;
+    }
+
+    if(val == AUDIO_HAL_PLUGIN_MSG_CODEC_TUNNEL_GET_CMD) {
+        kv_pairs = str_parms_to_str(query);
+        len = strlen(kv_pairs);
+        value = (char*)calloc(len, sizeof(char));
+        if (value == NULL) {
+            ret = -ENOMEM;
+            ALOGE("[%s] failed to allocate memory",__func__);
+            goto done_get_param;
+        }
+    } else {
+        err = str_parms_get_int(query, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_UC,
+                &use_case);
+        if (err < 0) {
+            ALOGI("%s: Invalid or missing usecase param for plugin msg", __func__);
+            use_case = AUDIO_HAL_PLUGIN_USECASE_INVALID;
+        } else {
+            str_parms_del(query, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_UC);
+
+            if ((use_case < 0) || (use_case >= AUDIO_HAL_PLUGIN_USECASE_MAX)) {
+                ALOGI("%s: Invalid usecase param for plugin msg", __func__);
+                use_case = AUDIO_HAL_PLUGIN_USECASE_INVALID;
+                goto done_get_param;
+            }
+
+            if (my_plugin->usecase_ref_count[use_case] == 0) {
+                ALOGI("%s: plugin usecase (%d) is not enabled",
+                        __func__, use_case);
+            } else {
+                /* TODO: confirm this handles all usecase */
+                if (my_plugin->out_snd_dev[use_case]) {
+                    snd_dev = my_plugin->out_snd_dev[use_case];
+                } else if (my_plugin->in_snd_dev[use_case]) {
+                    snd_dev = my_plugin->in_snd_dev[use_case];
+                } else {
+                    ALOGE("%s: No valid snd_device found for the usecase (%d)",
+                            __func__, use_case);
+                    ret = -EINVAL;
+                    goto done_get_param;
+                }
+            }
+        }
+    }
+
+    switch(val) {
+    case AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_VOLUME:
+    {
+        audio_hal_plugin_codec_get_pp_vol_t get_pp_vol;
+        memset(&get_pp_vol,0,sizeof(get_pp_vol));
+        err = str_parms_get_int(query, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_CMASK,
+                (int*)&get_pp_vol.ch_mask);
+        if ((err < 0)) {
+            ALOGI("%s: Invalid or missing CMASK param for GET_PP_VOLUME", __func__);
+            get_pp_vol.ch_mask = AUDIO_CHANNEL_NONE;
+        } else {
+            str_parms_del(query, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_CMASK);
+        }
+
+        audio_hal_plugin_msg_type_t msg =
+                AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_VOLUME;
+        get_pp_vol.usecase = use_case;
+        get_pp_vol.snd_dev = snd_dev;
+
+        ALOGD("%s: sending get codec pp vol msg to HAL plugin driver, %d, %d, %d",
+                __func__, (int)get_pp_vol.usecase, (int)get_pp_vol.snd_dev,
+                (int)get_pp_vol.ch_mask);
+
+        ret = my_plugin->audio_hal_plugin_send_msg(msg, &get_pp_vol, sizeof(get_pp_vol));
+        if (ret) {
+            ALOGE("%s: Failed to get plugin pp vol err: %d", __func__, ret);
+            goto done_get_param;
+        }
+
+        rbuf_dlen = sizeof(get_pp_vol.ret_gain)/sizeof(int32_t);
+        rbuf_dptr = calloc(rbuf_dlen, sizeof(uint32_t));
+        if(rbuf_dptr == NULL) {
+            ALOGE("[%s] Memory allocation failed for dword length %d",__func__,rbuf_dlen);
+            ret = -ENOMEM;
+            goto done_get_param;
+        }
+        memcpy(rbuf_dptr, &get_pp_vol.ret_gain, sizeof(get_pp_vol.ret_gain));
+        break;
+    }
+    case AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_FADE:
+    {
+        audio_hal_plugin_codec_get_pp_fade_t get_pp_fade;
+        memset(&get_pp_fade,0,sizeof(get_pp_fade));
+
+        audio_hal_plugin_msg_type_t msg =
+                AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_FADE;
+        get_pp_fade.usecase = use_case;
+        get_pp_fade.snd_dev = snd_dev;
+
+        ALOGD("%s: sending get codec pp fade msg to HAL plugin driver, %d, %d",
+                __func__, (int)get_pp_fade.usecase, (int)get_pp_fade.snd_dev);
+
+        ret = my_plugin->audio_hal_plugin_send_msg(msg, &get_pp_fade, sizeof(get_pp_fade));
+        if (ret) {
+            ALOGE("%s: Failed to get plugin pp fade err: %d", __func__, ret);
+            goto done_get_param;
+        }
+
+        rbuf_dlen = sizeof(get_pp_fade.ret_fade)/sizeof(int32_t);
+        rbuf_dptr = calloc(rbuf_dlen, sizeof(uint32_t));
+        if(rbuf_dptr == NULL) {
+            ALOGE("[%s] Memory allocation failed for dword length %d",__func__,rbuf_dlen);
+            ret = -ENOMEM;
+            goto done_get_param;
+        }
+        memcpy(rbuf_dptr, &get_pp_fade.ret_fade, sizeof(get_pp_fade.ret_fade));
+        break;
+    }
+    case AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_BALANCE:
+    {
+        audio_hal_plugin_codec_get_pp_balance_t get_pp_balance;
+        memset(&get_pp_balance,0,sizeof(get_pp_balance));
+
+        audio_hal_plugin_msg_type_t msg =
+                AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_BALANCE;
+        get_pp_balance.usecase = use_case;
+        get_pp_balance.snd_dev = snd_dev;
+
+        ALOGD("%s: sending get codec pp balance msg to HAL plugin driver, %d, %d",
+                __func__, (int)get_pp_balance.usecase, (int)get_pp_balance.snd_dev);
+
+        ret = my_plugin->audio_hal_plugin_send_msg(msg, &get_pp_balance,
+            sizeof(get_pp_balance));
+        if (ret) {
+            ALOGE("%s: Failed to get plugin pp balance err: %d", __func__, ret);
+            goto done_get_param;
+        }
+
+        rbuf_dlen = sizeof(get_pp_balance.ret_balance)/sizeof(int32_t);
+        rbuf_dptr = calloc(rbuf_dlen, sizeof(uint32_t));
+        if(rbuf_dptr == NULL) {
+            ALOGE("[%s] Memory allocation failed for dword length %d",__func__,rbuf_dlen);
+            ret = -ENOMEM;
+            goto done_get_param;
+        }
+        memcpy(rbuf_dptr, &get_pp_balance.ret_balance, sizeof(get_pp_balance.ret_balance));
+        break;
+    }
+    case AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_BMT:
+    {
+        int32_t filter_type;
+        audio_hal_plugin_codec_get_pp_bmt_t get_pp_bmt;
+        memset(&get_pp_bmt,0,sizeof(get_pp_bmt));
+        err = str_parms_get_int(query, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_BMT_FTYPE,
+                (int*)&filter_type);
+        if ((err < 0)) {
+            ALOGE("%s: Invalid or missing filter type param for GET_PP_BMT", __func__);
+            get_pp_bmt.filter_type = AUDIO_HAL_PLUGIN_CODEC_PP_FILTER_TYPE_INVALID;
+        } else {
+            str_parms_del(query, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_BMT_FTYPE);
+
+            if ((filter_type <= AUDIO_HAL_PLUGIN_CODEC_PP_FILTER_TYPE_INVALID) &&
+                    (filter_type >= AUDIO_HAL_PLUGIN_CODEC_PP_FILTER_TYPE_MAX)) {
+                ALOGE("%s: Invalid filter type value for SET_PP_BMT", __func__);
+                get_pp_bmt.filter_type = AUDIO_HAL_PLUGIN_CODEC_PP_FILTER_TYPE_INVALID;
+            } else {
+                get_pp_bmt.filter_type = filter_type;
+            }
+        }
+
+        audio_hal_plugin_msg_type_t msg =
+                AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_BMT;
+        get_pp_bmt.usecase = use_case;
+        get_pp_bmt.snd_dev = snd_dev;
+
+        ALOGD("%s: sending get codec pp bmt msg to HAL plugin driver, %d, %d, %d",
+                __func__, (int)get_pp_bmt.usecase, (int)get_pp_bmt.snd_dev,
+                (int)get_pp_bmt.filter_type);
+
+        ret = my_plugin->audio_hal_plugin_send_msg(msg, &get_pp_bmt, sizeof(get_pp_bmt));
+        if (ret) {
+            ALOGE("%s: Failed to get plugin pp bmt err: %d", __func__, ret);
+            goto done_get_param;
+        }
+
+        rbuf_dlen = sizeof(get_pp_bmt.ret_value)/sizeof(int32_t);
+        rbuf_dptr = calloc(rbuf_dlen, sizeof(uint32_t));
+        if(rbuf_dptr == NULL) {
+            ALOGE("[%s] Memory allocation failed for dword length %d",__func__,rbuf_dlen);
+            ret = -ENOMEM;
+            goto done_get_param;
+        }
+        memcpy(rbuf_dptr, &get_pp_bmt.ret_value, sizeof(get_pp_bmt.ret_value));
+        break;
+    }
+    case AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_EQ:
+    {
+        uint32_t rbuf_len = 0;
+        char *tmp_ptr = NULL;
+        audio_hal_plugin_codec_get_pp_eq_t get_pp_eq;
+        memset(&get_pp_eq,0,sizeof(get_pp_eq));
+
+        audio_hal_plugin_msg_type_t msg = AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_EQ;
+        get_pp_eq.usecase = use_case;
+        get_pp_eq.snd_dev = snd_dev;
+
+        ALOGD("%s: sending get codec pp eq msg to HAL plugin driver, %d, %d",
+                __func__, (int)get_pp_eq.usecase, (int)get_pp_eq.snd_dev);
+
+        ret = my_plugin->audio_hal_plugin_send_msg(msg, &get_pp_eq, sizeof(get_pp_eq));
+        if (ret) {
+            ALOGE("%s: Failed to get plugin pp eq err: %d", __func__, ret);
+            goto done_get_param;
+        }
+
+        rbuf_len = sizeof(get_pp_eq.ret_preset_id) + sizeof(get_pp_eq.ret_num_bands);
+        rbuf_dlen = rbuf_len / sizeof(uint32_t);
+        rbuf_dptr = calloc(rbuf_dlen, sizeof(uint32_t));
+        if(rbuf_dptr == NULL) {
+            ALOGE("[%s] Memory allocation failed for dword length %d",__func__,rbuf_dlen);
+            ret = -ENOMEM;
+            goto done_get_param;
+        }
+        tmp_ptr = (char*)rbuf_dptr;
+        memcpy(tmp_ptr, &get_pp_eq.ret_preset_id, sizeof(get_pp_eq.ret_preset_id));
+        tmp_ptr += sizeof(get_pp_eq.ret_preset_id);
+        memcpy(tmp_ptr, &get_pp_eq.ret_num_bands, sizeof(get_pp_eq.ret_num_bands));
+        break;
+    }
+    case AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_EQ_SUBBANDS:
+    {
+        uint32_t rbuf_len = 0;
+        audio_hal_plugin_codec_get_pp_eq_subbands_t get_pp_eq_subbands;
+        memset(&get_pp_eq_subbands,0,sizeof(get_pp_eq_subbands));
+        err = str_parms_get_int(query, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_EQ_NUM_BANDS,
+                (int*)&get_pp_eq_subbands.num_bands);
+        if ((err < 0)) {
+            ALOGE("%s: Invalid or missing num bands param for GET_PP_EQ_SUBBANDS",
+                    __func__);
+            ret = -EINVAL;
+            goto done_get_param;
+        } else {
+            str_parms_del(query, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_EQ_NUM_BANDS);
+
+            if(get_pp_eq_subbands.num_bands == 0) {
+                ALOGE("%s: Zero num bands param for GET_PP_EQ_SUBBANDS",
+                        __func__);
+                ret = -EINVAL;
+                goto done_get_param;
+            }
+        }
+        rbuf_len = get_pp_eq_subbands.num_bands *
+                sizeof(audio_hal_plugin_pp_eq_subband_binfo_t);
+
+        audio_hal_plugin_msg_type_t msg = AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_EQ_SUBBANDS;
+        get_pp_eq_subbands.usecase = use_case;
+        get_pp_eq_subbands.snd_dev = snd_dev;
+        get_pp_eq_subbands.ret_bands = calloc(rbuf_len, 1);
+        if(get_pp_eq_subbands.ret_bands == NULL) {
+            ret = -ENOMEM;
+            ALOGE("[%s] failed to allocate memory",__func__);
+            goto done_get_param;
+        }
+
+        ALOGD("%s: sending get codec pp eq subbands msg to plugin driver, %d, %d, %d",
+                __func__, (int)get_pp_eq_subbands.usecase,
+                (int)get_pp_eq_subbands.snd_dev, (int)get_pp_eq_subbands.num_bands);
+
+        ret = my_plugin->audio_hal_plugin_send_msg(msg, &get_pp_eq_subbands,
+                sizeof(get_pp_eq_subbands));
+        if (ret) {
+            ALOGE("%s: Failed to get plugin pp eq subbands err: %d", __func__, ret);
+            goto done_get_eq_subbands;
+        }
+
+        rbuf_dlen = rbuf_len / sizeof(uint32_t);
+        rbuf_dptr = calloc(rbuf_dlen, sizeof(uint32_t));
+        if(rbuf_dptr == NULL) {
+            ALOGE("[%s] Memory allocation failed for dword length %d",__func__,rbuf_dlen);
+            ret = -ENOMEM;
+            goto done_get_eq_subbands;
+        }
+        memcpy(rbuf_dptr, get_pp_eq_subbands.ret_bands, rbuf_len);
+
+done_get_eq_subbands:
+        if(get_pp_eq_subbands.ret_bands != NULL)
+            free(get_pp_eq_subbands.ret_bands);
+        break;
+    }
+    case AUDIO_HAL_PLUGIN_MSG_CODEC_TUNNEL_GET_CMD:
+    {
+        char *tmp_ptr = NULL;
+        audio_hal_plugin_codec_tunnel_get_t tunnel_get;
+        memset(&tunnel_get,0,sizeof(tunnel_get));
+
+        err = str_parms_get_int(query, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_TUNNEL_SIZE,
+                (int*)&tunnel_get.param_size);
+        if ((err < 0) || (!tunnel_get.param_size)) {
+            ALOGE("%s: Invalid or missing size param for TUNNEL GET command", __func__);
+            ret = -EINVAL;
+            goto done_get_param;
+        }
+        str_parms_del(query, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_TUNNEL_SIZE);
+
+        err = str_parms_get_str(query,
+                AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_TUNNEL_DATA, value, len);
+        if (err < 0) {
+            ALOGE("%s: Invalid or missing data param for TUNNEL GET command", __func__);
+            ret = -EINVAL;
+            goto done_get_param;
+        }
+        str_parms_del(query, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_TUNNEL_DATA);
+
+        err = str_parms_get_int(query, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_TUNNEL_GET_SIZE,
+                (int*)&tunnel_get.size_to_get);
+        if (err < 0 || (!tunnel_get.size_to_get)) {
+            ALOGE("%s: Invalid or missing size_to_get param for TUNNEL GET command",
+                    __func__);
+            ret = -EINVAL;
+            goto done_get_param;
+        }
+        str_parms_del(query, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_TUNNEL_GET_SIZE);
+
+        ret = ext_hw_plugin_string_to_dword(value, (void**)&tunnel_get.param_data,
+            tunnel_get.param_size);
+        if (ret) {
+            ALOGE("%s: Failed to parse payload for TUNNEL GET command", __func__);
+            ret = -EINVAL;
+            goto done_tunnel_get;
+        }
+
+        audio_hal_plugin_msg_type_t msg =
+                AUDIO_HAL_PLUGIN_MSG_CODEC_TUNNEL_GET_CMD;
+        tunnel_get.ret_data = calloc(tunnel_get.size_to_get, sizeof(int32_t));
+        if(tunnel_get.ret_data == NULL) {
+            ret = -ENOMEM;
+            ALOGE("[%s] failed to allocate memory",__func__);
+            goto done_tunnel_get;
+        }
+
+        ALOGD("%s: sending tunnel get cmd to plugin driver,size = %d, size_to_get = %d",
+                __func__, (int)tunnel_get.param_size, (int)tunnel_get.size_to_get);
+
+        ret = my_plugin->audio_hal_plugin_send_msg(msg, (void*)&tunnel_get,
+                sizeof(tunnel_get));
+        if (ret) {
+            ALOGE("%s: Failed to send plugin tunnel get cmd err: %d", __func__, ret);
+            goto done_tunnel_get;
+        }
+        if ((tunnel_get.ret_size == 0) ||
+                (tunnel_get.ret_size > tunnel_get.size_to_get)) {
+            ret = -EINVAL;
+            ALOGE("[%s] Invalid tunnel get cmd return size: %d",
+                    __func__, tunnel_get.ret_size);
+            goto done_tunnel_get;
+        }
+
+        rbuf_dlen = tunnel_get.ret_size + 1;
+        rbuf_dptr = calloc(rbuf_dlen, sizeof(uint32_t));
+        if(rbuf_dptr == NULL) {
+            ALOGE("[%s] Memory allocation failed for dword length %d",__func__,rbuf_dlen);
+            ret = -ENOMEM;
+            goto done_tunnel_get;
+        }
+        tmp_ptr = (char*)rbuf_dptr;
+        memcpy(tmp_ptr, &tunnel_get.ret_size, sizeof(uint32_t));
+        tmp_ptr += sizeof(uint32_t);
+        memcpy(tmp_ptr, tunnel_get.ret_data, 4*tunnel_get.ret_size);
+
+done_tunnel_get:
+        if (tunnel_get.param_data!= NULL)
+            free(tunnel_get.param_data);
+        if (tunnel_get.ret_data!= NULL)
+            free(tunnel_get.ret_data);
+        break;
+    }
+    default:
+        ALOGE("%s: Invalid plugin message type: %d", __func__, val);
+        ret = -EINVAL;
+    }
+
+    if(ret == 0) {
+        ret = ext_hw_plugin_dword_to_string(rbuf_dptr, rbuf_dlen, &rparms);
+        if (ret < 0) {
+            ALOGE("%s: Failed to convert param info for MSG_TYPE %d", __func__, val);
+            goto done_get_param;
+        }
+        ret = 0;
+        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_GETPARAM_RESULT, ret);
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_GETPARAM_DATA, rparms);
+    }
+
+done_get_param:
+    if(ret) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_GETPARAM_RESULT, ret);
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_GETPARAM_DATA, "");
+    }
+    if(rbuf_dptr!= NULL)
+        free(rbuf_dptr);
+    if(rparms!= NULL)
+        free(rparms);
+
+    ALOGI("%s: exit with code(%d)", __func__, ret);
+    if(kv_pairs != NULL)
+        free(kv_pairs);
+    if(value != NULL)
+        free(value);
+    return ret;
+}
+
+int audio_extn_ext_hw_plugin_set_mic_mute(void *plugin, bool mute)
+{
+    struct ext_hw_plugin_data *my_plugin = NULL;
+    audio_hal_plugin_codec_set_pp_mute_t pp_mute;
+    int ret = 0;
+
+    ALOGD("%s: received set mic mute (%d)", __func__, mute);
+
+    if (plugin == NULL) {
+        ALOGE("[%s] received null pointer",__func__);
+        return -EINVAL;
+    }
+
+    my_plugin = (struct ext_hw_plugin_data *)plugin;
+    if (!my_plugin->audio_hal_plugin_send_msg) {
+        ALOGE("%s: NULL audio_hal_plugin_send_msg func ptr", __func__);
+        return -EINVAL;
+    }
+
+    my_plugin->mic_mute = mute;
+
+    /* Set mic mute is currently supported only for HFP call use case. */
+    if (my_plugin->usecase_ref_count[AUDIO_HAL_PLUGIN_USECASE_HFP_VOICE_CALL]) {
+        pp_mute.snd_dev= my_plugin->in_snd_dev[AUDIO_HAL_PLUGIN_USECASE_HFP_VOICE_CALL];
+        pp_mute.usecase = AUDIO_HAL_PLUGIN_USECASE_HFP_VOICE_CALL;
+        pp_mute.ch_mask = AUDIO_CHANNEL_IN_ALL;
+        pp_mute.flag = mute;
+
+        ALOGV("%s: sending codec pp mute msg to HAL plugin driver, %d, %d, %x, %d",
+                __func__, (int)pp_mute.usecase, (int)pp_mute.snd_dev,
+                (int)pp_mute.ch_mask, (int)pp_mute.flag);
+        ret = my_plugin->audio_hal_plugin_send_msg(
+                AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_MUTE, &pp_mute,
+                sizeof(pp_mute));
+        if (ret) {
+            ALOGE("%s: Failed to set plugin pp mute err: %d", __func__, ret);
+        }
+    }
+
+    return ret;
+}
+
+int audio_extn_ext_hw_plugin_get_mic_mute(void *plugin, bool *mute)
+{
+    struct ext_hw_plugin_data *my_plugin = (struct ext_hw_plugin_data *)plugin;
+
+    if (my_plugin == NULL || mute == NULL) {
+        ALOGE("[%s] received null pointer", __func__);
+        return -EINVAL;
+    }
+
+    *mute = my_plugin->mic_mute;
+    ALOGD("%s: received get mic mute (%d)", __func__, *mute);
+
+    return 0;
+}
+
+int audio_extn_ext_hw_plugin_set_audio_gain(void *plugin,
+            struct audio_usecase *usecase, uint32_t gain)
+{
+    int32_t ret = 0;
+    struct ext_hw_plugin_data *my_plugin = (struct ext_hw_plugin_data *)plugin;
+    audio_hal_plugin_codec_set_pp_vol_t pp_vol;
+
+    if ((my_plugin == NULL) || (usecase == NULL)) {
+        ALOGE("%s: NULL input pointer", __func__);
+        return -EINVAL;
+    }
+
+    if (!my_plugin->audio_hal_plugin_send_msg) {
+        ALOGE("%s: NULL audio_hal_plugin_send_msg func ptr", __func__);
+        return -EINVAL;
+    }
+
+    memset(&pp_vol, 0, sizeof(pp_vol));
+
+    ret = ext_hw_plugin_check_plugin_usecase(usecase->id, &pp_vol.usecase);
+    if (ret) {
+        ALOGI("%s: Set audio gain skipped for audio usecase %d",
+                __func__, usecase->id);
+        return 0;
+    }
+
+#if 0
+    /* Skip active usecase check and continue vol set to plugin
+     * to allow volume cached per usecase in plugin.
+     */
+    if (!my_plugin->usecase_ref_count[pp_vol.usecase]) {
+        ALOGV("%s: Plugin usecase %d is not enabled",
+                __func__, pp_vol.usecase);
+        return 0;
+    }
+
+    if (my_plugin->out_snd_dev[pp_vol.usecase]) {
+        pp_vol.snd_dev = my_plugin->out_snd_dev[pp_vol.usecase];
+        pp_vol.ch_mask = AUDIO_CHANNEL_OUT_ALL;
+    } else if (my_plugin->in_snd_dev[pp_vol.usecase]) {
+        pp_vol.snd_dev = my_plugin->in_snd_dev[pp_vol.usecase];
+        pp_vol.ch_mask = AUDIO_CHANNEL_IN_ALL;
+    } else {
+        ALOGE("%s: No valid snd_device found for usecase %d",
+                __func__, pp_vol.usecase);
+        return -EINVAL;
+    }
+#endif
+
+    /* NOTE: Use in/out snd device from usecase to decide
+     *       which direction pp_volume should apply.
+     */
+    if (usecase->out_snd_device != SND_DEVICE_NONE) {
+        pp_vol.snd_dev = usecase->out_snd_device;
+        pp_vol.ch_mask = AUDIO_CHANNEL_OUT_ALL;
+    } else if (usecase->in_snd_device != SND_DEVICE_NONE) {
+        pp_vol.snd_dev = usecase->in_snd_device;
+        pp_vol.ch_mask = AUDIO_CHANNEL_IN_ALL;
+    } else {
+        ALOGE("%s: No valid snd_device found for usecase %d",
+                __func__, pp_vol.usecase);
+        return -EINVAL;
+    }
+
+    pp_vol.gain = gain;
+
+    ALOGD("%s: Sending codec pp vol msg to HAL plugin driver, %d, %d, %d, %d",
+            __func__, (int)pp_vol.usecase, (int)pp_vol.snd_dev,
+            (int)pp_vol.ch_mask, (int)pp_vol.gain);
+    ret = my_plugin->audio_hal_plugin_send_msg(
+            AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_VOLUME,
+            &pp_vol, sizeof(pp_vol));
+    if (ret) {
+        ALOGE("%s: Failed to set plugin pp vol err: %d", __func__, ret);
+    }
+    return ret;
+}
+#endif /* EXT_HW_PLUGIN_ENABLED */
diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c
index b0c14cd..89c42c8 100644
--- a/hal/audio_extn/hfp.c
+++ b/hal/audio_extn/hfp.c
@@ -38,6 +38,7 @@
 #include "platform_api.h"
 #include <stdlib.h>
 #include <cutils/str_parms.h>
+#include "audio_extn.h"
 
 #ifdef DYNAMIC_LOG_ENABLED
 #include <log_xml_parser.h>
@@ -55,6 +56,8 @@
 #define HFP_RX_VOLUME     "SEC AUXPCM LOOPBACK Volume"
 #elif defined PLATFORM_MSM8996
 #define HFP_RX_VOLUME     "PRI AUXPCM LOOPBACK Volume"
+#elif defined PLATFORM_AUTO
+#define HFP_RX_VOLUME     "Playback 36 Volume"
 #elif defined (PLATFORM_MSM8998) || defined (PLATFORM_MSMFALCON) || defined (PLATFORM_SDM845) || defined (PLATFORM_SDM710) || defined (PLATFORM_QCS605) || defined (PLATFORM_MSMNILE) || defined (PLATFORM_MSMSTEPPE) || defined (PLATFORM_QCS405)
 #define HFP_RX_VOLUME     "SLIMBUS_7 LOOPBACK Volume"
 #else
@@ -163,6 +166,12 @@
 
     select_devices(adev, hfpmod.ucid);
 
+    if ((uc_info->out_snd_device != SND_DEVICE_NONE) ||
+        (uc_info->in_snd_device != SND_DEVICE_NONE)) {
+        if (audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
+            ALOGE("%s: failed to start ext hw plugin", __func__);
+    }
+
     pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
     pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
     pcm_dev_asm_rx_id = hfpmod.hfp_pcm_dev_id;
@@ -280,6 +289,12 @@
         return -EINVAL;
     }
 
+    if ((uc_info->out_snd_device != SND_DEVICE_NONE) ||
+        (uc_info->in_snd_device != SND_DEVICE_NONE)) {
+        if (audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
+            ALOGE("%s: failed to stop ext hw plugin", __func__);
+    }
+
     /* 2. Disable echo reference while stopping hfp */
     platform_set_echo_reference(adev, false, uc_info->devices);
 
diff --git a/hal/audio_extn/passthru.c b/hal/audio_extn/passthru.c
index b608043..9180391 100644
--- a/hal/audio_extn/passthru.c
+++ b/hal/audio_extn/passthru.c
@@ -546,6 +546,12 @@
                                                    struct stream_out *out)
 {
     struct audio_backend_cfg backend_cfg;
+    backend_cfg.sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    backend_cfg.channels = CODEC_BACKEND_DEFAULT_CHANNELS;
+    backend_cfg.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+    backend_cfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    backend_cfg.passthrough_enabled = false;
+
     snd_device_t out_snd_device = SND_DEVICE_NONE;
     int max_edid_channels = platform_edid_get_max_channels(out->dev->platform);
 
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
index 26c1592..f084396 100644
--- a/hal/audio_extn/spkr_protection.c
+++ b/hal/audio_extn/spkr_protection.c
@@ -746,7 +746,7 @@
     struct timespec ts;
     bool acquire_device = false;
 
-    status.status = 0;
+    memset(&status, 0, sizeof(status));
     memset(&protCfg, 0, sizeof(protCfg));
     if (!adev) {
         ALOGE("%s: Invalid params", __func__);
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 18b12d4..7f41763 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -2409,6 +2409,11 @@
         return -EINVAL;
     }
 
+    if (uc_info->in_snd_device != SND_DEVICE_NONE) {
+        if (audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
+            ALOGE("%s: failed to stop ext hw plugin", __func__);
+    }
+
     /* Close in-call recording streams */
     voice_check_and_stop_incall_rec_usecase(adev, in);
 
@@ -2504,6 +2509,11 @@
                                  adev->perf_lock_opts_size);
     select_devices(adev, in->usecase);
 
+    if (uc_info->in_snd_device != SND_DEVICE_NONE) {
+        if (audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
+            ALOGE("%s: failed to start ext hw plugin", __func__);
+    }
+
     if (audio_extn_cin_attached_usecase(in->usecase)) {
        ret = audio_extn_cin_start_input_stream(in);
        if (ret)
@@ -2932,6 +2942,11 @@
         return -EINVAL;
     }
 
+    if (uc_info->out_snd_device != SND_DEVICE_NONE) {
+        if (audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
+            ALOGE("%s: failed to stop ext hw plugin", __func__);
+    }
+
     if (is_offload_usecase(out->usecase) &&
         !(audio_extn_passthru_is_passthrough_stream(out))) {
         if (adev->visualizer_stop_output != NULL)
@@ -3108,6 +3123,11 @@
     if (out->usecase == USECASE_INCALL_MUSIC_UPLINK)
         voice_set_device_mute_flag(adev, true);
 
+    if (uc_info->out_snd_device != SND_DEVICE_NONE) {
+        if (audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
+            ALOGE("%s: failed to start ext hw plugin", __func__);
+    }
+
     ALOGV("%s: Opening PCM device card_id(%d) device_id(%d) format(%#x)",
           __func__, adev->snd_card, out->pcm_device_id, out->config.format);
 
@@ -7016,6 +7036,8 @@
     pthread_mutex_lock(&adev->lock);
     ALOGD("%s state %d\n", __func__, state);
     ret = voice_set_mic_mute((struct audio_device *)dev, state);
+    if (adev->ext_hw_plugin)
+        ret = audio_extn_ext_hw_plugin_set_mic_mute(adev->ext_hw_plugin, state);
     pthread_mutex_unlock(&adev->lock);
 
     return ret;
@@ -7433,8 +7455,10 @@
     // between the callback and close_stream
     audio_extn_snd_mon_unregister_listener(stream);
 
-    /* Disable echo reference while closing input stream */
-    platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE);
+    // Disable echo reference if there are no active input and hfp call
+    // while closing input stream
+    if (!adev->active_input && !audio_extn_hfp_is_active(adev))
+        platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE);
 
     if (in == NULL) {
         ALOGE("%s: audio_stream_in ptr is NULL", __func__);
@@ -7550,6 +7574,8 @@
             free(adev->device_cfg_params);
             adev->device_cfg_params = NULL;
         }
+        if(adev->ext_hw_plugin)
+            audio_extn_ext_hw_plugin_deinit(adev->ext_hw_plugin);
         free(device);
         adev = NULL;
     }
@@ -7803,6 +7829,8 @@
         adev->device.close_output_stream = audio_extn_qaf_close_output_stream;
     }
 
+    adev->ext_hw_plugin = audio_extn_ext_hw_plugin_init(adev);
+
     if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) {
         adev->visualizer_lib = dlopen(VISUALIZER_LIBRARY_PATH, RTLD_NOW);
         if (adev->visualizer_lib == NULL) {
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index c1b8e07..8ae84e8 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -546,6 +546,7 @@
     struct audio_device_config_param *device_cfg_params;
     unsigned int interactive_usecase_state;
     bool dp_allowed_for_voice;
+    void *ext_hw_plugin;
 };
 
 int select_devices(struct audio_device *adev,
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index f2bd9de..e10a955 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -6724,7 +6724,7 @@
         bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
         sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
         channels = CODEC_BACKEND_DEFAULT_TX_CHANNELS;
-    } else if (my_data->is_internal_codec) {
+    } else if (my_data->is_internal_codec && !audio_is_usb_in_device(snd_device)) {
         sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
         channels = CODEC_BACKEND_DEFAULT_TX_CHANNELS;
         if (adev->active_input->bit_width == 24)
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 74ce72f..eb6edb0 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -495,6 +495,9 @@
 #elif PLATFORM_BEAR_FAMILY
 #define HFP_SCO_RX 17
 #define HFP_ASM_RX_TX 18
+#elif PLATFORM_AUTO
+#define HFP_SCO_RX 36
+#define HFP_ASM_RX_TX 29
 #else
 #define HFP_SCO_RX 23
 #define HFP_ASM_RX_TX 24