Merge "hal: use separate dual mic config for qrd device during voip call"
diff --git a/configs/msmnile_au/mixer_paths_adp.xml b/configs/msmnile_au/mixer_paths_adp.xml
index bcea162..e5ce0ab 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" />
diff --git a/configs/msmsteppe/audio_platform_info_qrd.xml b/configs/msmsteppe/audio_platform_info_qrd.xml
index 0e7dffc..61d6782 100644
--- a/configs/msmsteppe/audio_platform_info_qrd.xml
+++ b/configs/msmsteppe/audio_platform_info_qrd.xml
@@ -93,6 +93,7 @@
         <device name="SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1" acdb_id="10"/>
         <device name="SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2" acdb_id="10"/>
         <device name="SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET" acdb_id="45"/>
+        <device name="SND_DEVICE_IN_UNPROCESSED_USB_HEADSET_MIC" acdb_id="133"/>
         <device name="SND_DEVICE_IN_UNPROCESSED_MIC" acdb_id="143"/>
         <device name="SND_DEVICE_IN_UNPROCESSED_STEREO_MIC" acdb_id="144"/>
         <device name="SND_DEVICE_IN_UNPROCESSED_THREE_MIC" acdb_id="145"/>
diff --git a/hal/Android.mk b/hal/Android.mk
index 7a0c69f..febba73 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -65,6 +65,10 @@
 endif
 endif
 
+ifeq ($(TARGET_BOARD_AUTO),true)
+  LOCAL_CFLAGS += -DPLATFORM_AUTO
+endif
+
 LOCAL_CFLAGS += -Wno-macro-redefined
 
 LOCAL_HEADER_LIBRARIES := libhardware_headers
@@ -427,6 +431,11 @@
     LOCAL_SRC_FILES += audio_extn/sndmonitor.c
 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 d125b2f..ba096c9
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -884,6 +884,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,
@@ -902,6 +903,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 a3b374c..e74bd36 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -1107,4 +1107,29 @@
 snd_device_t audio_extn_ffv_get_capture_snd_device();
 void audio_extn_ffv_append_ec_ref_dev_name(char *device_name);
 #endif
+
+#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/fm.c b/hal/audio_extn/fm.c
index 24facea..02561ba 100644
--- a/hal/audio_extn/fm.c
+++ b/hal/audio_extn/fm.c
@@ -166,6 +166,7 @@
     int32_t pcm_dev_rx_id, pcm_dev_tx_id;
 
     ALOGD("%s: enter", __func__);
+    fmmod.is_fm_running = true;
 
     uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
 
@@ -220,9 +221,6 @@
     pcm_start(fmmod.fm_pcm_rx);
     pcm_start(fmmod.fm_pcm_tx);
 
-    fmmod.is_fm_running = true;
-    fm_set_volume(adev, fmmod.fm_volume, false);
-
     ALOGD("%s: exit: status(%d)", __func__, ret);
     return 0;
 
diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c
index a98d5e4..26ea72c 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_TRINKET)
 #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_hal_plugin.h b/hal/audio_hal_plugin.h
new file mode 100644
index 0000000..9b20d3c
--- /dev/null
+++ b/hal/audio_hal_plugin.h
@@ -0,0 +1,375 @@
+/* Copyright (c) 2014-2015, 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.
+*/
+
+#ifndef AUDIO_HAL_PLUGIN_H
+#define AUDIO_HAL_PLUGIN_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include <audio_hw.h>
+
+#define AUDIO_HAL_PLUGIN_EOK (0)
+#define AUDIO_HAL_PLUGIN_EFAIL (-1) /**< Undefined error */
+#define AUDIO_HAL_PLUGIN_ENOMEM (-2) /**< Out of memory */
+#define AUDIO_HAL_PLUGIN_EINVAL (-3) /**< Invalid argument */
+#define AUDIO_HAL_PLUGIN_EBUSY (-4) /**< Plugin driver is busy */
+#define AUDIO_HAL_PLUGIN_ENODEV (-5) /**< No device */
+#define AUDIO_HAL_PLUGIN_EALREADY (-6) /**< Already done */
+
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_MSG_TYPE     "ext_hw_plugin_msg_type"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_UC           "ext_hw_plugin_usecase"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_SND_DEVICE   "ext_hw_plugin_snd_device"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_DIRECTION    "ext_hw_plugin_direction"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_CMASK        "ext_hw_plugin_channel_mask"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_GAIN         "ext_hw_plugin_gain"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_MUTE_FLAG    "ext_hw_plugin_mute_flag"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_FADE         "ext_hw_plugin_fade"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_BALANCE      "ext_hw_plugin_balance"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_BMT_FTYPE    "ext_hw_plugin_bmt_filter_type"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_BMT_FLAG     "ext_hw_plugin_bmt_flag"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_BMT_VAL      "ext_hw_plugin_bmt_value"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_EQ_FLAG      "ext_hw_plugin_eq_flag"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_EQ_ID        "ext_hw_plugin_eq_id"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_EQ_NUM_BANDS "ext_hw_plugin_eq_num_bands"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_EQ_BAND_DATA "ext_hw_plugin_eq_band_data"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_TUNNEL_SIZE  "ext_hw_plugin_tunnel_size"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_TUNNEL_DATA  "ext_hw_plugin_tunnel_data"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_GETPARAM_RESULT "ext_hw_plugin_getparam_result"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_GETPARAM_DATA "ext_hw_plugin_getparam_data"
+#define AUDIO_PARAMETER_KEY_EXT_HW_PLUGIN_TUNNEL_GET_SIZE "ext_hw_plugin_tunnel_get_size"
+/**
+ * Type of audio hal plug-in messages
+ */
+typedef enum
+{
+    AUDIO_HAL_PLUGIN_MSG_INVALID = 0,
+    AUDIO_HAL_PLUGIN_MSG_CODEC_ENABLE, /**< setup codec routing path */
+    AUDIO_HAL_PLUGIN_MSG_CODEC_DISABLE, /**< tear down routing path */
+    AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_VOLUME, /**< set volume */
+    AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_MUTE, /**< mute/unmute control */
+    AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_FADE, /**< fade out control */
+    AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_BALANCE, /**< left/right balance control */
+    AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_BMT, /**< base/mid/treble control */
+    AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_EQ, /**< EQ control */
+    AUDIO_HAL_PLUGIN_MSG_CODEC_TUNNEL_CMD, /**< pass through cmds */
+    AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_VOLUME, /**< get volume params */
+    AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_FADE, /**< get fade params */
+    AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_BALANCE, /**< get balance params */
+    AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_BMT, /**< get bmt params */
+    AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_EQ, /**< get EQ params */
+    AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_EQ_SUBBANDS, /**< get EQ subbands params */
+    AUDIO_HAL_PLUGIN_MSG_CODEC_TUNNEL_GET_CMD, /**< pass through get cmds */
+    AUDIO_HAL_PLUGIN_MSG_MAX
+} audio_hal_plugin_msg_type_t;
+
+/**
+ * Type of audio hal plug-in use cases
+ */
+typedef enum
+{
+    AUDIO_HAL_PLUGIN_USECASE_INVALID = -1,
+    AUDIO_HAL_PLUGIN_USECASE_DEFAULT_PLAYBACK = 0,
+    AUDIO_HAL_PLUGIN_USECASE_DEFAULT_CAPTURE,
+    AUDIO_HAL_PLUGIN_USECASE_DRIVER_SIDE_PLAYBACK,
+    AUDIO_HAL_PLUGIN_USECASE_HFP_VOICE_CALL,
+    AUDIO_HAL_PLUGIN_USECASE_CS_VOICE_CALL,
+    AUDIO_HAL_PLUGIN_USECASE_FM_TUNER,
+    AUDIO_HAL_PLUGIN_USECASE_ICC,
+    AUDIO_HAL_PLUGIN_USECASE_EC_CAPTURE,
+    AUDIO_HAL_PLUGIN_USECASE_EC_REF_CAPTURE,
+    AUDIO_HAL_PLUGIN_USECASE_ANC,
+    AUDIO_HAL_PLUGIN_USECASE_LINE_IN_PASSTHROUGH,
+    AUDIO_HAL_PLUGIN_USECASE_HDMI_IN_PASSTHROUGH,
+    AUDIO_HAL_PLUGIN_USECASE_PHONE_PLAYBACK,
+    AUDIO_HAL_PLUGIN_USECASE_MAX
+} audio_hal_plugin_usecase_type_t;
+
+/**
+ * Type of audio hal plug-in direction used in set_param
+ */
+typedef enum
+{
+    AUDIO_HAL_PLUGIN_DIRECTION_INVALID = -1,
+    AUDIO_HAL_PLUGIN_DIRECTION_PLAYBACK = 0,
+    AUDIO_HAL_PLUGIN_DIRECTION_CAPTURE,
+    AUDIO_HAL_PLUGIN_DIRECTION_MAX
+} audio_hal_plugin_direction_type_t;
+
+/**
+ * Type of query status mask
+ */
+#define QUERY_VALUE_VALID            (0x0)
+#define QUERY_VALUE_NOT_SUPPORTED    (0x1)
+#define QUERY_VALUE_NOT_SET          (0x2)
+
+/**
+ * Type of signed 32-bit bounded value used in get_param
+ */
+typedef struct audio_hal_plugin_bint32
+{
+    uint32_t query_status_mask; /**< status of returned actual value */
+    int32_t value; /**< actual value */
+    int32_t min; /**< minimum for value */
+    int32_t max; /**< maximum for value */
+} audio_hal_plugin_bint32_t;
+
+/**
+ * Type of unsigned 32-bit bounded value used in get_param
+ */
+typedef struct audio_hal_plugin_buint32
+{
+    uint32_t query_status_mask; /**< status of returned actual value */
+    uint32_t value; /**< actual value */
+    uint32_t min; /**< minimum for value */
+    uint32_t max; /**< maximum for value */
+} audio_hal_plugin_buint32_t;
+
+/**
+ * Payload of AUDIO_HAL_PLUGIN_MSG_CODEC_ENABLE message
+ */
+typedef struct audio_hal_plugin_codec_enable
+{
+    snd_device_t snd_dev;  /**< Requested endpoint device to be enabled. @enum: SND_DEVICE_XXX */
+    audio_hal_plugin_usecase_type_t usecase;
+            /**< Requested use case. @enum: AUDIO_HAL_PLUGIN_USECASE_XXX */
+    uint32_t sample_rate;  /**< Requested sample rate for the endpoint device */
+    uint32_t bit_width;  /**< Requested bit width per sample for the endpoint device */
+    uint32_t num_chs;  /**< Requested number of channels for the endpoint device */
+} audio_hal_plugin_codec_enable_t;
+
+/**
+ * Payload of AUDIO_HAL_PLUGIN_MSG_CODEC_DISABLE message
+ */
+typedef struct audio_hal_plugin_codec_disable
+{
+    snd_device_t snd_dev; /**< Requested the endpoint device to be disabled */
+    audio_hal_plugin_usecase_type_t usecase; /**< Requested use case */
+} audio_hal_plugin_codec_disable_t;
+
+/**
+ * Payload of AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_VOLUME message
+ */
+typedef struct audio_hal_plugin_codec_set_pp_vol
+{
+    snd_device_t snd_dev; /**< The requested endpoint device */
+    audio_hal_plugin_usecase_type_t usecase; /**< Requested use case */
+    audio_channel_mask_t ch_mask; /**< Requested audio channel mask */
+    uint32_t gain; /**< The requested volume setting. */
+} audio_hal_plugin_codec_set_pp_vol_t;
+
+/**
+ * Payload of AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_MUTE message
+ */
+typedef struct audio_hal_plugin_codec_set_pp_mute
+{
+    snd_device_t snd_dev; /**< The requested endpoint device */
+    audio_hal_plugin_usecase_type_t usecase; /**< Requested use case */
+    audio_channel_mask_t ch_mask; /**< Requested audio channel mask */
+    bool flag; /**< Enable/Disable mute flag. 1: mute, 0: unmute */
+} audio_hal_plugin_codec_set_pp_mute_t;
+
+/**
+ * Payload of AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_FADE message
+ */
+typedef struct audio_hal_plugin_codec_set_pp_fade
+{
+    snd_device_t snd_dev; /**< The requested endpoint device */
+    audio_hal_plugin_usecase_type_t usecase; /**< Requested use case */
+    int32_t fade; /**< The requested fade configuration. */
+} audio_hal_plugin_codec_set_pp_fade_t;
+
+/**
+ * Payload of AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_BALANCE message
+ */
+typedef struct audio_hal_plugin_codec_set_pp_balance
+{
+    snd_device_t snd_dev; /**< The requested endpoint device */
+    audio_hal_plugin_usecase_type_t usecase; /**< Requested use case */
+    int32_t balance; /**< The requested balance configuration. */
+} audio_hal_plugin_codec_set_pp_balance_t;
+
+/**
+ * Payload of AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_BMT message
+ */
+typedef enum
+{
+    AUDIO_HAL_PLUGIN_CODEC_PP_FILTER_TYPE_INVALID = 0,
+    AUDIO_HAL_PLUGIN_CODEC_PP_FILTER_TYPE_BASS,
+    AUDIO_HAL_PLUGIN_CODEC_PP_FILTER_TYPE_MID,
+    AUDIO_HAL_PLUGIN_CODEC_PP_FILTER_TYPE_TREBLE,
+    AUDIO_HAL_PLUGIN_CODEC_PP_FILTER_TYPE_MAX
+} audio_hal_plugin_codec_pp_filter_type_t;
+
+typedef struct audio_hal_plugin_codec_set_pp_bmt
+{
+    snd_device_t snd_dev; /**< The requested endpoint device */
+    audio_hal_plugin_usecase_type_t usecase; /**< Requested use case */
+    audio_hal_plugin_codec_pp_filter_type_t filter_type; /**< Requested filter type */
+    bool enable_flag; /**< Enable flag. 0 - Disable, 1 - Enable */
+    int32_t value; /**< Requested value to be set */
+} audio_hal_plugin_codec_set_pp_bmt_t;
+
+/**
+ * Payload of AUDIO_HAL_PLUGIN_MSG_CODEC_SET_PP_EQ message
+ */
+typedef struct audio_hal_plugin_codec_pp_eq_subband
+{
+    uint32_t band_idx; /**< Band index. Supported value: 0 to (num_bands - 1) */
+    uint32_t center_freq; /**< Filter band center frequency in millihertz */
+    int32_t band_level; /**< Filter band gain in millibels */
+} audio_hal_plugin_codec_pp_eq_subband_t;
+
+typedef struct audio_hal_plugin_codec_set_pp_eq
+{
+    snd_device_t snd_dev; /**< The requested endpoint device */
+    audio_hal_plugin_usecase_type_t usecase; /**< Requested use case */
+    bool enable_flag; /**< Enable flag. 0 - Disable, 1 - Enable */
+    int32_t preset_id; /**< Specify to use either pre-defined preset EQ or
+                                        user-customized equalizers:
+                                        -1      - custom equalizer speficied through 'bands' struct
+                                        0 to N - pre-defined preset EQ index: ROCK/JAZZ/POP, etc */
+    uint32_t num_bands; /**< Number of EQ subbands when a custom preset_id is selected */
+    audio_hal_plugin_codec_pp_eq_subband_t *bands; /**< Equalizer sub-band struct list */
+} audio_hal_plugin_codec_set_pp_eq_t;
+
+/**
+ * Payload of AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_VOLUME message
+ */
+typedef struct audio_hal_plugin_codec_get_pp_vol
+{
+    snd_device_t snd_dev; /**< Requested endpoint device */
+    audio_hal_plugin_usecase_type_t usecase; /**< Requested use case */
+    audio_channel_mask_t ch_mask; /**< Requested audio channel mask */
+    audio_hal_plugin_buint32_t ret_gain; /**< Returned volume range and value */
+} audio_hal_plugin_codec_get_pp_vol_t;
+
+/**
+ * Payload of AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_FADE message
+ */
+typedef struct audio_hal_plugin_codec_get_pp_fade
+{
+    snd_device_t snd_dev; /**< The requested endpoint device */
+    audio_hal_plugin_usecase_type_t usecase; /**< Requested use case */
+    audio_hal_plugin_bint32_t ret_fade; /**< Returned fade range and value. */
+} audio_hal_plugin_codec_get_pp_fade_t;
+
+/**
+ * Payload of AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_BALANCE message
+ */
+typedef struct audio_hal_plugin_codec_get_pp_balance
+{
+    snd_device_t snd_dev; /**< The requested endpoint device */
+    audio_hal_plugin_usecase_type_t usecase; /**< Requested use case */
+    audio_hal_plugin_bint32_t ret_balance; /**< Returned balance range and value. */
+} audio_hal_plugin_codec_get_pp_balance_t;
+
+/**
+ * Payload of AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_BMT message
+ */
+typedef struct audio_hal_plugin_codec_get_pp_bmt
+{
+    snd_device_t snd_dev; /**< The requested endpoint device */
+    audio_hal_plugin_usecase_type_t usecase; /**< Requested use case */
+    audio_hal_plugin_codec_pp_filter_type_t filter_type; /**< Requested filter type */
+    audio_hal_plugin_bint32_t ret_value; /**< Returned range and value */
+} audio_hal_plugin_codec_get_pp_bmt_t;
+
+/**
+ * Payload of AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_EQ message
+ */
+typedef struct audio_hal_plugin_codec_get_pp_eq
+{
+    snd_device_t snd_dev; /**< The requested endpoint device */
+    audio_hal_plugin_usecase_type_t usecase; /**< Requested use case */
+    audio_hal_plugin_bint32_t ret_preset_id; /**< Returned preset id
+                                        -1      - custom equalizer speficied through 'bands' struct
+                                        0 to N - pre-defined preset EQ index: ROCK/JAZZ/POP, etc */
+    uint32_t ret_num_bands; /**< Returned number of EQ subbands supported
+                                          when a custom preset_id is selected */
+} audio_hal_plugin_codec_get_pp_eq_t;
+
+/**
+ * Eq_subband struct used in the following payload
+ */
+typedef struct audio_hal_plugin_pp_eq_subband_binfo
+{
+    audio_hal_plugin_buint32_t ret_center_freq; /**< Returned band center frequency range
+                                                                                            and value in millihertz */
+    audio_hal_plugin_bint32_t ret_band_level; /**< Returned band gain range and value in millibels */
+} audio_hal_plugin_pp_eq_subband_binfo_t;
+
+/**
+ * Payload of AUDIO_HAL_PLUGIN_MSG_CODEC_GET_PP_EQ_SUBBANDS message
+ */
+typedef struct audio_hal_plugin_codec_get_pp_eq_subbands
+{
+    snd_device_t snd_dev; /**< The requested endpoint device */
+    audio_hal_plugin_usecase_type_t usecase; /**< Requested use case */
+    uint32_t num_bands; /**< number of EQ subbands supported for custom eq
+                                          returned from get_pp_eq query */
+    audio_hal_plugin_pp_eq_subband_binfo_t *ret_bands; /**< Returned subband info list */
+} audio_hal_plugin_codec_get_pp_eq_subbands_t;
+
+/**
+ * Payload of AUDIO_HAL_PLUGIN_MSG_CODEC_TUNNEL_GET_CMD message
+ */
+typedef struct audio_hal_plugin_codec_tunnel_get
+{
+    int32_t *param_data; /**< Request param data from client */
+    uint32_t param_size; /**< Request 32-bit data size from client */
+    uint32_t size_to_get; /**< Expected 32-bit data size to get from cleint */
+    int32_t *ret_data; /**< Returned data */
+    uint32_t ret_size; /**< Returned 32-bit data size */
+} audio_hal_plugin_codec_tunnel_get_t;
+
+/**
+ * Initialize the audio hal plug-in module and underlying hw driver
+ * One time call at audio hal boot up time
+ */
+int32_t audio_hal_plugin_init (void);
+
+/**
+ * De-Initialize the audio hal plug-in module and underlying hw driver
+ * One time call when audio hal get unloaded from system
+ */
+int32_t audio_hal_plugin_deinit (void);
+
+/**
+ * Function to invoke the underlying HW driver realizing the functionality for a given use case.
+ */
+int32_t audio_hal_plugin_send_msg (
+             audio_hal_plugin_msg_type_t msg,
+             void * payload, uint32_t payload_size);
+
+#if defined(__cplusplus)
+}  /* extern "C" */
+#endif
+
+#endif
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 78f2560..d35ff0d 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -966,6 +966,7 @@
     snd_device_t snd_device;
     char mixer_path[MIXER_PATH_MAX_LENGTH];
     struct stream_out *out = NULL;
+    int ret = 0;
 
     if (usecase == NULL)
         return -EINVAL;
@@ -995,7 +996,14 @@
     strlcpy(mixer_path, use_case_table[usecase->id], MIXER_PATH_MAX_LENGTH);
     platform_add_backend_name(mixer_path, snd_device, usecase);
     ALOGD("%s: apply mixer and update path: %s", __func__, mixer_path);
-    audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+    ret = audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+    if (!ret && usecase->id == USECASE_AUDIO_PLAYBACK_FM) {
+        struct str_parms *parms = str_parms_create_str("fm_restore_volume=1");
+        if (parms) {
+            audio_extn_fm_set_parameters(adev, parms);
+            str_parms_destroy(parms);
+        }
+    }
     ALOGV("%s: exit", __func__);
     return 0;
 }
@@ -1477,11 +1485,6 @@
                                             usecase->stream.out->volume_l,
                                             usecase->stream.out->volume_r);
                     }
-                    if (usecase->id == USECASE_AUDIO_PLAYBACK_FM) {
-                        struct str_parms *parms = str_parms_create_str("fm_restore_volume=1");
-                        if (parms)
-                            audio_extn_fm_set_parameters(adev, parms);
-                    }
                 }
             }
         }
@@ -2419,6 +2422,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);
 
@@ -2514,6 +2522,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)
@@ -2934,6 +2947,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)
@@ -3122,6 +3140,11 @@
                 out->usecase == USECASE_INCALL_MUSIC_UPLINK2)
         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);
 
@@ -5846,7 +5869,7 @@
         ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
         return ret;
     }
-    position->time_nanoseconds = ts.tv_sec*1000000000L + ts.tv_nsec;
+    position->time_nanoseconds = ts.tv_sec*1000000000LL + ts.tv_nsec;
     return 0;
 }
 
@@ -6950,6 +6973,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;
@@ -7483,6 +7508,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;
     }
@@ -7736,6 +7763,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 202e09a..c13ca56 100755
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -536,6 +536,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 b8554f5..bae45b3 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -2561,6 +2561,26 @@
     my_data->current_backend_cfg[HDMI_TX_BACKEND].channels_mixer_ctl =
         strdup("QUAT_MI2S_TX Channels");
 
+    my_data->current_backend_cfg[HDMI_RX_BACKEND].bitwidth_mixer_ctl =
+        strdup("HDMI_RX Bit Format");
+    my_data->current_backend_cfg[HDMI_RX_BACKEND].samplerate_mixer_ctl =
+        strdup("HDMI_RX SampleRate");
+    my_data->current_backend_cfg[HDMI_RX_BACKEND].channels_mixer_ctl =
+        strdup("HDMI_RX Channels");
+    my_data->current_backend_cfg[DISP_PORT_RX_BACKEND].bitwidth_mixer_ctl =
+        strdup("Display Port RX Bit Format");
+    my_data->current_backend_cfg[DISP_PORT_RX_BACKEND].samplerate_mixer_ctl =
+        strdup("Display Port RX SampleRate");
+    my_data->current_backend_cfg[DISP_PORT_RX_BACKEND].channels_mixer_ctl =
+        strdup("Display Port RX Channels");
+
+    my_data->current_backend_cfg[USB_AUDIO_RX_BACKEND].bitwidth_mixer_ctl =
+        strdup("USB_AUDIO_RX Format");
+    my_data->current_backend_cfg[USB_AUDIO_RX_BACKEND].samplerate_mixer_ctl =
+        strdup("USB_AUDIO_RX SampleRate");
+    my_data->current_backend_cfg[USB_AUDIO_RX_BACKEND].channels_mixer_ctl =
+        strdup("USB_AUDIO_RX Channels");
+
     for (idx = 0; idx < MAX_CODEC_BACKENDS; idx++) {
         if (my_data->current_backend_cfg[idx].bitwidth_mixer_ctl) {
             ctl = mixer_get_ctl_by_name(adev->mixer,
@@ -2620,26 +2640,6 @@
         }
     }
 
-    my_data->current_backend_cfg[HDMI_RX_BACKEND].bitwidth_mixer_ctl =
-        strdup("HDMI_RX Bit Format");
-    my_data->current_backend_cfg[HDMI_RX_BACKEND].samplerate_mixer_ctl =
-        strdup("HDMI_RX SampleRate");
-    my_data->current_backend_cfg[HDMI_RX_BACKEND].channels_mixer_ctl =
-        strdup("HDMI_RX Channels");
-    my_data->current_backend_cfg[DISP_PORT_RX_BACKEND].bitwidth_mixer_ctl =
-        strdup("Display Port RX Bit Format");
-    my_data->current_backend_cfg[DISP_PORT_RX_BACKEND].samplerate_mixer_ctl =
-        strdup("Display Port RX SampleRate");
-    my_data->current_backend_cfg[DISP_PORT_RX_BACKEND].channels_mixer_ctl =
-        strdup("Display Port RX Channels");
-
-    my_data->current_backend_cfg[USB_AUDIO_RX_BACKEND].bitwidth_mixer_ctl =
-        strdup("USB_AUDIO_RX Format");
-    my_data->current_backend_cfg[USB_AUDIO_RX_BACKEND].samplerate_mixer_ctl =
-        strdup("USB_AUDIO_RX SampleRate");
-    my_data->current_backend_cfg[USB_AUDIO_RX_BACKEND].channels_mixer_ctl =
-        strdup("USB_AUDIO_RX Channels");
-
     if (property_get_bool("vendor.audio.apptype.multirec.enabled", false))
         my_data->use_generic_handset = true;
 
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 5fbff5f..23953e6 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -492,6 +492,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