audio: msm8909w caf release LW.BR.1.0-00410-8x09w.0

MSM8909w Audio HAL code copied from CAF release
LW.BR.1.0-00410-8x09w.0

dbcce50 hal: Port wcd9326 changes to 8909
410c530 hal: update error handling for pcm_prepare failures
ff79309 hal: fix compilation issues with audio FM extention
762d7eb policy_hal: add support for fm device loopback
7c418f9 audio_policy: modify few methods to appropriately override base
8b12163 audio: Add support to enable split A2DP
a0559fa Revert "Revert "policy_hal: Function prototype correction for custom policy"."

Fixed makefiles to be compatible with PDK without kernel source

Change-Id: I9c6f2139adee62426b877516deeb41d4ed8052b2
diff --git a/msm8909/hal/Android.mk b/msm8909/hal/Android.mk
new file mode 100644
index 0000000..7bb59ae
--- /dev/null
+++ b/msm8909/hal/Android.mk
@@ -0,0 +1,251 @@
+ifeq ($(strip $(BOARD_USES_ALSA_AUDIO)),true)
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_ARM_MODE := arm
+
+AUDIO_PLATFORM := $(TARGET_BOARD_PLATFORM)
+
+ifneq ($(filter msm8974 msm8226 msm8610 apq8084 msm8994,$(TARGET_BOARD_PLATFORM)),)
+  # B-family platform uses msm8974 code base
+  AUDIO_PLATFORM = msm8974
+  MULTIPLE_HW_VARIANTS_ENABLED := true
+ifneq ($(filter msm8610,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_CFLAGS := -DPLATFORM_MSM8610
+endif
+ifneq ($(filter msm8226,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_CFLAGS := -DPLATFORM_MSM8x26
+endif
+ifneq ($(filter apq8084,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_CFLAGS := -DPLATFORM_APQ8084
+endif
+ifneq ($(filter msm8994,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_CFLAGS := -DPLATFORM_MSM8994
+endif
+endif
+
+ifneq ($(filter msm8916 msm8909,$(TARGET_BOARD_PLATFORM)),)
+  AUDIO_PLATFORM = msm8916
+  MULTIPLE_HW_VARIANTS_ENABLED := true
+  LOCAL_CFLAGS := -DPLATFORM_MSM8916
+ifneq ($(filter msm8909,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_CFLAGS := -DPLATFORM_MSM8909
+endif
+endif
+
+LOCAL_SRC_FILES := \
+	audio_hw.c \
+	voice.c \
+	platform_info.c \
+	$(AUDIO_PLATFORM)/platform.c
+
+LOCAL_SRC_FILES += audio_extn/audio_extn.c \
+                   audio_extn/utils.c
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PCM_OFFLOAD)),true)
+    LOCAL_CFLAGS += -DPCM_OFFLOAD_ENABLED
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_ANC_HEADSET)),true)
+    LOCAL_CFLAGS += -DANC_HEADSET_ENABLED
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_FLUENCE)),true)
+    LOCAL_CFLAGS += -DFLUENCE_ENABLED
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PROXY_DEVICE)),true)
+    LOCAL_CFLAGS += -DAFE_PROXY_ENABLED
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_KPI_OPTIMIZE)),true)
+    LOCAL_CFLAGS += -DKPI_OPTIMIZE_ENABLED
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_FM_POWER_OPT)),true)
+    LOCAL_CFLAGS += -DFM_POWER_OPT
+    LOCAL_SRC_FILES += audio_extn/fm.c
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_USBAUDIO)),true)
+    LOCAL_CFLAGS += -DUSB_HEADSET_ENABLED
+    LOCAL_SRC_FILES += audio_extn/usb.c
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HFP)),true)
+    LOCAL_CFLAGS += -DHFP_ENABLED
+    LOCAL_SRC_FILES += audio_extn/hfp.c
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_CUSTOMSTEREO)),true)
+    LOCAL_CFLAGS += -DCUSTOM_STEREO_ENABLED
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_SSR)),true)
+    LOCAL_CFLAGS += -DSSR_ENABLED
+    LOCAL_SRC_FILES += audio_extn/ssr.c
+    LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/surround_sound/
+    LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/common/inc/
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_MULTI_VOICE_SESSIONS)),true)
+    LOCAL_CFLAGS += -DMULTI_VOICE_SESSION_ENABLED
+    LOCAL_SRC_FILES += voice_extn/voice_extn.c
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_INCALL_MUSIC)),true)
+    LOCAL_CFLAGS += -DINCALL_MUSIC_ENABLED
+endif
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_COMPRESS_VOIP)),true)
+    LOCAL_CFLAGS += -DCOMPRESS_VOIP_ENABLED
+    LOCAL_SRC_FILES += voice_extn/compress_voip.c
+endif
+
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXTN_FORMATS)),true)
+LOCAL_CFLAGS += -DFORMATS_ENABLED
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_SPKR_PROTECTION)),true)
+    LOCAL_CFLAGS += -DSPKR_PROT_ENABLED
+    LOCAL_SRC_FILES += audio_extn/spkr_protection.c
+endif
+
+ifdef MULTIPLE_HW_VARIANTS_ENABLED
+  LOCAL_CFLAGS += -DHW_VARIANTS_ENABLED
+  LOCAL_SRC_FILES += $(AUDIO_PLATFORM)/hw_info.c
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_COMPRESS_CAPTURE)),true)
+    LOCAL_CFLAGS += -DCOMPRESS_CAPTURE_ENABLED
+    LOCAL_SRC_FILES += audio_extn/compress_capture.c
+endif
+
+ifeq ($(strip $(DOLBY_DDP)),true)
+    LOCAL_CFLAGS += -DDS1_DOLBY_DDP_ENABLED
+    LOCAL_SRC_FILES += audio_extn/dolby.c
+endif
+
+ifeq ($(strip $(DOLBY_DAP)),true)
+    LOCAL_CFLAGS += -DDS1_DOLBY_DAP_ENABLED
+ifneq ($(strip $(DOLBY_DDP)),true)
+    LOCAL_SRC_FILES += audio_extn/dolby.c
+endif
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_MULTIPLE_TUNNEL)), true)
+    LOCAL_CFLAGS += -DMULTIPLE_OFFLOAD_ENABLED
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXTN_FLAC_DECODER)),true)
+    LOCAL_CFLAGS += -DFLAC_OFFLOAD_ENABLED
+    LOCAL_CFLAGS += -DCOMPRESS_METADATA_NEEDED
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_VORBIS_OFFLOAD)),true)
+    LOCAL_CFLAGS += -DVORBIS_OFFLOAD_ENABLED
+    LOCAL_CFLAGS += -DCOMPRESS_METADATA_NEEDED
+
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_WMA_OFFLOAD)),true)
+    LOCAL_CFLAGS += -DWMA_OFFLOAD_ENABLED
+    LOCAL_CFLAGS += -DCOMPRESS_METADATA_NEEDED
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_ALAC_OFFLOAD)),true)
+    LOCAL_CFLAGS += -DALAC_OFFLOAD_ENABLED
+    LOCAL_CFLAGS += -DCOMPRESS_METADATA_NEEDED
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_APE_OFFLOAD)),true)
+    LOCAL_CFLAGS += -DAPE_OFFLOAD_ENABLED
+    LOCAL_CFLAGS += -DCOMPRESS_METADATA_NEEDED
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_DEV_ARBI)),true)
+    LOCAL_CFLAGS += -DDEV_ARBI_ENABLED
+    LOCAL_SRC_FILES += audio_extn/dev_arbi.c
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_RECORD_PLAY_CONCURRENCY)),true)
+    LOCAL_CFLAGS += -DRECORD_PLAY_CONCURRENCY
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_ACDB_LICENSE)), true)
+    LOCAL_CFLAGS += -DDOLBY_ACDB_LICENSE
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_DS2_DOLBY_DAP)),true)
+    LOCAL_CFLAGS += -DDS2_DOLBY_DAP_ENABLED
+ifneq ($(strip $(DOLBY_DDP)),true)
+    ifneq ($(strip $(DOLBY_DAP)),true)
+        LOCAL_SRC_FILES += audio_extn/dolby.c
+    endif
+endif
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_SPLIT_A2DP)),true)
+    LOCAL_CFLAGS += -DSPLIT_A2DP_ENABLED
+    LOCAL_SRC_FILES += audio_extn/a2dp.c
+endif
+
+
+LOCAL_SHARED_LIBRARIES := \
+	liblog \
+	libcutils \
+	libtinyalsa \
+	libtinycompress \
+	libaudioroute \
+	libdl \
+	libhardware \
+	libexpat
+
+LOCAL_C_INCLUDES += \
+	external/tinyalsa/include \
+	external/tinycompress/include \
+	external/expat/lib \
+	$(call include-path-for, audio-route) \
+	$(call include-path-for, audio-effects) \
+	$(LOCAL_PATH)/$(AUDIO_PLATFORM) \
+	$(LOCAL_PATH)/audio_extn \
+	$(LOCAL_PATH)/voice_extn
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_LISTEN)),true)
+    LOCAL_CFLAGS += -DAUDIO_LISTEN_ENABLED
+    LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audio-listen
+    LOCAL_SRC_FILES += audio_extn/listen.c
+endif
+
+ifeq ($(strip $(BOARD_SUPPORTS_SOUND_TRIGGER)),true)
+    LOCAL_CFLAGS += -DSOUND_TRIGGER_ENABLED
+    LOCAL_CFLAGS += -DSOUND_TRIGGER_PLATFORM_NAME=$(TARGET_BOARD_PLATFORM)
+    LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/sound_trigger
+    LOCAL_SRC_FILES += audio_extn/soundtrigger.c
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_AUXPCM_BT)),true)
+    LOCAL_CFLAGS += -DAUXPCM_BT_ENABLED
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PM_SUPPORT)),true)
+    LOCAL_CFLAGS += -DPM_SUPPORT_ENABLED
+    LOCAL_SRC_FILES += audio_extn/pm.c
+    LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/libperipheralclient/inc
+    LOCAL_SHARED_LIBRARIES += libperipheral_client
+endif
+
+LOCAL_COPY_HEADERS_TO   := mm-audio
+LOCAL_COPY_HEADERS      := audio_extn/audio_defs.h
+
+LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM)
+
+LOCAL_MODULE_RELATIVE_PATH := hw
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/msm8909/hal/audio_extn/a2dp.c b/msm8909/hal/audio_extn/a2dp.c
new file mode 100644
index 0000000..6b22b69
--- /dev/null
+++ b/msm8909/hal/audio_extn/a2dp.c
@@ -0,0 +1,201 @@
+/*
+* Copyright (c) 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.
+*/
+#define LOG_TAG "split_a2dp"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+#include <errno.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include <stdlib.h>
+#include <cutils/str_parms.h>
+#include <hardware/audio.h>
+#include <hardware/hardware.h>
+
+#ifdef SPLIT_A2DP_ENABLED
+
+struct a2dp_data{
+    struct audio_stream_out *a2dp_stream;
+    struct audio_hw_device *a2dp_device;
+    bool a2dp_started;
+    bool a2dp_suspended;
+};
+
+struct a2dp_data a2dp;
+
+#define AUDIO_PARAMETER_A2DP_STARTED "A2dpStarted"
+
+static int open_a2dp_output()
+{
+    hw_module_t *mod;
+    int      format = AUDIO_FORMAT_PCM_16_BIT;
+    int rc=0;
+    uint32_t channels = AUDIO_CHANNEL_OUT_STEREO;
+    uint32_t sampleRate = DEFAULT_OUTPUT_SAMPLING_RATE;
+    struct audio_config config;
+
+    ALOGV("open_a2dp_output");
+
+    config.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+    config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+    config.format = AUDIO_FORMAT_PCM_16_BIT;
+
+    if (a2dp.a2dp_device == NULL){
+        rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, (const char*)"a2dp",
+                                    (const hw_module_t**)&mod);
+        if (rc != 0) {
+            ALOGE("Could not get a2dp hardware module");
+            return rc;
+        }
+        ALOGV("Opening A2DP device HAL for the first time");
+        rc = audio_hw_device_open(mod, &a2dp.a2dp_device);
+        if (rc != 0) {
+            ALOGE("couldn't open a2dp audio hw device");
+            return rc;
+        }
+    }
+
+    rc = a2dp.a2dp_device->open_output_stream(a2dp.a2dp_device, 0,AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
+                                    (audio_output_flags_t)AUDIO_OUTPUT_FLAG_NONE, &config, &a2dp.a2dp_stream, NULL);
+
+    if( rc != 0 ) {
+        ALOGE("Failed to open output stream for a2dp: status %d", rc);
+    }
+
+    a2dp.a2dp_suspended = false;
+    return rc;
+}
+
+static int close_a2dp_output()
+{
+
+    ALOGV("close_a2dp_output");
+    if(!a2dp.a2dp_device && !a2dp.a2dp_stream){
+        ALOGE("No Active A2dp output found");
+        return 0;
+    }
+
+    a2dp.a2dp_device->close_output_stream(a2dp.a2dp_device, a2dp.a2dp_stream);
+    a2dp.a2dp_stream = NULL;
+    a2dp.a2dp_started = false;
+    a2dp.a2dp_suspended = true;
+
+    return 0;
+}
+
+void audio_extn_a2dp_set_parameters(struct str_parms *parms)
+{
+     int ret, val;
+     char value[32]={0};
+
+     ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value,
+                            sizeof(value));
+     if( ret >= 0) {
+         val = atoi(value);
+         if (val & AUDIO_DEVICE_OUT_ALL_A2DP) {
+             ALOGV("Received device connect request for A2DP");
+             open_a2dp_output();
+         }
+     }
+
+     ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value,
+                         sizeof(value));
+
+     if( ret >= 0) {
+         val = atoi(value);
+         if (val & AUDIO_DEVICE_OUT_ALL_A2DP) {
+             ALOGV("Received device dis- connect request");
+             close_a2dp_output();
+         }
+     }
+
+     ret = str_parms_get_str(parms, "A2dpSuspended", value, sizeof(value));
+     if (ret >= 0) {
+         if (a2dp.a2dp_device && a2dp.a2dp_stream) {
+             a2dp.a2dp_device->set_parameters(a2dp.a2dp_device, str_parms_to_str(parms));
+             if (!strncmp(value,"true",sizeof(value))) {
+                 a2dp.a2dp_suspended = true;
+             } else {
+                 a2dp.a2dp_suspended = false;
+             }
+         }
+     }
+}
+
+void audio_extn_a2dp_start_playback()
+{
+    int ret = 0;
+    char buf[20]={0};
+
+    if (!a2dp.a2dp_started && a2dp.a2dp_device && a2dp.a2dp_stream) {
+
+         snprintf(buf,sizeof(buf),"%s=true",AUDIO_PARAMETER_A2DP_STARTED);
+        /* This call indicates BT HAL to start playback */
+        ret =  a2dp.a2dp_device->set_parameters(a2dp.a2dp_device, buf);
+        if (ret < 0 ) {
+           ALOGE("BT controller start failed, retry on the next write");
+           a2dp.a2dp_started = false;
+        } else {
+           a2dp.a2dp_started = true;
+           ALOGV("Start playback successful to BT HAL");
+        }
+    }
+}
+
+void audio_extn_a2dp_stop_playback()
+{
+    int ret =0;
+    char buf[20]={0};
+
+    if ( a2dp.a2dp_started && a2dp.a2dp_device && a2dp.a2dp_stream) {
+
+       snprintf(buf,sizeof(buf),"%s=false",AUDIO_PARAMETER_A2DP_STARTED);
+
+        ret = a2dp.a2dp_device->set_parameters(a2dp.a2dp_device, buf);
+
+        if (ret < 0)
+            ALOGE("out_standby to BT HAL failed");
+        else
+            ALOGV("out_standby to BT HAL successful");
+
+    }
+    a2dp.a2dp_started = false;
+    a2dp.a2dp_suspended = true;
+}
+
+void audio_extn_a2dp_init ()
+{
+  a2dp.a2dp_started = false;
+  a2dp.a2dp_suspended = true;
+  a2dp.a2dp_stream = NULL;
+  a2dp.a2dp_device = NULL;
+}
+#endif // SPLIT_A2DP_ENABLED
diff --git a/msm8909/hal/audio_extn/audio_defs.h b/msm8909/hal/audio_extn/audio_defs.h
new file mode 100644
index 0000000..cedb2a6
--- /dev/null
+++ b/msm8909/hal/audio_extn/audio_defs.h
@@ -0,0 +1,105 @@
+/*
+ * 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_DEFS_H
+#define AUDIO_DEFS_H
+
+
+/**
+ * extended audio codec parameters
+ */
+
+#define AUDIO_OFFLOAD_CODEC_WMA_FORMAT_TAG "music_offload_wma_format_tag"
+#define AUDIO_OFFLOAD_CODEC_WMA_BLOCK_ALIGN "music_offload_wma_block_align"
+#define AUDIO_OFFLOAD_CODEC_WMA_BIT_PER_SAMPLE "music_offload_wma_bit_per_sample"
+#define AUDIO_OFFLOAD_CODEC_WMA_CHANNEL_MASK "music_offload_wma_channel_mask"
+#define AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION "music_offload_wma_encode_option"
+#define AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION1 "music_offload_wma_encode_option1"
+#define AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION2 "music_offload_wma_encode_option2"
+#define AUDIO_OFFLOAD_CODEC_FORMAT  "music_offload_codec_format"
+#define AUDIO_OFFLOAD_CODEC_FLAC_MIN_BLK_SIZE "music_offload_flac_min_blk_size"
+#define AUDIO_OFFLOAD_CODEC_FLAC_MAX_BLK_SIZE "music_offload_flac_max_blk_size"
+#define AUDIO_OFFLOAD_CODEC_FLAC_MIN_FRAME_SIZE "music_offload_flac_min_frame_size"
+#define AUDIO_OFFLOAD_CODEC_FLAC_MAX_FRAME_SIZE "music_offload_flac_max_frame_size"
+
+#define AUDIO_OFFLOAD_CODEC_ALAC_FRAME_LENGTH "music_offload_alac_frame_length"
+#define AUDIO_OFFLOAD_CODEC_ALAC_COMPATIBLE_VERSION "music_offload_alac_compatible_version"
+#define AUDIO_OFFLOAD_CODEC_ALAC_BIT_DEPTH "music_offload_alac_bit_depth"
+#define AUDIO_OFFLOAD_CODEC_ALAC_PB "music_offload_alac_pb"
+#define AUDIO_OFFLOAD_CODEC_ALAC_MB "music_offload_alac_mb"
+#define AUDIO_OFFLOAD_CODEC_ALAC_KB "music_offload_alac_kb"
+#define AUDIO_OFFLOAD_CODEC_ALAC_NUM_CHANNELS "music_offload_alac_num_channels"
+#define AUDIO_OFFLOAD_CODEC_ALAC_MAX_RUN "music_offload_alac_max_run"
+#define AUDIO_OFFLOAD_CODEC_ALAC_MAX_FRAME_BYTES "music_offload_alac_max_frame_bytes"
+#define AUDIO_OFFLOAD_CODEC_ALAC_AVG_BIT_RATE "music_offload_alac_avg_bit_rate"
+#define AUDIO_OFFLOAD_CODEC_ALAC_SAMPLING_RATE "music_offload_alac_sampling_rate"
+#define AUDIO_OFFLOAD_CODEC_ALAC_CHANNEL_LAYOUT_TAG "music_offload_alac_channel_layout_tag"
+
+#define AUDIO_OFFLOAD_CODEC_APE_COMPATIBLE_VERSION "music_offload_ape_compatible_version"
+#define AUDIO_OFFLOAD_CODEC_APE_COMPRESSION_LEVEL "music_offload_ape_compression_level"
+#define AUDIO_OFFLOAD_CODEC_APE_FORMAT_FLAGS "music_offload_ape_format_flags"
+#define AUDIO_OFFLOAD_CODEC_APE_BLOCKS_PER_FRAME "music_offload_ape_blocks_per_frame"
+#define AUDIO_OFFLOAD_CODEC_APE_FINAL_FRAME_BLOCKS "music_offload_ape_final_frame_blocks"
+#define AUDIO_OFFLOAD_CODEC_APE_TOTAL_FRAMES "music_offload_ape_total_frames"
+#define AUDIO_OFFLOAD_CODEC_APE_BITS_PER_SAMPLE "music_offload_ape_bits_per_sample"
+#define AUDIO_OFFLOAD_CODEC_APE_NUM_CHANNELS "music_offload_ape_num_channels"
+#define AUDIO_OFFLOAD_CODEC_APE_SAMPLE_RATE "music_offload_ape_sample_rate"
+#define AUDIO_OFFLOAD_CODEC_APE_SEEK_TABLE_PRESENT "music_offload_seek_table_present"
+
+#define AUDIO_OFFLOAD_CODEC_VORBIS_BITSTREAM_FMT "music_offload_vorbis_bitstream_fmt"
+/* Query handle fm parameter*/
+#define AUDIO_PARAMETER_KEY_HANDLE_FM "handle_fm"
+
+/* Query fm volume */
+#define AUDIO_PARAMETER_KEY_FM_VOLUME "fm_volume"
+
+/* Query Fluence type */
+#define AUDIO_PARAMETER_KEY_FLUENCE "fluence"
+#define AUDIO_PARAMETER_VALUE_QUADMIC "quadmic"
+#define AUDIO_PARAMETER_VALUE_DUALMIC "dualmic"
+#define AUDIO_PARAMETER_KEY_NO_FLUENCE "none"
+
+/* Query if surround sound recording is supported */
+#define AUDIO_PARAMETER_KEY_SSR "ssr"
+
+/* Query if a2dp  is supported */
+#define AUDIO_PARAMETER_KEY_HANDLE_A2DP_DEVICE "isA2dpDeviceSupported"
+
+/* Query ADSP Status */
+#define AUDIO_PARAMETER_KEY_ADSP_STATUS "ADSP_STATUS"
+
+/* Query Sound Card Status */
+#define AUDIO_PARAMETER_KEY_SND_CARD_STATUS "SND_CARD_STATUS"
+
+/* Query if Proxy can be Opend */
+#define AUDIO_PARAMETER_KEY_CAN_OPEN_PROXY "can_open_proxy"
+
+#define AUDIO_PARAMETER_IS_HW_DECODER_SESSION_ALLOWED  "is_hw_dec_session_allowed"
+
+#endif /* AUDIO_DEFS_H */
diff --git a/msm8909/hal/audio_extn/audio_extn.c b/msm8909/hal/audio_extn/audio_extn.c
new file mode 100644
index 0000000..043177c
--- /dev/null
+++ b/msm8909/hal/audio_extn/audio_extn.c
@@ -0,0 +1,810 @@
+/*
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_extn"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <stdlib.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <cutils/properties.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "audio_extn.h"
+#include "platform.h"
+#include "platform_api.h"
+
+#include "sound/compress_params.h"
+
+#define MAX_SLEEP_RETRY 100
+#define WIFI_INIT_WAIT_SLEEP 50
+
+struct audio_extn_module {
+    bool anc_enabled;
+    bool aanc_enabled;
+    bool custom_stereo_enabled;
+    uint32_t proxy_channel_num;
+};
+
+static struct audio_extn_module aextnmod = {
+    .anc_enabled = 0,
+    .aanc_enabled = 0,
+    .custom_stereo_enabled = 0,
+    .proxy_channel_num = 2,
+};
+
+#define AUDIO_PARAMETER_KEY_ANC        "anc_enabled"
+#define AUDIO_PARAMETER_KEY_WFD        "wfd_channel_cap"
+#define AUDIO_PARAMETER_CAN_OPEN_PROXY "can_open_proxy"
+#define AUDIO_PARAMETER_CUSTOM_STEREO  "stereo_as_dual_mono"
+/* Query offload playback instances count */
+#define AUDIO_PARAMETER_OFFLOAD_NUM_ACTIVE "offload_num_active"
+
+#ifndef FM_POWER_OPT
+#define audio_extn_fm_set_parameters(adev, parms) (0)
+#else
+void audio_extn_fm_set_parameters(struct audio_device *adev,
+                                   struct str_parms *parms);
+#endif
+#ifndef HFP_ENABLED
+#define audio_extn_hfp_set_parameters(adev, parms) (0)
+#else
+void audio_extn_hfp_set_parameters(struct audio_device *adev,
+                                           struct str_parms *parms);
+#endif
+
+#ifndef CUSTOM_STEREO_ENABLED
+#define audio_extn_customstereo_set_parameters(adev, parms)         (0)
+#else
+void audio_extn_customstereo_set_parameters(struct audio_device *adev,
+                                           struct str_parms *parms)
+{
+    int ret = 0;
+    char value[32]={0};
+    bool custom_stereo_state = false;
+    const char *mixer_ctl_name = "Set Custom Stereo OnOff";
+    struct mixer_ctl *ctl;
+
+    ALOGV("%s", __func__);
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_CUSTOM_STEREO, value,
+                            sizeof(value));
+    if (ret >= 0) {
+        if (!strncmp("true", value, sizeof("true")) || atoi(value))
+            custom_stereo_state = true;
+
+        if (custom_stereo_state == aextnmod.custom_stereo_enabled)
+            return;
+
+        ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+        if (!ctl) {
+            ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                  __func__, mixer_ctl_name);
+            return;
+        }
+        if (mixer_ctl_set_value(ctl, 0, custom_stereo_state) < 0) {
+            ALOGE("%s: Could not set custom stereo state %d",
+                  __func__, custom_stereo_state);
+            return;
+        }
+        aextnmod.custom_stereo_enabled = custom_stereo_state;
+        ALOGV("%s: Setting custom stereo state success", __func__);
+    }
+}
+#endif /* CUSTOM_STEREO_ENABLED */
+
+#ifndef ANC_HEADSET_ENABLED
+#define audio_extn_set_anc_parameters(adev, parms)       (0)
+#else
+bool audio_extn_get_anc_enabled(void)
+{
+    ALOGD("%s: anc_enabled:%d", __func__, aextnmod.anc_enabled);
+    return (aextnmod.anc_enabled ? true: false);
+}
+
+bool audio_extn_should_use_handset_anc(int in_channels)
+{
+    char prop_aanc[PROPERTY_VALUE_MAX] = "false";
+
+    property_get("persist.aanc.enable", prop_aanc, "0");
+    if (!strncmp("true", prop_aanc, 4)) {
+        ALOGD("%s: AANC enabled in the property", __func__);
+        aextnmod.aanc_enabled = 1;
+    }
+
+    return (aextnmod.aanc_enabled && aextnmod.anc_enabled
+            && (in_channels == 1));
+}
+
+bool audio_extn_should_use_fb_anc(void)
+{
+  char prop_anc[PROPERTY_VALUE_MAX] = "feedforward";
+
+  property_get("persist.headset.anc.type", prop_anc, "0");
+  if (!strncmp("feedback", prop_anc, sizeof("feedback"))) {
+    ALOGD("%s: FB ANC headset type enabled\n", __func__);
+    return true;
+  }
+  return false;
+}
+
+void audio_extn_set_anc_parameters(struct audio_device *adev,
+                                   struct str_parms *parms)
+{
+    int ret;
+    char value[32] ={0};
+    struct listnode *node;
+    struct audio_usecase *usecase;
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_ANC, value,
+                            sizeof(value));
+    if (ret >= 0) {
+        if (strcmp(value, "true") == 0)
+            aextnmod.anc_enabled = true;
+        else
+            aextnmod.anc_enabled = false;
+
+        list_for_each(node, &adev->usecase_list) {
+            usecase = node_to_item(node, struct audio_usecase, list);
+            if (usecase->type == PCM_PLAYBACK) {
+                if (usecase->stream.out->devices == \
+                    AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+                    usecase->stream.out->devices ==  \
+                    AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+                        select_devices(adev, usecase->id);
+                        ALOGV("%s: switching device", __func__);
+                        break;
+                }
+            }
+        }
+    }
+
+    ALOGD("%s: anc_enabled:%d", __func__, aextnmod.anc_enabled);
+}
+#endif /* ANC_HEADSET_ENABLED */
+
+#ifndef FLUENCE_ENABLED
+#define audio_extn_set_fluence_parameters(adev, parms) (0)
+#define audio_extn_get_fluence_parameters(adev, query, reply) (0)
+#else
+void audio_extn_set_fluence_parameters(struct audio_device *adev,
+                                            struct str_parms *parms)
+{
+    int ret = 0, err;
+    char value[32];
+    struct listnode *node;
+    struct audio_usecase *usecase;
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_FLUENCE,
+                                 value, sizeof(value));
+    ALOGV_IF(err >= 0, "%s: Set Fluence Type to %s", __func__, value);
+    if (err >= 0) {
+        ret = platform_set_fluence_type(adev->platform, value);
+        if (ret != 0) {
+            ALOGE("platform_set_fluence_type returned error: %d", ret);
+        } else {
+            /*
+             *If the fluence is manually set/reset, devices
+             *need to get updated for all the usecases
+             *i.e. audio and voice.
+             */
+             list_for_each(node, &adev->usecase_list) {
+                 usecase = node_to_item(node, struct audio_usecase, list);
+                 select_devices(adev, usecase->id);
+             }
+        }
+    }
+}
+
+int audio_extn_get_fluence_parameters(const struct audio_device *adev,
+                       struct str_parms *query, struct str_parms *reply)
+{
+    int ret = 0, err;
+    char value[256] = {0};
+
+    err = str_parms_get_str(query, AUDIO_PARAMETER_KEY_FLUENCE, value,
+                                                          sizeof(value));
+    if (err >= 0) {
+        ret = platform_get_fluence_type(adev->platform, value, sizeof(value));
+        if (ret >= 0) {
+            ALOGV("%s: Fluence Type is %s", __func__, value);
+            str_parms_add_str(reply, AUDIO_PARAMETER_KEY_FLUENCE, value);
+        } else
+            goto done;
+    }
+done:
+    return ret;
+}
+#endif /* FLUENCE_ENABLED */
+
+#ifndef AFE_PROXY_ENABLED
+#define audio_extn_set_afe_proxy_parameters(adev, parms)  (0)
+#define audio_extn_get_afe_proxy_parameters(query, reply) (0)
+#else
+/* Front left channel. */
+#define PCM_CHANNEL_FL    1
+
+/* Front right channel. */
+#define PCM_CHANNEL_FR    2
+
+/* Front center channel. */
+#define PCM_CHANNEL_FC    3
+
+/* Left surround channel.*/
+#define PCM_CHANNEL_LS   4
+
+/* Right surround channel.*/
+#define PCM_CHANNEL_RS   5
+
+/* Low frequency effect channel. */
+#define PCM_CHANNEL_LFE  6
+
+/* Left back channel; Rear left channel. */
+#define PCM_CHANNEL_LB   8
+
+/* Right back channel; Rear right channel. */
+#define PCM_CHANNEL_RB   9
+
+static int32_t afe_proxy_set_channel_mapping(struct audio_device *adev,
+                                                     int channel_count)
+{
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Playback Channel Map";
+    int set_values[8] = {0};
+    int ret;
+    ALOGV("%s channel_count:%d",__func__, channel_count);
+
+    switch (channel_count) {
+    case 2:
+        set_values[0] = PCM_CHANNEL_FL;
+        set_values[1] = PCM_CHANNEL_FR;
+        break;
+    case 6:
+        set_values[0] = PCM_CHANNEL_FL;
+        set_values[1] = PCM_CHANNEL_FR;
+        set_values[2] = PCM_CHANNEL_FC;
+        set_values[3] = PCM_CHANNEL_LFE;
+        set_values[4] = PCM_CHANNEL_LS;
+        set_values[5] = PCM_CHANNEL_RS;
+        break;
+    case 8:
+        set_values[0] = PCM_CHANNEL_FL;
+        set_values[1] = PCM_CHANNEL_FR;
+        set_values[2] = PCM_CHANNEL_FC;
+        set_values[3] = PCM_CHANNEL_LFE;
+        set_values[4] = PCM_CHANNEL_LS;
+        set_values[5] = PCM_CHANNEL_RS;
+        set_values[6] = PCM_CHANNEL_LB;
+        set_values[7] = PCM_CHANNEL_RB;
+        break;
+    default:
+        ALOGE("unsupported channels(%d) for setting channel map",
+                                                    channel_count);
+        return -EINVAL;
+    }
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    ALOGV("AFE: set mapping(%d %d %d %d %d %d %d %d) for channel:%d",
+        set_values[0], set_values[1], set_values[2], set_values[3], set_values[4],
+        set_values[5], set_values[6], set_values[7], channel_count);
+    ret = mixer_ctl_set_array(ctl, set_values, channel_count);
+    return ret;
+}
+
+int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev,
+                                    int channel_count)
+{
+    int32_t ret = 0;
+    const char *channel_cnt_str = NULL;
+    struct mixer_ctl *ctl = NULL;
+    const char *mixer_ctl_name = "PROXY_RX Channels";
+
+    ALOGD("%s: entry", __func__);
+    /* use the existing channel count set by hardware params to
+    configure the back end for stereo as usb/a2dp would be
+    stereo by default */
+    ALOGD("%s: channels = %d", __func__, channel_count);
+    switch (channel_count) {
+    case 8: channel_cnt_str = "Eight"; break;
+    case 7: channel_cnt_str = "Seven"; break;
+    case 6: channel_cnt_str = "Six"; break;
+    case 5: channel_cnt_str = "Five"; break;
+    case 4: channel_cnt_str = "Four"; break;
+    case 3: channel_cnt_str = "Three"; break;
+    default: channel_cnt_str = "Two"; break;
+    }
+
+    if(channel_count >= 2 && channel_count <= 8) {
+       ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+       if (!ctl) {
+            ALOGE("%s: could not get ctl for mixer cmd - %s",
+                  __func__, mixer_ctl_name);
+        return -EINVAL;
+       }
+    }
+    mixer_ctl_set_enum_by_string(ctl, channel_cnt_str);
+
+    if (channel_count == 6 || channel_count == 8 || channel_count == 2) {
+        ret = afe_proxy_set_channel_mapping(adev, channel_count);
+    } else {
+        ALOGE("%s: set unsupported channel count(%d)",  __func__, channel_count);
+        ret = -EINVAL;
+    }
+
+    ALOGD("%s: exit", __func__);
+    return ret;
+}
+
+void audio_extn_set_afe_proxy_parameters(struct audio_device *adev,
+                                         struct str_parms *parms)
+{
+    int ret, val;
+    char value[32]={0};
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_WFD, value,
+                            sizeof(value));
+    if (ret >= 0) {
+        val = atoi(value);
+        aextnmod.proxy_channel_num = val;
+        adev->cur_wfd_channels = val;
+        ALOGD("%s: channel capability set to: %d", __func__,
+               aextnmod.proxy_channel_num);
+    }
+}
+
+int audio_extn_get_afe_proxy_parameters(struct str_parms *query,
+                                        struct str_parms *reply)
+{
+    int ret, val;
+    char value[32]={0};
+    char *str = NULL;
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_CAN_OPEN_PROXY, value,
+                            sizeof(value));
+    if (ret >= 0) {
+        if (audio_extn_usb_is_proxy_inuse())
+            val = 0;
+        else
+            val = 1;
+        str_parms_add_int(reply, AUDIO_PARAMETER_CAN_OPEN_PROXY, val);
+    }
+
+    return 0;
+}
+
+/* must be called with hw device mutex locked */
+int32_t audio_extn_read_afe_proxy_channel_masks(struct stream_out *out)
+{
+    int ret = 0;
+    int channels = aextnmod.proxy_channel_num;
+
+    switch (channels) {
+        /*
+         * Do not handle stereo output in Multi-channel cases
+         * Stereo case is handled in normal playback path
+         */
+    case 6:
+        ALOGV("%s: AFE PROXY supports 5.1", __func__);
+        out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1;
+        break;
+    case 8:
+        ALOGV("%s: AFE PROXY supports 5.1 and 7.1 channels", __func__);
+        out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1;
+        out->supported_channel_masks[1] = AUDIO_CHANNEL_OUT_7POINT1;
+        break;
+    default:
+        ALOGE("AFE PROXY does not support multi channel playback");
+        ret = -ENOSYS;
+        break;
+    }
+    return ret;
+}
+
+int32_t audio_extn_get_afe_proxy_channel_count()
+{
+    return aextnmod.proxy_channel_num;
+}
+
+#endif /* AFE_PROXY_ENABLED */
+
+static int get_active_offload_usecases(const struct audio_device *adev,
+                                       struct str_parms *query,
+                                       struct str_parms *reply)
+{
+    int ret, count = 0;
+    char value[32]={0};
+    struct listnode *node;
+    struct audio_usecase *usecase;
+
+    ALOGV("%s", __func__);
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_OFFLOAD_NUM_ACTIVE, value,
+                            sizeof(value));
+    if (ret >= 0) {
+        list_for_each(node, &adev->usecase_list) {
+            usecase = node_to_item(node, struct audio_usecase, list);
+            if (is_offload_usecase(usecase->id))
+                count++;
+        }
+        ALOGV("%s, number of active offload usecases: %d", __func__, count);
+        str_parms_add_int(reply, AUDIO_PARAMETER_OFFLOAD_NUM_ACTIVE, count);
+    }
+    return ret;
+}
+
+void audio_extn_set_parameters(struct audio_device *adev,
+                               struct str_parms *parms)
+{
+   audio_extn_set_anc_parameters(adev, parms);
+   audio_extn_set_fluence_parameters(adev, parms);
+   audio_extn_set_afe_proxy_parameters(adev, parms);
+   audio_extn_fm_set_parameters(adev, parms);
+   audio_extn_sound_trigger_set_parameters(adev, parms);
+   audio_extn_listen_set_parameters(adev, parms);
+   audio_extn_hfp_set_parameters(adev, parms);
+   audio_extn_a2dp_set_parameters(parms);
+   audio_extn_ddp_set_parameters(adev, parms);
+   audio_extn_ds2_set_parameters(adev, parms);
+   audio_extn_customstereo_set_parameters(adev, parms);
+   audio_extn_pm_set_parameters(parms);
+}
+
+void audio_extn_get_parameters(const struct audio_device *adev,
+                              struct str_parms *query,
+                              struct str_parms *reply)
+{
+    char *kv_pairs = NULL;
+    audio_extn_get_afe_proxy_parameters(query, reply);
+    audio_extn_get_fluence_parameters(adev, query, reply);
+    get_active_offload_usecases(adev, query, reply);
+
+    kv_pairs = str_parms_to_str(reply);
+    ALOGD_IF(kv_pairs != NULL, "%s: returns %s", __func__, kv_pairs);
+    free(kv_pairs);
+}
+
+#ifndef COMPRESS_METADATA_NEEDED
+#define audio_extn_parse_compress_metadata(out, parms) (0)
+#else
+int audio_extn_parse_compress_metadata(struct stream_out *out,
+                                       struct str_parms *parms)
+{
+    int ret = 0;
+    char value[32];
+
+    if (out->format == AUDIO_FORMAT_FLAC) {
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MIN_BLK_SIZE, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.flac_dec.min_blk_size = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MAX_BLK_SIZE, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.flac_dec.max_blk_size = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MIN_FRAME_SIZE, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.flac_dec.min_frame_size = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MAX_FRAME_SIZE, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.flac_dec.max_frame_size = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ALOGV("FLAC metadata: min_blk_size %d, max_blk_size %d min_frame_size %d max_frame_size %d",
+              out->compr_config.codec->options.flac_dec.min_blk_size,
+              out->compr_config.codec->options.flac_dec.max_blk_size,
+              out->compr_config.codec->options.flac_dec.min_frame_size,
+              out->compr_config.codec->options.flac_dec.max_frame_size);
+    }
+
+    else if (out->format == AUDIO_FORMAT_ALAC) {
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_FRAME_LENGTH, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.alac.frame_length = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_COMPATIBLE_VERSION, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.alac.compatible_version = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_BIT_DEPTH, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.alac.bit_depth = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_PB, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.alac.pb = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_MB, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.alac.mb = atoi(value);
+            out->send_new_metadata = 1;
+        }
+
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_KB, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.alac.kb = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_NUM_CHANNELS, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.alac.num_channels = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_MAX_RUN, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.alac.max_run = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_MAX_FRAME_BYTES, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.alac.max_frame_bytes = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_AVG_BIT_RATE, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.alac.avg_bit_rate = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_SAMPLING_RATE, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.alac.sample_rate = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_CHANNEL_LAYOUT_TAG, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.alac.channel_layout_tag = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ALOGV("ALAC CSD values: frameLength %d bitDepth %d numChannels %d"
+                " maxFrameBytes %d, avgBitRate %d, sampleRate %d",
+                out->compr_config.codec->options.alac.frame_length,
+                out->compr_config.codec->options.alac.bit_depth,
+                out->compr_config.codec->options.alac.num_channels,
+                out->compr_config.codec->options.alac.max_frame_bytes,
+                out->compr_config.codec->options.alac.avg_bit_rate,
+                out->compr_config.codec->options.alac.sample_rate);
+    }
+
+    else if (out->format == AUDIO_FORMAT_APE) {
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_COMPATIBLE_VERSION, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.ape.compatible_version = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_COMPRESSION_LEVEL, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.ape.compression_level = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_FORMAT_FLAGS, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.ape.format_flags = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_BLOCKS_PER_FRAME, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.ape.blocks_per_frame = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_FINAL_FRAME_BLOCKS, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.ape.final_frame_blocks = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_TOTAL_FRAMES, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.ape.total_frames = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_BITS_PER_SAMPLE, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.ape.bits_per_sample = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_NUM_CHANNELS, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.ape.num_channels = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_SAMPLE_RATE, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.ape.sample_rate = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_SEEK_TABLE_PRESENT, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.ape.seek_table_present = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ALOGV("APE CSD values: compatibleVersion %d compressionLevel %d"
+                " formatFlags %d blocksPerFrame %d finalFrameBlocks %d"
+                " totalFrames %d bitsPerSample %d numChannels %d"
+                " sampleRate %d seekTablePresent %d",
+                out->compr_config.codec->options.ape.compatible_version,
+                out->compr_config.codec->options.ape.compression_level,
+                out->compr_config.codec->options.ape.format_flags,
+                out->compr_config.codec->options.ape.blocks_per_frame,
+                out->compr_config.codec->options.ape.final_frame_blocks,
+                out->compr_config.codec->options.ape.total_frames,
+                out->compr_config.codec->options.ape.bits_per_sample,
+                out->compr_config.codec->options.ape.num_channels,
+                out->compr_config.codec->options.ape.sample_rate,
+                out->compr_config.codec->options.ape.seek_table_present);
+    }
+
+    else if (out->format == AUDIO_FORMAT_VORBIS) {
+        // transcoded bitstream mode
+        out->compr_config.codec->options.vorbis_dec.bit_stream_fmt = 1;
+        out->send_new_metadata = 1;
+    }
+
+    else if (out->format == AUDIO_FORMAT_WMA || out->format == AUDIO_FORMAT_WMA_PRO) {
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_FORMAT_TAG, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->format = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BLOCK_ALIGN, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.wma.super_block_align = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BIT_PER_SAMPLE, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.wma.bits_per_sample = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_CHANNEL_MASK, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.wma.channelmask = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.wma.encodeopt = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION1, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.wma.encodeopt1 = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION2, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.wma.encodeopt2 = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ALOGV("WMA params: fmt %x, balgn %x, sr %d, chmsk %x, encop %x, op1 %x, op2 %x",
+                out->compr_config.codec->format,
+                out->compr_config.codec->options.wma.super_block_align,
+                out->compr_config.codec->options.wma.bits_per_sample,
+                out->compr_config.codec->options.wma.channelmask,
+                out->compr_config.codec->options.wma.encodeopt,
+                out->compr_config.codec->options.wma.encodeopt1,
+                out->compr_config.codec->options.wma.encodeopt2);
+    }
+
+    return ret;
+}
+#endif
+
+#ifdef AUXPCM_BT_ENABLED
+int32_t audio_extn_read_xml(struct audio_device *adev, uint32_t mixer_card,
+                            const char* mixer_xml_path,
+                            const char* mixer_xml_path_auxpcm)
+{
+    char bt_soc[128];
+    bool wifi_init_complete = false;
+    int sleep_retry = 0;
+
+    while (!wifi_init_complete && sleep_retry < MAX_SLEEP_RETRY) {
+        property_get("qcom.bluetooth.soc", bt_soc, NULL);
+        if (strncmp(bt_soc, "unknown", sizeof("unknown"))) {
+            wifi_init_complete = true;
+        } else {
+            usleep(WIFI_INIT_WAIT_SLEEP*1000);
+            sleep_retry++;
+        }
+    }
+
+    if (!strncmp(bt_soc, "ath3k", sizeof("ath3k")))
+        adev->audio_route = audio_route_init(mixer_card, mixer_xml_path_auxpcm);
+    else
+        adev->audio_route = audio_route_init(mixer_card, mixer_xml_path);
+
+    return 0;
+}
+#endif /* AUXPCM_BT_ENABLED */
+
+#ifdef KPI_OPTIMIZE_ENABLED
+typedef int (*perf_lock_acquire_t)(int, int, int*, int);
+typedef int (*perf_lock_release_t)(int);
+
+static void *qcopt_handle;
+static perf_lock_acquire_t perf_lock_acq;
+static perf_lock_release_t perf_lock_rel;
+
+static int perf_lock_handle;
+char opt_lib_path[512] = {0};
+int perf_lock_opts[1] = {0x20E};
+
+int audio_extn_perf_lock_init(void)
+{
+    int ret = 0;
+    if (qcopt_handle == NULL) {
+        if (property_get("ro.vendor.extension_library",
+                         opt_lib_path, NULL) <= 0) {
+            ALOGE("%s: Failed getting perf property \n", __func__);
+            ret = -EINVAL;
+            goto err;
+        }
+        if ((qcopt_handle = dlopen(opt_lib_path, RTLD_NOW)) == NULL) {
+            ALOGE("%s: Failed to open perf handle \n", __func__);
+            ret = -EINVAL;
+            goto err;
+        } else {
+            perf_lock_acq = (perf_lock_acquire_t)dlsym(qcopt_handle,
+                                                       "perf_lock_acq");
+            if (perf_lock_acq == NULL) {
+                ALOGE("%s: Perf lock Acquire NULL \n", __func__);
+                ret = -EINVAL;
+                goto err;
+            }
+            perf_lock_rel = (perf_lock_release_t)dlsym(qcopt_handle,
+                                                       "perf_lock_rel");
+            if (perf_lock_rel == NULL) {
+                ALOGE("%s: Perf lock Release NULL \n", __func__);
+                ret = -EINVAL;
+                goto err;
+            }
+            ALOGE("%s: Perf lock handles Success \n", __func__);
+        }
+    }
+err:
+    return ret;
+}
+
+void audio_extn_perf_lock_acquire(void)
+{
+    if (perf_lock_acq)
+        perf_lock_handle = perf_lock_acq(perf_lock_handle, 0, perf_lock_opts, 1);
+    else
+        ALOGE("%s: Perf lock acquire error \n", __func__);
+}
+
+void audio_extn_perf_lock_release(void)
+{
+    if (perf_lock_rel && perf_lock_handle)
+        perf_lock_rel(perf_lock_handle);
+    else
+        ALOGE("%s: Perf lock release error \n", __func__);
+}
+#endif /* KPI_OPTIMIZE_ENABLED */
diff --git a/msm8909/hal/audio_extn/audio_extn.h b/msm8909/hal/audio_extn/audio_extn.h
new file mode 100644
index 0000000..51bb54b
--- /dev/null
+++ b/msm8909/hal/audio_extn/audio_extn.h
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AUDIO_EXTN_H
+#define AUDIO_EXTN_H
+
+#include <cutils/str_parms.h>
+
+#ifndef PCM_OFFLOAD_ENABLED
+#define AUDIO_FORMAT_PCM_OFFLOAD 0x17000000UL
+#define AUDIO_FORMAT_PCM_16_BIT_OFFLOAD (AUDIO_FORMAT_PCM_OFFLOAD | AUDIO_FORMAT_PCM_SUB_16_BIT)
+#define AUDIO_FORMAT_PCM_24_BIT_OFFLOAD (AUDIO_FORMAT_PCM_OFFLOAD | AUDIO_FORMAT_PCM_SUB_8_24_BIT)
+#define AUDIO_OFFLOAD_CODEC_FORMAT  "music_offload_codec_format"
+#define audio_is_offload_pcm(format) (0)
+#endif
+
+#ifndef AFE_PROXY_ENABLED
+#define AUDIO_DEVICE_OUT_PROXY 0x40000
+#endif
+
+#ifndef COMPRESS_VOIP_ENABLED
+#define AUDIO_OUTPUT_FLAG_VOIP_RX 0x4000
+#endif
+
+#ifndef INCALL_MUSIC_ENABLED
+#define AUDIO_OUTPUT_FLAG_INCALL_MUSIC 0x8000
+#endif
+
+#ifndef AUDIO_DEVICE_OUT_FM_TX
+#define AUDIO_DEVICE_OUT_FM_TX 0x8000000
+#endif
+
+#ifndef FLAC_OFFLOAD_ENABLED
+#define AUDIO_FORMAT_FLAC 0x1B000000UL
+#endif
+
+#ifndef WMA_OFFLOAD_ENABLED
+#define AUDIO_FORMAT_WMA 0x12000000UL
+#define AUDIO_FORMAT_WMA_PRO 0x13000000UL
+#endif
+
+#ifndef ALAC_OFFLOAD_ENABLED
+#define AUDIO_FORMAT_ALAC 0x1C000000UL
+#endif
+
+#ifndef APE_OFFLOAD_ENABLED
+#define AUDIO_FORMAT_APE 0x1D000000UL
+#endif
+
+#ifndef COMPRESS_METADATA_NEEDED
+#define audio_extn_parse_compress_metadata(out, parms) (0)
+#else
+int audio_extn_parse_compress_metadata(struct stream_out *out,
+                                       struct str_parms *parms);
+#endif
+
+#ifdef PCM_OFFLOAD_ENABLED_24
+#define PCM_OUTPUT_BIT_WIDTH (config->offload_info.bit_width)
+#else
+#define PCM_OUTPUT_BIT_WIDTH (CODEC_BACKEND_DEFAULT_BIT_WIDTH)
+#endif
+
+#define MAX_LENGTH_MIXER_CONTROL_IN_INT                  (128)
+
+void audio_extn_set_parameters(struct audio_device *adev,
+                               struct str_parms *parms);
+
+void audio_extn_get_parameters(const struct audio_device *adev,
+                               struct str_parms *query,
+                               struct str_parms *reply);
+
+#ifndef ANC_HEADSET_ENABLED
+#define audio_extn_get_anc_enabled()                     (0)
+#define audio_extn_should_use_fb_anc()                   (0)
+#define audio_extn_should_use_handset_anc(in_channels)   (0)
+#else
+bool audio_extn_get_anc_enabled(void);
+bool audio_extn_should_use_fb_anc(void);
+bool audio_extn_should_use_handset_anc(int in_channels);
+#endif
+
+#ifndef FLUENCE_ENABLED
+#define audio_extn_set_fluence_parameters(adev, parms) (0)
+#define audio_extn_get_fluence_parameters(adev, query, reply) (0)
+#else
+void audio_extn_set_fluence_parameters(struct audio_device *adev,
+                                           struct str_parms *parms);
+int audio_extn_get_fluence_parameters(const struct audio_device *adev,
+                  struct str_parms *query, struct str_parms *reply);
+#endif
+
+#ifndef AFE_PROXY_ENABLED
+#define audio_extn_set_afe_proxy_channel_mixer(adev,channel_count)     (0)
+#define audio_extn_read_afe_proxy_channel_masks(out)                   (0)
+#define audio_extn_get_afe_proxy_channel_count()                       (0)
+#else
+int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev,
+                                                    int channel_count);
+int32_t audio_extn_read_afe_proxy_channel_masks(struct stream_out *out);
+int32_t audio_extn_get_afe_proxy_channel_count();
+
+#endif
+
+#ifndef USB_HEADSET_ENABLED
+#define audio_extn_usb_init(adev)                        (0)
+#define audio_extn_usb_deinit()                          (0)
+#define audio_extn_usb_start_playback(adev)              (0)
+#define audio_extn_usb_stop_playback()                   (0)
+#define audio_extn_usb_start_capture(adev)               (0)
+#define audio_extn_usb_stop_capture()                    (0)
+#define audio_extn_usb_set_proxy_sound_card(sndcard_idx) (0)
+#define audio_extn_usb_is_proxy_inuse()                  (0)
+#else
+void initPlaybackVolume();
+void audio_extn_usb_init(void *adev);
+void audio_extn_usb_deinit();
+void audio_extn_usb_start_playback(void *adev);
+void audio_extn_usb_stop_playback();
+void audio_extn_usb_start_capture(void *adev);
+void audio_extn_usb_stop_capture();
+void audio_extn_usb_set_proxy_sound_card(uint32_t sndcard_idx);
+bool audio_extn_usb_is_proxy_inuse();
+#endif
+
+#ifndef SPLIT_A2DP_ENABLED
+#define audio_extn_a2dp_init()                       (0)
+#define audio_extn_a2dp_start_playback()             (0)
+#define audio_extn_a2dp_stop_playback()              (0)
+#define audio_extn_a2dp_set_parameters(parms)      (0)
+#else
+void audio_extn_a2dp_init();
+void audio_extn_a2dp_start_playback();
+void audio_extn_a2dp_stop_playback();
+void audio_extn_a2dp_set_parameters(struct str_parms *parms);
+#endif
+
+#ifndef SSR_ENABLED
+#define audio_extn_ssr_init(in)                       (0)
+#define audio_extn_ssr_deinit()                       (0)
+#define audio_extn_ssr_update_enabled()               (0)
+#define audio_extn_ssr_get_enabled()                  (0)
+#define audio_extn_ssr_read(stream, buffer, bytes)    (0)
+#else
+int32_t audio_extn_ssr_init(struct stream_in *in);
+int32_t audio_extn_ssr_deinit();
+void audio_extn_ssr_update_enabled();
+bool audio_extn_ssr_get_enabled();
+int32_t audio_extn_ssr_read(struct audio_stream_in *stream,
+                       void *buffer, size_t bytes);
+#endif
+
+#ifndef HW_VARIANTS_ENABLED
+#define hw_info_init(snd_card_name)                  (0)
+#define hw_info_deinit(hw_info)                      (0)
+#define hw_info_append_hw_type(hw_info,\
+        snd_device, device_name)                     (0)
+#else
+void *hw_info_init(const char *snd_card_name);
+void hw_info_deinit(void *hw_info);
+void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device,
+                             char *device_name);
+#endif
+
+#ifndef AUDIO_LISTEN_ENABLED
+#define audio_extn_listen_init(adev, snd_card)                  (0)
+#define audio_extn_listen_deinit(adev)                          (0)
+#define audio_extn_listen_update_device_status(snd_dev, event)  (0)
+#define audio_extn_listen_update_stream_status(uc_info, event)  (0)
+#define audio_extn_listen_set_parameters(adev, parms)           (0)
+#else
+enum listen_event_type {
+    LISTEN_EVENT_SND_DEVICE_FREE,
+    LISTEN_EVENT_SND_DEVICE_BUSY,
+    LISTEN_EVENT_STREAM_FREE,
+    LISTEN_EVENT_STREAM_BUSY
+};
+typedef enum listen_event_type listen_event_type_t;
+
+int audio_extn_listen_init(struct audio_device *adev, unsigned int snd_card);
+void audio_extn_listen_deinit(struct audio_device *adev);
+void audio_extn_listen_update_device_status(snd_device_t snd_device,
+                                     listen_event_type_t event);
+void audio_extn_listen_update_stream_status(struct audio_usecase *uc_info,
+                                     listen_event_type_t event);
+void audio_extn_listen_set_parameters(struct audio_device *adev,
+                                      struct str_parms *parms);
+#endif /* AUDIO_LISTEN_ENABLED */
+
+#ifndef SOUND_TRIGGER_ENABLED
+#define audio_extn_sound_trigger_init(adev)                            (0)
+#define audio_extn_sound_trigger_deinit(adev)                          (0)
+#define audio_extn_sound_trigger_update_device_status(snd_dev, event)  (0)
+#define audio_extn_sound_trigger_update_stream_status(uc_info, event)  (0)
+#define audio_extn_sound_trigger_set_parameters(adev, parms)           (0)
+#define audio_extn_sound_trigger_check_and_get_session(in)             (0)
+#define audio_extn_sound_trigger_stop_lab(in)                          (0)
+#else
+
+enum st_event_type {
+    ST_EVENT_SND_DEVICE_FREE,
+    ST_EVENT_SND_DEVICE_BUSY,
+    ST_EVENT_STREAM_FREE,
+    ST_EVENT_STREAM_BUSY
+};
+typedef enum st_event_type st_event_type_t;
+
+int audio_extn_sound_trigger_init(struct audio_device *adev);
+void audio_extn_sound_trigger_deinit(struct audio_device *adev);
+void audio_extn_sound_trigger_update_device_status(snd_device_t snd_device,
+                                     st_event_type_t event);
+void audio_extn_sound_trigger_update_stream_status(struct audio_usecase *uc_info,
+                                     st_event_type_t event);
+void audio_extn_sound_trigger_set_parameters(struct audio_device *adev,
+                                             struct str_parms *parms);
+void audio_extn_sound_trigger_check_and_get_session(struct stream_in *in);
+void audio_extn_sound_trigger_stop_lab(struct stream_in *in);
+#endif
+
+#ifndef AUXPCM_BT_ENABLED
+#define audio_extn_read_xml(adev, mixer_card, MIXER_XML_PATH, \
+                            MIXER_XML_PATH_AUXPCM)               (-ENOSYS)
+#else
+int32_t audio_extn_read_xml(struct audio_device *adev, uint32_t mixer_card,
+                            const char* mixer_xml_path,
+                            const char* mixer_xml_path_auxpcm);
+#endif /* AUXPCM_BT_ENABLED */
+#ifndef SPKR_PROT_ENABLED
+#define audio_extn_spkr_prot_init(adev)       (0)
+#define audio_extn_spkr_prot_start_processing(snd_device)    (-EINVAL)
+#define audio_extn_spkr_prot_calib_cancel(adev) (0)
+#define audio_extn_spkr_prot_stop_processing(snd_device)     (0)
+#define audio_extn_spkr_prot_is_enabled() (false)
+#define audio_extn_spkr_prot_get_acdb_id(snd_device)         (-EINVAL)
+#define audio_extn_get_spkr_prot_snd_device(snd_device) (snd_device)
+#else
+void audio_extn_spkr_prot_init(void *adev);
+int audio_extn_spkr_prot_start_processing(snd_device_t snd_device);
+void audio_extn_spkr_prot_stop_processing(snd_device_t snd_device);
+bool audio_extn_spkr_prot_is_enabled();
+int audio_extn_spkr_prot_get_acdb_id(snd_device_t snd_device);
+int audio_extn_get_spkr_prot_snd_device(snd_device_t snd_device);
+void audio_extn_spkr_prot_calib_cancel(void *adev);
+#endif
+
+#ifndef COMPRESS_CAPTURE_ENABLED
+#define audio_extn_compr_cap_init(in)                     (0)
+#define audio_extn_compr_cap_enabled()                    (0)
+#define audio_extn_compr_cap_format_supported(format)     (0)
+#define audio_extn_compr_cap_usecase_supported(usecase)   (0)
+#define audio_extn_compr_cap_get_buffer_size(format)      (0)
+#define audio_extn_compr_cap_read(in, buffer, bytes)      (0)
+#define audio_extn_compr_cap_deinit()                     (0)
+#else
+void audio_extn_compr_cap_init(struct stream_in *in);
+bool audio_extn_compr_cap_enabled();
+bool audio_extn_compr_cap_format_supported(audio_format_t format);
+bool audio_extn_compr_cap_usecase_supported(audio_usecase_t usecase);
+size_t audio_extn_compr_cap_get_buffer_size(audio_format_t format);
+size_t audio_extn_compr_cap_read(struct stream_in *in,
+                                        void *buffer, size_t bytes);
+void audio_extn_compr_cap_deinit();
+#endif
+
+#if defined(DS1_DOLBY_DDP_ENABLED) || defined(DS1_DOLBY_DAP_ENABLED)
+void audio_extn_dolby_set_dmid(struct audio_device *adev);
+#else
+#define audio_extn_dolby_set_dmid(adev)                 (0)
+#endif
+
+
+#if defined(DS1_DOLBY_DDP_ENABLED) || defined(DS1_DOLBY_DAP_ENABLED) || defined(DS2_DOLBY_DAP_ENABLED)
+void audio_extn_dolby_set_license(struct audio_device *adev);
+#else
+#define audio_extn_dolby_set_license(adev)              (0)
+#endif
+
+#ifndef DS1_DOLBY_DAP_ENABLED
+#define audio_extn_dolby_set_endpoint(adev)                 (0)
+#else
+void audio_extn_dolby_set_endpoint(struct audio_device *adev);
+#endif
+
+
+#if defined(DS1_DOLBY_DDP_ENABLED) || defined(DS2_DOLBY_DAP_ENABLED)
+bool audio_extn_is_dolby_format(audio_format_t format);
+int audio_extn_dolby_get_snd_codec_id(struct audio_device *adev,
+                                      struct stream_out *out,
+                                      audio_format_t format);
+#else
+#define audio_extn_is_dolby_format(format)              (0)
+#define audio_extn_dolby_get_snd_codec_id(adev, out, format)       (0)
+#endif
+
+#ifndef DS1_DOLBY_DDP_ENABLED
+#define audio_extn_ddp_set_parameters(adev, parms)      (0)
+#define audio_extn_dolby_send_ddp_endp_params(adev)     (0)
+#else
+void audio_extn_ddp_set_parameters(struct audio_device *adev,
+                                   struct str_parms *parms);
+void audio_extn_dolby_send_ddp_endp_params(struct audio_device *adev);
+#endif
+
+#ifndef HFP_ENABLED
+#define audio_extn_hfp_is_active(adev)                  (0)
+#define audio_extn_hfp_get_usecase()                    (-1)
+#else
+bool audio_extn_hfp_is_active(struct audio_device *adev);
+audio_usecase_t audio_extn_hfp_get_usecase();
+#endif
+
+#ifndef DEV_ARBI_ENABLED
+#define audio_extn_dev_arbi_init()                  (0)
+#define audio_extn_dev_arbi_deinit()                (0)
+#define audio_extn_dev_arbi_acquire(snd_device)     (0)
+#define audio_extn_dev_arbi_release(snd_device)     (0)
+#else
+int audio_extn_dev_arbi_init();
+int audio_extn_dev_arbi_deinit();
+int audio_extn_dev_arbi_acquire(snd_device_t snd_device);
+int audio_extn_dev_arbi_release(snd_device_t snd_device);
+#endif
+
+#ifndef PM_SUPPORT_ENABLED
+#define audio_extn_pm_set_parameters(params) (0)
+#define audio_extn_pm_vote(void) (0)
+#define audio_extn_pm_unvote(void) (0)
+#else
+void audio_extn_pm_set_parameters(struct str_parms *parms);
+int audio_extn_pm_vote (void);
+void audio_extn_pm_unvote(void);
+#endif
+
+void audio_extn_utils_update_streams_output_cfg_list(void *platform,
+                                  struct mixer *mixer,
+                                  struct listnode *streams_output_cfg_list);
+void audio_extn_utils_dump_streams_output_cfg_list(
+                                  struct listnode *streams_output_cfg_list);
+void audio_extn_utils_release_streams_output_cfg_list(
+                                  struct listnode *streams_output_cfg_list);
+void audio_extn_utils_update_stream_app_type_cfg(void *platform,
+                                  struct listnode *streams_output_cfg_list,
+                                  audio_devices_t devices,
+                                  audio_output_flags_t flags,
+                                  audio_format_t format,
+                                  uint32_t sample_rate,
+                                  uint32_t bit_width,
+                                  struct stream_app_type_cfg *app_type_cfg);
+int audio_extn_utils_send_app_type_cfg(struct audio_usecase *usecase);
+void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
+                                             struct audio_usecase *usecase);
+#ifdef DS2_DOLBY_DAP_ENABLED
+#define LIB_DS2_DAP_HAL "vendor/lib/libhwdaphal.so"
+#define SET_HW_INFO_FUNC "dap_hal_set_hw_info"
+typedef enum {
+    SND_CARD            = 0,
+    HW_ENDPOINT         = 1,
+    DMID                = 2,
+    DEVICE_BE_ID_MAP    = 3,
+    DAP_BYPASS          = 4,
+} dap_hal_hw_info_t;
+typedef int (*dap_hal_set_hw_info_t)(int32_t hw_info, void* data);
+typedef struct {
+     int (*device_id_to_be_id)[2];
+     int len;
+} dap_hal_device_be_id_map_t;
+
+int audio_extn_dap_hal_init(int snd_card);
+int audio_extn_dap_hal_deinit();
+void audio_extn_dolby_ds2_set_endpoint(struct audio_device *adev);
+int audio_extn_ds2_enable(struct audio_device *adev);
+int audio_extn_dolby_set_dap_bypass(struct audio_device *adev, int state);
+void audio_extn_ds2_set_parameters(struct audio_device *adev,
+                                   struct str_parms *parms);
+
+#else
+#define audio_extn_dap_hal_init(snd_card)                             (0)
+#define audio_extn_dap_hal_deinit()                                   (0)
+#define audio_extn_dolby_ds2_set_endpoint(adev)                       (0)
+#define audio_extn_ds2_enable(adev)                                   (0)
+#define audio_extn_dolby_set_dap_bypass(adev, state)                  (0)
+#define audio_extn_ds2_set_parameters(adev, parms);                   (0)
+#endif
+typedef enum {
+    DAP_STATE_ON = 0,
+    DAP_STATE_BYPASS,
+};
+#ifndef AUDIO_FORMAT_E_AC3_JOC
+#define AUDIO_FORMAT_E_AC3_JOC  0x19000000UL
+#endif
+ 
+#ifndef AUDIO_FORMAT_DTS_LBR
+#define AUDIO_FORMAT_DTS_LBR 0x1E000000UL
+#endif
+
+int read_line_from_file(const char *path, char *buf, size_t count);
+
+#ifndef KPI_OPTIMIZE_ENABLED
+#define audio_extn_perf_lock_init() (0)
+#define audio_extn_perf_lock_acquire() (0)
+#define audio_extn_perf_lock_release() (0)
+#else
+int audio_extn_perf_lock_init(void);
+void audio_extn_perf_lock_acquire(void);
+void audio_extn_perf_lock_release(void);
+#endif /* KPI_OPTIMIZE_ENABLED */
+#endif /* AUDIO_EXTN_H */
diff --git a/msm8909/hal/audio_extn/compress_capture.c b/msm8909/hal/audio_extn/compress_capture.c
new file mode 100644
index 0000000..47e6a9d
--- /dev/null
+++ b/msm8909/hal/audio_extn/compress_capture.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2013 - 2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_compress"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/str_parms.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+
+#include "sound/compress_params.h"
+#include "sound/compress_offload.h"
+
+#ifdef COMPRESS_CAPTURE_ENABLED
+
+#define COMPRESS_IN_CONFIG_CHANNELS 1
+#define COMPRESS_IN_CONFIG_PERIOD_SIZE 2048
+#define COMPRESS_IN_CONFIG_PERIOD_COUNT 16
+
+
+struct compress_in_module {
+    uint8_t             *in_buf;
+};
+
+static struct compress_in_module c_in_mod = {
+    .in_buf = NULL,
+};
+
+
+void audio_extn_compr_cap_init(struct stream_in *in)
+{
+    in->usecase = USECASE_AUDIO_RECORD_COMPRESS;
+    in->config.channels = COMPRESS_IN_CONFIG_CHANNELS;
+    in->config.period_size = COMPRESS_IN_CONFIG_PERIOD_SIZE;
+    in->config.period_count= COMPRESS_IN_CONFIG_PERIOD_COUNT;
+    in->config.format = AUDIO_FORMAT_AMR_WB;
+    c_in_mod.in_buf = (uint8_t*)calloc(1, in->config.period_size*2);
+}
+
+void audio_extn_compr_cap_deinit()
+{
+    if (c_in_mod.in_buf) {
+        free(c_in_mod.in_buf);
+        c_in_mod.in_buf = NULL;
+    }
+}
+
+bool audio_extn_compr_cap_enabled()
+{
+    char prop_value[PROPERTY_VALUE_MAX] = {0};
+    bool tunnel_encode = false;
+
+    property_get("tunnel.audio.encode",prop_value,"0");
+    if (!strncmp("true", prop_value, sizeof("true")))
+        return true;
+    else
+        return false;
+}
+
+bool audio_extn_compr_cap_format_supported(audio_format_t format)
+{
+    if (format == AUDIO_FORMAT_AMR_WB)
+        return true;
+    else
+        return false;
+}
+
+
+bool audio_extn_compr_cap_usecase_supported(audio_usecase_t usecase)
+{
+    if ((usecase == USECASE_AUDIO_RECORD_COMPRESS) ||
+        (usecase == USECASE_INCALL_REC_UPLINK_COMPRESS) ||
+        (usecase == USECASE_INCALL_REC_DOWNLINK_COMPRESS) ||
+        (usecase == USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS))
+        return true;
+    else
+        return false;
+}
+
+
+size_t audio_extn_compr_cap_get_buffer_size(audio_format_t format)
+{
+    if (format == AUDIO_FORMAT_AMR_WB)
+        /*One AMR WB frame is 61 bytes. Return that to the caller.
+        The buffer size is not altered, that is still period size.*/
+        return AMR_WB_FRAMESIZE;
+    else
+        return 0;
+}
+
+size_t audio_extn_compr_cap_read(struct stream_in * in,
+    void *buffer, size_t bytes)
+{
+    int ret;
+    struct snd_compr_audio_info *header;
+    uint32_t c_in_header;
+    uint32_t c_in_buf_size;
+
+    c_in_buf_size = in->config.period_size*2;
+
+    if (in->pcm) {
+        ret = pcm_read(in->pcm, c_in_mod.in_buf, c_in_buf_size);
+        if (ret < 0) {
+            ALOGE("pcm_read() returned failure: %d", ret);
+            return ret;
+        } else {
+            header = (struct snd_compr_audio_info *) c_in_mod.in_buf;
+            c_in_header = sizeof(*header) + header->reserved[0];
+            if (header->frame_size > 0) {
+                if (c_in_header  + header->frame_size > c_in_buf_size) {
+                    ALOGW("AMR WB read buffer overflow.");
+                    header->frame_size =
+                        bytes - sizeof(*header) - header->reserved[0];
+                }
+                ALOGV("c_in_buf: %p, data offset: %p, header size: %zu,"
+                    "reserved[0]: %u frame_size: %d", c_in_mod.in_buf,
+                        c_in_mod.in_buf + c_in_header,
+                        sizeof(*header), header->reserved[0],
+                        header->frame_size);
+                memcpy(buffer, c_in_mod.in_buf + c_in_header, header->frame_size);
+            } else {
+                ALOGE("pcm_read() with zero frame size");
+                ret = -EINVAL;
+            }
+        }
+    }
+
+    return 0;
+}
+
+#endif /* COMPRESS_CAPTURE_ENABLED end */
diff --git a/msm8909/hal/audio_extn/dev_arbi.c b/msm8909/hal/audio_extn/dev_arbi.c
new file mode 100644
index 0000000..d3c01c5
--- /dev/null
+++ b/msm8909/hal/audio_extn/dev_arbi.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2014, 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_hw_dev_arbi"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <cutils/log.h>
+#include <fcntl.h>
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/properties.h>
+#include "audio_extn.h"
+
+#ifdef DEV_ARBI_ENABLED
+
+typedef int (init_fn_t)();
+typedef int (deinit_fn_t)();
+typedef int (acquire_fn_t)(audio_devices_t aud_dev);
+typedef int (release_fn_t)(audio_devices_t aud_dev);
+
+typedef struct {
+    snd_device_t snd_device;
+    audio_devices_t aud_device;
+} snd_aud_dev_mapping_t;
+
+static void* lib_handle = NULL;
+
+static init_fn_t *init_fp = NULL;
+static deinit_fn_t *deinit_fp = NULL;
+static acquire_fn_t *acquire_fp = NULL;
+static release_fn_t *release_fp = NULL;
+
+static int load_dev_arbi_lib()
+{
+    int rc = -EINVAL;
+
+    if (lib_handle != NULL) {
+        ALOGE("%s: library already loaded", __func__);
+        return rc;
+    }
+
+    lib_handle = dlopen("libaudiodevarb.so", RTLD_NOW);
+    if (lib_handle != NULL) {
+        init_fp = (init_fn_t*)dlsym(lib_handle, "aud_dev_arbi_server_init");
+        deinit_fp = (deinit_fn_t*)dlsym(lib_handle, "aud_dev_arbi_server_deinit");
+        acquire_fp = (acquire_fn_t*)dlsym(lib_handle, "aud_dev_arbi_server_acquire");
+        release_fp = (release_fn_t*)dlsym(lib_handle, "aud_dev_arbi_server_release");
+
+        if ((init_fp == NULL) ||
+            (deinit_fp == NULL) ||
+            (acquire_fp == NULL) ||
+            (release_fp == NULL)) {
+
+            ALOGE("%s: error loading symbols from library", __func__);
+
+            init_fp = NULL;
+            deinit_fp = NULL;
+            acquire_fp = NULL;
+            release_fp = NULL;
+        } else
+            return 0;
+    }
+
+    return rc;
+}
+
+int audio_extn_dev_arbi_init()
+{
+    int rc = load_dev_arbi_lib();
+    if (!rc)
+        rc = init_fp();
+
+    return rc;
+}
+
+int audio_extn_dev_arbi_deinit()
+{
+    int rc = -EINVAL;
+
+    if(deinit_fp != NULL) {
+        rc = deinit_fp();
+
+        init_fp = NULL;
+        deinit_fp = NULL;
+        acquire_fp = NULL;
+        release_fp = NULL;
+
+        dlclose(lib_handle);
+        lib_handle = NULL;
+    }
+
+    return rc;
+}
+
+static audio_devices_t get_audio_device(snd_device_t snd_device)
+{
+    static snd_aud_dev_mapping_t snd_aud_dev_map[] = {
+        {SND_DEVICE_OUT_HANDSET, AUDIO_DEVICE_OUT_EARPIECE},
+        {SND_DEVICE_OUT_VOICE_HANDSET, AUDIO_DEVICE_OUT_EARPIECE}
+    };
+
+    audio_devices_t aud_device = AUDIO_DEVICE_NONE;
+    uint32_t ind = 0;
+
+    for (ind = 0; ind < ARRAY_SIZE(snd_aud_dev_map); ++ind) {
+        if (snd_device == snd_aud_dev_map[ind].snd_device) {
+            aud_device = snd_aud_dev_map[ind].aud_device;
+            break;
+        }
+    }
+
+    return aud_device;
+}
+
+int audio_extn_dev_arbi_acquire(snd_device_t snd_device)
+{
+    int rc = -EINVAL;
+    audio_devices_t audio_device = get_audio_device(snd_device);
+
+    if ((acquire_fp != NULL) && (audio_device != AUDIO_DEVICE_NONE))
+        rc = acquire_fp(audio_device);
+
+    return rc;
+}
+
+int audio_extn_dev_arbi_release(snd_device_t snd_device)
+{
+    int rc = -EINVAL;
+    audio_devices_t audio_device = get_audio_device(snd_device);
+
+    if ((release_fp != NULL) && (audio_device != AUDIO_DEVICE_NONE))
+        rc = release_fp(audio_device);
+
+    return rc;
+}
+
+#endif /*DEV_ARBI_ENABLED*/
diff --git a/msm8909/hal/audio_extn/dolby.c b/msm8909/hal/audio_extn/dolby.c
new file mode 100644
index 0000000..e1b64be
--- /dev/null
+++ b/msm8909/hal/audio_extn/dolby.c
@@ -0,0 +1,685 @@
+/*
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_dolby"
+#define LOG_NDEBUG 0
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/str_parms.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include "audio_extn.h"
+#include "sound/compress_params.h"
+#include "sound/devdep_params.h"
+
+#ifdef DS1_DOLBY_DDP_ENABLED
+
+#define AUDIO_PARAMETER_DDP_DEV          "ddp_device"
+#define AUDIO_PARAMETER_DDP_CH_CAP       "ddp_chancap"
+#define AUDIO_PARAMETER_DDP_MAX_OUT_CHAN "ddp_maxoutchan"
+#define AUDIO_PARAMETER_DDP_OUT_MODE     "ddp_outmode"
+#define AUDIO_PARAMETER_DDP_OUT_LFE_ON   "ddp_outlfeon"
+#define AUDIO_PARAMETER_DDP_COMP_MODE    "ddp_compmode"
+#define AUDIO_PARAMETER_DDP_STEREO_MODE  "ddp_stereomode"
+
+#define PARAM_ID_MAX_OUTPUT_CHANNELS    0x00010DE2
+#define PARAM_ID_CTL_RUNNING_MODE       0x0
+#define PARAM_ID_CTL_ERROR_CONCEAL      0x00010DE3
+#define PARAM_ID_CTL_ERROR_MAX_RPTS     0x00010DE4
+#define PARAM_ID_CNV_ERROR_CONCEAL      0x00010DE5
+#define PARAM_ID_CTL_SUBSTREAM_SELECT   0x00010DE6
+#define PARAM_ID_CTL_INPUT_MODE         0x0
+#define PARAM_ID_OUT_CTL_OUTMODE        0x00010DE0
+#define PARAM_ID_OUT_CTL_OUTLFE_ON      0x00010DE1
+#define PARAM_ID_OUT_CTL_COMPMODE       0x00010D74
+#define PARAM_ID_OUT_CTL_STEREO_MODE    0x00010D76
+#define PARAM_ID_OUT_CTL_DUAL_MODE      0x00010D75
+#define PARAM_ID_OUT_CTL_DRCSCALE_HIGH  0x00010D7A
+#define PARAM_ID_OUT_CTL_DRCSCALE_LOW   0x00010D79
+#define PARAM_ID_OUT_CTL_OUT_PCMSCALE   0x00010D78
+#define PARAM_ID_OUT_CTL_MDCT_BANDLIMIT 0x00010DE7
+#define PARAM_ID_OUT_CTL_DRC_SUPPRESS   0x00010DE8
+
+/* DS1-DDP Endp Params */
+#define DDP_ENDP_NUM_PARAMS 17
+#define DDP_ENDP_NUM_DEVICES 21
+static int ddp_endp_params_id[DDP_ENDP_NUM_PARAMS] = {
+    PARAM_ID_MAX_OUTPUT_CHANNELS, PARAM_ID_CTL_RUNNING_MODE,
+    PARAM_ID_CTL_ERROR_CONCEAL, PARAM_ID_CTL_ERROR_MAX_RPTS,
+    PARAM_ID_CNV_ERROR_CONCEAL, PARAM_ID_CTL_SUBSTREAM_SELECT,
+    PARAM_ID_CTL_INPUT_MODE, PARAM_ID_OUT_CTL_OUTMODE,
+    PARAM_ID_OUT_CTL_OUTLFE_ON, PARAM_ID_OUT_CTL_COMPMODE,
+    PARAM_ID_OUT_CTL_STEREO_MODE, PARAM_ID_OUT_CTL_DUAL_MODE,
+    PARAM_ID_OUT_CTL_DRCSCALE_HIGH, PARAM_ID_OUT_CTL_DRCSCALE_LOW,
+    PARAM_ID_OUT_CTL_OUT_PCMSCALE, PARAM_ID_OUT_CTL_MDCT_BANDLIMIT,
+    PARAM_ID_OUT_CTL_DRC_SUPPRESS
+};
+
+static struct ddp_endp_params {
+    int  device;
+    int  dev_ch_cap;
+    int  param_val[DDP_ENDP_NUM_PARAMS];
+    bool is_param_valid[DDP_ENDP_NUM_PARAMS];
+} ddp_endp_params[DDP_ENDP_NUM_DEVICES] = {
+          {AUDIO_DEVICE_OUT_EARPIECE, 2,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 } },
+          {AUDIO_DEVICE_OUT_SPEAKER, 2,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_WIRED_HEADSET, 2,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_WIRED_HEADPHONE, 2,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_BLUETOOTH_SCO, 2,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, 2,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, 2,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, 2,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, 2,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, 2,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_AUX_DIGITAL, 2,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 2, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_AUX_DIGITAL, 6,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 2, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_AUX_DIGITAL, 8,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 2, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET, 2,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, 2,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_USB_ACCESSORY, 2,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_USB_DEVICE, 2,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_FM, 2,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_FM_TX, 2,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_PROXY, 2,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 2, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+          {AUDIO_DEVICE_OUT_PROXY, 6,
+              {8, 0, 0, 0, 0, 0, 0, 21, 1, 2, 0, 0, 0, 0, 0, 0, 0},
+              {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} },
+};
+
+int update_ddp_endp_table(int device, int dev_ch_cap, int param_id,
+                          int param_val)
+{
+    int idx = 0;
+    int param_idx = 0;
+    ALOGV("%s: dev 0x%x dev_ch_cap %d param_id 0x%x param_val %d",
+           __func__, device, dev_ch_cap , param_id, param_val);
+
+    for(idx=0; idx<DDP_ENDP_NUM_DEVICES; idx++) {
+        if(ddp_endp_params[idx].device == device) {
+            if(ddp_endp_params[idx].dev_ch_cap == dev_ch_cap) {
+                break;
+            }
+        }
+    }
+
+    if(idx>=DDP_ENDP_NUM_DEVICES) {
+        ALOGE("%s: device not available in DDP endp config table", __func__);
+        return -EINVAL;
+    }
+
+    for(param_idx=0; param_idx<DDP_ENDP_NUM_PARAMS; param_idx++) {
+        if (ddp_endp_params_id[param_idx] == param_id) {
+            break;
+        }
+    }
+
+    if(param_idx>=DDP_ENDP_NUM_PARAMS) {
+        ALOGE("param not available in DDP endp config table");
+        return -EINVAL;
+    }
+
+    ALOGV("ddp_endp_params[%d].param_val[%d] = %d", idx, param_idx, param_val);
+    ddp_endp_params[idx].param_val[param_idx] = param_val;
+    return 0;
+}
+
+void send_ddp_endp_params_stream(struct stream_out *out,
+                                 int device, int dev_ch_cap,
+                                 bool set_cache __unused)
+{
+    int idx, i;
+    int ddp_endp_params_data[2*DDP_ENDP_NUM_PARAMS + 1];
+    int length = 0;
+    for(idx=0; idx<DDP_ENDP_NUM_DEVICES; idx++) {
+        if(ddp_endp_params[idx].device & device) {
+            if(ddp_endp_params[idx].dev_ch_cap == dev_ch_cap) {
+                break;
+            }
+        }
+    }
+    if(idx>=DDP_ENDP_NUM_DEVICES) {
+        ALOGE("device not available in DDP endp config table");
+        return;
+    }
+
+    length += 1; /* offset 0 is for num of parameter. increase offset by 1 */
+    for (i=0; i<DDP_ENDP_NUM_PARAMS; i++) {
+        if(ddp_endp_params[idx].is_param_valid[i]) {
+            ddp_endp_params_data[length++] = ddp_endp_params_id[i];
+            ddp_endp_params_data[length++] = ddp_endp_params[idx].param_val[i];
+        }
+    }
+    ddp_endp_params_data[0] = (length-1)/2;
+    if(length) {
+        char mixer_ctl_name[128];
+        struct audio_device *adev = out->dev;
+        struct mixer_ctl *ctl;
+        int pcm_device_id = platform_get_pcm_device_id(out->usecase,
+                                                       PCM_PLAYBACK);
+        snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+                 "Audio Stream %d Dec Params", pcm_device_id);
+        ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+        if (!ctl) {
+            ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                  __func__, mixer_ctl_name);
+            return;
+        }
+        mixer_ctl_set_array(ctl, ddp_endp_params_data, length);
+    }
+    return;
+}
+
+void send_ddp_endp_params(struct audio_device *adev,
+                          int ddp_dev, int dev_ch_cap)
+{
+    struct listnode *node;
+    struct audio_usecase *usecase;
+
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if ((usecase->type == PCM_PLAYBACK) &&
+            (usecase->devices & ddp_dev) &&
+            (usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
+            ((usecase->stream.out->format == AUDIO_FORMAT_AC3) ||
+             (usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
+             (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC))) {
+            send_ddp_endp_params_stream(usecase->stream.out, ddp_dev,
+                                        dev_ch_cap, false /* set cache */);
+        }
+    }
+}
+
+void audio_extn_dolby_send_ddp_endp_params(struct audio_device *adev)
+{
+    struct listnode *node;
+    struct audio_usecase *usecase;
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if ((usecase->type == PCM_PLAYBACK) &&
+            (usecase->devices & AUDIO_DEVICE_OUT_ALL) &&
+            (usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
+            ((usecase->stream.out->format == AUDIO_FORMAT_AC3) ||
+             (usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
+             (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC))) {
+            /*
+             * Use wfd /hdmi sink channel cap for dolby params if device is wfd
+             * or hdmi. Otherwise use stereo configuration
+             */
+            int channel_cap = usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL ?
+                              adev->cur_hdmi_channels :
+                              usecase->devices & AUDIO_DEVICE_OUT_PROXY ?
+                              adev->cur_wfd_channels : 2;
+            send_ddp_endp_params_stream(usecase->stream.out, usecase->devices,
+                                        channel_cap, false /* set cache */);
+        }
+    }
+}
+
+void audio_extn_ddp_set_parameters(struct audio_device *adev,
+                                   struct str_parms *parms)
+{
+    int ddp_dev, dev_ch_cap;
+    int val, ret;
+    char value[32]={0};
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SND_CARD_STATUS, value,
+                            sizeof(value));
+    if (ret >= 0) {
+        char *snd_card_status = value + 2;
+        if (strncmp(snd_card_status, "ONLINE", sizeof("ONLINE")) == 0)
+            audio_extn_dolby_set_license(adev);
+    }
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_DDP_DEV, value,
+                            sizeof(value));
+    if (ret >= 0) {
+        ddp_dev = atoi(value);
+        if (!(AUDIO_DEVICE_OUT_ALL & ddp_dev))
+            return;
+    } else
+        return;
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_DDP_CH_CAP, value,
+                            sizeof(value));
+    if (ret >= 0) {
+        dev_ch_cap = atoi(value);
+        if ((dev_ch_cap != 2) && (dev_ch_cap != 6) && (dev_ch_cap != 8))
+            return;
+    } else
+        return;
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_DDP_MAX_OUT_CHAN, value,
+                            sizeof(value));
+    if (ret >= 0) {
+        val = atoi(value);
+        update_ddp_endp_table(ddp_dev, dev_ch_cap,
+                              PARAM_ID_MAX_OUTPUT_CHANNELS, val);
+    }
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_DDP_OUT_MODE, value,
+                            sizeof(value));
+    if (ret >= 0) {
+        val = atoi(value);
+        update_ddp_endp_table(ddp_dev, dev_ch_cap,
+                              PARAM_ID_OUT_CTL_OUTMODE, val);
+    }
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_DDP_OUT_LFE_ON, value,
+                            sizeof(value));
+    if (ret >= 0) {
+        val = atoi(value);
+        update_ddp_endp_table(ddp_dev, dev_ch_cap,
+                              PARAM_ID_OUT_CTL_OUTLFE_ON, val);
+    }
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_DDP_COMP_MODE, value,
+                            sizeof(value));
+    if (ret >= 0) {
+        val = atoi(value);
+        update_ddp_endp_table(ddp_dev, dev_ch_cap,
+                              PARAM_ID_OUT_CTL_COMPMODE, val);
+    }
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_DDP_STEREO_MODE, value,
+                            sizeof(value));
+    if (ret >= 0) {
+        val = atoi(value);
+        update_ddp_endp_table(ddp_dev, dev_ch_cap,
+                              PARAM_ID_OUT_CTL_STEREO_MODE, val);
+    }
+    /* TODO: Do we need device channel caps here?
+     * We dont have that information as this is from dolby modules
+     */
+    send_ddp_endp_params(adev, ddp_dev, dev_ch_cap);
+}
+#endif /* DS1_DOLBY_DDP_ENABLED */
+
+#if defined(DS1_DOLBY_DDP_ENABLED) || defined(DS2_DOLBY_DAP_ENABLED)
+int audio_extn_dolby_get_snd_codec_id(struct audio_device *adev,
+                                      struct stream_out *out,
+                                      audio_format_t format)
+{
+    int id = 0;
+    /*
+     * Use wfd /hdmi sink channel cap for dolby params if device is wfd
+     * or hdmi. Otherwise use stereo configuration
+     */
+    int channel_cap = out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL ?
+                      adev->cur_hdmi_channels :
+                      out->devices & AUDIO_DEVICE_OUT_PROXY ?
+                      adev->cur_wfd_channels : 2;
+
+    switch (format) {
+    case AUDIO_FORMAT_AC3:
+        id = SND_AUDIOCODEC_AC3;
+#ifdef DS1_DOLBY_DDP_ENABLED
+        send_ddp_endp_params_stream(out, out->devices,
+                            channel_cap, true /* set_cache */);
+#endif
+        audio_extn_dolby_set_dmid(adev);
+        break;
+    case AUDIO_FORMAT_E_AC3:
+    case AUDIO_FORMAT_E_AC3_JOC:
+        id = SND_AUDIOCODEC_EAC3;
+#ifdef DS1_DOLBY_DDP_ENABLED
+        send_ddp_endp_params_stream(out, out->devices,
+                            channel_cap, true /* set_cache */);
+#endif
+        audio_extn_dolby_set_dmid(adev);
+        break;
+    default:
+        ALOGE("%s: Unsupported audio format :%x", __func__, format);
+    }
+
+    return id;
+}
+
+bool audio_extn_is_dolby_format(audio_format_t format)
+{
+    if (format == AUDIO_FORMAT_AC3 ||
+            format == AUDIO_FORMAT_E_AC3 ||
+            format == AUDIO_FORMAT_E_AC3_JOC)
+        return true;
+    else
+        return false;
+}
+#endif /* DS1_DOLBY_DDP_ENABLED || DS2_DOLBY_DAP_ENABLED */
+
+#ifdef DS1_DOLBY_DAP_ENABLED
+void audio_extn_dolby_set_endpoint(struct audio_device *adev)
+{
+    struct listnode *node;
+    struct audio_usecase *usecase;
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "DS1 DAP Endpoint";
+    int endpoint = 0, ret;
+    bool send = false;
+
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if ((usecase->type == PCM_PLAYBACK) &&
+            (usecase->id != USECASE_AUDIO_PLAYBACK_LOW_LATENCY)) {
+            endpoint |= usecase->devices & AUDIO_DEVICE_OUT_ALL;
+            send = true;
+        }
+    }
+    if (!send)
+        return;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return;
+    }
+    ret = mixer_ctl_set_value(ctl, 0, endpoint);
+    if (ret)
+        ALOGE("%s: Dolby set endpint cannot be set error:%d",__func__, ret);
+
+    return;
+}
+#endif /* DS1_DOLBY_DAP_ENABLED */
+
+
+#if defined(DS1_DOLBY_DDP_ENABLED) || defined(DS1_DOLBY_DAP_ENABLED)
+void audio_extn_dolby_set_dmid(struct audio_device *adev)
+{
+    struct listnode *node;
+    struct audio_usecase *usecase;
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "DS1 Security";
+    char c_dmid[128] = {0};
+    int i_dmid, ret;
+    bool send = false;
+
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if (usecase->type == PCM_PLAYBACK)
+            send = true;
+    }
+    if (!send)
+        return;
+
+    property_get("dmid",c_dmid,"0");
+    i_dmid = atoll(c_dmid);
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return;
+    }
+    ALOGV("%s Dolby device manufacturer id is:%d",__func__,i_dmid);
+    ret = mixer_ctl_set_value(ctl, 0, i_dmid);
+    if (ret)
+        ALOGE("%s: Dolby DMID cannot be set error:%d",__func__, ret);
+
+    return;
+}
+
+#ifndef DS2_DOLBY_DAP_ENABLED
+void audio_extn_dolby_set_license(struct audio_device *adev)
+{
+    int ret, key=0;
+    char value[128] = {0};
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "DS1 License";
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return;
+    }
+
+    property_get("audio.ds1.metainfo.key",value,"0");
+#ifdef DOLBY_ACDB_LICENSE
+    key = atoi(value);
+#else
+    key = 0;
+#endif
+    ALOGV("%s Setting DS1 License, key:0x%x",__func__, key);
+    ret = mixer_ctl_set_value(ctl, 0, key);
+    if (ret)
+        ALOGE("%s: cannot set license, error:%d",__func__, ret);
+
+    return;
+}
+#endif
+#endif /* DS1_DOLBY_DDP_ENABLED || DS1_DOLBY_DAP_ENABLED */
+
+#ifdef DS2_DOLBY_DAP_ENABLED
+struct ds2_extn_module  {
+   void *ds2_handle;
+   dap_hal_set_hw_info_t dap_hal_set_hw_info;
+};
+
+static struct ds2_extn_module ds2extnmod = {
+    .ds2_handle = NULL,
+    .dap_hal_set_hw_info = NULL,
+};
+
+int audio_extn_dap_hal_init(int snd_card) {
+    char c_dmid[128] = {0};
+    void *handle = NULL;
+    int i_dmid, ret = -EINVAL;
+    dap_hal_device_be_id_map_t device_be_id_map;
+
+    ALOGV("%s: opening DAP HAL lib\n", __func__);
+    ds2extnmod.ds2_handle = dlopen(LIB_DS2_DAP_HAL, RTLD_NOW);
+    if (ds2extnmod.ds2_handle == NULL) {
+        ALOGE("%s: DLOPEN failed for %s error %s", __func__, LIB_DS2_DAP_HAL,
+              dlerror());
+        goto ret;
+    }
+    ds2extnmod.dap_hal_set_hw_info = (dap_hal_set_hw_info_t)dlsym(ds2extnmod.ds2_handle, SET_HW_INFO_FUNC);
+    if (ds2extnmod.dap_hal_set_hw_info == NULL) {
+           ALOGE("%s: dlsym error %s for %s", __func__, SET_HW_INFO_FUNC,
+                 dlerror());
+           goto close;
+    }
+    ds2extnmod.dap_hal_set_hw_info(SND_CARD, (void*)(&snd_card));
+    ALOGV("%s Sound card number is:%d",__func__,snd_card);
+
+    platform_get_device_to_be_id_map(&device_be_id_map.device_id_to_be_id, &device_be_id_map.len);
+    ds2extnmod.dap_hal_set_hw_info(DEVICE_BE_ID_MAP, (void*)(&device_be_id_map));
+    ALOGV("%s Set be id map len:%d",__func__,device_be_id_map.len);
+    ret = 0;
+    goto ret;
+
+close:
+    dlclose(ds2extnmod.ds2_handle);
+    ds2extnmod.ds2_handle = NULL;
+    ds2extnmod.dap_hal_set_hw_info = NULL;
+ret:
+    return ret;
+}
+
+int audio_extn_dap_hal_deinit() {
+    if (ds2extnmod.ds2_handle != NULL) {
+       dlclose(ds2extnmod.ds2_handle);
+       ds2extnmod.ds2_handle = NULL;
+    }
+    ds2extnmod.dap_hal_set_hw_info = NULL;
+    return 0;
+}
+
+void audio_extn_dolby_ds2_set_endpoint(struct audio_device *adev) {
+    struct listnode *node;
+    struct audio_usecase *usecase;
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "DS1 DAP Endpoint";
+    int endpoint = 0, ret;
+    bool send = false;
+
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if ((usecase->type == PCM_PLAYBACK) &&
+            (usecase->id != USECASE_AUDIO_PLAYBACK_LOW_LATENCY)) {
+            endpoint |= usecase->devices & AUDIO_DEVICE_OUT_ALL;
+            send = true;
+        }
+    }
+    if (!send)
+        return;
+
+    if (ds2extnmod.dap_hal_set_hw_info) {
+        ds2extnmod.dap_hal_set_hw_info(HW_ENDPOINT, (void*)(&endpoint));
+        ALOGE("%s: Dolby set endpint :0x%x",__func__, endpoint);
+    } else {
+        ALOGE("%s: dap_hal_set_hw_info is NULL",__func__);
+    }
+
+    return;
+}
+
+int audio_extn_ds2_enable(struct audio_device *adev) {
+
+    char value[PROPERTY_VALUE_MAX] = {0};
+    bool ds2_enabled = false;
+    const char *mixer_ctl_name = "DS2 OnOff";
+    struct mixer_ctl *ctl;
+
+    property_get("audio.dolby.ds2.enabled", value, NULL);
+    ds2_enabled = atoi(value) || !strncmp("true", value, 4);
+
+    ALOGV("%s:", __func__);
+    if(ds2_enabled) {
+        ALOGD("%s:ds2_enabled %d", __func__, ds2_enabled);
+        ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+        if (!ctl) {
+            ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                                   __func__, mixer_ctl_name);
+            return -EINVAL;
+        }
+
+        if (mixer_ctl_set_value(ctl, 0, ds2_enabled) < 0) {
+            ALOGE("%s: Could not set ds2 enable %d",
+                            __func__, ds2_enabled);
+            return -EINVAL;
+        }
+    }
+    return 0;
+}
+
+int audio_extn_dolby_set_dap_bypass(struct audio_device *adev, int state) {
+
+    ALOGV("%s: state %d", __func__, state);
+    if (ds2extnmod.dap_hal_set_hw_info) {
+        ds2extnmod.dap_hal_set_hw_info(DAP_BYPASS, (void*)(&state));
+        ALOGV("%s: Dolby set bypas :0x%x", __func__, state);
+    } else {
+        ALOGV("%s: dap_hal_set_hw_info is NULL", __func__);
+    }
+    return 0;
+}
+
+void audio_extn_dolby_set_license(struct audio_device *adev)
+{
+    int i_key=0;
+    char c_key[128] = {0};
+    char c_dmid[128] = {0};
+    int i_dmid, ret = -EINVAL;
+    struct dolby_param_license dolby_license;
+
+#ifdef DOLBY_ACDB_LICENSE
+    property_get("audio.ds1.metainfo.key",c_key,"0");
+    i_key = atoi(c_key);
+#else
+    /* As ACDB based license mechanism is disabled, force set the license key to 0*/
+    i_key = 0;
+#endif
+    property_get("dmid",c_dmid,"0");
+    i_dmid = atoll(c_dmid);
+    ALOGV("%s Setting DS1 License, key:0x%x dmid %d",__func__, i_key,i_dmid);
+    dolby_license.dmid = i_dmid;
+    dolby_license.license_key = i_key;
+    if (ds2extnmod.dap_hal_set_hw_info) {
+        ds2extnmod.dap_hal_set_hw_info(DMID, (void*)(&dolby_license.dmid));
+    } else {
+        ALOGV("%s: dap_hal_set_hw_info is NULL", __func__);
+        return ret;
+    }
+    return 0;
+}
+
+
+void audio_extn_ds2_set_parameters(struct audio_device *adev,
+                                   struct str_parms *parms)
+{
+    int val, ret;
+    char value[32]={0};
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SND_CARD_STATUS, value,
+                            sizeof(value));
+    if (ret >= 0) {
+        char *snd_card_status = value + 2;
+        if (strncmp(snd_card_status, "ONLINE", sizeof("ONLINE")) == 0){
+            audio_extn_dolby_set_license(adev);
+        }
+    }
+}
+#endif
diff --git a/msm8909/hal/audio_extn/fm.c b/msm8909/hal/audio_extn/fm.c
new file mode 100644
index 0000000..61c21d2
--- /dev/null
+++ b/msm8909/hal/audio_extn/fm.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_fm"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <math.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include <stdlib.h>
+#include <cutils/str_parms.h>
+
+#ifdef FM_POWER_OPT
+#define AUDIO_PARAMETER_KEY_HANDLE_FM "handle_fm"
+#define AUDIO_PARAMETER_KEY_FM_VOLUME "fm_volume"
+#define AUDIO_PARAMETER_KEY_REC_PLAY_CONC "rec_play_conc_on"
+
+static struct pcm_config pcm_config_fm = {
+    .channels = 2,
+    .rate = 48000,
+    .period_size = 256,
+    .period_count = 4,
+    .format = PCM_FORMAT_S16_LE,
+    .start_threshold = 0,
+    .stop_threshold = INT_MAX,
+    .avail_min = 0,
+};
+
+struct fm_module {
+    struct pcm *fm_pcm_rx;
+    struct pcm *fm_pcm_tx;
+    bool is_fm_running;
+    float fm_volume;
+    bool restart_fm;
+    int scard_state;
+};
+
+static struct fm_module fmmod = {
+  .fm_pcm_rx = NULL,
+  .fm_pcm_tx = NULL,
+  .fm_volume = 0,
+  .is_fm_running = 0,
+  .restart_fm = 0,
+  .scard_state = SND_CARD_STATE_ONLINE,
+};
+
+static int32_t fm_set_volume(struct audio_device *adev, float value)
+{
+    int32_t vol, ret = 0;
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = FM_RX_VOLUME;
+
+    ALOGV("%s: entry", __func__);
+    ALOGD("%s: (%f)\n", __func__, value);
+
+    if (value < 0.0) {
+        ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
+        value = 0.0;
+    } else if (value > 1.0) {
+        ALOGW("%s: (%f) Over 1.0, assuming 1.0\n", __func__, value);
+        value = 1.0;
+    }
+    vol  = lrint((value * 0x2000) + 0.5);
+    fmmod.fm_volume = value;
+
+    if (!fmmod.is_fm_running) {
+        ALOGV("%s: FM not active, ignoring set_fm_volume call", __func__);
+        return -EIO;
+    }
+
+    ALOGD("%s: Setting FM volume to %d \n", __func__, vol);
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    mixer_ctl_set_value(ctl, 0, vol);
+    ALOGV("%s: exit", __func__);
+    return ret;
+}
+
+static int32_t fm_stop(struct audio_device *adev)
+{
+    int32_t i, ret = 0;
+    struct audio_usecase *uc_info;
+
+    ALOGD("%s: enter", __func__);
+    fmmod.is_fm_running = false;
+
+    /* 1. Close the PCM devices */
+    if (fmmod.fm_pcm_rx) {
+        pcm_close(fmmod.fm_pcm_rx);
+        fmmod.fm_pcm_rx = NULL;
+    }
+    if (fmmod.fm_pcm_tx) {
+        pcm_close(fmmod.fm_pcm_tx);
+        fmmod.fm_pcm_tx = NULL;
+    }
+
+    uc_info = get_usecase_from_list(adev, USECASE_AUDIO_PLAYBACK_FM);
+    if (uc_info == NULL) {
+        ALOGE("%s: Could not find the usecase (%d) in the list",
+              __func__, USECASE_VOICE_CALL);
+        return -EINVAL;
+    }
+
+    /* 2. Get and set stream specific mixer controls */
+    disable_audio_route(adev, uc_info);
+
+    /* 3. Disable the rx and tx devices */
+    disable_snd_device(adev, uc_info->out_snd_device);
+    disable_snd_device(adev, uc_info->in_snd_device);
+
+    list_remove(&uc_info->list);
+    free(uc_info);
+
+    ALOGD("%s: exit: status(%d)", __func__, ret);
+    return ret;
+}
+
+static int32_t fm_start(struct audio_device *adev)
+{
+    int32_t i, ret = 0;
+    struct audio_usecase *uc_info;
+    int32_t pcm_dev_rx_id, pcm_dev_tx_id;
+
+    ALOGD("%s: enter", __func__);
+
+    uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+
+    if (!uc_info)
+        return -ENOMEM;
+
+    uc_info->id = USECASE_AUDIO_PLAYBACK_FM;
+    uc_info->type = PCM_PLAYBACK;
+    uc_info->stream.out = adev->primary_output;
+    uc_info->devices = adev->primary_output->devices;
+    uc_info->in_snd_device = SND_DEVICE_NONE;
+    uc_info->out_snd_device = SND_DEVICE_NONE;
+
+    list_add_tail(&adev->usecase_list, &uc_info->list);
+
+    select_devices(adev, USECASE_AUDIO_PLAYBACK_FM);
+
+    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);
+
+    if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0) {
+        ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(%d)",
+              __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
+        ret = -EIO;
+        goto exit;
+    }
+
+    ALOGV("%s: FM PCM devices (rx: %d tx: %d) for the usecase(%d)",
+              __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
+
+    ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
+          __func__, adev->snd_card, pcm_dev_rx_id);
+    fmmod.fm_pcm_rx = pcm_open(adev->snd_card,
+                               pcm_dev_rx_id,
+                               PCM_OUT, &pcm_config_fm);
+    if (fmmod.fm_pcm_rx && !pcm_is_ready(fmmod.fm_pcm_rx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(fmmod.fm_pcm_rx));
+        ret = -EIO;
+        goto exit;
+    }
+
+    ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+          __func__, adev->snd_card, pcm_dev_tx_id);
+    fmmod.fm_pcm_tx = pcm_open(adev->snd_card,
+                               pcm_dev_tx_id,
+                               PCM_IN, &pcm_config_fm);
+    if (fmmod.fm_pcm_tx && !pcm_is_ready(fmmod.fm_pcm_tx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(fmmod.fm_pcm_tx));
+        ret = -EIO;
+        goto exit;
+    }
+    pcm_start(fmmod.fm_pcm_rx);
+    pcm_start(fmmod.fm_pcm_tx);
+
+    fmmod.is_fm_running = true;
+    fm_set_volume(adev, fmmod.fm_volume);
+
+    ALOGD("%s: exit: status(%d)", __func__, ret);
+    return 0;
+
+exit:
+    fm_stop(adev);
+    ALOGE("%s: Problem in FM start: status(%d)", __func__, ret);
+    return ret;
+}
+
+void audio_extn_fm_set_parameters(struct audio_device *adev,
+                                  struct str_parms *parms)
+{
+    int ret, val;
+    char value[32]={0};
+    float vol =0.0;
+
+    ALOGV("%s: enter", __func__);
+    ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value));
+    if (ret >= 0) {
+        char *snd_card_status = value+2;
+        if (strstr(snd_card_status, "OFFLINE")) {
+            fmmod.scard_state = SND_CARD_STATE_OFFLINE;
+        }
+        else if (strstr(snd_card_status, "ONLINE")) {
+            fmmod.scard_state = SND_CARD_STATE_ONLINE;
+        }
+    }
+    if(fmmod.is_fm_running) {
+        if (fmmod.scard_state == SND_CARD_STATE_OFFLINE) {
+            ALOGD("sound card is OFFLINE, stop FM");
+            fm_stop(adev);
+            fmmod.restart_fm = 1;
+        }
+
+        ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
+                                value, sizeof(value));
+        if (ret >= 0) {
+            val = atoi(value);
+            if(val > 0)
+                select_devices(adev, USECASE_AUDIO_PLAYBACK_FM);
+        }
+    }
+    if (fmmod.restart_fm && (fmmod.scard_state == SND_CARD_STATE_ONLINE)) {
+        ALOGD("sound card is ONLINE, restart FM");
+        fmmod.restart_fm = 0;
+        fm_start(adev);
+    }
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HANDLE_FM,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        val = atoi(value);
+        ALOGD("%s: FM usecase", __func__);
+        if (val != 0) {
+            if(val & AUDIO_DEVICE_OUT_FM
+               && fmmod.is_fm_running == false) {
+                adev->primary_output->devices = val & ~AUDIO_DEVICE_OUT_FM;
+                fm_start(adev);
+            } else if (!(val & AUDIO_DEVICE_OUT_FM)
+                     && fmmod.is_fm_running == true)
+                fm_stop(adev);
+       }
+    }
+
+    memset(value, 0, sizeof(value));
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_FM_VOLUME,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        if (sscanf(value, "%f", &vol) != 1){
+            ALOGE("%s: error in retrieving fm volume", __func__);
+            ret = -EIO;
+            goto exit;
+        }
+        ALOGD("%s: set_fm_volume usecase", __func__);
+        fm_set_volume(adev, vol);
+    }
+
+#ifdef RECORD_PLAY_CONCURRENCY
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_REC_PLAY_CONC,
+                               value, sizeof(value));
+    if ((ret >= 0)
+          && (fmmod.is_fm_running == true)) {
+
+        if (!strncmp("true", value, sizeof("true")))
+            ALOGD("Record play concurrency ON Forcing FM device reroute");
+        else
+            ALOGD("Record play concurrency OFF Forcing FM device reroute");
+
+        select_devices(adev, USECASE_AUDIO_PLAYBACK_FM);
+        fm_set_volume(adev,fmmod.fm_volume);
+    }
+#endif
+exit:
+    ALOGV("%s: exit", __func__);
+}
+#endif /* FM_POWER_OPT end */
diff --git a/msm8909/hal/audio_extn/hfp.c b/msm8909/hal/audio_extn/hfp.c
new file mode 100644
index 0000000..a0588a3
--- /dev/null
+++ b/msm8909/hal/audio_extn/hfp.c
@@ -0,0 +1,363 @@
+/* hfp.c
+Copyright (c) 2012-2014, 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_hw_hfp"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <math.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include <stdlib.h>
+#include <cutils/str_parms.h>
+
+#ifdef HFP_ENABLED
+#define AUDIO_PARAMETER_HFP_ENABLE      "hfp_enable"
+#define AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE "hfp_set_sampling_rate"
+#define AUDIO_PARAMETER_KEY_HFP_VOLUME "hfp_volume"
+
+#ifdef PLATFORM_MSM8994
+#define HFP_RX_VOLUME     "SEC AUXPCM LOOPBACK Volume"
+#else
+#define HFP_RX_VOLUME     "Internal HFP RX Volume"
+#endif
+
+static int32_t start_hfp(struct audio_device *adev,
+                               struct str_parms *parms);
+
+static int32_t stop_hfp(struct audio_device *adev);
+
+struct hfp_module {
+    struct pcm *hfp_sco_rx;
+    struct pcm *hfp_sco_tx;
+    struct pcm *hfp_pcm_rx;
+    struct pcm *hfp_pcm_tx;
+    bool is_hfp_running;
+    float hfp_volume;
+    audio_usecase_t ucid;
+};
+
+static struct hfp_module hfpmod = {
+    .hfp_sco_rx = NULL,
+    .hfp_sco_tx = NULL,
+    .hfp_pcm_rx = NULL,
+    .hfp_pcm_tx = NULL,
+    .hfp_volume = 0,
+    .is_hfp_running = 0,
+    .ucid = USECASE_AUDIO_HFP_SCO,
+};
+static struct pcm_config pcm_config_hfp = {
+    .channels = 1,
+    .rate = 8000,
+    .period_size = 240,
+    .period_count = 2,
+    .format = PCM_FORMAT_S16_LE,
+    .start_threshold = 0,
+    .stop_threshold = INT_MAX,
+    .avail_min = 0,
+};
+
+static int32_t hfp_set_volume(struct audio_device *adev, float value)
+{
+    int32_t vol, ret = 0;
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = HFP_RX_VOLUME;
+
+    ALOGV("%s: entry", __func__);
+    ALOGD("%s: (%f)\n", __func__, value);
+
+    hfpmod.hfp_volume = value;
+    if (value < 0.0) {
+        ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
+        value = 0.0;
+    } else {
+        value = ((value > 15.000000) ? 1.0 : (value / 15));
+        ALOGW("%s: Volume brought with in range (%f)\n", __func__, value);
+    }
+    vol  = lrint((value * 0x2000) + 0.5);
+
+    if (!hfpmod.is_hfp_running) {
+        ALOGV("%s: HFP not active, ignoring set_hfp_volume call", __func__);
+        return -EIO;
+    }
+
+    ALOGD("%s: Setting HFP volume to %d \n", __func__, vol);
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    if(mixer_ctl_set_value(ctl, 0, vol) < 0) {
+        ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, vol);
+        return -EINVAL;
+    }
+
+    ALOGV("%s: exit", __func__);
+    return ret;
+}
+
+static int32_t start_hfp(struct audio_device *adev,
+                         struct str_parms *parms __unused)
+{
+    int32_t i, ret = 0;
+    struct audio_usecase *uc_info;
+    int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id;
+
+    ALOGD("%s: enter", __func__);
+
+    uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+
+    if (!uc_info)
+        return -ENOMEM;
+
+    uc_info->id = hfpmod.ucid;
+    uc_info->type = PCM_HFP_CALL;
+    uc_info->stream.out = adev->primary_output;
+    uc_info->devices = adev->primary_output->devices;
+    uc_info->in_snd_device = SND_DEVICE_NONE;
+    uc_info->out_snd_device = SND_DEVICE_NONE;
+
+    list_add_tail(&adev->usecase_list, &uc_info->list);
+
+    select_devices(adev, hfpmod.ucid);
+
+    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 = HFP_ASM_RX_TX;
+    pcm_dev_asm_tx_id = HFP_ASM_RX_TX;
+    if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0 ||
+        pcm_dev_asm_rx_id < 0 || pcm_dev_asm_tx_id < 0 ) {
+        ALOGE("%s: Invalid PCM devices (rx: %d tx: %d asm: rx tx %d) for the usecase(%d)",
+              __func__, pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, uc_info->id);
+        ret = -EIO;
+        goto exit;
+    }
+
+    ALOGV("%s: HFP PCM devices (hfp rx tx: %d pcm rx tx: %d) for the usecase(%d)",
+              __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
+
+    ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
+          __func__, adev->snd_card, pcm_dev_rx_id);
+    hfpmod.hfp_sco_rx = pcm_open(adev->snd_card,
+                                  pcm_dev_asm_rx_id,
+                                  PCM_OUT, &pcm_config_hfp);
+    if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_rx));
+        ret = -EIO;
+        goto exit;
+    }
+    ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+          __func__, adev->snd_card, pcm_dev_tx_id);
+    hfpmod.hfp_pcm_rx = pcm_open(adev->snd_card,
+                                   pcm_dev_rx_id,
+                                   PCM_OUT, &pcm_config_hfp);
+    if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_rx));
+        ret = -EIO;
+        goto exit;
+    }
+    hfpmod.hfp_sco_tx = pcm_open(adev->snd_card,
+                                  pcm_dev_asm_tx_id,
+                                  PCM_IN, &pcm_config_hfp);
+    if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_tx));
+        ret = -EIO;
+        goto exit;
+    }
+    ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+          __func__, adev->snd_card, pcm_dev_tx_id);
+    hfpmod.hfp_pcm_tx = pcm_open(adev->snd_card,
+                                   pcm_dev_tx_id,
+                                   PCM_IN, &pcm_config_hfp);
+    if (hfpmod.hfp_pcm_tx && !pcm_is_ready(hfpmod.hfp_pcm_tx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_tx));
+        ret = -EIO;
+        goto exit;
+    }
+    if (pcm_start(hfpmod.hfp_sco_rx) < 0) {
+        ALOGE("%s: pcm start for hfp sco rx failed", __func__);
+        ret = -EINVAL;
+        goto exit;
+    }
+    if (pcm_start(hfpmod.hfp_sco_tx) < 0) {
+        ALOGE("%s: pcm start for hfp sco tx failed", __func__);
+        ret = -EINVAL;
+        goto exit;
+    }
+    if (pcm_start(hfpmod.hfp_pcm_rx) < 0) {
+        ALOGE("%s: pcm start for hfp pcm rx failed", __func__);
+        ret = -EINVAL;
+        goto exit;
+    }
+    if (pcm_start(hfpmod.hfp_pcm_tx) < 0) {
+        ALOGE("%s: pcm start for hfp pcm tx failed", __func__);
+        ret = -EINVAL;
+        goto exit;
+    }
+
+    hfpmod.is_hfp_running = true;
+    hfp_set_volume(adev, hfpmod.hfp_volume);
+
+    ALOGD("%s: exit: status(%d)", __func__, ret);
+    return 0;
+
+exit:
+    stop_hfp(adev);
+    ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret);
+    return ret;
+}
+
+static int32_t stop_hfp(struct audio_device *adev)
+{
+    int32_t i, ret = 0;
+    struct audio_usecase *uc_info;
+
+    ALOGD("%s: enter", __func__);
+    hfpmod.is_hfp_running = false;
+
+    /* 1. Close the PCM devices */
+    if (hfpmod.hfp_sco_rx) {
+        pcm_close(hfpmod.hfp_sco_rx);
+        hfpmod.hfp_sco_rx = NULL;
+    }
+    if (hfpmod.hfp_sco_tx) {
+        pcm_close(hfpmod.hfp_sco_tx);
+        hfpmod.hfp_sco_tx = NULL;
+    }
+    if (hfpmod.hfp_pcm_rx) {
+        pcm_close(hfpmod.hfp_pcm_rx);
+        hfpmod.hfp_pcm_rx = NULL;
+    }
+    if (hfpmod.hfp_pcm_tx) {
+        pcm_close(hfpmod.hfp_pcm_tx);
+        hfpmod.hfp_pcm_tx = NULL;
+    }
+
+    uc_info = get_usecase_from_list(adev, hfpmod.ucid);
+    if (uc_info == NULL) {
+        ALOGE("%s: Could not find the usecase (%d) in the list",
+              __func__, hfpmod.ucid);
+        return -EINVAL;
+    }
+
+    /* 2. Disable echo reference while stopping hfp */
+    platform_set_echo_reference(adev->platform, false);
+
+    /* 3. Get and set stream specific mixer controls */
+    disable_audio_route(adev, uc_info);
+
+    /* 4. Disable the rx and tx devices */
+    disable_snd_device(adev, uc_info->out_snd_device);
+    disable_snd_device(adev, uc_info->in_snd_device);
+
+    list_remove(&uc_info->list);
+    free(uc_info);
+
+    ALOGD("%s: exit: status(%d)", __func__, ret);
+    return ret;
+}
+
+bool audio_extn_hfp_is_active(struct audio_device *adev)
+{
+    struct audio_usecase *hfp_usecase = NULL;
+    hfp_usecase = get_usecase_from_list(adev, hfpmod.ucid);
+
+    if (hfp_usecase != NULL)
+        return true;
+    else
+        return false;
+}
+
+audio_usecase_t audio_extn_hfp_get_usecase()
+{
+    return hfpmod.ucid;
+}
+
+void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
+{
+    int ret;
+    int rate;
+    int val;
+    float vol;
+    char value[32]={0};
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
+                            sizeof(value));
+    if (ret >= 0) {
+           if (!strncmp(value,"true",sizeof(value)))
+               ret = start_hfp(adev,parms);
+           else
+               stop_hfp(adev);
+    }
+    memset(value, 0, sizeof(value));
+    ret = str_parms_get_str(parms,AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE, value,
+                            sizeof(value));
+    if (ret >= 0) {
+           rate = atoi(value);
+           if (rate == 8000){
+               hfpmod.ucid = USECASE_AUDIO_HFP_SCO;
+               pcm_config_hfp.rate = rate;
+           } else if (rate == 16000){
+               hfpmod.ucid = USECASE_AUDIO_HFP_SCO_WB;
+               pcm_config_hfp.rate = rate;
+           } else
+               ALOGE("Unsupported rate..");
+    }
+
+    if (hfpmod.is_hfp_running) {
+        memset(value, 0, sizeof(value));
+        ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
+                                value, sizeof(value));
+        if (ret >= 0) {
+            val = atoi(value);
+            if (val > 0)
+                select_devices(adev, hfpmod.ucid);
+        }
+    }
+
+    memset(value, 0, sizeof(value));
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_VOLUME,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        if (sscanf(value, "%f", &vol) != 1){
+            ALOGE("%s: error in retrieving hfp volume", __func__);
+            ret = -EIO;
+            goto exit;
+        }
+        ALOGD("%s: set_hfp_volume usecase, Vol: [%f]", __func__, vol);
+        hfp_set_volume(adev, vol);
+    }
+exit:
+    ALOGV("%s Exit",__func__);
+}
+#endif /*HFP_ENABLED*/
diff --git a/msm8909/hal/audio_extn/listen.c b/msm8909/hal/audio_extn/listen.c
new file mode 100644
index 0000000..4cb2d2d
--- /dev/null
+++ b/msm8909/hal/audio_extn/listen.c
@@ -0,0 +1,260 @@
+/* Copyright (c) 2013-2014, 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 "listen_hal_loader"
+/* #define LOG_NDEBUG 0 */
+/* #define LOG_NDDEBUG 0 */
+#include <stdbool.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/log.h>
+#ifdef AUDIO_LISTEN_ENABLED
+#include <listen_types.h>
+#endif
+#include "audio_hw.h"
+#include "audio_extn.h"
+#include "platform.h"
+#include "platform_api.h"
+
+
+#ifdef AUDIO_LISTEN_ENABLED
+
+#define LIB_LISTEN_LOADER "/vendor/lib/liblistenhardware.so"
+
+#define LISTEN_LOAD_SYMBOLS(dev, func_p, func_type, symbol) \
+{\
+    dev->func_p = (func_type)dlsym(dev->lib_handle,#symbol);\
+    if (dev->func_p == NULL) {\
+            ALOGE("%s: dlsym error %s for %s",\
+                    __func__, dlerror(), #symbol);\
+            free(dev);\
+            dev = NULL;\
+            return -EINVAL;\
+    }\
+}
+
+
+typedef int (*create_listen_hw_t)(unsigned int snd_card,
+                                  struct audio_route *audio_route);
+typedef void (*destroy_listen_hw_t)();
+
+typedef int (*open_listen_session_t)(struct audio_hw_device *,
+                                    struct listen_open_params*,
+                                    struct listen_session**);
+
+typedef int (*close_listen_session_t)(struct audio_hw_device *dev,
+                                    struct listen_session* handle);
+
+typedef int (*set_mad_observer_t)(struct audio_hw_device *dev,
+                                      listen_callback_t cb_func);
+
+typedef int (*listen_set_parameters_t)(struct audio_hw_device *dev,
+                                const char *kv_pairs);
+typedef char* (*get_parameters_t)(const struct audio_hw_device *dev,
+                                    const char *keys);
+typedef void (*listen_notify_event_t)(event_type_t event_type);
+
+struct listen_audio_device {
+    void *lib_handle;
+    struct audio_device *adev;
+
+    create_listen_hw_t create_listen_hw;
+    destroy_listen_hw_t destroy_listen_hw;
+    open_listen_session_t open_listen_session;
+    close_listen_session_t close_listen_session;
+    set_mad_observer_t set_mad_observer;
+    listen_set_parameters_t listen_set_parameters;
+    get_parameters_t get_parameters;
+    listen_notify_event_t notify_event;
+};
+
+static struct listen_audio_device *listen_dev;
+
+void audio_extn_listen_update_device_status(snd_device_t snd_device,
+                                     listen_event_type_t event)
+{
+    bool raise_event = false;
+    int device_type = -1;
+
+    if (snd_device >= SND_DEVICE_OUT_BEGIN &&
+        snd_device < SND_DEVICE_OUT_END)
+        device_type = PCM_PLAYBACK;
+    else if (snd_device >= SND_DEVICE_IN_BEGIN &&
+        snd_device < SND_DEVICE_IN_END)
+        device_type = PCM_CAPTURE;
+    else {
+        ALOGE("%s: invalid device 0x%x, for event %d",
+                           __func__, snd_device, event);
+        return;
+    }
+
+    if (listen_dev) {
+        raise_event = platform_listen_device_needs_event(snd_device);
+        ALOGI("%s(): device 0x%x of type %d for Event %d, with Raise=%d",
+            __func__, snd_device, device_type, event, raise_event);
+        if (raise_event && (device_type == PCM_CAPTURE)) {
+            switch(event) {
+            case LISTEN_EVENT_SND_DEVICE_FREE:
+                listen_dev->notify_event(AUDIO_DEVICE_IN_INACTIVE);
+                break;
+            case LISTEN_EVENT_SND_DEVICE_BUSY:
+                listen_dev->notify_event(AUDIO_DEVICE_IN_ACTIVE);
+                break;
+            default:
+                ALOGW("%s:invalid event %d for device 0x%x",
+                                      __func__, event, snd_device);
+            }
+        }/*Events for output device, if required can be placed here in else*/
+    }
+}
+
+void audio_extn_listen_update_stream_status(struct audio_usecase *uc_info,
+                                     listen_event_type_t event)
+{
+    bool raise_event = false;
+    audio_usecase_t uc_id;
+    int usecase_type = -1;
+
+    if (uc_info == NULL) {
+        ALOGE("%s: usecase is NULL!!!", __func__);
+        return;
+    }
+    uc_id = uc_info->id;
+    usecase_type = uc_info->type;
+
+    if (listen_dev) {
+        raise_event = platform_listen_usecase_needs_event(uc_id);
+        ALOGI("%s(): uc_id %d of type %d for Event %d, with Raise=%d",
+            __func__, uc_id, usecase_type, event, raise_event);
+        if (raise_event && (usecase_type == PCM_PLAYBACK)) {
+            switch(event) {
+            case LISTEN_EVENT_STREAM_FREE:
+                listen_dev->notify_event(AUDIO_STREAM_OUT_INACTIVE);
+                break;
+            case LISTEN_EVENT_STREAM_BUSY:
+                listen_dev->notify_event(AUDIO_STREAM_OUT_ACTIVE);
+                break;
+            default:
+                ALOGW("%s:invalid event %d, for usecase %d",
+                                      __func__, event, uc_id);
+            }
+        }/*Events for capture usecase, if required can be placed here in else*/
+    }
+}
+
+void audio_extn_listen_set_parameters(struct audio_device *adev,
+                               struct str_parms *parms)
+{
+    ALOGV("%s: enter", __func__);
+    if (listen_dev) {
+         char *kv_pairs = str_parms_to_str(parms);
+         ALOGV_IF(kv_pairs != NULL, "%s: %s", __func__, kv_pairs);
+         listen_dev->listen_set_parameters(&adev->device, kv_pairs);
+         free(kv_pairs);
+    }
+
+    return;
+}
+
+int audio_extn_listen_init(struct audio_device *adev, unsigned int snd_card)
+{
+    int ret;
+    void *lib_handle;
+
+    ALOGI("%s: Enter", __func__);
+
+    lib_handle = dlopen(LIB_LISTEN_LOADER, RTLD_NOW);
+
+    if (lib_handle == NULL) {
+        ALOGE("%s: DLOPEN failed for %s. error = %s", __func__, LIB_LISTEN_LOADER,
+                dlerror());
+        return -EINVAL;
+    } else {
+        ALOGI("%s: DLOPEN successful for %s", __func__, LIB_LISTEN_LOADER);
+
+        listen_dev = (struct listen_audio_device*)
+            calloc(1, sizeof(struct listen_audio_device));
+
+        if (!listen_dev) {
+            ALOGE("failed to allocate listen_dev mem");
+            return -ENOMEM;
+        }
+
+        listen_dev->lib_handle = lib_handle;
+        listen_dev->adev = adev;
+
+        LISTEN_LOAD_SYMBOLS(listen_dev, create_listen_hw,
+                create_listen_hw_t, create_listen_hw);
+
+        LISTEN_LOAD_SYMBOLS(listen_dev, destroy_listen_hw,
+                destroy_listen_hw_t, destroy_listen_hw);
+
+        LISTEN_LOAD_SYMBOLS(listen_dev, open_listen_session,
+                open_listen_session_t, open_listen_session);
+
+        adev->device.open_listen_session = listen_dev->open_listen_session;
+
+        LISTEN_LOAD_SYMBOLS(listen_dev, close_listen_session,
+                close_listen_session_t, close_listen_session);
+
+        adev->device.close_listen_session = listen_dev->close_listen_session;
+
+        LISTEN_LOAD_SYMBOLS(listen_dev, set_mad_observer,
+                set_mad_observer_t, set_mad_observer);
+
+        adev->device.set_mad_observer = listen_dev->set_mad_observer;
+
+        LISTEN_LOAD_SYMBOLS(listen_dev, listen_set_parameters,
+                listen_set_parameters_t, listen_hw_set_parameters);
+
+        adev->device.listen_set_parameters = listen_dev->listen_set_parameters;
+
+        LISTEN_LOAD_SYMBOLS(listen_dev, get_parameters,
+                get_parameters_t, listen_hw_get_parameters);
+
+        LISTEN_LOAD_SYMBOLS(listen_dev, notify_event,
+                listen_notify_event_t, listen_hw_notify_event);
+
+        listen_dev->create_listen_hw(snd_card, adev->audio_route);
+    }
+    return 0;
+}
+
+void audio_extn_listen_deinit(struct audio_device *adev)
+{
+    ALOGI("%s: Enter", __func__);
+
+    if (listen_dev && (listen_dev->adev == adev) && listen_dev->lib_handle) {
+        listen_dev->destroy_listen_hw();
+        dlclose(listen_dev->lib_handle);
+        free(listen_dev);
+        listen_dev = NULL;
+    }
+}
+
+#endif /* AUDIO_LISTEN_ENABLED */
diff --git a/msm8909/hal/audio_extn/pm.c b/msm8909/hal/audio_extn/pm.c
new file mode 100644
index 0000000..7b76f60
--- /dev/null
+++ b/msm8909/hal/audio_extn/pm.c
@@ -0,0 +1,149 @@
+/* Copyright (c) 2014, 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_hw_pm"
+/*#define LOG_NDEBUG 0*/
+
+#include "pm.h"
+#include <cutils/log.h>
+
+static s_audio_subsys audio_ss;
+
+int audio_extn_pm_vote(void)
+{
+    int err, intfd, ret;
+    FILE *fd;
+    enum pm_event subsys_state;
+    char halPropVal[PROPERTY_VALUE_MAX];
+    bool prop_unload_image = false;
+    bool pm_reg = false;
+    bool pm_supp = false;
+
+    platform_get_subsys_image_name((char *)&audio_ss.img_name);
+    ALOGD("%s: register with peripheral manager for %s",__func__, audio_ss.img_name);
+    ret = pm_client_register(audio_extn_pm_event_notifier,
+                      &audio_ss,
+                      audio_ss.img_name,
+                      PM_CLIENT_NAME,
+                      &subsys_state,
+                      &audio_ss.pm_handle);
+    if (ret == PM_RET_SUCCESS) {
+        pm_reg = true;
+        pm_supp = true;
+        ALOGV("%s: registered with peripheral manager for %s",
+                  __func__, audio_ss.img_name);
+    } else if (ret == PM_RET_UNSUPPORTED) {
+        pm_reg = true;
+        pm_supp = false;
+        ALOGV("%s: peripheral mgr unsupported for %s",
+              __func__, audio_ss.img_name);
+        return ret;
+    } else {
+       return ret;
+    }
+    if (pm_supp == true &&
+       pm_reg == true) {
+       ALOGD("%s: Voting for subsystem power up", __func__);
+       pm_client_connect(audio_ss.pm_handle);
+
+       if (property_get("sys.audio.init", halPropVal, NULL)) {
+           prop_unload_image = !(strncmp("false", halPropVal, sizeof("false")));
+       }
+       /*
+        * adsp-loader loads modem/adsp image at boot up to play boot tone,
+        * before peripheral manager service is up. Once PM is up, vote to PM
+        * and unload the image to give control to PM to load/unload image
+        */
+       if (prop_unload_image) {
+           intfd = open(BOOT_IMG_SYSFS_PATH, O_WRONLY);
+           if (intfd == -1) {
+               ALOGE("failed to open fd in write mode, %d", errno);
+           } else {
+               ALOGD("%s: write to sysfs to unload image", __func__);
+               err = write(intfd, UNLOAD_IMAGE, 1);
+               close(intfd);
+               property_set("sys.audio.init", "true");
+          }
+       }
+    }
+    return 0;
+}
+
+void audio_extn_pm_unvote(void)
+{
+    ALOGD("%s", __func__);
+    if (audio_ss.pm_handle) {
+        pm_client_disconnect(audio_ss.pm_handle);
+        pm_client_unregister(audio_ss.pm_handle);
+    }
+}
+
+void audio_extn_pm_set_parameters(struct str_parms *parms)
+{
+    int ret;
+    char value[32];
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_DEV_SHUTDOWN, value, sizeof(value));
+    if (ret >= 0) {
+        if (strstr(value, "true")) {
+            ALOGD("Device shutdown notification received, unregister with PM");
+            audio_extn_pm_unvote();
+        }
+    }
+}
+
+void audio_extn_pm_event_notifier(void *client_data, enum pm_event event)
+{
+    pm_client_event_acknowledge(audio_ss.pm_handle, event);
+
+    /* Closing and re-opening of session is done based on snd card status given
+     * by AudioDaemon during SS offline/online (legacy code). Just return for now.
+     */
+    switch (event) {
+    case EVENT_PERIPH_GOING_OFFLINE:
+        ALOGV("%s: %s is going offline", __func__, audio_ss.img_name);
+    break;
+
+    case EVENT_PERIPH_IS_OFFLINE:
+        ALOGV("%s: %s is offline", __func__, audio_ss.img_name);
+    break;
+
+    case EVENT_PERIPH_GOING_ONLINE:
+        ALOGV("%s: %s is going online", __func__, audio_ss.img_name);
+    break;
+
+    case EVENT_PERIPH_IS_ONLINE:
+        ALOGV("%s: %s is online", __func__, audio_ss.img_name);
+    break;
+
+    default:
+        ALOGV("%s: invalid event received from PM", __func__);
+    break;
+    }
+}
diff --git a/msm8909/hal/audio_extn/pm.h b/msm8909/hal/audio_extn/pm.h
new file mode 100644
index 0000000..daa376e
--- /dev/null
+++ b/msm8909/hal/audio_extn/pm.h
@@ -0,0 +1,68 @@
+/* Copyright (c) 2014, 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_EXTN_PM_H
+#define AUDIO_EXTN_PM_H
+
+#include <errno.h>
+#include <math.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <pm-service.h>
+#include "audio_hw.h"
+#include <platform.h>
+#include <cutils/properties.h>
+#include <cutils/log.h>
+
+
+/* Client name to be registered with PM */
+#define PM_CLIENT_NAME "audio"
+/* Command to sysfs to unload image */
+#define UNLOAD_IMAGE "0"
+#define MAX_NAME_LEN 32
+#define BOOT_IMG_SYSFS_PATH "/sys/kernel/boot_adsp/boot"
+
+typedef struct {
+    //MAX_NAME_LEN defined in mdm_detect.h
+    char img_name[MAX_NAME_LEN];
+    //this handle is used by peripheral mgr
+    void *pm_handle;
+}s_audio_subsys;
+
+/* Vote to peripheral manager for required subsystem */
+int audio_extn_pm_vote (void);
+
+/* Unvote to peripheral manager */
+void audio_extn_pm_unvote (void);
+
+/* Get subsytem status notification from PM */
+void audio_extn_pm_event_notifier (void *client_data, enum pm_event event);
+
+#endif // AUDIO_EXTN_PM_H
diff --git a/msm8909/hal/audio_extn/soundtrigger.c b/msm8909/hal/audio_extn/soundtrigger.c
new file mode 100644
index 0000000..5f4c6ba
--- /dev/null
+++ b/msm8909/hal/audio_extn/soundtrigger.c
@@ -0,0 +1,358 @@
+/* Copyright (c) 2013-2014, 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 "soundtrigger"
+/* #define LOG_NDEBUG 0 */
+#define LOG_NDDEBUG 0
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/log.h>
+#include "audio_hw.h"
+#include "audio_extn.h"
+#include "platform.h"
+#include "platform_api.h"
+#include "sound_trigger_prop_intf.h"
+
+#define XSTR(x) STR(x)
+#define STR(x) #x
+
+struct sound_trigger_info  {
+    struct sound_trigger_session_info st_ses;
+    bool lab_stopped;
+    struct listnode list;
+};
+
+struct sound_trigger_audio_device {
+    void *lib_handle;
+    struct audio_device *adev;
+    sound_trigger_hw_call_back_t st_callback;
+    struct listnode st_ses_list;
+    pthread_mutex_t lock;
+};
+
+static struct sound_trigger_audio_device *st_dev;
+
+static struct sound_trigger_info *
+get_sound_trigger_info(int capture_handle)
+{
+    struct sound_trigger_info  *st_ses_info = NULL;
+    struct listnode *node;
+    ALOGD("%s: list %d capture_handle %d", __func__,
+           list_empty(&st_dev->st_ses_list), capture_handle);
+    list_for_each(node, &st_dev->st_ses_list) {
+        st_ses_info = node_to_item(node, struct sound_trigger_info , list);
+        if (st_ses_info->st_ses.capture_handle == capture_handle)
+            return st_ses_info;
+    }
+    return NULL;
+}
+
+int audio_hw_call_back(sound_trigger_event_type_t event,
+                       sound_trigger_event_info_t* config)
+{
+    int status = 0;
+    struct sound_trigger_info  *st_ses_info;
+
+    if (!st_dev)
+       return -EINVAL;
+
+    pthread_mutex_lock(&st_dev->lock);
+    switch (event) {
+    case ST_EVENT_SESSION_REGISTER:
+        if (!config) {
+            ALOGE("%s: NULL config", __func__);
+            status = -EINVAL;
+            break;
+        }
+        st_ses_info= calloc(1, sizeof(struct sound_trigger_info ));
+        if (!st_ses_info) {
+            ALOGE("%s: st_ses_info alloc failed", __func__);
+            status = -ENOMEM;
+            break;
+        }
+        memcpy(&st_ses_info->st_ses, &config->st_ses, sizeof (config->st_ses));
+        ALOGV("%s: add capture_handle %d pcm %p", __func__,
+              st_ses_info->st_ses.capture_handle, st_ses_info->st_ses.pcm);
+        list_add_tail(&st_dev->st_ses_list, &st_ses_info->list);
+        break;
+
+    case ST_EVENT_SESSION_DEREGISTER:
+        if (!config) {
+            ALOGE("%s: NULL config", __func__);
+            status = -EINVAL;
+            break;
+        }
+        st_ses_info = get_sound_trigger_info(config->st_ses.capture_handle);
+        if (!st_ses_info) {
+            ALOGE("%s: pcm %p not in the list!", __func__, config->st_ses.pcm);
+            status = -EINVAL;
+            break;
+        }
+        ALOGV("%s: remove capture_handle %d pcm %p", __func__,
+              st_ses_info->st_ses.capture_handle, st_ses_info->st_ses.pcm);
+        list_remove(&st_ses_info->list);
+        free(st_ses_info);
+        break;
+    default:
+        ALOGW("%s: Unknown event %d", __func__, event);
+        break;
+    }
+    pthread_mutex_unlock(&st_dev->lock);
+    return status;
+}
+
+void audio_extn_sound_trigger_stop_lab(struct stream_in *in)
+{
+    int status = 0;
+    struct sound_trigger_info  *st_ses_info = NULL;
+    audio_event_info_t event;
+
+    if (!st_dev || !in)
+       return;
+
+    pthread_mutex_lock(&st_dev->lock);
+    st_ses_info = get_sound_trigger_info(in->capture_handle);
+    pthread_mutex_unlock(&st_dev->lock);
+    if (st_ses_info) {
+        event.u.ses_info = st_ses_info->st_ses;
+        ALOGV("%s: AUDIO_EVENT_STOP_LAB pcm %p", __func__, st_ses_info->st_ses.pcm);
+        st_dev->st_callback(AUDIO_EVENT_STOP_LAB, &event);
+    }
+}
+void audio_extn_sound_trigger_check_and_get_session(struct stream_in *in)
+{
+    struct sound_trigger_info  *st_ses_info = NULL;
+    struct listnode *node;
+
+    if (!st_dev || !in)
+       return;
+
+    pthread_mutex_lock(&st_dev->lock);
+    in->is_st_session = false;
+    ALOGV("%s: list %d capture_handle %d", __func__,
+          list_empty(&st_dev->st_ses_list), in->capture_handle);
+    list_for_each(node, &st_dev->st_ses_list) {
+        st_ses_info = node_to_item(node, struct sound_trigger_info , list);
+        if (st_ses_info->st_ses.capture_handle == in->capture_handle) {
+            in->pcm = st_ses_info->st_ses.pcm;
+            in->config = st_ses_info->st_ses.config;
+            in->channel_mask = audio_channel_in_mask_from_count(in->config.channels);
+            in->is_st_session = true;
+            ALOGD("%s: capture_handle %d is sound trigger", __func__, in->capture_handle);
+            break;
+        }
+    }
+    pthread_mutex_unlock(&st_dev->lock);
+}
+
+void audio_extn_sound_trigger_update_device_status(snd_device_t snd_device,
+                                     st_event_type_t event)
+{
+    bool raise_event = false;
+    int device_type = -1;
+
+    if (!st_dev)
+       return;
+
+    if (snd_device >= SND_DEVICE_OUT_BEGIN &&
+        snd_device < SND_DEVICE_OUT_END)
+        device_type = PCM_PLAYBACK;
+    else if (snd_device >= SND_DEVICE_IN_BEGIN &&
+        snd_device < SND_DEVICE_IN_END)
+        device_type = PCM_CAPTURE;
+    else {
+        ALOGE("%s: invalid device 0x%x, for event %d",
+                           __func__, snd_device, event);
+        return;
+    }
+
+    raise_event = platform_sound_trigger_device_needs_event(snd_device);
+    ALOGI("%s: device 0x%x of type %d for Event %d, with Raise=%d",
+        __func__, snd_device, device_type, event, raise_event);
+    if (raise_event && (device_type == PCM_CAPTURE)) {
+        switch(event) {
+        case ST_EVENT_SND_DEVICE_FREE:
+            st_dev->st_callback(AUDIO_EVENT_CAPTURE_DEVICE_INACTIVE, NULL);
+            break;
+        case ST_EVENT_SND_DEVICE_BUSY:
+            st_dev->st_callback(AUDIO_EVENT_CAPTURE_DEVICE_ACTIVE, NULL);
+            break;
+        default:
+            ALOGW("%s:invalid event %d for device 0x%x",
+                                  __func__, event, snd_device);
+        }
+    }/*Events for output device, if required can be placed here in else*/
+}
+
+void audio_extn_sound_trigger_update_stream_status(struct audio_usecase *uc_info,
+                                     st_event_type_t event)
+{
+    bool raise_event = false;
+    audio_usecase_t uc_id;
+    int usecase_type = -1;
+
+    if (!st_dev) {
+        return;
+    }
+
+    if (uc_info == NULL) {
+        ALOGE("%s: usecase is NULL!!!", __func__);
+        return;
+    }
+    uc_id = uc_info->id;
+    usecase_type = uc_info->type;
+
+    raise_event = platform_sound_trigger_usecase_needs_event(uc_id);
+    ALOGD("%s: uc_id %d of type %d for Event %d, with Raise=%d",
+        __func__, uc_id, usecase_type, event, raise_event);
+    if (raise_event && (usecase_type == PCM_PLAYBACK)) {
+        switch(event) {
+        case ST_EVENT_STREAM_FREE:
+            st_dev->st_callback(AUDIO_EVENT_PLAYBACK_STREAM_INACTIVE, NULL);
+            break;
+        case ST_EVENT_STREAM_BUSY:
+            st_dev->st_callback(AUDIO_EVENT_PLAYBACK_STREAM_ACTIVE, NULL);
+            break;
+        default:
+            ALOGW("%s:invalid event %d, for usecase %d",
+                                  __func__, event, uc_id);
+        }
+    }/*Events for capture usecase, if required can be placed here in else*/
+}
+
+void audio_extn_sound_trigger_set_parameters(struct audio_device *adev __unused,
+                               struct str_parms *params)
+{
+    audio_event_info_t event;
+    char value[32];
+    int ret, val;
+
+    if(!st_dev || !params) {
+        ALOGE("%s: str_params NULL", __func__);
+        return;
+    }
+
+    ret = str_parms_get_str(params, "SND_CARD_STATUS", value,
+                            sizeof(value));
+    if (ret > 0) {
+        if (strstr(value, "OFFLINE")) {
+            event.u.status = SND_CARD_STATUS_OFFLINE;
+            st_dev->st_callback(AUDIO_EVENT_SSR, &event);
+        }
+        else if (strstr(value, "ONLINE")) {
+            event.u.status = SND_CARD_STATUS_ONLINE;
+            st_dev->st_callback(AUDIO_EVENT_SSR, &event);
+        }
+        else
+            ALOGE("%s: unknown snd_card_status", __func__);
+    }
+
+    ret = str_parms_get_str(params, "CPE_STATUS", value, sizeof(value));
+    if (ret > 0) {
+        if (strstr(value, "OFFLINE")) {
+            event.u.status = CPE_STATUS_OFFLINE;
+            st_dev->st_callback(AUDIO_EVENT_SSR, &event);
+        }
+        else if (strstr(value, "ONLINE")) {
+            event.u.status = CPE_STATUS_ONLINE;
+            st_dev->st_callback(AUDIO_EVENT_SSR, &event);
+        }
+        else
+            ALOGE("%s: unknown CPE status", __func__);
+    }
+
+    ret = str_parms_get_int(params, "SVA_NUM_SESSIONS", &val);
+    if (ret >= 0) {
+        event.u.value = val;
+        st_dev->st_callback(AUDIO_EVENT_NUM_ST_SESSIONS, &event);
+    }
+}
+
+int audio_extn_sound_trigger_init(struct audio_device *adev)
+{
+    int status = 0;
+    char sound_trigger_lib[100];
+    void *lib_handle;
+
+    ALOGI("%s: Enter", __func__);
+
+    st_dev = (struct sound_trigger_audio_device*)
+                        calloc(1, sizeof(struct sound_trigger_audio_device));
+    if (!st_dev) {
+        ALOGE("%s: ERROR. sound trigger alloc failed", __func__);
+        return -ENOMEM;
+    }
+
+    snprintf(sound_trigger_lib, sizeof(sound_trigger_lib),
+             "/system/vendor/lib/hw/sound_trigger.primary.%s.so",
+              XSTR(SOUND_TRIGGER_PLATFORM_NAME));
+
+    st_dev->lib_handle = dlopen(sound_trigger_lib, RTLD_NOW);
+
+    if (st_dev->lib_handle == NULL) {
+        ALOGE("%s: DLOPEN failed for %s. error = %s", __func__, sound_trigger_lib,
+                dlerror());
+        status = -EINVAL;
+        goto cleanup;
+    }
+    ALOGI("%s: DLOPEN successful for %s", __func__, sound_trigger_lib);
+
+    st_dev->st_callback = (sound_trigger_hw_call_back_t)
+              dlsym(st_dev->lib_handle, "sound_trigger_hw_call_back");
+
+    if (st_dev->st_callback == NULL) {
+       ALOGE("%s: ERROR. dlsym Error:%s sound_trigger_hw_call_back", __func__,
+               dlerror());
+       goto cleanup;
+    }
+
+    st_dev->adev = adev;
+    list_init(&st_dev->st_ses_list);
+
+    return 0;
+
+cleanup:
+    if (st_dev->lib_handle)
+        dlclose(st_dev->lib_handle);
+    free(st_dev);
+    st_dev = NULL;
+    return status;
+
+}
+
+void audio_extn_sound_trigger_deinit(struct audio_device *adev)
+{
+    ALOGI("%s: Enter", __func__);
+    if (st_dev && (st_dev->adev == adev) && st_dev->lib_handle) {
+        dlclose(st_dev->lib_handle);
+        free(st_dev);
+        st_dev = NULL;
+    }
+}
diff --git a/msm8909/hal/audio_extn/spkr_protection.c b/msm8909/hal/audio_extn/spkr_protection.c
new file mode 100644
index 0000000..a350198
--- /dev/null
+++ b/msm8909/hal/audio_extn/spkr_protection.c
@@ -0,0 +1,916 @@
+/*
+ * Copyright (c) 2013 - 2014, 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_hw_spkr_prot"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <math.h>
+#include <cutils/log.h>
+#include <fcntl.h>
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <math.h>
+#include <cutils/properties.h>
+#include "audio_extn.h"
+#include <linux/msm_audio_calibration.h>
+
+#ifdef SPKR_PROT_ENABLED
+
+/*Range of spkr temparatures -30C to 80C*/
+#define MIN_SPKR_TEMP_Q6 (-30 * (1 << 6))
+#define MAX_SPKR_TEMP_Q6 (80 * (1 << 6))
+#define VI_FEED_CHANNEL "VI_FEED_TX Channels"
+
+/*Set safe temp value to 40C*/
+#define SAFE_SPKR_TEMP 40
+#define SAFE_SPKR_TEMP_Q6 (SAFE_SPKR_TEMP * (1 << 6))
+
+/*Range of resistance values 2ohms to 40 ohms*/
+#define MIN_RESISTANCE_SPKR_Q24 (2 * (1 << 24))
+#define MAX_RESISTANCE_SPKR_Q24 (40 * (1 << 24))
+
+/*Path where the calibration file will be stored*/
+#define CALIB_FILE "/data/misc/audio/audio.cal"
+
+/*Time between retries for calibartion or intial wait time
+  after boot up*/
+#define WAIT_TIME_SPKR_CALIB (60 * 1000 * 1000)
+
+#define MIN_SPKR_IDLE_SEC (60 * 30)
+
+/*Once calibration is started sleep for 1 sec to allow
+  the calibration to kick off*/
+#define SLEEP_AFTER_CALIB_START (3000)
+
+/*If calibration is in progress wait for 200 msec before querying
+  for status again*/
+#define WAIT_FOR_GET_CALIB_STATUS (200 * 1000)
+
+/*Speaker states*/
+#define SPKR_NOT_CALIBRATED -1
+#define SPKR_CALIBRATED 1
+
+/*Speaker processing state*/
+#define SPKR_PROCESSING_IN_PROGRESS 1
+#define SPKR_PROCESSING_IN_IDLE 0
+
+/*Modes of Speaker Protection*/
+enum speaker_protection_mode {
+    SPKR_PROTECTION_DISABLED = -1,
+    SPKR_PROTECTION_MODE_PROCESSING = 0,
+    SPKR_PROTECTION_MODE_CALIBRATE = 1,
+};
+
+struct speaker_prot_session {
+    int spkr_prot_mode;
+    int spkr_processing_state;
+    int thermal_client_handle;
+    pthread_mutex_t mutex_spkr_prot;
+    pthread_t spkr_calibration_thread;
+    pthread_mutex_t spkr_prot_thermalsync_mutex;
+    pthread_cond_t spkr_prot_thermalsync;
+    int cancel_spkr_calib;
+    pthread_cond_t spkr_calib_cancel;
+    pthread_mutex_t spkr_calib_cancelack_mutex;
+    pthread_cond_t spkr_calibcancel_ack;
+    pthread_t speaker_prot_threadid;
+    void *thermal_handle;
+    void *adev_handle;
+    int spkr_prot_t0;
+    struct pcm *pcm_rx;
+    struct pcm *pcm_tx;
+    int (*client_register_callback)
+    (char *client_name, int (*callback)(int), void *data);
+    void (*thermal_client_unregister_callback)(int handle);
+    int (*thermal_client_request)(char *client_name, int req_data);
+    bool spkr_prot_enable;
+    bool spkr_in_use;
+   struct timespec spkr_last_time_used;
+};
+
+static struct pcm_config pcm_config_skr_prot = {
+    .channels = 4,
+    .rate = 48000,
+    .period_size = 256,
+    .period_count = 4,
+    .format = PCM_FORMAT_S16_LE,
+    .start_threshold = 0,
+    .stop_threshold = INT_MAX,
+    .avail_min = 0,
+};
+
+static struct speaker_prot_session handle;
+static int vi_feed_no_channels;
+
+static void spkr_prot_set_spkrstatus(bool enable)
+{
+    struct timespec ts;
+    if (enable)
+       handle.spkr_in_use = true;
+    else {
+       handle.spkr_in_use = false;
+       clock_gettime(CLOCK_MONOTONIC, &handle.spkr_last_time_used);
+   }
+}
+
+void audio_extn_spkr_prot_calib_cancel(void *adev)
+{
+    pthread_t threadid;
+    struct audio_usecase *uc_info;
+    int count = 0;
+    threadid = pthread_self();
+    ALOGV("%s: Entry", __func__);
+    if (pthread_equal(handle.speaker_prot_threadid, threadid) || !adev) {
+        ALOGE("%s: Invalid params", __func__);
+        return;
+    }
+    uc_info = get_usecase_from_list(adev, USECASE_AUDIO_SPKR_CALIB_RX);
+    if (uc_info) {
+            pthread_mutex_lock(&handle.mutex_spkr_prot);
+            pthread_mutex_lock(&handle.spkr_calib_cancelack_mutex);
+            handle.cancel_spkr_calib = 1;
+            pthread_cond_signal(&handle.spkr_calib_cancel);
+            pthread_mutex_unlock(&handle.mutex_spkr_prot);
+            pthread_cond_wait(&handle.spkr_calibcancel_ack,
+            &handle.spkr_calib_cancelack_mutex);
+            pthread_mutex_unlock(&handle.spkr_calib_cancelack_mutex);
+    }
+    ALOGV("%s: Exit", __func__);
+}
+
+static bool is_speaker_in_use(unsigned long *sec)
+{
+    struct timespec temp;
+    if (!sec) {
+        ALOGE("%s: Invalid params", __func__);
+        return true;
+    }
+     if (handle.spkr_in_use) {
+        *sec = 0;
+         return true;
+     } else {
+         clock_gettime(CLOCK_MONOTONIC, &temp);
+         *sec = temp.tv_sec - handle.spkr_last_time_used.tv_sec;
+         return false;
+     }
+}
+
+
+static int get_spkr_prot_cal(int cal_fd,
+				struct audio_cal_info_msm_spk_prot_status *status)
+{
+    int ret = 0;
+    struct audio_cal_fb_spk_prot_status    cal_data;
+
+    if (cal_fd < 0) {
+        ALOGE("%s: Error: cal_fd = %d", __func__, cal_fd);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    if (status == NULL) {
+        ALOGE("%s: Error: status NULL", __func__);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    cal_data.hdr.data_size = sizeof(cal_data);
+    cal_data.hdr.version = VERSION_0_0;
+    cal_data.hdr.cal_type = AFE_FB_SPKR_PROT_CAL_TYPE;
+    cal_data.hdr.cal_type_size = sizeof(cal_data.cal_type);
+    cal_data.cal_type.cal_hdr.version = VERSION_0_0;
+    cal_data.cal_type.cal_hdr.buffer_number = 0;
+    cal_data.cal_type.cal_data.mem_handle = -1;
+
+    if (ioctl(cal_fd, AUDIO_GET_CALIBRATION, &cal_data)) {
+        ALOGE("%s: Error: AUDIO_GET_CALIBRATION failed!",
+            __func__);
+        ret = -ENODEV;
+        goto done;
+    }
+
+    status->r0[SP_V2_SPKR_1] = cal_data.cal_type.cal_info.r0[SP_V2_SPKR_1];
+    status->r0[SP_V2_SPKR_2] = cal_data.cal_type.cal_info.r0[SP_V2_SPKR_2];
+    status->status = cal_data.cal_type.cal_info.status;
+done:
+    return ret;
+}
+
+static int set_spkr_prot_cal(int cal_fd,
+				struct audio_cal_info_spk_prot_cfg *protCfg)
+{
+    int ret = 0;
+    struct audio_cal_fb_spk_prot_cfg    cal_data;
+    char value[PROPERTY_VALUE_MAX];
+
+    if (cal_fd < 0) {
+        ALOGE("%s: Error: cal_fd = %d", __func__, cal_fd);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    if (protCfg == NULL) {
+        ALOGE("%s: Error: status NULL", __func__);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    memset(&cal_data, 0, sizeof(cal_data));
+    cal_data.hdr.data_size = sizeof(cal_data);
+    cal_data.hdr.version = VERSION_0_0;
+    cal_data.hdr.cal_type = AFE_FB_SPKR_PROT_CAL_TYPE;
+    cal_data.hdr.cal_type_size = sizeof(cal_data.cal_type);
+    cal_data.cal_type.cal_hdr.version = VERSION_0_0;
+    cal_data.cal_type.cal_hdr.buffer_number = 0;
+    cal_data.cal_type.cal_info.r0[SP_V2_SPKR_1] = protCfg->r0[SP_V2_SPKR_1];
+    cal_data.cal_type.cal_info.r0[SP_V2_SPKR_2] = protCfg->r0[SP_V2_SPKR_2];
+    cal_data.cal_type.cal_info.t0[SP_V2_SPKR_1] = protCfg->t0[SP_V2_SPKR_1];
+    cal_data.cal_type.cal_info.t0[SP_V2_SPKR_2] = protCfg->t0[SP_V2_SPKR_2];
+    cal_data.cal_type.cal_info.mode = protCfg->mode;
+    property_get("persist.spkr.cal.duration", value, "0");
+    if (atoi(value) > 0) {
+        ALOGD("%s: quick calibration enabled", __func__);
+        cal_data.cal_type.cal_info.quick_calib_flag = 1;
+    } else {
+        ALOGD("%s: quick calibration disabled", __func__);
+        cal_data.cal_type.cal_info.quick_calib_flag = 0;
+    }
+
+    cal_data.cal_type.cal_data.mem_handle = -1;
+
+    if (ioctl(cal_fd, AUDIO_SET_CALIBRATION, &cal_data)) {
+        ALOGE("%s: Error: AUDIO_SET_CALIBRATION failed!",
+            __func__);
+        ret = -ENODEV;
+        goto done;
+    }
+done:
+    return ret;
+}
+
+static int vi_feed_get_channels(struct audio_device *adev)
+{
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = VI_FEED_CHANNEL;
+    int value;
+
+    ALOGV("%s: entry", __func__);
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        goto error;
+    }
+    value = mixer_ctl_get_value(ctl, 0);
+    if (value < 0)
+        goto error;
+    else
+        return value+1;
+error:
+     return -EINVAL;
+}
+
+static int spkr_calibrate(int t0)
+{
+    struct audio_device *adev = handle.adev_handle;
+    struct audio_cal_info_spk_prot_cfg protCfg;
+    struct audio_cal_info_msm_spk_prot_status status;
+    bool cleanup = false, disable_rx = false, disable_tx = false;
+    int acdb_fd = -1;
+    struct audio_usecase *uc_info_rx = NULL, *uc_info_tx = NULL;
+    int32_t pcm_dev_rx_id = -1, pcm_dev_tx_id = -1;
+    struct timespec ts;
+    bool acquire_device = false;
+
+    if (!adev) {
+        ALOGE("%s: Invalid params", __func__);
+        return -EINVAL;
+    }
+    if (!list_empty(&adev->usecase_list)) {
+        ALOGD("%s: Usecase present retry speaker protection", __func__);
+        return -EAGAIN;
+    }
+    acdb_fd = open("/dev/msm_audio_cal",O_RDWR | O_NONBLOCK);
+    if (acdb_fd < 0) {
+        ALOGE("%s: spkr_prot_thread open msm_acdb failed", __func__);
+        return -ENODEV;
+    } else {
+        protCfg.mode = MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS;
+        /* HAL for speaker protection gets only one Temperature */
+        protCfg.t0[SP_V2_SPKR_1] = t0;
+        protCfg.t0[SP_V2_SPKR_2] = t0;
+        if (set_spkr_prot_cal(acdb_fd, &protCfg)) {
+            ALOGE("%s: spkr_prot_thread set failed AUDIO_SET_SPEAKER_PROT",
+            __func__);
+            status.status = -ENODEV;
+            goto exit;
+        }
+    }
+    uc_info_rx = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+    if (!uc_info_rx) {
+        return -ENOMEM;
+    }
+    uc_info_rx->id = USECASE_AUDIO_SPKR_CALIB_RX;
+    uc_info_rx->type = PCM_PLAYBACK;
+    uc_info_rx->in_snd_device = SND_DEVICE_NONE;
+    uc_info_rx->stream.out = adev->primary_output;
+    uc_info_rx->out_snd_device = SND_DEVICE_OUT_SPEAKER_PROTECTED;
+    disable_rx = true;
+    list_add_tail(&adev->usecase_list, &uc_info_rx->list);
+    enable_snd_device(adev, SND_DEVICE_OUT_SPEAKER_PROTECTED);
+    enable_audio_route(adev, uc_info_rx);
+
+    pcm_dev_rx_id = platform_get_pcm_device_id(uc_info_rx->id, PCM_PLAYBACK);
+    ALOGV("%s: pcm device id %d", __func__, pcm_dev_rx_id);
+    if (pcm_dev_rx_id < 0) {
+        ALOGE("%s: Invalid pcm device for usecase (%d)",
+              __func__, uc_info_rx->id);
+        status.status = -ENODEV;
+        goto exit;
+    }
+    handle.pcm_rx = handle.pcm_tx = NULL;
+    handle.pcm_rx = pcm_open(adev->snd_card,
+                             pcm_dev_rx_id,
+                             PCM_OUT, &pcm_config_skr_prot);
+    if (handle.pcm_rx && !pcm_is_ready(handle.pcm_rx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(handle.pcm_rx));
+        status.status = -EIO;
+        goto exit;
+    }
+    uc_info_tx = (struct audio_usecase *)
+    calloc(1, sizeof(struct audio_usecase));
+    if (!uc_info_tx) {
+        status.status = -ENOMEM;
+        goto exit;
+    }
+    uc_info_tx->id = USECASE_AUDIO_SPKR_CALIB_TX;
+    uc_info_tx->type = PCM_CAPTURE;
+    uc_info_tx->in_snd_device = SND_DEVICE_IN_CAPTURE_VI_FEEDBACK;
+    uc_info_tx->out_snd_device = SND_DEVICE_NONE;
+
+    disable_tx = true;
+    list_add_tail(&adev->usecase_list, &uc_info_tx->list);
+    enable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK);
+    enable_audio_route(adev, uc_info_tx);
+
+    pcm_dev_tx_id = platform_get_pcm_device_id(uc_info_tx->id, PCM_CAPTURE);
+    if (pcm_dev_tx_id < 0) {
+        ALOGE("%s: Invalid pcm device for usecase (%d)",
+              __func__, uc_info_tx->id);
+        status.status = -ENODEV;
+        goto exit;
+    }
+    handle.pcm_tx = pcm_open(adev->snd_card,
+                             pcm_dev_tx_id,
+                             PCM_IN, &pcm_config_skr_prot);
+    if (handle.pcm_tx && !pcm_is_ready(handle.pcm_tx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(handle.pcm_tx));
+        status.status = -EIO;
+        goto exit;
+    }
+    if (pcm_start(handle.pcm_rx) < 0) {
+        ALOGE("%s: pcm start for RX failed", __func__);
+        status.status = -EINVAL;
+        goto exit;
+    }
+    if (pcm_start(handle.pcm_tx) < 0) {
+        ALOGE("%s: pcm start for TX failed", __func__);
+        status.status = -EINVAL;
+        goto exit;
+    }
+    cleanup = true;
+    clock_gettime(CLOCK_REALTIME, &ts);
+    ts.tv_sec += (SLEEP_AFTER_CALIB_START/1000);
+    ts.tv_nsec = 0;
+    pthread_mutex_lock(&handle.mutex_spkr_prot);
+    pthread_mutex_unlock(&adev->lock);
+    acquire_device = true;
+    (void)pthread_cond_timedwait(&handle.spkr_calib_cancel,
+        &handle.mutex_spkr_prot, &ts);
+    ALOGD("%s: Speaker calibration done", __func__);
+    cleanup = true;
+    pthread_mutex_lock(&handle.spkr_calib_cancelack_mutex);
+    if (handle.cancel_spkr_calib) {
+        status.status = -EAGAIN;
+        goto exit;
+    }
+    if (acdb_fd > 0) {
+        status.status = -EINVAL;
+        while (!get_spkr_prot_cal(acdb_fd, &status)) {
+            /*sleep for 200 ms to check for status check*/
+            if (!status.status) {
+                ALOGD("%s: spkr_prot_thread calib Success R0 %d %d",
+                 __func__, status.r0[SP_V2_SPKR_1], status.r0[SP_V2_SPKR_2]);
+                FILE *fp;
+
+                vi_feed_no_channels = vi_feed_get_channels(adev);
+                ALOGD("%s: vi_feed_no_channels %d", __func__, vi_feed_no_channels);
+                if (vi_feed_no_channels < 0) {
+                    ALOGE("%s: no of channels negative !!", __func__);
+                    /* limit the number of channels to 2*/
+                    vi_feed_no_channels = 2;
+                }
+
+                fp = fopen(CALIB_FILE,"wb");
+                if (!fp) {
+                    ALOGE("%s: spkr_prot_thread File open failed %s",
+                    __func__, strerror(errno));
+                    status.status = -ENODEV;
+                } else {
+                    int i;
+                    /* HAL for speaker protection is always calibrating for stereo usecase*/
+                    for (i = 0; i < vi_feed_no_channels; i++) {
+                        fwrite(&status.r0[i], sizeof(status.r0[i]), 1, fp);
+                        fwrite(&protCfg.t0[i], sizeof(protCfg.t0[i]), 1, fp);
+                    }
+                    fclose(fp);
+                }
+                break;
+            } else if (status.status == -EAGAIN) {
+                  ALOGD("%s: spkr_prot_thread try again", __func__);
+                  usleep(WAIT_FOR_GET_CALIB_STATUS);
+            } else {
+                ALOGE("%s: spkr_prot_thread get failed status %d",
+                __func__, status.status);
+                break;
+            }
+        }
+exit:
+        if (handle.pcm_rx)
+            pcm_close(handle.pcm_rx);
+        handle.pcm_rx = NULL;
+        if (handle.pcm_tx)
+            pcm_close(handle.pcm_tx);
+        handle.pcm_tx = NULL;
+        /* Clear TX calibration to handset mic */
+        platform_send_audio_calibration(adev->platform,
+        SND_DEVICE_IN_HANDSET_MIC,
+        platform_get_default_app_type(adev->platform), 8000);
+        if (!status.status) {
+            protCfg.mode = MSM_SPKR_PROT_CALIBRATED;
+            protCfg.r0[SP_V2_SPKR_1] = status.r0[SP_V2_SPKR_1];
+            protCfg.r0[SP_V2_SPKR_2] = status.r0[SP_V2_SPKR_2];
+            if (set_spkr_prot_cal(acdb_fd, &protCfg))
+                ALOGE("%s: spkr_prot_thread disable calib mode", __func__);
+            else
+                handle.spkr_prot_mode = MSM_SPKR_PROT_CALIBRATED;
+        } else {
+            protCfg.mode = MSM_SPKR_PROT_NOT_CALIBRATED;
+            handle.spkr_prot_mode = MSM_SPKR_PROT_NOT_CALIBRATED;
+            if (set_spkr_prot_cal(acdb_fd, &protCfg))
+                ALOGE("%s: spkr_prot_thread disable calib mode failed", __func__);
+        }
+        if (acdb_fd > 0)
+            close(acdb_fd);
+
+        if (!handle.cancel_spkr_calib && cleanup) {
+            pthread_mutex_unlock(&handle.spkr_calib_cancelack_mutex);
+            pthread_cond_wait(&handle.spkr_calib_cancel,
+            &handle.mutex_spkr_prot);
+            pthread_mutex_lock(&handle.spkr_calib_cancelack_mutex);
+        }
+        if (disable_rx) {
+            list_remove(&uc_info_rx->list);
+            disable_snd_device(adev, SND_DEVICE_OUT_SPEAKER_PROTECTED);
+            disable_audio_route(adev, uc_info_rx);
+        }
+        if (disable_tx) {
+            list_remove(&uc_info_tx->list);
+            disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK);
+            disable_audio_route(adev, uc_info_tx);
+        }
+        if (uc_info_rx) free(uc_info_rx);
+        if (uc_info_tx) free(uc_info_tx);
+        if (cleanup) {
+            if (handle.cancel_spkr_calib)
+                pthread_cond_signal(&handle.spkr_calibcancel_ack);
+            handle.cancel_spkr_calib = 0;
+            pthread_mutex_unlock(&handle.spkr_calib_cancelack_mutex);
+            pthread_mutex_unlock(&handle.mutex_spkr_prot);
+        }
+    }
+    if (acquire_device)
+        pthread_mutex_lock(&adev->lock);
+    return status.status;
+}
+
+static void* spkr_calibration_thread()
+{
+    unsigned long sec = 0;
+    int t0;
+    bool goahead = false;
+    struct audio_cal_info_spk_prot_cfg protCfg;
+    FILE *fp;
+    int acdb_fd;
+    struct audio_device *adev = handle.adev_handle;
+    unsigned long min_idle_time = MIN_SPKR_IDLE_SEC;
+    char value[PROPERTY_VALUE_MAX];
+
+    /* If the value of this persist.spkr.cal.duration is 0
+     * then it means it will take 30min to calibrate
+     * and if the value is greater than zero then it would take
+     * that much amount of time to calibrate.
+     */
+    property_get("persist.spkr.cal.duration", value, "0");
+    if (atoi(value) > 0)
+        min_idle_time = atoi(value);
+    handle.speaker_prot_threadid = pthread_self();
+    ALOGD("spkr_prot_thread enable prot Entry");
+    acdb_fd = open("/dev/msm_audio_cal",O_RDWR | O_NONBLOCK);
+    if (acdb_fd > 0) {
+        /*Set processing mode with t0/r0*/
+        protCfg.mode = MSM_SPKR_PROT_NOT_CALIBRATED;
+        if (set_spkr_prot_cal(acdb_fd, &protCfg)) {
+            ALOGE("%s: spkr_prot_thread enable prot failed", __func__);
+            handle.spkr_prot_mode = MSM_SPKR_PROT_DISABLED;
+            close(acdb_fd);
+        } else
+            handle.spkr_prot_mode = MSM_SPKR_PROT_NOT_CALIBRATED;
+    } else {
+        handle.spkr_prot_mode = MSM_SPKR_PROT_DISABLED;
+        ALOGE("%s: Failed to open acdb node", __func__);
+    }
+    if (handle.spkr_prot_mode == MSM_SPKR_PROT_DISABLED) {
+        ALOGD("%s: Speaker protection disabled", __func__);
+        pthread_exit(0);
+        return NULL;
+    }
+
+    fp = fopen(CALIB_FILE,"rb");
+    if (fp) {
+        int i;
+        bool spkr_calibrated = true;
+        /* HAL for speaker protection is always calibrating for stereo usecase*/
+        vi_feed_no_channels = vi_feed_get_channels(adev);
+        ALOGD("%s: vi_feed_no_channels %d", __func__, vi_feed_no_channels);
+        if (vi_feed_no_channels < 0) {
+            ALOGE("%s: no of channels negative !!", __func__);
+            /* limit the number of channels to 2*/
+            vi_feed_no_channels = 2;
+        }
+        for (i = 0; i < vi_feed_no_channels; i++) {
+            fread(&protCfg.r0[i], sizeof(protCfg.r0[i]), 1, fp);
+            fread(&protCfg.t0[i], sizeof(protCfg.t0[i]), 1, fp);
+        }
+        ALOGD("%s: spkr_prot_thread r0 value %d %d",
+               __func__, protCfg.r0[SP_V2_SPKR_1], protCfg.r0[SP_V2_SPKR_2]);
+        ALOGD("%s: spkr_prot_thread t0 value %d %d",
+               __func__, protCfg.t0[SP_V2_SPKR_1], protCfg.t0[SP_V2_SPKR_2]);
+        fclose(fp);
+        /*Valid tempature range: -30C to 80C(in q6 format)
+          Valid Resistance range: 2 ohms to 40 ohms(in q24 format)*/
+        for (i = 0; i < vi_feed_no_channels; i++) {
+            if (!((protCfg.t0[i] > MIN_SPKR_TEMP_Q6) && (protCfg.t0[i] < MAX_SPKR_TEMP_Q6)
+                && (protCfg.r0[i] >= MIN_RESISTANCE_SPKR_Q24)
+                && (protCfg.r0[i] < MAX_RESISTANCE_SPKR_Q24))) {
+                spkr_calibrated = false;
+                break;
+            }
+        }
+        if (spkr_calibrated) {
+            ALOGD("%s: Spkr calibrated", __func__);
+            protCfg.mode = MSM_SPKR_PROT_CALIBRATED;
+            if (set_spkr_prot_cal(acdb_fd, &protCfg)) {
+                ALOGE("%s: enable prot failed", __func__);
+                handle.spkr_prot_mode = MSM_SPKR_PROT_DISABLED;
+            } else
+                handle.spkr_prot_mode = MSM_SPKR_PROT_CALIBRATED;
+            close(acdb_fd);
+            pthread_exit(0);
+            return NULL;
+        }
+        close(acdb_fd);
+    }
+
+    while (1) {
+        ALOGV("%s: start calibration", __func__);
+        if (!handle.thermal_client_request("spkr",1)) {
+            ALOGD("%s: wait for callback from thermal daemon", __func__);
+            pthread_mutex_lock(&handle.spkr_prot_thermalsync_mutex);
+            pthread_cond_wait(&handle.spkr_prot_thermalsync,
+            &handle.spkr_prot_thermalsync_mutex);
+            /*Convert temp into q6 format*/
+            t0 = (handle.spkr_prot_t0 * (1 << 6));
+            pthread_mutex_unlock(&handle.spkr_prot_thermalsync_mutex);
+            if (t0 < MIN_SPKR_TEMP_Q6 || t0 > MAX_SPKR_TEMP_Q6) {
+                ALOGE("%s: Calibration temparature error %d", __func__,
+                      handle.spkr_prot_t0);
+                continue;
+            }
+            ALOGD("%s: Request t0 success value %d", __func__,
+            handle.spkr_prot_t0);
+        } else {
+            ALOGE("%s: Request t0 failed", __func__);
+            /*Assume safe value for temparature*/
+            t0 = SAFE_SPKR_TEMP_Q6;
+        }
+        goahead = false;
+        pthread_mutex_lock(&adev->lock);
+        if (is_speaker_in_use(&sec)) {
+            ALOGD("%s: Speaker in use retry calibration", __func__);
+            pthread_mutex_unlock(&adev->lock);
+            continue;
+        } else {
+            ALOGD("%s: speaker idle %ld min time %ld", __func__, sec, min_idle_time);
+            if (sec < min_idle_time) {
+                ALOGD("%s: speaker idle is less retry", __func__);
+                pthread_mutex_unlock(&adev->lock);
+                continue;
+            }
+            goahead = true;
+        }
+        if (!list_empty(&adev->usecase_list)) {
+            ALOGD("%s: Usecase active re-try calibration", __func__);
+            goahead = false;
+            pthread_mutex_unlock(&adev->lock);
+        }
+        if (goahead) {
+                int status;
+                status = spkr_calibrate(t0);
+                pthread_mutex_unlock(&adev->lock);
+                if (status == -EAGAIN) {
+                    ALOGE("%s: failed to calibrate try again %s",
+                    __func__, strerror(status));
+                    continue;
+                } else {
+                    ALOGE("%s: calibrate status %s", __func__, strerror(status));
+                }
+                ALOGD("%s: spkr_prot_thread end calibration", __func__);
+                break;
+        }
+    }
+    if (handle.thermal_client_handle)
+        handle.thermal_client_unregister_callback(handle.thermal_client_handle);
+    handle.thermal_client_handle = 0;
+    if (handle.thermal_handle)
+        dlclose(handle.thermal_handle);
+    handle.thermal_handle = NULL;
+    pthread_exit(0);
+    return NULL;
+}
+
+static int thermal_client_callback(int temp)
+{
+    pthread_mutex_lock(&handle.spkr_prot_thermalsync_mutex);
+    ALOGD("%s: spkr_prot set t0 %d and signal", __func__, temp);
+    if (handle.spkr_prot_mode == MSM_SPKR_PROT_NOT_CALIBRATED)
+        handle.spkr_prot_t0 = temp;
+    pthread_cond_signal(&handle.spkr_prot_thermalsync);
+    pthread_mutex_unlock(&handle.spkr_prot_thermalsync_mutex);
+    return 0;
+}
+
+void audio_extn_spkr_prot_init(void *adev)
+{
+    char value[PROPERTY_VALUE_MAX];
+    ALOGD("%s: Initialize speaker protection module", __func__);
+    memset(&handle, 0, sizeof(handle));
+    if (!adev) {
+        ALOGE("%s: Invalid params", __func__);
+        return;
+    }
+    property_get("persist.speaker.prot.enable", value, "");
+    handle.spkr_prot_enable = false;
+    if (!strncmp("true", value, 4))
+       handle.spkr_prot_enable = true;
+    if (!handle.spkr_prot_enable) {
+        ALOGD("%s: Speaker protection disabled", __func__);
+        return;
+    }
+    handle.adev_handle = adev;
+    handle.spkr_prot_mode = MSM_SPKR_PROT_DISABLED;
+    handle.spkr_processing_state = SPKR_PROCESSING_IN_IDLE;
+    handle.spkr_prot_t0 = -1;
+    pthread_cond_init(&handle.spkr_prot_thermalsync, NULL);
+    pthread_cond_init(&handle.spkr_calib_cancel, NULL);
+    pthread_cond_init(&handle.spkr_calibcancel_ack, NULL);
+    pthread_mutex_init(&handle.mutex_spkr_prot, NULL);
+    pthread_mutex_init(&handle.spkr_calib_cancelack_mutex, NULL);
+    pthread_mutex_init(&handle.spkr_prot_thermalsync_mutex, NULL);
+    handle.thermal_handle = dlopen("/vendor/lib/libthermalclient.so",
+            RTLD_NOW);
+    if (!handle.thermal_handle) {
+        ALOGE("%s: DLOPEN for thermal client failed", __func__);
+    } else {
+        /*Query callback function symbol*/
+        handle.client_register_callback =
+       (int (*)(char *, int (*)(int),void *))
+        dlsym(handle.thermal_handle, "thermal_client_register_callback");
+        handle.thermal_client_unregister_callback =
+        (void (*)(int) )
+        dlsym(handle.thermal_handle, "thermal_client_unregister_callback");
+        if (!handle.client_register_callback ||
+            !handle.thermal_client_unregister_callback) {
+            ALOGE("%s: DLSYM thermal_client_register_callback failed", __func__);
+        } else {
+            /*Register callback function*/
+            handle.thermal_client_handle =
+            handle.client_register_callback("spkr", thermal_client_callback, NULL);
+            if (!handle.thermal_client_handle) {
+                ALOGE("%s: client_register_callback failed", __func__);
+            } else {
+                ALOGD("%s: spkr_prot client_register_callback success", __func__);
+                handle.thermal_client_request = (int (*)(char *, int))
+                dlsym(handle.thermal_handle, "thermal_client_request");
+            }
+        }
+    }
+    if (handle.thermal_client_request) {
+        ALOGD("%s: Create calibration thread", __func__);
+        (void)pthread_create(&handle.spkr_calibration_thread,
+        (const pthread_attr_t *) NULL, spkr_calibration_thread, &handle);
+    } else {
+        ALOGE("%s: thermal_client_request failed", __func__);
+        if (handle.thermal_client_handle &&
+            handle.thermal_client_unregister_callback)
+            handle.thermal_client_unregister_callback(handle.thermal_client_handle);
+        if (handle.thermal_handle)
+            dlclose(handle.thermal_handle);
+        handle.thermal_handle = NULL;
+        handle.spkr_prot_enable = false;
+    }
+
+    if (handle.spkr_prot_enable) {
+        char platform[PROPERTY_VALUE_MAX];
+        property_get("ro.board.platform", platform, "");
+        if (!strncmp("apq8084", platform, sizeof("apq8084"))) {
+            platform_set_snd_device_backend(SND_DEVICE_OUT_VOICE_SPEAKER,
+                                            "speaker-protected");
+        }
+    }
+}
+
+int audio_extn_spkr_prot_get_acdb_id(snd_device_t snd_device)
+{
+    int acdb_id;
+
+    switch(snd_device) {
+    case SND_DEVICE_OUT_SPEAKER:
+        acdb_id = platform_get_snd_device_acdb_id(SND_DEVICE_OUT_SPEAKER_PROTECTED);
+        break;
+    case SND_DEVICE_OUT_VOICE_SPEAKER:
+        acdb_id = platform_get_snd_device_acdb_id(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED);
+        break;
+    default:
+        acdb_id = -EINVAL;
+        break;
+    }
+    return acdb_id;
+}
+
+int audio_extn_get_spkr_prot_snd_device(snd_device_t snd_device)
+{
+    if (!handle.spkr_prot_enable)
+        return snd_device;
+
+    switch(snd_device) {
+    case SND_DEVICE_OUT_SPEAKER:
+        return SND_DEVICE_OUT_SPEAKER_PROTECTED;
+    case SND_DEVICE_OUT_VOICE_SPEAKER:
+        return SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED;
+    default:
+        return snd_device;
+    }
+}
+
+int audio_extn_spkr_prot_start_processing(snd_device_t snd_device)
+{
+    struct audio_usecase *uc_info_tx;
+    struct audio_device *adev = handle.adev_handle;
+    int32_t pcm_dev_tx_id = -1, ret = 0;
+
+    ALOGV("%s: Entry", __func__);
+    /* cancel speaker calibration */
+    if (!adev) {
+       ALOGE("%s: Invalid params", __func__);
+       return -EINVAL;
+    }
+    snd_device = audio_extn_get_spkr_prot_snd_device(snd_device);
+    spkr_prot_set_spkrstatus(true);
+    uc_info_tx = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+    if (!uc_info_tx) {
+        return -ENOMEM;
+    }
+    ALOGV("%s: snd_device(%d: %s)", __func__, snd_device,
+           platform_get_snd_device_name(snd_device));
+    audio_route_apply_and_update_path(adev->audio_route,
+           platform_get_snd_device_name(snd_device));
+
+    pthread_mutex_lock(&handle.mutex_spkr_prot);
+    if (handle.spkr_processing_state == SPKR_PROCESSING_IN_IDLE) {
+        uc_info_tx->id = USECASE_AUDIO_SPKR_CALIB_TX;
+        uc_info_tx->type = PCM_CAPTURE;
+        uc_info_tx->in_snd_device = SND_DEVICE_IN_CAPTURE_VI_FEEDBACK;
+        uc_info_tx->out_snd_device = SND_DEVICE_NONE;
+        handle.pcm_tx = NULL;
+        list_add_tail(&adev->usecase_list, &uc_info_tx->list);
+        enable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK);
+        enable_audio_route(adev, uc_info_tx);
+
+        pcm_dev_tx_id = platform_get_pcm_device_id(uc_info_tx->id, PCM_CAPTURE);
+        if (pcm_dev_tx_id < 0) {
+            ALOGE("%s: Invalid pcm device for usecase (%d)",
+                  __func__, uc_info_tx->id);
+            ret = -ENODEV;
+            goto exit;
+        }
+        handle.pcm_tx = pcm_open(adev->snd_card,
+                                 pcm_dev_tx_id,
+                                 PCM_IN, &pcm_config_skr_prot);
+        if (handle.pcm_tx && !pcm_is_ready(handle.pcm_tx)) {
+            ALOGE("%s: %s", __func__, pcm_get_error(handle.pcm_tx));
+            ret = -EIO;
+            goto exit;
+        }
+        if (pcm_start(handle.pcm_tx) < 0) {
+            ALOGE("%s: pcm start for TX failed", __func__);
+            ret = -EINVAL;
+        }
+    }
+
+exit:
+   /* Clear VI feedback cal and replace with handset MIC  */
+   platform_send_audio_calibration(adev->platform,
+        SND_DEVICE_IN_HANDSET_MIC,
+        platform_get_default_app_type(adev->platform), 8000);
+    if (ret) {
+        if (handle.pcm_tx)
+            pcm_close(handle.pcm_tx);
+        handle.pcm_tx = NULL;
+        list_remove(&uc_info_tx->list);
+        disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK);
+        disable_audio_route(adev, uc_info_tx);
+        free(uc_info_tx);
+    } else
+        handle.spkr_processing_state = SPKR_PROCESSING_IN_PROGRESS;
+    pthread_mutex_unlock(&handle.mutex_spkr_prot);
+    ALOGV("%s: Exit", __func__);
+    return ret;
+}
+
+void audio_extn_spkr_prot_stop_processing(snd_device_t snd_device)
+{
+    struct audio_usecase *uc_info_tx;
+    struct audio_device *adev = handle.adev_handle;
+
+    ALOGV("%s: Entry", __func__);
+    snd_device = audio_extn_get_spkr_prot_snd_device(snd_device);
+    spkr_prot_set_spkrstatus(false);
+    pthread_mutex_lock(&handle.mutex_spkr_prot);
+    if (adev && handle.spkr_processing_state == SPKR_PROCESSING_IN_PROGRESS) {
+        uc_info_tx = get_usecase_from_list(adev, USECASE_AUDIO_SPKR_CALIB_TX);
+        if (handle.pcm_tx)
+            pcm_close(handle.pcm_tx);
+        handle.pcm_tx = NULL;
+        disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK);
+        if (uc_info_tx) {
+            list_remove(&uc_info_tx->list);
+            disable_audio_route(adev, uc_info_tx);
+            free(uc_info_tx);
+        }
+    }
+    handle.spkr_processing_state = SPKR_PROCESSING_IN_IDLE;
+    pthread_mutex_unlock(&handle.mutex_spkr_prot);
+    if (adev)
+        audio_route_reset_and_update_path(adev->audio_route,
+                                      platform_get_snd_device_name(snd_device));
+    ALOGV("%s: Exit", __func__);
+}
+
+bool audio_extn_spkr_prot_is_enabled()
+{
+    return handle.spkr_prot_enable;
+}
+#endif /*SPKR_PROT_ENABLED*/
diff --git a/msm8909/hal/audio_extn/ssr.c b/msm8909/hal/audio_extn/ssr.c
new file mode 100644
index 0000000..07b28b0
--- /dev/null
+++ b/msm8909/hal/audio_extn/ssr.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_ssr"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/str_parms.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include "surround_filters_interface.h"
+
+#ifdef SSR_ENABLED
+#define COEFF_ARRAY_SIZE            4
+#define FILT_SIZE                   ((512+1)* 6)  /* # ((FFT bins)/2+1)*numOutputs */
+#define SSR_CHANNEL_INPUT_NUM       4
+#define SSR_CHANNEL_OUTPUT_NUM      6
+#define SSR_PERIOD_COUNT            8
+#define SSR_PERIOD_SIZE             512
+#define SSR_INPUT_FRAME_SIZE        (SSR_PERIOD_SIZE * SSR_PERIOD_COUNT)
+
+#define SURROUND_FILE_1R "/system/etc/surround_sound/filter1r.pcm"
+#define SURROUND_FILE_2R "/system/etc/surround_sound/filter2r.pcm"
+#define SURROUND_FILE_3R "/system/etc/surround_sound/filter3r.pcm"
+#define SURROUND_FILE_4R "/system/etc/surround_sound/filter4r.pcm"
+
+#define SURROUND_FILE_1I "/system/etc/surround_sound/filter1i.pcm"
+#define SURROUND_FILE_2I "/system/etc/surround_sound/filter2i.pcm"
+#define SURROUND_FILE_3I "/system/etc/surround_sound/filter3i.pcm"
+#define SURROUND_FILE_4I "/system/etc/surround_sound/filter4i.pcm"
+
+#define LIB_SURROUND_PROC       "libsurround_proc.so"
+
+typedef int  (*surround_filters_init_t)(void *, int, int, Word16 **,
+                                        Word16 **, int, int, int, Profiler *);
+typedef void (*surround_filters_release_t)(void *);
+typedef int  (*surround_filters_set_channel_map_t)(void *, const int *);
+typedef void (*surround_filters_intl_process_t)(void *, Word16 *, Word16 *);
+
+struct ssr_module {
+    FILE                *fp_4ch;
+    FILE                *fp_6ch;
+    Word16             **real_coeffs;
+    Word16             **imag_coeffs;
+    void                *surround_obj;
+    Word16             *surround_raw_buffer;
+    bool                is_ssr_enabled;
+
+    void *surround_filters_handle;
+    surround_filters_init_t surround_filters_init;
+    surround_filters_release_t surround_filters_release;
+    surround_filters_set_channel_map_t surround_filters_set_channel_map;
+    surround_filters_intl_process_t surround_filters_intl_process;
+};
+
+static struct ssr_module ssrmod = {
+    .fp_4ch = NULL,
+    .fp_6ch = NULL,
+    .real_coeffs = NULL,
+    .imag_coeffs = NULL,
+    .surround_obj = NULL,
+    .surround_raw_buffer = NULL,
+    .is_ssr_enabled = 0,
+
+    .surround_filters_handle = NULL,
+    .surround_filters_init = NULL,
+    .surround_filters_release = NULL,
+    .surround_filters_set_channel_map = NULL,
+    .surround_filters_intl_process = NULL,
+};
+
+/* Use AAC/DTS channel mapping as default channel mapping: C,FL,FR,Ls,Rs,LFE */
+static const int chan_map[] = { 1, 2, 4, 3, 0, 5};
+
+/* Rotine to read coeffs from File and updates real and imaginary
+   coeff array member variable */
+static int32_t ssr_read_coeffs_from_file()
+{
+    FILE    *flt1r;
+    FILE    *flt2r;
+    FILE    *flt3r;
+    FILE    *flt4r;
+    FILE    *flt1i;
+    FILE    *flt2i;
+    FILE    *flt3i;
+    FILE    *flt4i;
+    int i;
+
+    if ( (flt1r = fopen(SURROUND_FILE_1R, "rb")) == NULL ) {
+        ALOGE("%s: Cannot open filter co-efficient "
+              "file %s", __func__, SURROUND_FILE_1R);
+        return -EINVAL;
+    }
+
+    if ( (flt2r = fopen(SURROUND_FILE_2R, "rb")) == NULL ) {
+        ALOGE("%s: Cannot open filter "
+              "co-efficient file %s", __func__, SURROUND_FILE_2R);
+        return -EINVAL;
+    }
+
+    if ( (flt3r = fopen(SURROUND_FILE_3R, "rb")) == NULL ) {
+        ALOGE("%s: Cannot open filter "
+              "co-efficient file %s", __func__, SURROUND_FILE_3R);
+        return  -EINVAL;
+    }
+
+    if ( (flt4r = fopen(SURROUND_FILE_4R, "rb")) == NULL ) {
+        ALOGE("%s: Cannot open filter "
+              "co-efficient file %s", __func__, SURROUND_FILE_4R);
+        return  -EINVAL;
+    }
+
+    if ( (flt1i = fopen(SURROUND_FILE_1I, "rb")) == NULL ) {
+        ALOGE("%s: Cannot open filter "
+              "co-efficient file %s", __func__, SURROUND_FILE_1I);
+        return -EINVAL;
+    }
+
+    if ( (flt2i = fopen(SURROUND_FILE_2I, "rb")) == NULL ) {
+        ALOGE("%s: Cannot open filter "
+              "co-efficient file %s", __func__, SURROUND_FILE_2I);
+        return -EINVAL;
+    }
+
+    if ( (flt3i = fopen(SURROUND_FILE_3I, "rb")) == NULL ) {
+        ALOGE("%s: Cannot open filter "
+              "co-efficient file %s", __func__, SURROUND_FILE_3I);
+        return -EINVAL;
+    }
+
+    if ( (flt4i = fopen(SURROUND_FILE_4I, "rb")) == NULL ) {
+        ALOGE("%s: Cannot open filter "
+              "co-efficient file %s", __func__, SURROUND_FILE_4I);
+        return -EINVAL;
+    }
+    ALOGV("%s: readCoeffsFromFile all filter "
+          "files opened", __func__);
+
+    for (i=0; i<COEFF_ARRAY_SIZE; i++) {
+        ssrmod.real_coeffs[i] = (Word16 *)calloc(FILT_SIZE, sizeof(Word16));
+    }
+    for (i=0; i<COEFF_ARRAY_SIZE; i++) {
+        ssrmod.imag_coeffs[i] = (Word16 *)calloc(FILT_SIZE, sizeof(Word16));
+    }
+
+    /* Read real co-efficients */
+    if (NULL != ssrmod.real_coeffs[0]) {
+        fread(ssrmod.real_coeffs[0], sizeof(int16), FILT_SIZE, flt1r);
+    }
+    if (NULL != ssrmod.real_coeffs[0]) {
+        fread(ssrmod.real_coeffs[1], sizeof(int16), FILT_SIZE, flt2r);
+    }
+    if (NULL != ssrmod.real_coeffs[0]) {
+        fread(ssrmod.real_coeffs[2], sizeof(int16), FILT_SIZE, flt3r);
+    }
+    if (NULL != ssrmod.real_coeffs[0]) {
+        fread(ssrmod.real_coeffs[3], sizeof(int16), FILT_SIZE, flt4r);
+    }
+
+    /* read imaginary co-efficients */
+    if (NULL != ssrmod.imag_coeffs[0]) {
+        fread(ssrmod.imag_coeffs[0], sizeof(int16), FILT_SIZE, flt1i);
+    }
+    if (NULL != ssrmod.imag_coeffs[0]) {
+        fread(ssrmod.imag_coeffs[1], sizeof(int16), FILT_SIZE, flt2i);
+    }
+    if (NULL != ssrmod.imag_coeffs[0]) {
+        fread(ssrmod.imag_coeffs[2], sizeof(int16), FILT_SIZE, flt3i);
+    }
+    if (NULL != ssrmod.imag_coeffs[0]) {
+        fread(ssrmod.imag_coeffs[3], sizeof(int16), FILT_SIZE, flt4i);
+    }
+
+    fclose(flt1r);
+    fclose(flt2r);
+    fclose(flt3r);
+    fclose(flt4r);
+    fclose(flt1i);
+    fclose(flt2i);
+    fclose(flt3i);
+    fclose(flt4i);
+
+    return 0;
+}
+
+static int32_t ssr_init_surround_sound_lib(unsigned long buffersize)
+{
+    /* sub_woofer channel assignment: default as first
+       microphone input channel */
+    int sub_woofer = 0;
+    /* frequency upper bound for sub_woofer:
+       frequency=(low_freq-1)/FFT_SIZE*samplingRate, default as 4 */
+    int low_freq = 4;
+    /* frequency upper bound for spatial processing:
+       frequency=(high_freq-1)/FFT_SIZE*samplingRate, default as 100 */
+    int high_freq = 100;
+    int i, ret = 0;
+
+    if ( ssrmod.surround_obj ) {
+        ALOGE("%s: ola filter library is already initialized", __func__);
+        return 0;
+    }
+
+    /* Allocate memory for input buffer */
+    ssrmod.surround_raw_buffer = (Word16 *) calloc(buffersize,
+                                              sizeof(Word16));
+    if ( !ssrmod.surround_raw_buffer ) {
+       ALOGE("%s: Memory allocation failure. Not able to allocate "
+             "memory for surroundInputBuffer", __func__);
+       goto init_fail;
+    }
+
+    /* Allocate memory for real and imag coeffs array */
+    ssrmod.real_coeffs = (Word16 **) calloc(COEFF_ARRAY_SIZE, sizeof(Word16 *));
+    if ( !ssrmod.real_coeffs ) {
+        ALOGE("%s: Memory allocation failure during real "
+              "Coefficient array", __func__);
+        goto init_fail;
+    }
+
+    ssrmod.imag_coeffs = (Word16 **) calloc(COEFF_ARRAY_SIZE, sizeof(Word16 *));
+    if ( !ssrmod.imag_coeffs ) {
+        ALOGE("%s: Memory allocation failure during imaginary "
+              "Coefficient array", __func__);
+        goto init_fail;
+    }
+
+    if( ssr_read_coeffs_from_file() != 0) {
+        ALOGE("%s: Error while loading coeffs from file", __func__);
+        goto init_fail;
+    }
+
+    ssrmod.surround_filters_handle = dlopen(LIB_SURROUND_PROC, RTLD_NOW);
+    if (ssrmod.surround_filters_handle == NULL) {
+        ALOGE("%s: DLOPEN failed for %s", __func__, LIB_SURROUND_PROC);
+    } else {
+        ALOGV("%s: DLOPEN successful for %s", __func__, LIB_SURROUND_PROC);
+        ssrmod.surround_filters_init = (surround_filters_init_t)
+        dlsym(ssrmod.surround_filters_handle, "surround_filters_init");
+
+        ssrmod.surround_filters_release = (surround_filters_release_t)
+         dlsym(ssrmod.surround_filters_handle, "surround_filters_release");
+
+        ssrmod.surround_filters_set_channel_map = (surround_filters_set_channel_map_t)
+         dlsym(ssrmod.surround_filters_handle, "surround_filters_set_channel_map");
+
+        ssrmod.surround_filters_intl_process = (surround_filters_intl_process_t)
+        dlsym(ssrmod.surround_filters_handle, "surround_filters_intl_process");
+
+        if (!ssrmod.surround_filters_init ||
+            !ssrmod.surround_filters_release ||
+            !ssrmod.surround_filters_set_channel_map ||
+            !ssrmod.surround_filters_intl_process){
+            ALOGW("%s: Could not find the one of the symbols from %s",
+                  __func__, LIB_SURROUND_PROC);
+            goto init_fail;
+        }
+    }
+
+    /* calculate the size of data to allocate for surround_obj */
+    ret = ssrmod.surround_filters_init(NULL,
+                  6, // Num output channel
+                  4,     // Num input channel
+                  ssrmod.real_coeffs,       // Coeffs hardcoded in header
+                  ssrmod.imag_coeffs,       // Coeffs hardcoded in header
+                  sub_woofer,
+                  low_freq,
+                  high_freq,
+                  NULL);
+
+    if ( ret > 0 ) {
+        ALOGV("%s: Allocating surroundObj size is %d", __func__, ret);
+        ssrmod.surround_obj = (void *)malloc(ret);
+        if (NULL != ssrmod.surround_obj) {
+            memset(ssrmod.surround_obj,0,ret);
+            /* initialize after allocating the memory for surround_obj */
+            ret = ssrmod.surround_filters_init(ssrmod.surround_obj,
+                        6,
+                        4,
+                        ssrmod.real_coeffs,
+                        ssrmod.imag_coeffs,
+                        sub_woofer,
+                        low_freq,
+                        high_freq,
+                        NULL);
+            if (0 != ret) {
+               ALOGE("%s: surround_filters_init failed with ret:%d",__func__, ret);
+               ssrmod.surround_filters_release(ssrmod.surround_obj);
+               goto init_fail;
+            }
+        } else {
+            ALOGE("%s: Allocationg surround_obj failed", __func__);
+            goto init_fail;
+        }
+    } else {
+        ALOGE("%s: surround_filters_init(surround_obj=Null) "
+              "failed with ret: %d", __func__, ret);
+        goto init_fail;
+    }
+
+    (void) ssrmod.surround_filters_set_channel_map(ssrmod.surround_obj, chan_map);
+
+    return 0;
+
+init_fail:
+    if (ssrmod.surround_obj) {
+        free(ssrmod.surround_obj);
+        ssrmod.surround_obj = NULL;
+    }
+    if (ssrmod.surround_raw_buffer) {
+        free(ssrmod.surround_raw_buffer);
+        ssrmod.surround_raw_buffer = NULL;
+    }
+    if (ssrmod.real_coeffs){
+        for (i =0; i<COEFF_ARRAY_SIZE; i++ ) {
+            if (ssrmod.real_coeffs[i]) {
+                free(ssrmod.real_coeffs[i]);
+                ssrmod.real_coeffs[i] = NULL;
+            }
+        }
+        free(ssrmod.real_coeffs);
+        ssrmod.real_coeffs = NULL;
+    }
+    if (ssrmod.imag_coeffs){
+        for (i =0; i<COEFF_ARRAY_SIZE; i++ ) {
+            if (ssrmod.imag_coeffs[i]) {
+                free(ssrmod.imag_coeffs[i]);
+                ssrmod.imag_coeffs[i] = NULL;
+            }
+        }
+        free(ssrmod.imag_coeffs);
+        ssrmod.imag_coeffs = NULL;
+    }
+
+    return -ENOMEM;
+}
+
+void audio_extn_ssr_update_enabled()
+{
+    char ssr_enabled[PROPERTY_VALUE_MAX] = "false";
+
+    property_get("ro.qc.sdk.audio.ssr",ssr_enabled,"0");
+    if (!strncmp("true", ssr_enabled, 4)) {
+        ALOGD("%s: surround sound recording is supported", __func__);
+        ssrmod.is_ssr_enabled = true;
+    } else {
+        ALOGD("%s: surround sound recording is not supported", __func__);
+        ssrmod.is_ssr_enabled = false;
+    }
+}
+
+bool audio_extn_ssr_get_enabled()
+{
+    ALOGV("%s: is_ssr_enabled:%d", __func__, ssrmod.is_ssr_enabled);
+    return (ssrmod.is_ssr_enabled ? true: false);
+}
+
+int32_t audio_extn_ssr_init(struct stream_in *in)
+{
+    uint32_t ret;
+    char c_multi_ch_dump[128] = {0};
+    uint32_t buffer_size;
+
+    ALOGD("%s: ssr case ", __func__);
+    in->config.channels = SSR_CHANNEL_INPUT_NUM;
+    in->config.period_size = SSR_PERIOD_SIZE;
+    in->config.period_count = SSR_PERIOD_COUNT;
+
+    /* use 4k hardcoded buffer size for ssr*/
+    buffer_size = SSR_INPUT_FRAME_SIZE;
+    ALOGV("%s: buffer_size: %d", __func__, buffer_size);
+
+    ret = ssr_init_surround_sound_lib(buffer_size);
+    if (0 != ret) {
+        ALOGE("%s: initSurroundSoundLibrary failed: %d  "
+              "handle->bufferSize:%d", __func__, ret, buffer_size);
+        return ret;
+    }
+
+    property_get("ssr.pcmdump",c_multi_ch_dump,"0");
+    if (0 == strncmp("true", c_multi_ch_dump, sizeof("ssr.dump-pcm"))) {
+        /* Remember to change file system permission of data(e.g. chmod 777 data/),
+          otherwise, fopen may fail */
+        if ( !ssrmod.fp_4ch)
+            ssrmod.fp_4ch = fopen("/data/4ch.pcm", "wb");
+        if ( !ssrmod.fp_6ch)
+            ssrmod.fp_6ch = fopen("/data/6ch.pcm", "wb");
+        if ((!ssrmod.fp_4ch) || (!ssrmod.fp_6ch))
+            ALOGE("%s: mfp_4ch or mfp_6ch open failed: mfp_4ch:%p mfp_6ch:%p",
+                  __func__, ssrmod.fp_4ch, ssrmod.fp_6ch);
+    }
+
+    return 0;
+}
+
+int32_t audio_extn_ssr_deinit()
+{
+    int i;
+
+    if (ssrmod.surround_obj) {
+        ALOGV("%s: entry", __func__);
+        ssrmod.surround_filters_release(ssrmod.surround_obj);
+        if (ssrmod.surround_obj)
+            free(ssrmod.surround_obj);
+        ssrmod.surround_obj = NULL;
+        if (ssrmod.real_coeffs){
+            for (i =0; i<COEFF_ARRAY_SIZE; i++ ) {
+                if (ssrmod.real_coeffs[i]) {
+                    free(ssrmod.real_coeffs[i]);
+                    ssrmod.real_coeffs[i] = NULL;
+                }
+            }
+            free(ssrmod.real_coeffs);
+            ssrmod.real_coeffs = NULL;
+        }
+        if (ssrmod.imag_coeffs){
+            for (i =0; i<COEFF_ARRAY_SIZE; i++ ) {
+                if (ssrmod.imag_coeffs[i]) {
+                    free(ssrmod.imag_coeffs[i]);
+                    ssrmod.imag_coeffs[i] = NULL;
+                }
+            }
+            free(ssrmod.imag_coeffs);
+            ssrmod.imag_coeffs = NULL;
+        }
+        if (ssrmod.surround_raw_buffer) {
+            free(ssrmod.surround_raw_buffer);
+            ssrmod.surround_raw_buffer = NULL;
+        }
+        if (ssrmod.fp_4ch)
+            fclose(ssrmod.fp_4ch);
+        if (ssrmod.fp_6ch)
+            fclose(ssrmod.fp_6ch);
+    }
+
+    if(ssrmod.surround_filters_handle) {
+        dlclose(ssrmod.surround_filters_handle);
+        ssrmod.surround_filters_handle = NULL;
+    }
+    ALOGV("%s: exit", __func__);
+
+    return 0;
+}
+
+int32_t audio_extn_ssr_read(struct audio_stream_in *stream,
+                       void *buffer, size_t bytes)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    struct audio_device *adev = in->dev;
+    size_t peroid_bytes;
+    int32_t ret;
+
+    /* Convert bytes for 6ch to 4ch*/
+    peroid_bytes = (bytes / SSR_CHANNEL_OUTPUT_NUM) * SSR_CHANNEL_INPUT_NUM;
+
+    if (!ssrmod.surround_obj) {
+        ALOGE("%s: surround_obj not initialized", __func__);
+        return -ENOMEM;
+    }
+
+    ret = pcm_read(in->pcm, ssrmod.surround_raw_buffer, peroid_bytes);
+    if (ret < 0) {
+        ALOGE("%s: %s ret:%d", __func__, pcm_get_error(in->pcm),ret);
+        return ret;
+    }
+
+    /* apply ssr libs to conver 4ch to 6ch */
+    ssrmod.surround_filters_intl_process(ssrmod.surround_obj,
+        buffer, ssrmod.surround_raw_buffer);
+
+    /*dump for raw pcm data*/
+    if (ssrmod.fp_4ch)
+        fwrite(ssrmod.surround_raw_buffer, 1, peroid_bytes, ssrmod.fp_4ch);
+    if (ssrmod.fp_6ch)
+        fwrite(buffer, 1, bytes, ssrmod.fp_6ch);
+
+    return ret;
+}
+
+#endif /* SSR_ENABLED */
diff --git a/msm8909/hal/audio_extn/usb.c b/msm8909/hal/audio_extn/usb.c
new file mode 100644
index 0000000..13e3138
--- /dev/null
+++ b/msm8909/hal/audio_extn/usb.c
@@ -0,0 +1,730 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_usb"
+#define LOG_NDEBUG 0
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <system/audio.h>
+#include <tinyalsa/asoundlib.h>
+
+#ifdef USB_HEADSET_ENABLED
+#define USB_LOW_LATENCY_OUTPUT_PERIOD_SIZE   512
+#define USB_LOW_LATENCY_OUTPUT_PERIOD_COUNT  8
+#define USB_DEFAULT_OUTPUT_SAMPLING_RATE     48000
+
+#define USB_PROXY_DEFAULT_SAMPLING_RATE      48000
+#define USB_PROXY_OPEN_RETRY_COUNT           100
+#define USB_PROXY_OPEN_WAIT_TIME             20
+#define USB_PROXY_PERIOD_SIZE                3072
+#define USB_PROXY_RATE_8000                  8000
+#define USB_PROXY_RATE_16000                 16000
+#define USB_PROXY_RATE_48000                 48000
+#define USB_PERIOD_SIZE                      2048
+#define USB_BUFF_SIZE                        2048
+#define AFE_PROXY_PERIOD_COUNT               32
+#define AFE_PROXY_PLAYBACK_DEVICE            8
+#define AFE_PROXY_CAPTURE_DEVICE             7
+
+struct usb_module {
+    uint32_t usb_card;
+    uint32_t proxy_card;
+    uint32_t usb_device_id;
+    uint32_t proxy_device_id;
+
+    int32_t channels_playback;
+    int32_t sample_rate_playback;
+    int32_t channels_record;
+    int32_t sample_rate_record;
+
+    bool is_playback_running;
+    bool is_record_running;
+
+    pthread_t usb_playback_thr;
+    pthread_t usb_record_thr;
+    pthread_mutex_t usb_playback_lock;
+    pthread_mutex_t usb_record_lock;
+
+    struct pcm *proxy_pcm_playback_handle;
+    struct pcm *usb_pcm_playback_handle;
+    struct pcm *proxy_pcm_record_handle;
+    struct pcm *usb_pcm_record_handle;
+    struct audio_device *adev;
+};
+
+static struct usb_module *usbmod = NULL;
+static pthread_once_t alloc_usbmod_once_ctl = PTHREAD_ONCE_INIT;
+
+struct pcm_config pcm_config_usbmod = {
+    .channels = 2,
+    .rate = USB_DEFAULT_OUTPUT_SAMPLING_RATE,
+    .period_size = USB_LOW_LATENCY_OUTPUT_PERIOD_SIZE,
+    .period_count = USB_LOW_LATENCY_OUTPUT_PERIOD_COUNT,
+    .format = PCM_FORMAT_S16_LE,
+    .start_threshold = USB_LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
+    .stop_threshold = INT_MAX,
+    .avail_min = USB_LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
+};
+
+static void usb_alloc()
+{
+    usbmod = calloc(1, sizeof(struct usb_module));
+}
+
+// Some USB audio accessories have a really low default volume set. Look for a suitable
+// volume control and set the volume to default volume level.
+static void initPlaybackVolume() {
+    ALOGD("initPlaybackVolume");
+    struct mixer *usbMixer = mixer_open(1);
+
+    if (usbMixer) {
+         struct mixer_ctl *ctl = NULL;
+         unsigned int usbPlaybackVolume;
+         unsigned int i;
+         unsigned int num_ctls = mixer_get_num_ctls(usbMixer);
+
+         // Look for the first control named ".*Playback Volume" that isn't for a microphone
+         for (i = 0; i < num_ctls; i++) {
+             ctl = mixer_get_ctl(usbMixer, i);
+             if ((ctl) && (strstr((const char *)mixer_ctl_get_name(ctl), "Playback Volume") &&
+                 !strstr((const char *)mixer_ctl_get_name(ctl), "Mic"))) {
+                   break;
+             }
+         }
+         if (ctl != NULL) {
+            ALOGD("Found a volume control for USB: %s", mixer_ctl_get_name(ctl) );
+            usbPlaybackVolume = mixer_ctl_get_value(ctl, 0);
+            ALOGD("Value got from mixer_ctl_get is:%u", usbPlaybackVolume);
+            if (mixer_ctl_set_value(ctl,0,usbPlaybackVolume) < 0) {
+               ALOGE("Failed to set volume; default volume might be used");
+            }
+         } else {
+            ALOGE("No playback volume control found; default volume will be used");
+         }
+         mixer_close(usbMixer);
+    } else {
+         ALOGE("Failed to open mixer for card 1");
+    }
+}
+
+static int usb_get_numof_rates(char *rates_str)
+{
+    int i, size = 0;
+    char *next_sr_string, *temp_ptr;
+    next_sr_string = strtok_r(rates_str, " ,", &temp_ptr);
+
+    if (next_sr_string == NULL) {
+        ALOGE("%s: get_numof_rates: could not find rates string", __func__);
+        return 0;
+    }
+
+    for (i = 1; next_sr_string != NULL; i++) {
+        size ++;
+        next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr);
+    }
+    return size;
+}
+
+static int usb_get_capability(char *type, int32_t *channels,
+                                    int32_t *sample_rate)
+{
+    ALOGD("%s: for %s", __func__, type);
+    long unsigned file_size;
+    FILE *fp;
+    char *buffer;
+    int32_t err = 1;
+    int32_t size = 0;
+    int32_t fd=-1, i, channels_playback;
+    char *str_start, *channel_start, *rates_str_start, *next_sr_str,
+         *next_sr_string, *temp_ptr;
+    struct stat st;
+    char *read_buf = NULL;
+    char *rates_str = NULL;
+    char *rates_str_for_val = NULL;
+    int  *rates_supported = NULL;
+    char path[128];
+    int ret = 0;
+
+    memset(&st, 0x0, sizeof(struct stat));
+    *sample_rate = 0;
+    snprintf(path, sizeof(path), "/proc/asound/card%u/stream0",
+             usbmod->usb_card);
+
+    fd = open(path, O_RDONLY);
+    if (fd <0) {
+        ALOGE("%s: error failed to open config file %s error: %d\n",
+              __func__, path, errno);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    if (fstat(fd, &st) < 0) {
+        ALOGE("%s: error failed to stat %s error %d\n",
+             __func__, path, errno);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    file_size = st.st_size;
+
+    read_buf = (char *)calloc(1, USB_BUFF_SIZE + 1);
+
+    if (!read_buf) {
+        ALOGE("Failed to create read_buf");
+        ret = -ENOMEM;
+        goto done;
+    }
+
+    err = read(fd, read_buf, USB_BUFF_SIZE);
+    str_start = strstr(read_buf, type);
+    if (str_start == NULL) {
+        ALOGE("%s: error %s section not found in usb config file",
+               __func__, type);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    channel_start = strstr(str_start, "Channels:");
+    if (channel_start == NULL) {
+        ALOGE("%s: error could not find Channels information", __func__);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    channel_start = strstr(channel_start, " ");
+    if (channel_start == NULL) {
+        ALOGE("%s: error channel section not found in usb config file",
+               __func__);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    channels_playback = atoi(channel_start);
+    if (channels_playback == 1) {
+        *channels = 1;
+    } else {
+        *channels = 2;
+    }
+
+    ALOGD("%s: channels supported by device: %d", __func__, *channels);
+    rates_str_start = strstr(str_start, "Rates:");
+    if (rates_str_start == NULL) {
+        ALOGE("%s: error cant find rates information", __func__);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    rates_str_start = strstr(rates_str_start, " ");
+    if (rates_str_start == NULL) {
+        ALOGE("%s: error channel section not found in usb config file",
+               __func__);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    char *target = strchr(rates_str_start, '\n');
+    if (target == NULL) {
+        ALOGE("%s: error end of line not found", __func__);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    size = target - rates_str_start;
+    if ((rates_str = (char *)malloc(size + 1)) == NULL) {
+        ALOGE("%s: error unable to allocate memory to hold sample rate strings",
+              __func__);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    if ((rates_str_for_val = (char *)malloc(size + 1)) == NULL) {
+        ALOGE("%s: error unable to allocate memory to hold sample rate string",
+               __func__);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    memcpy(rates_str, rates_str_start, size);
+    memcpy(rates_str_for_val, rates_str_start, size);
+    rates_str[size] = '\0';
+    rates_str_for_val[size] = '\0';
+
+    size = usb_get_numof_rates(rates_str);
+    if (!size) {
+        ALOGE("%s: error could not get rate size, returning", __func__);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    rates_supported = (int *)malloc(sizeof(int) * size);
+
+    if (!rates_supported) {
+        ALOGE("couldn't allocate mem for rates_supported");
+        ret = -EINVAL;
+        goto done;
+    }
+
+    next_sr_string = strtok_r(rates_str_for_val, " ,", &temp_ptr);
+    if (next_sr_string == NULL) {
+        ALOGE("%s: error could not get first rate val", __func__);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    rates_supported[0] = atoi(next_sr_string);
+    ALOGD("%s: rates_supported[0] for playback: %d",
+           __func__, rates_supported[0]);
+    for (i = 1; i<size; i++) {
+        next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr);
+        if (next_sr_string == NULL) {
+            rates_supported[i] = -1; // fill in an invalid sr for the rest
+            continue;
+        }
+        rates_supported[i] = atoi(next_sr_string);
+        ALOGD("rates_supported[%d] for playback: %d",i, rates_supported[i]);
+    }
+
+    for (i = 0; i<size; i++) {
+        if ((rates_supported[i] > *sample_rate) &&
+            (rates_supported[i] <= 48000)) {
+            /* Sample Rate should be one of the proxy supported rates only
+               This is because proxy port is used to read from/write to DSP */
+            if ((rates_supported[i] == USB_PROXY_RATE_8000) ||
+                (rates_supported[i] == USB_PROXY_RATE_16000) ||
+                (rates_supported[i] == USB_PROXY_RATE_48000)) {
+                *sample_rate = rates_supported[i];
+            }
+        }
+    }
+    ALOGD("%s: sample_rate: %d", __func__, *sample_rate);
+
+done:
+    if (fd >= 0) close(fd);
+    if (rates_str_for_val) free(rates_str_for_val);
+    if (rates_str) free(rates_str);
+    if (rates_supported) free(rates_supported);
+    if (read_buf) free(read_buf);
+    return ret;
+}
+
+static int32_t usb_playback_entry(void *adev)
+{
+    unsigned char usbbuf[USB_PROXY_PERIOD_SIZE] = {0};
+    int32_t ret, bytes, proxy_open_retry_count;
+
+    ALOGD("%s: entry", __func__);
+    /* update audio device pointer */
+    usbmod->adev = (struct audio_device*)adev;
+    proxy_open_retry_count = USB_PROXY_OPEN_RETRY_COUNT;
+
+    /* get capabilities */
+    pthread_mutex_lock(&usbmod->usb_playback_lock);
+    ret = usb_get_capability((char *)"Playback:",
+            &usbmod->channels_playback, &usbmod->sample_rate_playback);
+    if (ret) {
+        ALOGE("%s: could not get playback capabilities from usb device",
+               __func__);
+        pthread_mutex_unlock(&usbmod->usb_playback_lock);
+        return -EINVAL;
+    }
+    /* update config for usb
+       1 pcm frame(sample)= 4 bytes since two channels*/
+    pcm_config_usbmod.period_size = USB_PERIOD_SIZE/4;
+    pcm_config_usbmod.channels = usbmod->channels_playback;
+    pcm_config_usbmod.rate = usbmod->sample_rate_playback;
+    ALOGV("%s: usb device %u:period %u:channels %u:sample", __func__,
+          pcm_config_usbmod.period_size, pcm_config_usbmod.channels,
+          pcm_config_usbmod.rate);
+
+    usbmod->usb_pcm_playback_handle = pcm_open(usbmod->usb_card, \
+                                    usbmod->usb_device_id, PCM_OUT |
+                                    PCM_MMAP | PCM_NOIRQ , &pcm_config_usbmod);
+
+    if ((usbmod->usb_pcm_playback_handle \
+        && !pcm_is_ready(usbmod->usb_pcm_playback_handle))
+        || (!usbmod->is_playback_running)) {
+        ALOGE("%s: failed: %s", __func__,
+               pcm_get_error(usbmod->usb_pcm_playback_handle));
+        pcm_close(usbmod->usb_pcm_playback_handle);
+        usbmod->usb_pcm_playback_handle = NULL;
+        pthread_mutex_unlock(&usbmod->usb_playback_lock);
+        return -ENOMEM;
+    }
+    ALOGD("%s: USB configured for playback", __func__);
+
+    /* update config for proxy*/
+    pcm_config_usbmod.period_size = USB_PROXY_PERIOD_SIZE/3;
+    pcm_config_usbmod.rate = usbmod->sample_rate_playback;
+    pcm_config_usbmod.channels = usbmod->channels_playback;
+    pcm_config_usbmod.period_count = AFE_PROXY_PERIOD_COUNT;
+    usbmod->proxy_device_id = AFE_PROXY_PLAYBACK_DEVICE;
+    ALOGD("%s: proxy device %u:period %u:channels %u:sample", __func__,
+          pcm_config_usbmod.period_size, pcm_config_usbmod.channels,
+          pcm_config_usbmod.rate);
+
+    while(proxy_open_retry_count){
+        usbmod->proxy_pcm_playback_handle = pcm_open(usbmod->proxy_card,
+                                            usbmod->proxy_device_id, PCM_IN |
+                                     PCM_MMAP | PCM_NOIRQ, &pcm_config_usbmod);
+        if(usbmod->proxy_pcm_playback_handle
+            && !pcm_is_ready(usbmod->proxy_pcm_playback_handle)){
+                     pcm_close(usbmod->proxy_pcm_playback_handle);
+                     proxy_open_retry_count--;
+                     usleep(USB_PROXY_OPEN_WAIT_TIME * 1000);
+                     ALOGE("%s: pcm_open for proxy failed retrying = %d",
+                            __func__, proxy_open_retry_count);
+                }
+                else{
+                  break;
+                }
+    }
+
+    if ((usbmod->proxy_pcm_playback_handle
+        && !pcm_is_ready(usbmod->proxy_pcm_playback_handle))
+        || (!usbmod->is_playback_running)) {
+        ALOGE("%s: failed: %s", __func__,
+               pcm_get_error(usbmod->proxy_pcm_playback_handle));
+        pcm_close(usbmod->proxy_pcm_playback_handle);
+        usbmod->proxy_pcm_playback_handle = NULL;
+        pthread_mutex_unlock(&usbmod->usb_playback_lock);
+        return -ENOMEM;
+    }
+    ALOGD("%s: PROXY configured for playback", __func__);
+    pthread_mutex_unlock(&usbmod->usb_playback_lock);
+
+    ALOGD("Init USB volume");
+    initPlaybackVolume();
+    /* main loop to read from proxy and write to usb */
+    while (usbmod->is_playback_running) {
+        /* read data from proxy */
+        ret = pcm_mmap_read(usbmod->proxy_pcm_playback_handle,
+                                 (void *)usbbuf, USB_PROXY_PERIOD_SIZE);
+        /* Write to usb */
+        ret = pcm_mmap_write(usbmod->usb_pcm_playback_handle,
+                                (void *)usbbuf, USB_PROXY_PERIOD_SIZE);
+        if(!usbmod->is_playback_running)
+            break;
+
+        memset(usbbuf, 0, USB_PROXY_PERIOD_SIZE);
+    } /* main loop end */
+
+    ALOGD("%s: exiting USB playback thread",__func__);
+    return 0;
+}
+
+static void* usb_playback_launcher(void *adev)
+{
+    int32_t ret;
+
+    usbmod->is_playback_running = true;
+    ret = usb_playback_entry(adev);
+
+    if (ret) {
+        ALOGE("%s: failed with err:%d", __func__, ret);
+        usbmod->is_playback_running = false;
+    }
+    return NULL;
+}
+
+static int32_t usb_record_entry(void *adev)
+{
+    unsigned char usbbuf[USB_PROXY_PERIOD_SIZE] = {0};
+    int32_t ret, bytes, proxy_open_retry_count;
+    ALOGD("%s: entry", __func__);
+
+    /* update audio device pointer */
+    usbmod->adev = (struct audio_device*)adev;
+    proxy_open_retry_count = USB_PROXY_OPEN_RETRY_COUNT;
+
+    /* get capabilities */
+    pthread_mutex_lock(&usbmod->usb_record_lock);
+    ret = usb_get_capability((char *)"Capture:",
+            &usbmod->channels_record, &usbmod->sample_rate_record);
+    if (ret) {
+        ALOGE("%s: could not get capture capabilities from usb device",
+               __func__);
+        pthread_mutex_unlock(&usbmod->usb_record_lock);
+        return -EINVAL;
+    }
+    /* update config for usb
+       1 pcm frame(sample)= 4 bytes since two channels*/
+    pcm_config_usbmod.period_size = USB_PERIOD_SIZE/4;
+    pcm_config_usbmod.channels = usbmod->channels_record;
+    pcm_config_usbmod.rate = usbmod->sample_rate_record;
+    ALOGV("%s: usb device %u:period %u:channels %u:sample", __func__,
+          pcm_config_usbmod.period_size, pcm_config_usbmod.channels,
+          pcm_config_usbmod.rate);
+
+    usbmod->usb_pcm_record_handle = pcm_open(usbmod->usb_card, \
+                                    usbmod->usb_device_id, PCM_IN |
+                                    PCM_MMAP | PCM_NOIRQ , &pcm_config_usbmod);
+
+    if ((usbmod->usb_pcm_record_handle \
+        && !pcm_is_ready(usbmod->usb_pcm_record_handle))
+        || (!usbmod->is_record_running)) {
+        ALOGE("%s: failed: %s", __func__,
+               pcm_get_error(usbmod->usb_pcm_record_handle));
+        pcm_close(usbmod->usb_pcm_record_handle);
+        usbmod->usb_pcm_record_handle = NULL;
+        pthread_mutex_unlock(&usbmod->usb_record_lock);
+        return -ENOMEM;
+    }
+    ALOGD("%s: USB configured for capture", __func__);
+
+    /* update config for proxy*/
+    pcm_config_usbmod.period_size = USB_PROXY_PERIOD_SIZE/4;
+    pcm_config_usbmod.rate = usbmod->sample_rate_record;
+    pcm_config_usbmod.channels = usbmod->channels_record;
+    pcm_config_usbmod.period_count = AFE_PROXY_PERIOD_COUNT * 2;
+    usbmod->proxy_device_id = AFE_PROXY_CAPTURE_DEVICE;
+    ALOGV("%s: proxy device %u:period %u:channels %u:sample", __func__,
+          pcm_config_usbmod.period_size, pcm_config_usbmod.channels,
+          pcm_config_usbmod.rate);
+
+    while(proxy_open_retry_count){
+        usbmod->proxy_pcm_record_handle = pcm_open(usbmod->proxy_card,
+                                            usbmod->proxy_device_id, PCM_OUT |
+                                     PCM_MMAP | PCM_NOIRQ, &pcm_config_usbmod);
+        if(usbmod->proxy_pcm_record_handle
+            && !pcm_is_ready(usbmod->proxy_pcm_record_handle)){
+                     pcm_close(usbmod->proxy_pcm_record_handle);
+                     proxy_open_retry_count--;
+                     usleep(USB_PROXY_OPEN_WAIT_TIME * 1000);
+                     ALOGE("%s: pcm_open for proxy(recording) failed retrying = %d",
+                            __func__, proxy_open_retry_count);
+                }
+                else{
+                  break;
+                }
+    }
+    if ((usbmod->proxy_pcm_record_handle
+        && !pcm_is_ready(usbmod->proxy_pcm_record_handle))
+        || (!usbmod->is_record_running)) {
+        ALOGE("%s: failed: %s", __func__,
+               pcm_get_error(usbmod->proxy_pcm_record_handle));
+        pcm_close(usbmod->proxy_pcm_record_handle);
+        usbmod->proxy_pcm_record_handle = NULL;
+        pthread_mutex_unlock(&usbmod->usb_record_lock);
+        return -ENOMEM;
+    }
+    ALOGD("%s: PROXY configured for capture", __func__);
+    pthread_mutex_unlock(&usbmod->usb_record_lock);
+
+    /* main loop to read from usb and write to proxy */
+    while (usbmod->is_record_running) {
+        /* read data from usb */
+        ret = pcm_mmap_read(usbmod->usb_pcm_record_handle,
+                                 (void *)usbbuf, USB_PROXY_PERIOD_SIZE);
+        /* Write to proxy */
+        ret = pcm_mmap_write(usbmod->proxy_pcm_record_handle,
+                                (void *)usbbuf, USB_PROXY_PERIOD_SIZE);
+        if(!usbmod->is_record_running)
+            break;
+
+        memset(usbbuf, 0, USB_PROXY_PERIOD_SIZE);
+    } /* main loop end */
+
+    ALOGD("%s: exiting USB capture thread",__func__);
+    return 0;
+}
+
+static void* usb_capture_launcher(void *adev)
+{
+    int32_t ret;
+
+    usbmod->is_record_running = true;
+    ret = usb_record_entry(adev);
+
+    if (ret) {
+        ALOGE("%s: failed with err:%d", __func__, ret);
+        usbmod->is_record_running = false;
+    }
+    return NULL;
+}
+
+void audio_extn_usb_init(void *adev)
+{
+    pthread_once(&alloc_usbmod_once_ctl, usb_alloc);
+
+    usbmod->is_playback_running = false;
+    usbmod->is_record_running = false;
+
+    usbmod->usb_pcm_playback_handle = NULL;
+    usbmod->proxy_pcm_playback_handle = NULL;
+
+    usbmod->usb_pcm_record_handle = NULL;
+    usbmod->proxy_pcm_record_handle = NULL;
+
+    usbmod->usb_card = 1;
+    usbmod->usb_device_id = 0;
+    usbmod->proxy_card = 0;
+    usbmod->proxy_device_id = AFE_PROXY_PLAYBACK_DEVICE;
+    usbmod->adev = (struct audio_device*)adev;
+
+     pthread_mutex_init(&usbmod->usb_playback_lock,
+                        (const pthread_mutexattr_t *) NULL);
+     pthread_mutex_init(&usbmod->usb_record_lock,
+                        (const pthread_mutexattr_t *) NULL);
+}
+
+void audio_extn_usb_deinit()
+{
+    if (NULL != usbmod){
+        free(usbmod);
+        usbmod = NULL;
+    }
+}
+
+void audio_extn_usb_set_proxy_sound_card(uint32_t sndcard_idx)
+{
+    /* Proxy port and USB headset are related to two different sound cards */
+    if (sndcard_idx == usbmod->usb_card) {
+        usbmod->usb_card = usbmod->proxy_card;
+    }
+
+    usbmod->proxy_card = sndcard_idx;
+}
+
+void audio_extn_usb_start_playback(void *adev)
+{
+    int32_t ret;
+
+    if (NULL == usbmod){
+        ALOGE("%s: USB device object is NULL", __func__);
+        return;
+    }
+
+    if (usbmod->is_playback_running){
+        ALOGE("%s: USB playback thread already running", __func__);
+        return;
+    }
+
+    ALOGD("%s: creating USB playback thread", __func__);
+    ret = pthread_create(&usbmod->usb_playback_thr, NULL,
+                         usb_playback_launcher, (void*)adev);
+    if (ret)
+        ALOGE("%s: failed to create USB playback thread with err:%d",
+              __func__, ret);
+}
+
+void audio_extn_usb_stop_playback()
+{
+    int32_t ret;
+    ALOGD("%s: entry", __func__);
+
+    usbmod->is_playback_running = false;
+    if (NULL != usbmod->proxy_pcm_playback_handle)
+        pcm_stop(usbmod->proxy_pcm_playback_handle);
+
+    if (NULL != usbmod->usb_pcm_playback_handle)
+        pcm_stop(usbmod->usb_pcm_playback_handle);
+
+    if(usbmod->usb_playback_thr) {
+        ret = pthread_join(usbmod->usb_playback_thr,NULL);
+        ALOGE("%s: return for pthread_join = %d", __func__, ret);
+        usbmod->usb_playback_thr = (pthread_t)NULL;
+    }
+
+    pthread_mutex_lock(&usbmod->usb_playback_lock);
+    if (NULL != usbmod->usb_pcm_playback_handle){
+        pcm_close(usbmod->usb_pcm_playback_handle);
+        usbmod->usb_pcm_playback_handle = NULL;
+    }
+
+    if (NULL != usbmod->proxy_pcm_playback_handle){
+        pcm_close(usbmod->proxy_pcm_playback_handle);
+        usbmod->proxy_pcm_playback_handle = NULL;
+    }
+    pthread_mutex_unlock(&usbmod->usb_playback_lock);
+
+    ALOGD("%s: exiting",__func__);
+}
+
+void audio_extn_usb_start_capture(void *adev)
+{
+    int32_t ret;
+
+    if (NULL == usbmod){
+        ALOGE("%s: USB device object is NULL", __func__);
+        return;
+    }
+
+    if (usbmod->is_record_running){
+        ALOGE("%s: USB capture thread already running", __func__);
+        return;
+    }
+
+    ALOGD("%s: creating USB capture thread", __func__);
+    ret = pthread_create(&usbmod->usb_record_thr, NULL,
+                         usb_capture_launcher, (void*)adev);
+    if (ret)
+        ALOGE("%s: failed to create USB capture thread with err:%d",
+              __func__, ret);
+}
+
+void audio_extn_usb_stop_capture()
+{
+    int32_t ret;
+    ALOGD("%s: entry", __func__);
+
+    usbmod->is_record_running = false;
+    if (NULL != usbmod->proxy_pcm_record_handle)
+        pcm_stop(usbmod->proxy_pcm_record_handle);
+
+    if (NULL != usbmod->usb_pcm_record_handle)
+        pcm_stop(usbmod->usb_pcm_record_handle);
+
+    if(usbmod->usb_record_thr) {
+        ret = pthread_join(usbmod->usb_record_thr,NULL);
+        ALOGE("%s: return for pthread_join = %d", __func__, ret);
+        usbmod->usb_record_thr = (pthread_t)NULL;
+    }
+
+    pthread_mutex_lock(&usbmod->usb_record_lock);
+    if (NULL != usbmod->usb_pcm_record_handle){
+        pcm_close(usbmod->usb_pcm_record_handle);
+        usbmod->usb_pcm_record_handle = NULL;
+    }
+
+    if (NULL != usbmod->proxy_pcm_record_handle){
+        pcm_close(usbmod->proxy_pcm_record_handle);
+        usbmod->proxy_pcm_record_handle = NULL;
+    }
+    pthread_mutex_unlock(&usbmod->usb_record_lock);
+
+    ALOGD("%s: exiting",__func__);
+}
+
+bool audio_extn_usb_is_proxy_inuse()
+{
+    if( usbmod->is_record_running || usbmod->is_playback_running)
+        return true;
+    else
+        return false;
+}
+#endif /*USB_HEADSET_ENABLED end*/
diff --git a/msm8909/hal/audio_extn/utils.c b/msm8909/hal/audio_extn/utils.c
new file mode 100644
index 0000000..0429a45
--- /dev/null
+++ b/msm8909/hal/audio_extn/utils.c
@@ -0,0 +1,592 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_utils"
+/* #define LOG_NDEBUG 0 */
+
+#include <errno.h>
+#include <cutils/properties.h>
+#include <cutils/config_utils.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/str_parms.h>
+#include <cutils/log.h>
+#include <cutils/misc.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include "audio_extn.h"
+
+#define AUDIO_OUTPUT_POLICY_VENDOR_CONFIG_FILE "/vendor/etc/audio_output_policy.conf"
+
+#define OUTPUTS_TAG "outputs"
+
+#define DYNAMIC_VALUE_TAG "dynamic"
+#define FLAGS_TAG "flags"
+#define FORMATS_TAG "formats"
+#define SAMPLING_RATES_TAG "sampling_rates"
+#define BIT_WIDTH_TAG "bit_width"
+#define APP_TYPE_TAG "app_type"
+
+#define STRING_TO_ENUM(string) { #string, string }
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+struct string_to_enum {
+    const char *name;
+    uint32_t value;
+};
+
+const struct string_to_enum s_flag_name_to_enum_table[] = {
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST),
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
+#ifdef INCALL_MUSIC_ENABLED
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_INCALL_MUSIC),
+#endif
+#ifdef COMPRESS_VOIP_ENABLED
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_VOIP_RX),
+#endif
+};
+
+const struct string_to_enum s_format_name_to_enum_table[] = {
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT),
+    STRING_TO_ENUM(AUDIO_FORMAT_MP3),
+    STRING_TO_ENUM(AUDIO_FORMAT_AAC),
+    STRING_TO_ENUM(AUDIO_FORMAT_VORBIS),
+    STRING_TO_ENUM(AUDIO_FORMAT_AMR_NB),
+    STRING_TO_ENUM(AUDIO_FORMAT_AMR_WB),
+    STRING_TO_ENUM(AUDIO_FORMAT_AC3),
+    STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
+#ifdef FORMATS_ENABLED
+    STRING_TO_ENUM(AUDIO_FORMAT_DTS),
+    STRING_TO_ENUM(AUDIO_FORMAT_DTS_LBR),
+    STRING_TO_ENUM(AUDIO_FORMAT_WMA),
+    STRING_TO_ENUM(AUDIO_FORMAT_WMA_PRO),
+    STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADIF),
+    STRING_TO_ENUM(AUDIO_FORMAT_AMR_WB_PLUS),
+    STRING_TO_ENUM(AUDIO_FORMAT_EVRC),
+    STRING_TO_ENUM(AUDIO_FORMAT_EVRCB),
+    STRING_TO_ENUM(AUDIO_FORMAT_EVRCWB),
+    STRING_TO_ENUM(AUDIO_FORMAT_QCELP),
+    STRING_TO_ENUM(AUDIO_FORMAT_MP2),
+    STRING_TO_ENUM(AUDIO_FORMAT_EVRCNW),
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT_OFFLOAD),
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_OFFLOAD),
+    STRING_TO_ENUM(AUDIO_FORMAT_FLAC),
+    STRING_TO_ENUM(AUDIO_FORMAT_ALAC),
+    STRING_TO_ENUM(AUDIO_FORMAT_APE),
+#endif
+};
+
+static uint32_t string_to_enum(const struct string_to_enum *table, size_t size,
+                               const char *name)
+{
+    size_t i;
+    for (i = 0; i < size; i++) {
+        if (strcmp(table[i].name, name) == 0) {
+            ALOGV("%s found %s", __func__, table[i].name);
+            return table[i].value;
+        }
+    }
+    return 0;
+}
+
+static audio_output_flags_t parse_flag_names(char *name)
+{
+    uint32_t flag = 0;
+    char *flag_name = strtok(name, "|");
+    while (flag_name != NULL) {
+        if (strlen(flag_name) != 0) {
+            flag |= string_to_enum(s_flag_name_to_enum_table,
+                               ARRAY_SIZE(s_flag_name_to_enum_table),
+                               flag_name);
+        }
+        flag_name = strtok(NULL, "|");
+    }
+
+    ALOGV("parse_flag_names: flag - %d", flag);
+    return (audio_output_flags_t)flag;
+}
+
+static void parse_format_names(char *name, struct streams_output_cfg *so_info)
+{
+    struct stream_format *sf_info = NULL;
+    char *str = strtok(name, "|");
+
+    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0)
+        return;
+
+    list_init(&so_info->format_list);
+    while (str != NULL) {
+        audio_format_t format = (audio_format_t)string_to_enum(s_format_name_to_enum_table,
+                                              ARRAY_SIZE(s_format_name_to_enum_table), str);
+        ALOGV("%s: format - %d", __func__, format);
+        if (format != 0) {
+            sf_info = (struct stream_format *)calloc(1, sizeof(struct stream_format));
+            if (sf_info == NULL)
+                break; /* return whatever was parsed */
+
+            sf_info->format = format;
+            list_add_tail(&so_info->format_list, &sf_info->list);
+        }
+        str = strtok(NULL, "|");
+    }
+}
+
+static void parse_sample_rate_names(char *name, struct streams_output_cfg *so_info)
+{
+    struct stream_sample_rate *ss_info = NULL;
+    uint32_t sample_rate = 48000;
+    char *str = strtok(name, "|");
+
+    if (str != NULL && 0 == strcmp(str, DYNAMIC_VALUE_TAG))
+        return;
+
+    list_init(&so_info->sample_rate_list);
+    while (str != NULL) {
+        sample_rate = (uint32_t)strtol(str, (char **)NULL, 10);
+        ALOGV("%s: sample_rate - %d", __func__, sample_rate);
+        if (0 != sample_rate) {
+            ss_info = (struct stream_sample_rate *)calloc(1, sizeof(struct stream_sample_rate));
+            if (ss_info == NULL)
+                break; /* return whatever was parsed */
+
+            ss_info->sample_rate = sample_rate;
+            list_add_tail(&so_info->sample_rate_list, &ss_info->list);
+        }
+        str = strtok(NULL, "|");
+    }
+}
+
+static int parse_bit_width_names(char *name)
+{
+    int bit_width = 16;
+    char *str = strtok(name, "|");
+
+    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG))
+        bit_width = (int)strtol(str, (char **)NULL, 10);
+
+    ALOGV("%s: bit_width - %d", __func__, bit_width);
+    return bit_width;
+}
+
+static int parse_app_type_names(void *platform, char *name)
+{
+    int app_type = platform_get_default_app_type(platform);
+    char *str = strtok(name, "|");
+
+    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG))
+        app_type = (int)strtol(str, (char **)NULL, 10);
+
+    ALOGV("%s: app_type - %d", __func__, app_type);
+    return app_type;
+}
+
+static void update_streams_output_cfg_list(cnode *root, void *platform,
+                                           struct listnode *streams_output_cfg_list)
+{
+    cnode *node = root->first_child;
+    struct streams_output_cfg *so_info;
+
+    ALOGV("%s", __func__);
+    so_info = (struct streams_output_cfg *)calloc(1, sizeof(struct streams_output_cfg));
+
+    if (!so_info) {
+        ALOGE("failed to allocate mem for so_info list element");
+        return;
+    }
+
+    while (node) {
+        if (strcmp(node->name, FLAGS_TAG) == 0) {
+            so_info->flags = parse_flag_names((char *)node->value);
+        } else if (strcmp(node->name, FORMATS_TAG) == 0) {
+            parse_format_names((char *)node->value, so_info);
+        } else if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
+            so_info->app_type_cfg.sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+            parse_sample_rate_names((char *)node->value, so_info);
+        } else if (strcmp(node->name, BIT_WIDTH_TAG) == 0) {
+            so_info->app_type_cfg.bit_width = parse_bit_width_names((char *)node->value);
+        } else if (strcmp(node->name, APP_TYPE_TAG) == 0) {
+            so_info->app_type_cfg.app_type = parse_app_type_names(platform, (char *)node->value);
+        }
+        node = node->next;
+    }
+    list_add_tail(streams_output_cfg_list, &so_info->list);
+}
+
+static void load_output(cnode *root, void *platform,
+                        struct listnode *streams_output_cfg_list)
+{
+    cnode *node = config_find(root, OUTPUTS_TAG);
+    if (node == NULL) {
+        ALOGE("%s: could not load output, node is NULL", __func__);
+        return;
+    }
+
+    node = node->first_child;
+    while (node) {
+        ALOGV("%s: loading output %s", __func__, node->name);
+        update_streams_output_cfg_list(node, platform, streams_output_cfg_list);
+        node = node->next;
+    }
+}
+
+static void send_app_type_cfg(void *platform, struct mixer *mixer,
+                              struct listnode *streams_output_cfg_list)
+{
+    int app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {-1};
+    int length = 0, i, num_app_types = 0;
+    struct listnode *node;
+    bool update;
+    struct mixer_ctl *ctl = NULL;
+    const char *mixer_ctl_name = "App Type Config";
+    struct streams_output_cfg *so_info;
+
+    if (!mixer) {
+        ALOGE("%s: mixer is null",__func__);
+        return;
+    }
+    ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",__func__, mixer_ctl_name);
+        return;
+    }
+    if (streams_output_cfg_list == NULL) {
+        app_type_cfg[length++] = 1;
+        app_type_cfg[length++] = platform_get_default_app_type(platform);
+        app_type_cfg[length++] = 48000;
+        app_type_cfg[length++] = 16;
+        mixer_ctl_set_array(ctl, app_type_cfg, length);
+        return;
+    }
+
+    app_type_cfg[length++] = num_app_types;
+    list_for_each(node, streams_output_cfg_list) {
+        so_info = node_to_item(node, struct streams_output_cfg, list);
+        update = true;
+        for (i=0; i<length; i=i+3) {
+            if (app_type_cfg[i+1] == -1)
+                break;
+            else if (app_type_cfg[i+1] == so_info->app_type_cfg.app_type) {
+                update = false;
+                break;
+            }
+        }
+        if (update && ((length + 3) <= MAX_LENGTH_MIXER_CONTROL_IN_INT)) {
+            num_app_types += 1 ;
+            app_type_cfg[length++] = so_info->app_type_cfg.app_type;
+            app_type_cfg[length++] = so_info->app_type_cfg.sample_rate;
+            app_type_cfg[length++] = so_info->app_type_cfg.bit_width;
+        }
+    }
+    ALOGV("%s: num_app_types: %d", __func__, num_app_types);
+    if (num_app_types) {
+        app_type_cfg[0] = num_app_types;
+        mixer_ctl_set_array(ctl, app_type_cfg, length);
+    }
+}
+
+void audio_extn_utils_update_streams_output_cfg_list(void *platform,
+                                       struct mixer *mixer,
+                                       struct listnode *streams_output_cfg_list)
+{
+    cnode *root;
+    char *data;
+
+    ALOGV("%s", __func__);
+    list_init(streams_output_cfg_list);
+    data = (char *)load_file(AUDIO_OUTPUT_POLICY_VENDOR_CONFIG_FILE, NULL);
+    if (data == NULL) {
+        send_app_type_cfg(platform, mixer, NULL);
+        ALOGE("%s: could not load output policy config file", __func__);
+        return;
+    }
+
+    root = config_node("", "");
+    if (root == NULL) {
+        ALOGE("cfg_list, NULL config root");
+        return;
+    }
+
+    config_load(root, data);
+    load_output(root, platform, streams_output_cfg_list);
+
+    send_app_type_cfg(platform, mixer, streams_output_cfg_list);
+}
+
+void audio_extn_utils_dump_streams_output_cfg_list(
+                                       struct listnode *streams_output_cfg_list)
+{
+    int i=0;
+    struct listnode *node_i, *node_j;
+    struct streams_output_cfg *so_info;
+    struct stream_format *sf_info;
+    struct stream_sample_rate *ss_info;
+    ALOGV("%s", __func__);
+    list_for_each(node_i, streams_output_cfg_list) {
+        so_info = node_to_item(node_i, struct streams_output_cfg, list);
+        ALOGV("%s: flags-%d, output_sample_rate-%d, output_bit_width-%d, app_type-%d",
+               __func__, so_info->flags, so_info->app_type_cfg.sample_rate,
+               so_info->app_type_cfg.bit_width, so_info->app_type_cfg.app_type);
+        list_for_each(node_j, &so_info->format_list) {
+            sf_info = node_to_item(node_j, struct stream_format, list);
+            ALOGV("format-%x", sf_info->format);
+        }
+        list_for_each(node_j, &so_info->sample_rate_list) {
+            ss_info = node_to_item(node_j, struct stream_sample_rate, list);
+            ALOGV("sample rate-%d", ss_info->sample_rate);
+        }
+    }
+}
+
+void audio_extn_utils_release_streams_output_cfg_list(
+                                       struct listnode *streams_output_cfg_list)
+{
+    struct listnode *node_i, *node_j;
+    struct streams_output_cfg *so_info;
+    struct stream_format *sf_info;
+
+    ALOGV("%s", __func__);
+    while (!list_empty(streams_output_cfg_list)) {
+        node_i = list_head(streams_output_cfg_list);
+        so_info = node_to_item(node_i, struct streams_output_cfg, list);
+        while (!list_empty(&so_info->format_list)) {
+            node_j = list_head(&so_info->format_list);
+            list_remove(node_j);
+            free(node_to_item(node_j, struct stream_format, list));
+        }
+        while (!list_empty(&so_info->sample_rate_list)) {
+            node_j = list_head(&so_info->sample_rate_list);
+            list_remove(node_j);
+            free(node_to_item(node_j, struct stream_sample_rate, list));
+        }
+        list_remove(node_i);
+        free(node_to_item(node_i, struct streams_output_cfg, list));
+    }
+}
+
+static bool set_output_cfg(struct streams_output_cfg *so_info,
+                           struct stream_app_type_cfg *app_type_cfg,
+                           uint32_t sample_rate, uint32_t bit_width)
+ {
+    struct listnode *node_i;
+    struct stream_sample_rate *ss_info;
+    list_for_each(node_i, &so_info->sample_rate_list) {
+        ss_info = node_to_item(node_i, struct stream_sample_rate, list);
+        if ((sample_rate <= ss_info->sample_rate) &&
+            (bit_width == so_info->app_type_cfg.bit_width)) {
+            app_type_cfg->app_type = so_info->app_type_cfg.app_type;
+            app_type_cfg->sample_rate = ss_info->sample_rate;
+            app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
+            ALOGV("%s app_type_cfg->app_type %d, app_type_cfg->sample_rate %d, app_type_cfg->bit_width %d",
+                   __func__, app_type_cfg->app_type, app_type_cfg->sample_rate, app_type_cfg->bit_width);
+            return true;
+        }
+    }
+    /*
+     * Reiterate through the list assuming dafault sample rate.
+     * Handles scenario where input sample rate is higher
+     * than all sample rates in list for the input bit width.
+     */
+    sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    list_for_each(node_i, &so_info->sample_rate_list) {
+        ss_info = node_to_item(node_i, struct stream_sample_rate, list);
+        if ((sample_rate <= ss_info->sample_rate) &&
+            (bit_width == so_info->app_type_cfg.bit_width)) {
+            app_type_cfg->app_type = so_info->app_type_cfg.app_type;
+            app_type_cfg->sample_rate = sample_rate;
+            app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
+            ALOGV("%s Assuming default sample rate. app_type_cfg->app_type %d, app_type_cfg->sample_rate %d, app_type_cfg->bit_width %d",
+                   __func__, app_type_cfg->app_type, app_type_cfg->sample_rate, app_type_cfg->bit_width);
+            return true;
+        }
+    }
+    return false;
+}
+
+void audio_extn_utils_update_stream_app_type_cfg(void *platform,
+                                  struct listnode *streams_output_cfg_list,
+                                  audio_devices_t devices,
+                                  audio_output_flags_t flags,
+                                  audio_format_t format,
+                                  uint32_t sample_rate,
+                                  uint32_t bit_width,
+                                  struct stream_app_type_cfg *app_type_cfg)
+{
+    struct listnode *node_i, *node_j, *node_k;
+    struct streams_output_cfg *so_info;
+    struct stream_format *sf_info;
+    struct stream_sample_rate *ss_info;
+
+    if ((24 == bit_width) &&
+        (devices & AUDIO_DEVICE_OUT_SPEAKER)) {
+        sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+        ALOGI("%s Allowing 24-bit playback on speaker ONLY at default sampling rate", __func__);
+    }
+
+    ALOGV("%s: flags: %x, format: %x sample_rate %d",
+           __func__, flags, format, sample_rate);
+    list_for_each(node_i, streams_output_cfg_list) {
+        so_info = node_to_item(node_i, struct streams_output_cfg, list);
+        if (so_info->flags == flags) {
+            list_for_each(node_j, &so_info->format_list) {
+                sf_info = node_to_item(node_j, struct stream_format, list);
+                if (sf_info->format == format) {
+                    if (set_output_cfg(so_info, app_type_cfg, sample_rate, bit_width))
+                        return;
+                }
+            }
+        }
+    }
+    list_for_each(node_i, streams_output_cfg_list) {
+        so_info = node_to_item(node_i, struct streams_output_cfg, list);
+        if (so_info->flags == AUDIO_OUTPUT_FLAG_PRIMARY) {
+            ALOGV("Compatible output profile not found.");
+            app_type_cfg->app_type = so_info->app_type_cfg.app_type;
+            app_type_cfg->sample_rate = so_info->app_type_cfg.sample_rate;
+            app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
+            ALOGV("%s Default to primary output: App type: %d sample_rate %d",
+                  __func__, so_info->app_type_cfg.app_type, app_type_cfg->sample_rate);
+            return;
+        }
+    }
+    ALOGW("%s: App type could not be selected. Falling back to default", __func__);
+    app_type_cfg->app_type = platform_get_default_app_type(platform);
+    app_type_cfg->sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    app_type_cfg->bit_width = 16;
+}
+
+int audio_extn_utils_send_app_type_cfg(struct audio_usecase *usecase)
+{
+    char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT];
+    int app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT], len = 0, rc;
+    struct stream_out *out;
+    struct audio_device *adev;
+    struct mixer_ctl *ctl;
+    int pcm_device_id, acdb_dev_id, snd_device = usecase->out_snd_device;
+    int32_t sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+
+    ALOGV("%s", __func__);
+
+    if (usecase->type != PCM_PLAYBACK) {
+        ALOGV("%s: not a playback path, no need to cfg app type", __func__);
+        rc = 0;
+        goto exit_send_app_type_cfg;
+    }
+    if ((usecase->id != USECASE_AUDIO_PLAYBACK_DEEP_BUFFER) &&
+        (usecase->id != USECASE_AUDIO_PLAYBACK_LOW_LATENCY) &&
+        (usecase->id != USECASE_AUDIO_PLAYBACK_MULTI_CH) &&
+        (usecase->id != USECASE_AUDIO_PLAYBACK_OFFLOAD)) {
+        ALOGV("%s: a playback path where app type cfg is not required", __func__);
+        rc = 0;
+        goto exit_send_app_type_cfg;
+    }
+    out = usecase->stream.out;
+    adev = out->dev;
+
+    snd_device = usecase->out_snd_device;
+
+    pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
+
+    snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+             "Audio Stream %d App Type Cfg", pcm_device_id);
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__,
+              mixer_ctl_name);
+        rc = -EINVAL;
+        goto exit_send_app_type_cfg;
+    }
+    snd_device = (snd_device == SND_DEVICE_OUT_SPEAKER) ?
+                 audio_extn_get_spkr_prot_snd_device(snd_device) : snd_device;
+    acdb_dev_id = platform_get_snd_device_acdb_id(snd_device);
+    if (acdb_dev_id < 0) {
+        ALOGE("%s: Couldn't get the acdb dev id", __func__);
+        rc = -EINVAL;
+        goto exit_send_app_type_cfg;
+    }
+
+    if ((24 == usecase->stream.out->bit_width) &&
+        (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER)) {
+        sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+    } else {
+        sample_rate = out->app_type_cfg.sample_rate;
+    }
+
+    app_type_cfg[len++] = out->app_type_cfg.app_type;
+    app_type_cfg[len++] = acdb_dev_id;
+    app_type_cfg[len++] = sample_rate;
+
+    mixer_ctl_set_array(ctl, app_type_cfg, len);
+    ALOGI("%s app_type %d, acdb_dev_id %d, sample_rate %d",
+           __func__, out->app_type_cfg.app_type, acdb_dev_id, sample_rate);
+    rc = 0;
+exit_send_app_type_cfg:
+    return rc;
+}
+
+int read_line_from_file(const char *path, char *buf, size_t count)
+{
+    char * fgets_ret;
+    FILE * fd;
+    int rv;
+
+    fd = fopen(path, "r");
+    if (fd == NULL)
+        return -1;
+
+    fgets_ret = fgets(buf, (int)count, fd);
+    if (NULL != fgets_ret) {
+        rv = (int)strlen(buf);
+    } else {
+        rv = ferror(fd);
+    }
+    fclose(fd);
+
+   return rv;
+}
+
+void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
+                                             struct audio_usecase *usecase)
+{
+    int type = usecase->type;
+
+    if (type == PCM_PLAYBACK) {
+        struct stream_out *out = usecase->stream.out;
+        int snd_device = usecase->out_snd_device;
+        snd_device = (snd_device == SND_DEVICE_OUT_SPEAKER) ?
+                     audio_extn_get_spkr_prot_snd_device(snd_device) : snd_device;
+        platform_send_audio_calibration(adev->platform, usecase,
+                                        out->app_type_cfg.app_type,
+                                        out->app_type_cfg.sample_rate);
+    }
+    if ((type == PCM_HFP_CALL) || (type == PCM_CAPTURE)) {
+        /* when app type is default. the sample rate is not used to send cal */
+        platform_send_audio_calibration(adev->platform, usecase,
+                                        platform_get_default_app_type(adev->platform),
+                                        48000);
+    }
+}
+
diff --git a/msm8909/hal/audio_hw.c b/msm8909/hal/audio_hw.c
new file mode 100644
index 0000000..1c177fc
--- /dev/null
+++ b/msm8909/hal/audio_hw.c
@@ -0,0 +1,3539 @@
+/*
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_primary"
+/*#define LOG_NDEBUG 0*/
+/*#define VERY_VERY_VERBOSE_LOGGING*/
+#ifdef VERY_VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <math.h>
+#include <dlfcn.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
+
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <cutils/properties.h>
+#include <cutils/atomic.h>
+#include <cutils/sched_policy.h>
+
+#include <hardware/audio_effect.h>
+#include <system/thread_defs.h>
+#include <audio_effects/effect_aec.h>
+#include <audio_effects/effect_ns.h>
+#include "audio_hw.h"
+#include "platform_api.h"
+#include <platform.h>
+#include "audio_extn.h"
+#include "voice_extn.h"
+
+#include "sound/compress_params.h"
+#include "sound/asound.h"
+
+#define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4
+/* ToDo: Check and update a proper value in msec */
+#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96
+#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
+
+#define PROXY_OPEN_RETRY_COUNT           100
+#define PROXY_OPEN_WAIT_TIME             20
+
+#define USECASE_AUDIO_PLAYBACK_PRIMARY USECASE_AUDIO_PLAYBACK_DEEP_BUFFER
+
+static unsigned int configured_low_latency_capture_period_size =
+        LOW_LATENCY_CAPTURE_PERIOD_SIZE;
+
+struct pcm_config pcm_config_deep_buffer = {
+    .channels = 2,
+    .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
+    .period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE,
+    .period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT,
+    .format = PCM_FORMAT_S16_LE,
+    .start_threshold = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
+    .stop_threshold = INT_MAX,
+    .avail_min = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
+};
+
+struct pcm_config pcm_config_low_latency = {
+    .channels = 2,
+    .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
+    .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
+    .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
+    .format = PCM_FORMAT_S16_LE,
+    .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
+    .stop_threshold = INT_MAX,
+    .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
+};
+
+struct pcm_config pcm_config_hdmi_multi = {
+    .channels = HDMI_MULTI_DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */
+    .rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */
+    .period_size = HDMI_MULTI_PERIOD_SIZE,
+    .period_count = HDMI_MULTI_PERIOD_COUNT,
+    .format = PCM_FORMAT_S16_LE,
+    .start_threshold = 0,
+    .stop_threshold = INT_MAX,
+    .avail_min = 0,
+};
+
+struct pcm_config pcm_config_audio_capture = {
+    .channels = 2,
+    .period_count = AUDIO_CAPTURE_PERIOD_COUNT,
+    .format = PCM_FORMAT_S16_LE,
+};
+
+#define AFE_PROXY_CHANNEL_COUNT 2
+#define AFE_PROXY_SAMPLING_RATE 48000
+
+#define AFE_PROXY_PLAYBACK_PERIOD_SIZE  768
+#define AFE_PROXY_PLAYBACK_PERIOD_COUNT 4
+
+struct pcm_config pcm_config_afe_proxy_playback = {
+    .channels = AFE_PROXY_CHANNEL_COUNT,
+    .rate = AFE_PROXY_SAMPLING_RATE,
+    .period_size = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
+    .period_count = AFE_PROXY_PLAYBACK_PERIOD_COUNT,
+    .format = PCM_FORMAT_S16_LE,
+    .start_threshold = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
+    .stop_threshold = INT_MAX,
+    .avail_min = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
+};
+
+#define AFE_PROXY_RECORD_PERIOD_SIZE  768
+#define AFE_PROXY_RECORD_PERIOD_COUNT 4
+
+struct pcm_config pcm_config_afe_proxy_record = {
+    .channels = AFE_PROXY_CHANNEL_COUNT,
+    .rate = AFE_PROXY_SAMPLING_RATE,
+    .period_size = AFE_PROXY_RECORD_PERIOD_SIZE,
+    .period_count = AFE_PROXY_RECORD_PERIOD_COUNT,
+    .format = PCM_FORMAT_S16_LE,
+    .start_threshold = AFE_PROXY_RECORD_PERIOD_SIZE,
+    .stop_threshold = INT_MAX,
+    .avail_min = AFE_PROXY_RECORD_PERIOD_SIZE,
+};
+
+const char * const use_case_table[AUDIO_USECASE_MAX] = {
+    [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback",
+    [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback",
+    [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback",
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
+#ifdef MULTIPLE_OFFLOAD_ENABLED
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD2] = "compress-offload-playback2",
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD3] = "compress-offload-playback3",
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD4] = "compress-offload-playback4",
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD5] = "compress-offload-playback5",
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD6] = "compress-offload-playback6",
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD7] = "compress-offload-playback7",
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD8] = "compress-offload-playback8",
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD9] = "compress-offload-playback9",
+#endif
+    [USECASE_AUDIO_RECORD] = "audio-record",
+    [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress",
+    [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
+    [USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record",
+    [USECASE_AUDIO_PLAYBACK_FM] = "play-fm",
+    [USECASE_AUDIO_HFP_SCO] = "hfp-sco",
+    [USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb",
+    [USECASE_VOICE_CALL] = "voice-call",
+
+    [USECASE_VOICE2_CALL] = "voice2-call",
+    [USECASE_VOLTE_CALL] = "volte-call",
+    [USECASE_QCHAT_CALL] = "qchat-call",
+    [USECASE_VOWLAN_CALL] = "vowlan-call",
+    [USECASE_COMPRESS_VOIP_CALL] = "compress-voip-call",
+    [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink",
+    [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink",
+    [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink",
+    [USECASE_INCALL_REC_UPLINK_COMPRESS] = "incall-rec-uplink-compress",
+    [USECASE_INCALL_REC_DOWNLINK_COMPRESS] = "incall-rec-downlink-compress",
+    [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS] = "incall-rec-uplink-and-downlink-compress",
+
+    [USECASE_INCALL_MUSIC_UPLINK] = "incall_music_uplink",
+    [USECASE_INCALL_MUSIC_UPLINK2] = "incall_music_uplink2",
+    [USECASE_AUDIO_SPKR_CALIB_RX] = "spkr-rx-calib",
+    [USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record",
+
+    [USECASE_AUDIO_PLAYBACK_AFE_PROXY] = "afe-proxy-playback",
+    [USECASE_AUDIO_RECORD_AFE_PROXY] = "afe-proxy-record",
+};
+
+static const audio_usecase_t offload_usecases[] = {
+    USECASE_AUDIO_PLAYBACK_OFFLOAD,
+#ifdef MULTIPLE_OFFLOAD_ENABLED
+    USECASE_AUDIO_PLAYBACK_OFFLOAD2,
+    USECASE_AUDIO_PLAYBACK_OFFLOAD3,
+    USECASE_AUDIO_PLAYBACK_OFFLOAD4,
+    USECASE_AUDIO_PLAYBACK_OFFLOAD5,
+    USECASE_AUDIO_PLAYBACK_OFFLOAD6,
+    USECASE_AUDIO_PLAYBACK_OFFLOAD7,
+    USECASE_AUDIO_PLAYBACK_OFFLOAD8,
+    USECASE_AUDIO_PLAYBACK_OFFLOAD9,
+#endif
+};
+
+#define STRING_TO_ENUM(string) { #string, string }
+
+struct string_to_enum {
+    const char *name;
+    uint32_t value;
+};
+
+static const struct string_to_enum out_channels_name_to_enum_table[] = {
+    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
+    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
+    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
+};
+
+static const struct string_to_enum out_formats_name_to_enum_table[] = {
+    STRING_TO_ENUM(AUDIO_FORMAT_AC3),
+    STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
+    STRING_TO_ENUM(AUDIO_FORMAT_E_AC3_JOC),
+};
+
+static struct audio_device *adev = NULL;
+static pthread_mutex_t adev_init_lock;
+static unsigned int audio_device_ref_count;
+
+static int set_voice_volume_l(struct audio_device *adev, float volume);
+
+static int check_and_set_gapless_mode(struct audio_device *adev) {
+
+
+    char value[PROPERTY_VALUE_MAX] = {0};
+    bool gapless_enabled = false;
+    const char *mixer_ctl_name = "Compress Gapless Playback";
+    struct mixer_ctl *ctl;
+
+    ALOGV("%s:", __func__);
+    property_get("audio.offload.gapless.enabled", value, NULL);
+    gapless_enabled = atoi(value) || !strncmp("true", value, 4);
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                               __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+
+    if (mixer_ctl_set_value(ctl, 0, gapless_enabled) < 0) {
+        ALOGE("%s: Could not set gapless mode %d",
+                       __func__, gapless_enabled);
+         return -EINVAL;
+    }
+    return 0;
+}
+
+static bool is_supported_format(audio_format_t format)
+{
+    if (format == AUDIO_FORMAT_MP3 ||
+        format == AUDIO_FORMAT_AAC_LC ||
+        format == AUDIO_FORMAT_AAC_HE_V1 ||
+        format == AUDIO_FORMAT_AAC_HE_V2 ||
+        format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD ||
+        format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD ||
+        format == AUDIO_FORMAT_FLAC ||
+        format == AUDIO_FORMAT_ALAC ||
+        format == AUDIO_FORMAT_APE ||
+        format == AUDIO_FORMAT_VORBIS ||
+        format == AUDIO_FORMAT_WMA ||
+        format == AUDIO_FORMAT_WMA_PRO)
+           return true;
+
+    return false;
+}
+
+static int get_snd_codec_id(audio_format_t format)
+{
+    int id = 0;
+
+    switch (format & AUDIO_FORMAT_MAIN_MASK) {
+    case AUDIO_FORMAT_MP3:
+        id = SND_AUDIOCODEC_MP3;
+        break;
+    case AUDIO_FORMAT_AAC:
+        id = SND_AUDIOCODEC_AAC;
+        break;
+    case AUDIO_FORMAT_PCM_OFFLOAD:
+        id = SND_AUDIOCODEC_PCM;
+        break;
+    case AUDIO_FORMAT_FLAC:
+        id = SND_AUDIOCODEC_FLAC;
+        break;
+    case AUDIO_FORMAT_ALAC:
+        id = SND_AUDIOCODEC_ALAC;
+        break;
+    case AUDIO_FORMAT_APE:
+        id = SND_AUDIOCODEC_APE;
+        break;
+    case AUDIO_FORMAT_VORBIS:
+        id = SND_AUDIOCODEC_VORBIS;
+        break;
+    case AUDIO_FORMAT_WMA:
+        id = SND_AUDIOCODEC_WMA;
+        break;
+    case AUDIO_FORMAT_WMA_PRO:
+        id = SND_AUDIOCODEC_WMA_PRO;
+        break;
+    default:
+        ALOGE("%s: Unsupported audio format :%x", __func__, format);
+    }
+
+    return id;
+}
+
+int get_snd_card_state(struct audio_device *adev)
+{
+    int snd_scard_state;
+
+    if (!adev)
+        return SND_CARD_STATE_OFFLINE;
+
+    pthread_mutex_lock(&adev->snd_card_status.lock);
+    snd_scard_state = adev->snd_card_status.state;
+    pthread_mutex_unlock(&adev->snd_card_status.lock);
+
+    return snd_scard_state;
+}
+
+static int set_snd_card_state(struct audio_device *adev, int snd_scard_state)
+{
+    if (!adev)
+        return -ENOSYS;
+
+    pthread_mutex_lock(&adev->snd_card_status.lock);
+    adev->snd_card_status.state = snd_scard_state;
+    pthread_mutex_unlock(&adev->snd_card_status.lock);
+
+    return 0;
+}
+
+static int enable_audio_route_for_voice_usecases(struct audio_device *adev,
+                                                 struct audio_usecase *uc_info)
+{
+    struct listnode *node;
+    struct audio_usecase *usecase;
+
+    if (uc_info == NULL)
+        return -EINVAL;
+
+    /* Re-route all voice usecases on the shared backend other than the
+       specified usecase to new snd devices */
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if ((usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) &&
+             (usecase != uc_info))
+            enable_audio_route(adev, usecase);
+    }
+    return 0;
+}
+
+int pcm_ioctl(struct pcm *pcm, int request, ...)
+{
+    va_list ap;
+    void * arg;
+    int pcm_fd = *(int*)pcm;
+
+    va_start(ap, request);
+    arg = va_arg(ap, void *);
+    va_end(ap);
+
+    return ioctl(pcm_fd, request, arg);
+}
+
+int enable_audio_route(struct audio_device *adev,
+                       struct audio_usecase *usecase)
+{
+    snd_device_t snd_device;
+    char mixer_path[MIXER_PATH_MAX_LENGTH];
+
+    if (usecase == NULL)
+        return -EINVAL;
+
+    ALOGV("%s: enter: usecase(%d)", __func__, usecase->id);
+
+    if (usecase->type == PCM_CAPTURE)
+        snd_device = usecase->in_snd_device;
+    else
+        snd_device = usecase->out_snd_device;
+
+#ifdef DS1_DOLBY_DAP_ENABLED
+    audio_extn_dolby_set_dmid(adev);
+    audio_extn_dolby_set_endpoint(adev);
+#endif
+    audio_extn_dolby_ds2_set_endpoint(adev);
+    audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_BUSY);
+    audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_BUSY);
+    audio_extn_utils_send_audio_calibration(adev, usecase);
+    audio_extn_utils_send_app_type_cfg(usecase);
+    strcpy(mixer_path, use_case_table[usecase->id]);
+    platform_add_backend_name(mixer_path, snd_device);
+    ALOGD("%s: apply mixer and update path: %s", __func__, mixer_path);
+    audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+    ALOGV("%s: exit", __func__);
+    return 0;
+}
+
+int disable_audio_route(struct audio_device *adev,
+                        struct audio_usecase *usecase)
+{
+    snd_device_t snd_device;
+    char mixer_path[MIXER_PATH_MAX_LENGTH];
+
+    if (usecase == NULL || usecase->id == USECASE_INVALID)
+        return -EINVAL;
+
+    ALOGV("%s: enter: usecase(%d)", __func__, usecase->id);
+    if (usecase->type == PCM_CAPTURE)
+        snd_device = usecase->in_snd_device;
+    else
+        snd_device = usecase->out_snd_device;
+    strcpy(mixer_path, use_case_table[usecase->id]);
+    platform_add_backend_name(mixer_path, snd_device);
+    ALOGD("%s: reset and update mixer path: %s", __func__, mixer_path);
+    audio_route_reset_and_update_path(adev->audio_route, mixer_path);
+    audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_FREE);
+    audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_FREE);
+    ALOGV("%s: exit", __func__);
+    return 0;
+}
+
+int enable_snd_device(struct audio_device *adev,
+                      snd_device_t snd_device)
+{
+    char device_name[DEVICE_NAME_MAX_SIZE] = {0};
+
+    if (snd_device < SND_DEVICE_MIN ||
+        snd_device >= SND_DEVICE_MAX) {
+        ALOGE("%s: Invalid sound device %d", __func__, snd_device);
+        return -EINVAL;
+    }
+
+    adev->snd_dev_ref_cnt[snd_device]++;
+
+    if(platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0 ) {
+        ALOGE("%s: Invalid sound device returned", __func__);
+        return -EINVAL;
+    }
+    if (adev->snd_dev_ref_cnt[snd_device] > 1) {
+        ALOGV("%s: snd_device(%d: %s) is already active",
+              __func__, snd_device, device_name);
+        return 0;
+    }
+
+    if (audio_extn_spkr_prot_is_enabled())
+         audio_extn_spkr_prot_calib_cancel(adev);
+    /* start usb playback thread */
+    if(SND_DEVICE_OUT_USB_HEADSET == snd_device ||
+       SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET == snd_device)
+        audio_extn_usb_start_playback(adev);
+
+    /* start usb capture thread */
+    if(SND_DEVICE_IN_USB_HEADSET_MIC == snd_device)
+       audio_extn_usb_start_capture(adev);
+
+    if (SND_DEVICE_OUT_BT_A2DP == snd_device ||
+       (SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP) == snd_device)
+        audio_extn_a2dp_start_playback();
+
+    if ((snd_device == SND_DEVICE_OUT_SPEAKER ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER) &&
+        audio_extn_spkr_prot_is_enabled()) {
+       if (audio_extn_spkr_prot_get_acdb_id(snd_device) < 0) {
+           adev->snd_dev_ref_cnt[snd_device]--;
+           return -EINVAL;
+       }
+        if (audio_extn_spkr_prot_start_processing(snd_device)) {
+            ALOGE("%s: spkr_start_processing failed", __func__);
+            return -EINVAL;
+        }
+    } else {
+        ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, device_name);
+        /* due to the possibility of calibration overwrite between listen
+            and audio, notify listen hal before audio calibration is sent */
+        audio_extn_sound_trigger_update_device_status(snd_device,
+                                        ST_EVENT_SND_DEVICE_BUSY);
+        audio_extn_listen_update_device_status(snd_device,
+                                        LISTEN_EVENT_SND_DEVICE_BUSY);
+        if (platform_get_snd_device_acdb_id(snd_device) < 0) {
+            adev->snd_dev_ref_cnt[snd_device]--;
+            audio_extn_sound_trigger_update_device_status(snd_device,
+                                            ST_EVENT_SND_DEVICE_FREE);
+            audio_extn_listen_update_device_status(snd_device,
+                                        LISTEN_EVENT_SND_DEVICE_FREE);
+            return -EINVAL;
+        }
+        audio_extn_dev_arbi_acquire(snd_device);
+        audio_route_apply_and_update_path(adev->audio_route, device_name);
+    }
+    return 0;
+}
+
+int disable_snd_device(struct audio_device *adev,
+                       snd_device_t snd_device)
+{
+    char device_name[DEVICE_NAME_MAX_SIZE] = {0};
+
+    if (snd_device < SND_DEVICE_MIN ||
+        snd_device >= SND_DEVICE_MAX) {
+        ALOGE("%s: Invalid sound device %d", __func__, snd_device);
+        return -EINVAL;
+    }
+    if (adev->snd_dev_ref_cnt[snd_device] <= 0) {
+        ALOGE("%s: device ref cnt is already 0", __func__);
+        return -EINVAL;
+    }
+
+    adev->snd_dev_ref_cnt[snd_device]--;
+
+    if(platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0) {
+        ALOGE("%s: Invalid sound device returned", __func__);
+        return -EINVAL;
+    }
+
+    if (adev->snd_dev_ref_cnt[snd_device] == 0) {
+        ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, device_name);
+        /* exit usb play back thread */
+        if(SND_DEVICE_OUT_USB_HEADSET == snd_device ||
+           SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET == snd_device)
+            audio_extn_usb_stop_playback();
+
+        /* exit usb capture thread */
+        if(SND_DEVICE_IN_USB_HEADSET_MIC == snd_device)
+            audio_extn_usb_stop_capture();
+
+        if (SND_DEVICE_OUT_BT_A2DP == snd_device ||
+           (SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP) == snd_device)
+            audio_extn_a2dp_stop_playback();
+
+        if ((snd_device == SND_DEVICE_OUT_SPEAKER ||
+            snd_device == SND_DEVICE_OUT_VOICE_SPEAKER) &&
+            audio_extn_spkr_prot_is_enabled()) {
+            audio_extn_spkr_prot_stop_processing(snd_device);
+        } else {
+            audio_route_reset_and_update_path(adev->audio_route, device_name);
+            audio_extn_dev_arbi_release(snd_device);
+        }
+
+        audio_extn_sound_trigger_update_device_status(snd_device,
+                                        ST_EVENT_SND_DEVICE_FREE);
+        audio_extn_listen_update_device_status(snd_device,
+                                        LISTEN_EVENT_SND_DEVICE_FREE);
+    }
+
+    return 0;
+}
+
+static void check_usecases_codec_backend(struct audio_device *adev,
+                                          struct audio_usecase *uc_info,
+                                          snd_device_t snd_device)
+{
+    struct listnode *node;
+    struct audio_usecase *usecase;
+    bool switch_device[AUDIO_USECASE_MAX];
+    int i, num_uc_to_switch = 0;
+
+    /*
+     * This function is to make sure that all the usecases that are active on
+     * the hardware codec backend are always routed to any one device that is
+     * handled by the hardware codec.
+     * For example, if low-latency and deep-buffer usecases are currently active
+     * on speaker and out_set_parameters(headset) is received on low-latency
+     * output, then we have to make sure deep-buffer is also switched to headset,
+     * because of the limitation that both the devices cannot be enabled
+     * at the same time as they share the same backend.
+     */
+    /*
+     * This call is to check if we need to force routing for a particular stream
+     * If there is a backend configuration change for the device when a
+     * new stream starts, then ADM needs to be closed and re-opened with the new
+     * configuraion. This call check if we need to re-route all the streams
+     * associated with the backend. Touch tone + 24 bit playback.
+     */
+    bool force_routing = platform_check_and_set_codec_backend_cfg(adev, uc_info);
+
+    /* Disable all the usecases on the shared backend other than the
+       specified usecase */
+    for (i = 0; i < AUDIO_USECASE_MAX; i++)
+        switch_device[i] = false;
+
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if (usecase->type != PCM_CAPTURE &&
+                usecase != uc_info &&
+                (usecase->out_snd_device != snd_device || force_routing)  &&
+                usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
+            ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
+                  __func__, use_case_table[usecase->id],
+                  platform_get_snd_device_name(usecase->out_snd_device));
+            disable_audio_route(adev, usecase);
+            switch_device[usecase->id] = true;
+            num_uc_to_switch++;
+        }
+    }
+
+    if (num_uc_to_switch) {
+        /* All streams have been de-routed. Disable the device */
+
+        /* Make sure the previous devices to be disabled first and then enable the
+           selected devices */
+        list_for_each(node, &adev->usecase_list) {
+            usecase = node_to_item(node, struct audio_usecase, list);
+            if (switch_device[usecase->id]) {
+                disable_snd_device(adev, usecase->out_snd_device);
+            }
+        }
+
+        list_for_each(node, &adev->usecase_list) {
+            usecase = node_to_item(node, struct audio_usecase, list);
+            if (switch_device[usecase->id]) {
+                enable_snd_device(adev, snd_device);
+            }
+        }
+
+        /* Re-route all the usecases on the shared backend other than the
+           specified usecase to new snd devices */
+        list_for_each(node, &adev->usecase_list) {
+            usecase = node_to_item(node, struct audio_usecase, list);
+            /* Update the out_snd_device only before enabling the audio route */
+            if (switch_device[usecase->id] ) {
+                usecase->out_snd_device = snd_device;
+                if (usecase->type != VOICE_CALL && usecase->type != VOIP_CALL)
+                    enable_audio_route(adev, usecase);
+            }
+        }
+    }
+}
+
+static void check_and_route_capture_usecases(struct audio_device *adev,
+                                             struct audio_usecase *uc_info,
+                                             snd_device_t snd_device)
+{
+    struct listnode *node;
+    struct audio_usecase *usecase;
+    bool switch_device[AUDIO_USECASE_MAX];
+    int i, num_uc_to_switch = 0;
+
+    /*
+     * This function is to make sure that all the active capture usecases
+     * are always routed to the same input sound device.
+     * For example, if audio-record and voice-call usecases are currently
+     * active on speaker(rx) and speaker-mic (tx) and out_set_parameters(earpiece)
+     * is received for voice call then we have to make sure that audio-record
+     * usecase is also switched to earpiece i.e. voice-dmic-ef,
+     * because of the limitation that two devices cannot be enabled
+     * at the same time if they share the same backend.
+     */
+    for (i = 0; i < AUDIO_USECASE_MAX; i++)
+        switch_device[i] = false;
+
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if (usecase->type != PCM_PLAYBACK &&
+                usecase != uc_info &&
+                usecase->in_snd_device != snd_device) {
+            ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
+                  __func__, use_case_table[usecase->id],
+                  platform_get_snd_device_name(usecase->in_snd_device));
+            disable_audio_route(adev, usecase);
+            switch_device[usecase->id] = true;
+            num_uc_to_switch++;
+        }
+    }
+
+    if (num_uc_to_switch) {
+        /* All streams have been de-routed. Disable the device */
+
+        /* Make sure the previous devices to be disabled first and then enable the
+           selected devices */
+        list_for_each(node, &adev->usecase_list) {
+            usecase = node_to_item(node, struct audio_usecase, list);
+            if (switch_device[usecase->id]) {
+                disable_snd_device(adev, usecase->in_snd_device);
+            }
+        }
+
+        list_for_each(node, &adev->usecase_list) {
+            usecase = node_to_item(node, struct audio_usecase, list);
+            if (switch_device[usecase->id]) {
+                enable_snd_device(adev, snd_device);
+            }
+        }
+
+        /* Re-route all the usecases on the shared backend other than the
+           specified usecase to new snd devices */
+        list_for_each(node, &adev->usecase_list) {
+            usecase = node_to_item(node, struct audio_usecase, list);
+            /* Update the in_snd_device only before enabling the audio route */
+            if (switch_device[usecase->id] ) {
+                usecase->in_snd_device = snd_device;
+                if (usecase->type != VOICE_CALL && usecase->type != VOIP_CALL)
+                    enable_audio_route(adev, usecase);
+            }
+        }
+    }
+}
+
+/* must be called with hw device mutex locked */
+static int read_hdmi_channel_masks(struct stream_out *out)
+{
+    int ret = 0;
+    int channels = platform_edid_get_max_channels(out->dev->platform);
+
+    switch (channels) {
+        /*
+         * Do not handle stereo output in Multi-channel cases
+         * Stereo case is handled in normal playback path
+         */
+    case 6:
+        ALOGV("%s: HDMI supports 5.1", __func__);
+        out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1;
+        break;
+    case 8:
+        ALOGV("%s: HDMI supports 5.1 and 7.1 channels", __func__);
+        out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1;
+        out->supported_channel_masks[1] = AUDIO_CHANNEL_OUT_7POINT1;
+        break;
+    default:
+        ALOGE("HDMI does not support multi channel playback");
+        ret = -ENOSYS;
+        break;
+    }
+    return ret;
+}
+
+static audio_usecase_t get_voice_usecase_id_from_list(struct audio_device *adev)
+{
+    struct audio_usecase *usecase;
+    struct listnode *node;
+
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if (usecase->type == VOICE_CALL) {
+            ALOGV("%s: usecase id %d", __func__, usecase->id);
+            return usecase->id;
+        }
+    }
+    return USECASE_INVALID;
+}
+
+struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
+                                            audio_usecase_t uc_id)
+{
+    struct audio_usecase *usecase;
+    struct listnode *node;
+
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if (usecase->id == uc_id)
+            return usecase;
+    }
+    return NULL;
+}
+
+int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
+{
+    snd_device_t out_snd_device = SND_DEVICE_NONE;
+    snd_device_t in_snd_device = SND_DEVICE_NONE;
+    struct audio_usecase *usecase = NULL;
+    struct audio_usecase *vc_usecase = NULL;
+    struct audio_usecase *voip_usecase = NULL;
+    struct audio_usecase *hfp_usecase = NULL;
+    audio_usecase_t hfp_ucid;
+    struct listnode *node;
+    int status = 0;
+
+    usecase = get_usecase_from_list(adev, uc_id);
+    if (usecase == NULL) {
+        ALOGE("%s: Could not find the usecase(%d)", __func__, uc_id);
+        return -EINVAL;
+    }
+
+    if ((usecase->type == VOICE_CALL) ||
+        (usecase->type == VOIP_CALL)  ||
+        (usecase->type == PCM_HFP_CALL)) {
+        out_snd_device = platform_get_output_snd_device(adev->platform,
+                                                        usecase->stream.out->devices);
+        in_snd_device = platform_get_input_snd_device(adev->platform, usecase->stream.out->devices);
+        usecase->devices = usecase->stream.out->devices;
+    } else {
+        /*
+         * If the voice call is active, use the sound devices of voice call usecase
+         * so that it would not result any device switch. All the usecases will
+         * be switched to new device when select_devices() is called for voice call
+         * usecase. This is to avoid switching devices for voice call when
+         * check_usecases_codec_backend() is called below.
+         */
+        if (voice_is_in_call(adev) && adev->mode == AUDIO_MODE_IN_CALL) {
+            vc_usecase = get_usecase_from_list(adev,
+                                               get_voice_usecase_id_from_list(adev));
+            if ((vc_usecase) && ((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
+                (usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL))) {
+                in_snd_device = vc_usecase->in_snd_device;
+                out_snd_device = vc_usecase->out_snd_device;
+            }
+        } else if (voice_extn_compress_voip_is_active(adev)) {
+            voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
+            if ((voip_usecase) && ((voip_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
+                (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
+                 (voip_usecase->stream.out != adev->primary_output))) {
+                    in_snd_device = voip_usecase->in_snd_device;
+                    out_snd_device = voip_usecase->out_snd_device;
+            }
+        } else if (audio_extn_hfp_is_active(adev)) {
+            hfp_ucid = audio_extn_hfp_get_usecase();
+            hfp_usecase = get_usecase_from_list(adev, hfp_ucid);
+            if ((hfp_usecase) && (hfp_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)) {
+                   in_snd_device = hfp_usecase->in_snd_device;
+                   out_snd_device = hfp_usecase->out_snd_device;
+            }
+        }
+        if (usecase->type == PCM_PLAYBACK) {
+            usecase->devices = usecase->stream.out->devices;
+            in_snd_device = SND_DEVICE_NONE;
+            if (out_snd_device == SND_DEVICE_NONE) {
+                out_snd_device = platform_get_output_snd_device(adev->platform,
+                                            usecase->stream.out->devices);
+                if (usecase->stream.out == adev->primary_output &&
+                        adev->active_input &&
+                        out_snd_device != usecase->out_snd_device) {
+                    select_devices(adev, adev->active_input->usecase);
+                }
+            }
+        } else if (usecase->type == PCM_CAPTURE) {
+            usecase->devices = usecase->stream.in->device;
+            out_snd_device = SND_DEVICE_NONE;
+            if (in_snd_device == SND_DEVICE_NONE) {
+                audio_devices_t out_device = AUDIO_DEVICE_NONE;
+                if ((adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
+                    (adev->mode == AUDIO_MODE_IN_COMMUNICATION &&
+                     adev->active_input->source == AUDIO_SOURCE_MIC)) &&
+                     adev->primary_output && !adev->primary_output->standby) {
+                    out_device = adev->primary_output->devices;
+                    platform_set_echo_reference(adev->platform, false);
+                } else if (usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY) {
+                    out_device = AUDIO_DEVICE_OUT_TELEPHONY_TX;
+                }
+                in_snd_device = platform_get_input_snd_device(adev->platform, out_device);
+            }
+        }
+    }
+
+    if (out_snd_device == usecase->out_snd_device &&
+        in_snd_device == usecase->in_snd_device) {
+        return 0;
+    }
+
+    ALOGD("%s: out_snd_device(%d: %s) in_snd_device(%d: %s)", __func__,
+          out_snd_device, platform_get_snd_device_name(out_snd_device),
+          in_snd_device,  platform_get_snd_device_name(in_snd_device));
+
+    /*
+     * Limitation: While in call, to do a device switch we need to disable
+     * and enable both RX and TX devices though one of them is same as current
+     * device.
+     */
+    if ((usecase->type == VOICE_CALL) &&
+        (usecase->in_snd_device != SND_DEVICE_NONE) &&
+        (usecase->out_snd_device != SND_DEVICE_NONE)) {
+        status = platform_switch_voice_call_device_pre(adev->platform);
+    }
+
+    /* Disable current sound devices */
+    if (usecase->out_snd_device != SND_DEVICE_NONE) {
+        disable_audio_route(adev, usecase);
+        disable_snd_device(adev, usecase->out_snd_device);
+    }
+
+    if (usecase->in_snd_device != SND_DEVICE_NONE) {
+        disable_audio_route(adev, usecase);
+        disable_snd_device(adev, usecase->in_snd_device);
+    }
+
+    /* Applicable only on the targets that has external modem.
+     * New device information should be sent to modem before enabling
+     * the devices to reduce in-call device switch time.
+     */
+    if ((usecase->type == VOICE_CALL) &&
+        (usecase->in_snd_device != SND_DEVICE_NONE) &&
+        (usecase->out_snd_device != SND_DEVICE_NONE)) {
+        status = platform_switch_voice_call_enable_device_config(adev->platform,
+                                                                 out_snd_device,
+                                                                 in_snd_device);
+    }
+
+    /* Enable new sound devices */
+    if (out_snd_device != SND_DEVICE_NONE) {
+        if (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)
+            check_usecases_codec_backend(adev, usecase, out_snd_device);
+        enable_snd_device(adev, out_snd_device);
+    }
+
+    if (in_snd_device != SND_DEVICE_NONE) {
+        check_and_route_capture_usecases(adev, usecase, in_snd_device);
+        enable_snd_device(adev, in_snd_device);
+    }
+
+    if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
+        status = platform_switch_voice_call_device_post(adev->platform,
+                                                        out_snd_device,
+                                                        in_snd_device);
+        enable_audio_route_for_voice_usecases(adev, usecase);
+    }
+
+    usecase->in_snd_device = in_snd_device;
+    usecase->out_snd_device = out_snd_device;
+
+    if (usecase->type == PCM_PLAYBACK) {
+        audio_extn_utils_update_stream_app_type_cfg(adev->platform,
+                                                &adev->streams_output_cfg_list,
+                                                usecase->stream.out->devices,
+                                                usecase->stream.out->flags,
+                                                usecase->stream.out->format,
+                                                usecase->stream.out->sample_rate,
+                                                usecase->stream.out->bit_width,
+                                                &usecase->stream.out->app_type_cfg);
+        ALOGI("%s Selected apptype: %d", __func__, usecase->stream.out->app_type_cfg.app_type);
+    }
+
+    enable_audio_route(adev, usecase);
+
+    /* Applicable only on the targets that has external modem.
+     * Enable device command should be sent to modem only after
+     * enabling voice call mixer controls
+     */
+    if (usecase->type == VOICE_CALL)
+        status = platform_switch_voice_call_usecase_route_post(adev->platform,
+                                                               out_snd_device,
+                                                               in_snd_device);
+    ALOGD("%s: done",__func__);
+
+    return status;
+}
+
+static int stop_input_stream(struct stream_in *in)
+{
+    int i, ret = 0;
+    struct audio_usecase *uc_info;
+    struct audio_device *adev = in->dev;
+
+    adev->active_input = NULL;
+
+    ALOGV("%s: enter: usecase(%d: %s)", __func__,
+          in->usecase, use_case_table[in->usecase]);
+    uc_info = get_usecase_from_list(adev, in->usecase);
+    if (uc_info == NULL) {
+        ALOGE("%s: Could not find the usecase (%d) in the list",
+              __func__, in->usecase);
+        return -EINVAL;
+    }
+
+    /* Close in-call recording streams */
+    voice_check_and_stop_incall_rec_usecase(adev, in);
+
+    /* 1. Disable stream specific mixer controls */
+    disable_audio_route(adev, uc_info);
+
+    /* 2. Disable the tx device */
+    disable_snd_device(adev, uc_info->in_snd_device);
+
+    list_remove(&uc_info->list);
+    free(uc_info);
+
+    ALOGV("%s: exit: status(%d)", __func__, ret);
+    return ret;
+}
+
+int start_input_stream(struct stream_in *in)
+{
+    /* 1. Enable output device and stream routing controls */
+    int ret = 0;
+    struct audio_usecase *uc_info;
+    struct audio_device *adev = in->dev;
+    int snd_card_status = get_snd_card_state(adev);
+
+    int usecase = platform_update_usecase_from_source(in->source,in->usecase);
+    if (get_usecase_from_list(adev, usecase) == NULL)
+        in->usecase = usecase;
+
+    ALOGD("%s: enter: stream(%p)usecase(%d: %s)",
+          __func__, &in->stream, in->usecase, use_case_table[in->usecase]);
+
+
+    if (SND_CARD_STATE_OFFLINE == snd_card_status) {
+        ALOGE("%s: sound card is not active/SSR returning error", __func__);
+        ret = -EIO;
+        goto error_config;
+    }
+
+    /* Check if source matches incall recording usecase criteria */
+    ret = voice_check_and_set_incall_rec_usecase(adev, in);
+    if (ret)
+        goto error_config;
+    else
+        ALOGV("%s: usecase(%d)", __func__, in->usecase);
+
+    if (get_usecase_from_list(adev, in->usecase) != NULL) {
+        ALOGE("%s: use case assigned already in use, stream(%p)usecase(%d: %s)",
+            __func__, &in->stream, in->usecase, use_case_table[in->usecase]);
+        goto error_config;
+    }
+
+    in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
+    if (in->pcm_device_id < 0) {
+        ALOGE("%s: Could not find PCM device id for the usecase(%d)",
+              __func__, in->usecase);
+        ret = -EINVAL;
+        goto error_config;
+    }
+
+    adev->active_input = in;
+    uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+
+    if (!uc_info) {
+        ret = -ENOMEM;
+        goto error_config;
+    }
+
+    uc_info->id = in->usecase;
+    uc_info->type = PCM_CAPTURE;
+    uc_info->stream.in = in;
+    uc_info->devices = in->device;
+    uc_info->in_snd_device = SND_DEVICE_NONE;
+    uc_info->out_snd_device = SND_DEVICE_NONE;
+
+    list_add_tail(&adev->usecase_list, &uc_info->list);
+    audio_extn_perf_lock_acquire();
+    select_devices(adev, in->usecase);
+
+    ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
+          __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
+
+    unsigned int flags = PCM_IN;
+    unsigned int pcm_open_retry_count = 0;
+
+    if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) {
+        flags |= PCM_MMAP | PCM_NOIRQ;
+        pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
+    }
+
+    while (1) {
+        in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
+                           flags, &in->config);
+        if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
+            ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
+            if (in->pcm != NULL) {
+                pcm_close(in->pcm);
+                in->pcm = NULL;
+            }
+            if (pcm_open_retry_count-- == 0) {
+                ret = -EIO;
+                goto error_open;
+            }
+            usleep(PROXY_OPEN_WAIT_TIME * 1000);
+            continue;
+        }
+        break;
+    }
+
+    ALOGV("%s: pcm_prepare", __func__);
+    ret = pcm_prepare(in->pcm);
+    if (ret < 0) {
+        ALOGE("%s: pcm_prepare returned %d", __func__, ret);
+        pcm_close(in->pcm);
+        in->pcm = NULL;
+        goto error_open;
+    }
+
+    audio_extn_perf_lock_release();
+
+    ALOGD("%s: exit", __func__);
+
+    return ret;
+
+error_open:
+    stop_input_stream(in);
+    audio_extn_perf_lock_release();
+
+error_config:
+    adev->active_input = NULL;
+    ALOGD("%s: exit: status(%d)", __func__, ret);
+
+    return ret;
+}
+
+/* must be called with out->lock locked */
+static int send_offload_cmd_l(struct stream_out* out, int command)
+{
+    struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd));
+
+    if (!cmd) {
+        ALOGE("failed to allocate mem for command 0x%x", command);
+        return -ENOMEM;
+    }
+
+    ALOGVV("%s %d", __func__, command);
+
+    cmd->cmd = command;
+    list_add_tail(&out->offload_cmd_list, &cmd->node);
+    pthread_cond_signal(&out->offload_cond);
+    return 0;
+}
+
+/* must be called iwth out->lock locked */
+static void stop_compressed_output_l(struct stream_out *out)
+{
+    out->offload_state = OFFLOAD_STATE_IDLE;
+    out->playback_started = 0;
+    out->send_new_metadata = 1;
+    if (out->compr != NULL) {
+        compress_stop(out->compr);
+        while (out->offload_thread_blocked) {
+            pthread_cond_wait(&out->cond, &out->lock);
+        }
+    }
+}
+
+bool is_offload_usecase(audio_usecase_t uc_id)
+{
+    unsigned int i;
+    for (i = 0; i < sizeof(offload_usecases)/sizeof(offload_usecases[0]); i++) {
+        if (uc_id == offload_usecases[i])
+            return true;
+    }
+    return false;
+}
+
+static audio_usecase_t get_offload_usecase(struct audio_device *adev)
+{
+    audio_usecase_t ret = USECASE_AUDIO_PLAYBACK_OFFLOAD;
+    unsigned int i, num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
+    char value[PROPERTY_VALUE_MAX] = {0};
+
+    property_get("audio.offload.multiple.enabled", value, NULL);
+    if (!(atoi(value) || !strncmp("true", value, 4)))
+        num_usecase = 1; /* If prop is not set, limit the num of offload usecases to 1 */
+
+    ALOGV("%s: num_usecase: %d", __func__, num_usecase);
+    for (i = 0; i < num_usecase; i++) {
+        if (!(adev->offload_usecases_state & (0x1<<i))) {
+            adev->offload_usecases_state |= 0x1 << i;
+            ret = offload_usecases[i];
+            break;
+        }
+    }
+    ALOGV("%s: offload usecase is %d", __func__, ret);
+    return ret;
+}
+
+static void free_offload_usecase(struct audio_device *adev,
+                                 audio_usecase_t uc_id)
+{
+    unsigned int i;
+    for (i = 0; i < sizeof(offload_usecases)/sizeof(offload_usecases[0]); i++) {
+        if (offload_usecases[i] == uc_id) {
+            adev->offload_usecases_state &= ~(0x1<<i);
+            break;
+        }
+    }
+    ALOGV("%s: free offload usecase %d", __func__, uc_id);
+}
+
+static void *offload_thread_loop(void *context)
+{
+    struct stream_out *out = (struct stream_out *) context;
+    struct listnode *item;
+    int ret = 0;
+
+    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+    set_sched_policy(0, SP_FOREGROUND);
+    prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0);
+
+    ALOGV("%s", __func__);
+    pthread_mutex_lock(&out->lock);
+    for (;;) {
+        struct offload_cmd *cmd = NULL;
+        stream_callback_event_t event;
+        bool send_callback = false;
+
+        ALOGVV("%s offload_cmd_list %d out->offload_state %d",
+              __func__, list_empty(&out->offload_cmd_list),
+              out->offload_state);
+        if (list_empty(&out->offload_cmd_list)) {
+            ALOGV("%s SLEEPING", __func__);
+            pthread_cond_wait(&out->offload_cond, &out->lock);
+            ALOGV("%s RUNNING", __func__);
+            continue;
+        }
+
+        item = list_head(&out->offload_cmd_list);
+        cmd = node_to_item(item, struct offload_cmd, node);
+        list_remove(item);
+
+        ALOGVV("%s STATE %d CMD %d out->compr %p",
+               __func__, out->offload_state, cmd->cmd, out->compr);
+
+        if (cmd->cmd == OFFLOAD_CMD_EXIT) {
+            free(cmd);
+            break;
+        }
+
+        if (out->compr == NULL) {
+            ALOGE("%s: Compress handle is NULL", __func__);
+            pthread_cond_signal(&out->cond);
+            continue;
+        }
+        out->offload_thread_blocked = true;
+        pthread_mutex_unlock(&out->lock);
+        send_callback = false;
+        switch(cmd->cmd) {
+        case OFFLOAD_CMD_WAIT_FOR_BUFFER:
+            ALOGD("copl(%p):calling compress_wait", out);
+            compress_wait(out->compr, -1);
+            ALOGD("copl(%p):out of compress_wait", out);
+            send_callback = true;
+            event = STREAM_CBK_EVENT_WRITE_READY;
+            break;
+        case OFFLOAD_CMD_PARTIAL_DRAIN:
+            ret = compress_next_track(out->compr);
+            if(ret == 0) {
+                ALOGD("copl(%p):calling compress_partial_drain", out);
+                ret = compress_partial_drain(out->compr);
+                ALOGD("copl(%p):out of compress_partial_drain", out);
+                if (ret < 0)
+                    ret = -errno;
+            }
+            else if (ret == -ETIMEDOUT)
+                compress_drain(out->compr);
+            else
+                ALOGE("%s: Next track returned error %d",__func__, ret);
+
+            if (ret != -ENETRESET) {
+                send_callback = true;
+                event = STREAM_CBK_EVENT_DRAIN_READY;
+                ALOGV("copl(%p):send drain callback, ret %d", out, ret);
+            } else
+                ALOGE("%s: Block drain ready event during SSR", __func__);
+            break;
+        case OFFLOAD_CMD_DRAIN:
+            ALOGD("copl(%p):calling compress_drain", out);
+            compress_drain(out->compr);
+            ALOGD("copl(%p):calling compress_drain", out);
+            send_callback = true;
+            event = STREAM_CBK_EVENT_DRAIN_READY;
+            break;
+        default:
+            ALOGE("%s unknown command received: %d", __func__, cmd->cmd);
+            break;
+        }
+        pthread_mutex_lock(&out->lock);
+        out->offload_thread_blocked = false;
+        pthread_cond_signal(&out->cond);
+        if (send_callback) {
+            out->offload_callback(event, NULL, out->offload_cookie);
+        }
+        free(cmd);
+    }
+
+    pthread_cond_signal(&out->cond);
+    while (!list_empty(&out->offload_cmd_list)) {
+        item = list_head(&out->offload_cmd_list);
+        list_remove(item);
+        free(node_to_item(item, struct offload_cmd, node));
+    }
+    pthread_mutex_unlock(&out->lock);
+
+    return NULL;
+}
+
+static int create_offload_callback_thread(struct stream_out *out)
+{
+    pthread_cond_init(&out->offload_cond, (const pthread_condattr_t *) NULL);
+    list_init(&out->offload_cmd_list);
+    pthread_create(&out->offload_thread, (const pthread_attr_t *) NULL,
+                    offload_thread_loop, out);
+    return 0;
+}
+
+static int destroy_offload_callback_thread(struct stream_out *out)
+{
+    pthread_mutex_lock(&out->lock);
+    stop_compressed_output_l(out);
+    send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);
+
+    pthread_mutex_unlock(&out->lock);
+    pthread_join(out->offload_thread, (void **) NULL);
+    pthread_cond_destroy(&out->offload_cond);
+
+    return 0;
+}
+
+static bool allow_hdmi_channel_config(struct audio_device *adev)
+{
+    struct listnode *node;
+    struct audio_usecase *usecase;
+    bool ret = true;
+
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if (usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+            /*
+             * If voice call is already existing, do not proceed further to avoid
+             * disabling/enabling both RX and TX devices, CSD calls, etc.
+             * Once the voice call done, the HDMI channels can be configured to
+             * max channels of remaining use cases.
+             */
+            if (usecase->id == USECASE_VOICE_CALL) {
+                ALOGD("%s: voice call is active, no change in HDMI channels",
+                      __func__);
+                ret = false;
+                break;
+            } else if (usecase->id == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
+                ALOGD("%s: multi channel playback is active, "
+                      "no change in HDMI channels", __func__);
+                ret = false;
+                break;
+            } else if (is_offload_usecase(usecase->id) &&
+                       audio_channel_count_from_out_mask(usecase->stream.out->channel_mask) > 2) {
+                ALOGD("%s: multi-channel(%x) compress offload playback is active, "
+                      "no change in HDMI channels", __func__, usecase->stream.out->channel_mask);
+                ret = false;
+                break;
+            }
+        }
+    }
+    return ret;
+}
+
+static int check_and_set_hdmi_channels(struct audio_device *adev,
+                                       unsigned int channels)
+{
+    struct listnode *node;
+    struct audio_usecase *usecase;
+
+    /* Check if change in HDMI channel config is allowed */
+    if (!allow_hdmi_channel_config(adev))
+        return 0;
+
+    if (channels == adev->cur_hdmi_channels) {
+        ALOGD("%s: Requested channels are same as current channels(%d)", __func__, channels);
+        return 0;
+    }
+
+    platform_set_hdmi_channels(adev->platform, channels);
+    adev->cur_hdmi_channels = channels;
+
+    /*
+     * Deroute all the playback streams routed to HDMI so that
+     * the back end is deactivated. Note that backend will not
+     * be deactivated if any one stream is connected to it.
+     */
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if (usecase->type == PCM_PLAYBACK &&
+                usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+            disable_audio_route(adev, usecase);
+        }
+    }
+
+    /*
+     * Enable all the streams disabled above. Now the HDMI backend
+     * will be activated with new channel configuration
+     */
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if (usecase->type == PCM_PLAYBACK &&
+                usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+            enable_audio_route(adev, usecase);
+        }
+    }
+
+    return 0;
+}
+
+static int stop_output_stream(struct stream_out *out)
+{
+    int i, ret = 0;
+    struct audio_usecase *uc_info;
+    struct audio_device *adev = out->dev;
+
+    ALOGV("%s: enter: usecase(%d: %s)", __func__,
+          out->usecase, use_case_table[out->usecase]);
+    uc_info = get_usecase_from_list(adev, out->usecase);
+    if (uc_info == NULL) {
+        ALOGE("%s: Could not find the usecase (%d) in the list",
+              __func__, out->usecase);
+        return -EINVAL;
+    }
+
+    if (is_offload_usecase(out->usecase)) {
+        if (adev->visualizer_stop_output != NULL)
+            adev->visualizer_stop_output(out->handle, out->pcm_device_id);
+        if (adev->offload_effects_stop_output != NULL)
+            adev->offload_effects_stop_output(out->handle, out->pcm_device_id);
+    }
+
+    /* 1. Get and set stream specific mixer controls */
+    disable_audio_route(adev, uc_info);
+
+    /* 2. Disable the rx device */
+    disable_snd_device(adev, uc_info->out_snd_device);
+
+    list_remove(&uc_info->list);
+    free(uc_info);
+
+    /* Must be called after removing the usecase from list */
+    if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
+        check_and_set_hdmi_channels(adev, DEFAULT_HDMI_OUT_CHANNELS);
+
+    ALOGV("%s: exit: status(%d)", __func__, ret);
+    return ret;
+}
+
+int start_output_stream(struct stream_out *out)
+{
+    int ret = 0;
+    int sink_channels = 0;
+    char prop_value[PROPERTY_VALUE_MAX] = {0};
+    struct audio_usecase *uc_info;
+    struct audio_device *adev = out->dev;
+    int snd_card_status = get_snd_card_state(adev);
+
+    if ((out->usecase < 0) || (out->usecase >= AUDIO_USECASE_MAX)) {
+        ret = -EINVAL;
+        goto error_config;
+    }
+
+    ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x)",
+          __func__, &out->stream, out->usecase, use_case_table[out->usecase],
+          out->devices);
+
+    if (SND_CARD_STATE_OFFLINE == snd_card_status) {
+        ALOGE("%s: sound card is not active/SSR returning error", __func__);
+        ret = -EIO;
+        goto error_config;
+    }
+
+    out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
+    if (out->pcm_device_id < 0) {
+        ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
+              __func__, out->pcm_device_id, out->usecase);
+        ret = -EINVAL;
+        goto error_config;
+    }
+
+    uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+
+    if (!uc_info) {
+        ret = -ENOMEM;
+        goto error_config;
+    }
+
+    uc_info->id = out->usecase;
+    uc_info->type = PCM_PLAYBACK;
+    uc_info->stream.out = out;
+    uc_info->devices = out->devices;
+    uc_info->in_snd_device = SND_DEVICE_NONE;
+    uc_info->out_snd_device = SND_DEVICE_NONE;
+
+    /* This must be called before adding this usecase to the list */
+    if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+        property_get("audio.use.hdmi.sink.cap", prop_value, NULL);
+        if (!strncmp("true", prop_value, 4)) {
+            sink_channels = platform_edid_get_max_channels(out->dev->platform);
+            ALOGD("%s: set HDMI channel count[%d] based on sink capability", __func__, sink_channels);
+            check_and_set_hdmi_channels(adev, sink_channels);
+        } else {
+            if (is_offload_usecase(out->usecase))
+                check_and_set_hdmi_channels(adev, out->compr_config.codec->ch_in);
+            else
+                check_and_set_hdmi_channels(adev, out->config.channels);
+        }
+    }
+
+    list_add_tail(&adev->usecase_list, &uc_info->list);
+
+    select_devices(adev, out->usecase);
+
+    ALOGV("%s: Opening PCM device card_id(%d) device_id(%d) format(%#x)",
+          __func__, adev->snd_card, out->pcm_device_id, out->config.format);
+    if (!is_offload_usecase(out->usecase)) {
+        unsigned int flags = PCM_OUT;
+        unsigned int pcm_open_retry_count = 0;
+        if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY) {
+            flags |= PCM_MMAP | PCM_NOIRQ;
+            pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
+        } else
+            flags |= PCM_MONOTONIC;
+
+        while (1) {
+            out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
+                               flags, &out->config);
+            if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
+                ALOGE("%s: %s", __func__, pcm_get_error(out->pcm));
+                if (out->pcm != NULL) {
+                    pcm_close(out->pcm);
+                    out->pcm = NULL;
+                }
+                if (pcm_open_retry_count-- == 0) {
+                    ret = -EIO;
+                    goto error_open;
+                }
+                usleep(PROXY_OPEN_WAIT_TIME * 1000);
+                continue;
+            }
+            break;
+        }
+
+        ALOGV("%s: pcm_prepare", __func__);
+        if (pcm_is_ready(out->pcm)) {
+            ret = pcm_prepare(out->pcm);
+            if (ret < 0) {
+                ALOGE("%s: pcm_prepare returned %d", __func__, ret);
+                pcm_close(out->pcm);
+                out->pcm = NULL;
+                goto error_open;
+            }
+        }
+    } else {
+        out->pcm = NULL;
+        out->compr = compress_open(adev->snd_card,
+                                   out->pcm_device_id,
+                                   COMPRESS_IN, &out->compr_config);
+        if (out->compr && !is_compress_ready(out->compr)) {
+            ALOGE("%s: %s", __func__, compress_get_error(out->compr));
+            compress_close(out->compr);
+            out->compr = NULL;
+            ret = -EIO;
+            goto error_open;
+        }
+        if (out->offload_callback)
+            compress_nonblock(out->compr, out->non_blocking);
+
+#ifdef DS1_DOLBY_DDP_ENABLED
+        if (audio_extn_is_dolby_format(out->format))
+            audio_extn_dolby_send_ddp_endp_params(adev);
+#endif
+
+        if (adev->visualizer_start_output != NULL)
+            adev->visualizer_start_output(out->handle, out->pcm_device_id);
+        if (adev->offload_effects_start_output != NULL)
+            adev->offload_effects_start_output(out->handle, out->pcm_device_id);
+    }
+
+    ALOGD("%s: exit", __func__);
+
+    return 0;
+error_open:
+    stop_output_stream(out);
+error_config:
+    return ret;
+}
+
+static int check_input_parameters(uint32_t sample_rate,
+                                  audio_format_t format,
+                                  int channel_count)
+{
+    int ret = 0;
+
+    if ((format != AUDIO_FORMAT_PCM_16_BIT) &&
+        !voice_extn_compress_voip_is_format_supported(format) &&
+            !audio_extn_compr_cap_format_supported(format))  ret = -EINVAL;
+
+    switch (channel_count) {
+    case 1:
+    case 2:
+    case 6:
+        break;
+    default:
+        ret = -EINVAL;
+    }
+
+    switch (sample_rate) {
+    case 8000:
+    case 11025:
+    case 12000:
+    case 16000:
+    case 22050:
+    case 24000:
+    case 32000:
+    case 44100:
+    case 48000:
+        break;
+    default:
+        ret = -EINVAL;
+    }
+
+    return ret;
+}
+
+static size_t get_input_buffer_size(uint32_t sample_rate,
+                                    audio_format_t format,
+                                    int channel_count,
+                                    bool is_low_latency)
+{
+    size_t size = 0;
+
+    if (check_input_parameters(sample_rate, format, channel_count) != 0)
+        return 0;
+
+    size = (sample_rate * AUDIO_CAPTURE_PERIOD_DURATION_MSEC) / 1000;
+    if (is_low_latency)
+        size = configured_low_latency_capture_period_size;
+    /* ToDo: should use frame_size computed based on the format and
+       channel_count here. */
+    size *= sizeof(short) * channel_count;
+
+    /* make sure the size is multiple of 32 bytes
+     * At 48 kHz mono 16-bit PCM:
+     *  5.000 ms = 240 frames = 15*16*1*2 = 480, a whole multiple of 32 (15)
+     *  3.333 ms = 160 frames = 10*16*1*2 = 320, a whole multiple of 32 (10)
+     */
+    size += 0x1f;
+    size &= ~0x1f;
+
+    return size;
+}
+
+static uint32_t out_get_sample_rate(const struct audio_stream *stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+
+    return out->sample_rate;
+}
+
+static int out_set_sample_rate(struct audio_stream *stream __unused,
+                               uint32_t rate __unused)
+{
+    return -ENOSYS;
+}
+
+static size_t out_get_buffer_size(const struct audio_stream *stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+
+    if (is_offload_usecase(out->usecase))
+        return out->compr_config.fragment_size;
+    else if(out->usecase == USECASE_COMPRESS_VOIP_CALL)
+        return voice_extn_compress_voip_out_get_buffer_size(out);
+
+    return out->config.period_size *
+                audio_stream_out_frame_size((const struct audio_stream_out *)stream);
+}
+
+static uint32_t out_get_channels(const struct audio_stream *stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+
+    return out->channel_mask;
+}
+
+static audio_format_t out_get_format(const struct audio_stream *stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+
+    return out->format;
+}
+
+static int out_set_format(struct audio_stream *stream __unused,
+                          audio_format_t format __unused)
+{
+    return -ENOSYS;
+}
+
+static int out_standby(struct audio_stream *stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    struct audio_device *adev = out->dev;
+
+    ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
+          stream, out->usecase, use_case_table[out->usecase]);
+    if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
+        /* Ignore standby in case of voip call because the voip output
+         * stream is closed in adev_close_output_stream()
+         */
+        ALOGD("%s: Ignore Standby in VOIP call", __func__);
+        return 0;
+    }
+
+    pthread_mutex_lock(&out->lock);
+    if (!out->standby) {
+        pthread_mutex_lock(&adev->lock);
+        out->standby = true;
+        if (!is_offload_usecase(out->usecase)) {
+            if (out->pcm) {
+                pcm_close(out->pcm);
+                out->pcm = NULL;
+            }
+        } else {
+            ALOGD("copl(%p):standby", out);
+            stop_compressed_output_l(out);
+            out->gapless_mdata.encoder_delay = 0;
+            out->gapless_mdata.encoder_padding = 0;
+            if (out->compr != NULL) {
+                compress_close(out->compr);
+                out->compr = NULL;
+            }
+        }
+        stop_output_stream(out);
+        pthread_mutex_unlock(&adev->lock);
+    }
+    pthread_mutex_unlock(&out->lock);
+    ALOGV("%s: exit", __func__);
+    return 0;
+}
+
+static int out_dump(const struct audio_stream *stream __unused,
+                    int fd __unused)
+{
+    return 0;
+}
+
+static int parse_compress_metadata(struct stream_out *out, struct str_parms *parms)
+{
+    int ret = 0;
+    char value[32];
+    bool is_meta_data_params = false;
+
+    if (!out || !parms) {
+        ALOGE("%s: return invalid ",__func__);
+        return -EINVAL;
+    }
+
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FORMAT, value, sizeof(value));
+    if (ret >= 0) {
+        if (atoi(value) == SND_AUDIOSTREAMFORMAT_MP4ADTS) {
+            out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_MP4ADTS;
+            ALOGV("ADTS format is set in offload mode");
+        }
+        out->send_new_metadata = 1;
+    }
+
+    ret = audio_extn_parse_compress_metadata(out, parms);
+
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_SAMPLE_RATE, value, sizeof(value));
+    if(ret >= 0)
+        is_meta_data_params = true;
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_NUM_CHANNEL, value, sizeof(value));
+    if(ret >= 0)
+        is_meta_data_params = true;
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE, value, sizeof(value));
+    if(ret >= 0)
+        is_meta_data_params = true;
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value));
+    if (ret >= 0) {
+        is_meta_data_params = true;
+        out->gapless_mdata.encoder_delay = atoi(value); //whats a good limit check?
+    }
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value));
+    if (ret >= 0) {
+        is_meta_data_params = true;
+        out->gapless_mdata.encoder_padding = atoi(value);
+    }
+
+    if(!is_meta_data_params) {
+        ALOGV("%s: Not gapless meta data params", __func__);
+        return 0;
+    }
+    out->send_new_metadata = 1;
+    ALOGV("%s new encoder delay %u and padding %u", __func__,
+          out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding);
+
+    return 0;
+}
+
+static bool output_drives_call(struct audio_device *adev, struct stream_out *out)
+{
+    return out == adev->primary_output || out == adev->voice_tx_output;
+}
+
+static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    struct audio_device *adev = out->dev;
+    struct audio_usecase *usecase;
+    struct listnode *node;
+    struct str_parms *parms;
+    char value[32];
+    int ret = 0, val = 0, err;
+    bool select_new_device = false;
+
+    ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s",
+          __func__, out->usecase, use_case_table[out->usecase], kvpairs);
+    parms = str_parms_create_str(kvpairs);
+    if (!parms)
+        goto error;
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
+    if (err >= 0) {
+        val = atoi(value);
+        pthread_mutex_lock(&out->lock);
+        pthread_mutex_lock(&adev->lock);
+
+        /*
+         * When HDMI cable is unplugged/usb hs is disconnected the
+         * music playback is paused and the policy manager sends routing=0
+         * But the audioflingercontinues to write data until standby time
+         * (3sec). As the HDMI core is turned off, the write gets blocked.
+         * Avoid this by routing audio to speaker until standby.
+         */
+        if ((out->devices == AUDIO_DEVICE_OUT_AUX_DIGITAL ||
+                out->devices == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET) &&
+                val == AUDIO_DEVICE_NONE) {
+            val = AUDIO_DEVICE_OUT_SPEAKER;
+        }
+
+        /*
+         * select_devices() call below switches all the usecases on the same
+         * backend to the new device. Refer to check_usecases_codec_backend() in
+         * the select_devices(). But how do we undo this?
+         *
+         * For example, music playback is active on headset (deep-buffer usecase)
+         * and if we go to ringtones and select a ringtone, low-latency usecase
+         * will be started on headset+speaker. As we can't enable headset+speaker
+         * and headset devices at the same time, select_devices() switches the music
+         * playback to headset+speaker while starting low-lateny usecase for ringtone.
+         * So when the ringtone playback is completed, how do we undo the same?
+         *
+         * We are relying on the out_set_parameters() call on deep-buffer output,
+         * once the ringtone playback is ended.
+         * NOTE: We should not check if the current devices are same as new devices.
+         *       Because select_devices() must be called to switch back the music
+         *       playback to headset.
+         */
+        if (val != 0) {
+            out->devices = val;
+
+            if (!out->standby)
+                select_devices(adev, out->usecase);
+
+            if ((adev->mode == AUDIO_MODE_IN_CALL) &&
+                    output_drives_call(adev, out)) {
+                adev->current_call_output = out;
+                if (!voice_is_in_call(adev))
+                    ret = voice_start_call(adev);
+                else
+                    voice_update_devices_for_all_voice_usecases(adev);
+            }
+        }
+
+        pthread_mutex_unlock(&adev->lock);
+        pthread_mutex_unlock(&out->lock);
+    }
+
+    if (out == adev->primary_output) {
+        pthread_mutex_lock(&adev->lock);
+        audio_extn_set_parameters(adev, parms);
+        pthread_mutex_unlock(&adev->lock);
+    }
+    if (is_offload_usecase(out->usecase)) {
+        pthread_mutex_lock(&out->lock);
+        parse_compress_metadata(out, parms);
+        pthread_mutex_unlock(&out->lock);
+    }
+
+    str_parms_destroy(parms);
+error:
+    ALOGV("%s: exit: code(%d)", __func__, ret);
+    return ret;
+}
+
+static char* out_get_parameters(const struct audio_stream *stream, const char *keys)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    struct str_parms *query = str_parms_create_str(keys);
+    char *str;
+    char value[256];
+    struct str_parms *reply = str_parms_create();
+    size_t i, j;
+    int ret;
+    bool first = true;
+
+    if (!query || !reply) {
+        ALOGE("out_get_parameters: failed to allocate mem for query or reply");
+        return NULL;
+    }
+
+    ALOGV("%s: enter: keys - %s", __func__, keys);
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value, sizeof(value));
+    if (ret >= 0) {
+        value[0] = '\0';
+        i = 0;
+        while (out->supported_channel_masks[i] != 0) {
+            for (j = 0; j < ARRAY_SIZE(out_channels_name_to_enum_table); j++) {
+                if (out_channels_name_to_enum_table[j].value == out->supported_channel_masks[i]) {
+                    if (!first) {
+                        strcat(value, "|");
+                    }
+                    strcat(value, out_channels_name_to_enum_table[j].name);
+                    first = false;
+                    break;
+                }
+            }
+            i++;
+        }
+        str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
+        str = str_parms_to_str(reply);
+    } else {
+        voice_extn_out_get_parameters(out, query, reply);
+        str = str_parms_to_str(reply);
+        if (!strncmp(str, "", sizeof(""))) {
+            free(str);
+            str = strdup(keys);
+        }
+    }
+    str_parms_destroy(query);
+    str_parms_destroy(reply);
+    ALOGV("%s: exit: returns - %s", __func__, str);
+    return str;
+}
+
+static uint32_t out_get_latency(const struct audio_stream_out *stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+
+    if (is_offload_usecase(out->usecase))
+        return COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
+
+    return (out->config.period_count * out->config.period_size * 1000) /
+           (out->config.rate);
+}
+
+static int out_set_volume(struct audio_stream_out *stream, float left,
+                          float right)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int volume[2];
+
+    if (out->usecase == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
+        /* only take left channel into account: the API is for stereo anyway */
+        out->muted = (left == 0.0f);
+        return 0;
+    } else if (is_offload_usecase(out->usecase)) {
+        char mixer_ctl_name[128];
+        struct audio_device *adev = out->dev;
+        struct mixer_ctl *ctl;
+        int pcm_device_id = platform_get_pcm_device_id(out->usecase,
+                                                       PCM_PLAYBACK);
+
+        snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+                 "Compress Playback %d Volume", pcm_device_id);
+        ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+        if (!ctl) {
+            ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                  __func__, mixer_ctl_name);
+            return -EINVAL;
+        }
+        volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX);
+        volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX);
+        mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
+        return 0;
+    }
+
+    return -ENOSYS;
+}
+
+static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
+                         size_t bytes)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    struct audio_device *adev = out->dev;
+    int snd_scard_state = get_snd_card_state(adev);
+    ssize_t ret = 0;
+
+    pthread_mutex_lock(&out->lock);
+
+    if (SND_CARD_STATE_OFFLINE == snd_scard_state) {
+        // increase written size during SSR to avoid mismatch
+        // with the written frames count in AF
+        if (!is_offload_usecase(out->usecase))
+            out->written += bytes / (out->config.channels * sizeof(short));
+
+        if (out->pcm) {
+            ALOGD(" %s: sound card is not active/SSR state", __func__);
+            ret= -EIO;
+            goto exit;
+        } else if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+            //during SSR for compress usecase we should return error to flinger
+            ALOGD(" copl %s: sound card is not active/SSR state", __func__);
+            pthread_mutex_unlock(&out->lock);
+            return -ENETRESET;
+        }
+    }
+
+    if (out->standby) {
+        out->standby = false;
+        pthread_mutex_lock(&adev->lock);
+        if (out->usecase == USECASE_COMPRESS_VOIP_CALL)
+            ret = voice_extn_compress_voip_start_output_stream(out);
+        else
+            ret = start_output_stream(out);
+        pthread_mutex_unlock(&adev->lock);
+        /* ToDo: If use case is compress offload should return 0 */
+        if (ret != 0) {
+            out->standby = true;
+            goto exit;
+        }
+    }
+
+    if (is_offload_usecase(out->usecase)) {
+        ALOGD("copl(%p): writing buffer (%zu bytes) to compress device", out, bytes);
+        if (out->send_new_metadata) {
+            ALOGD("copl(%p):send new gapless metadata", out);
+            compress_set_gapless_metadata(out->compr, &out->gapless_mdata);
+            out->send_new_metadata = 0;
+        }
+
+        ret = compress_write(out->compr, buffer, bytes);
+        if (ret < 0)
+            ret = -errno;
+        ALOGVV("%s: writing buffer (%d bytes) to compress device returned %d", __func__, bytes, ret);
+        if (ret >= 0 && ret < (ssize_t)bytes) {
+            ALOGD("No space available in compress driver, post msg to cb thread");
+            send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
+        } else if (-ENETRESET == ret) {
+            ALOGE("copl %s: received sound card offline state on compress write", __func__);
+            set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
+            pthread_mutex_unlock(&out->lock);
+            out_standby(&out->stream.common);
+            return ret;
+        }
+        if (!out->playback_started && ret >= 0) {
+            compress_start(out->compr);
+            out->playback_started = 1;
+            out->offload_state = OFFLOAD_STATE_PLAYING;
+        }
+        pthread_mutex_unlock(&out->lock);
+        return ret;
+    } else {
+        if (out->pcm) {
+            if (out->muted)
+                memset((void *)buffer, 0, bytes);
+            ALOGVV("%s: writing buffer (%d bytes) to pcm device", __func__, bytes);
+            if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY)
+                ret = pcm_mmap_write(out->pcm, (void *)buffer, bytes);
+            else
+                ret = pcm_write(out->pcm, (void *)buffer, bytes);
+            if (ret < 0)
+                ret = -errno;
+            else if (ret == 0)
+                out->written += bytes / (out->config.channels * sizeof(short));
+        }
+    }
+
+exit:
+    /* ToDo: There may be a corner case when SSR happens back to back during
+       start/stop. Need to post different error to handle that. */
+    if (-ENETRESET == ret) {
+        set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
+    }
+
+    pthread_mutex_unlock(&out->lock);
+
+    if (ret != 0) {
+        if (out->pcm)
+            ALOGE("%s: error %ld - %s", __func__, ret, pcm_get_error(out->pcm));
+        if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
+            pthread_mutex_lock(&adev->lock);
+            voice_extn_compress_voip_close_output_stream(&out->stream.common);
+            pthread_mutex_unlock(&adev->lock);
+            out->standby = true;
+        }
+        out_standby(&out->stream.common);
+        usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
+                        out_get_sample_rate(&out->stream.common));
+
+    }
+    return bytes;
+}
+
+static int out_get_render_position(const struct audio_stream_out *stream,
+                                   uint32_t *dsp_frames)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    struct audio_device *adev = out->dev;
+
+    if (dsp_frames == NULL)
+        return -EINVAL;
+
+    *dsp_frames = 0;
+    if (is_offload_usecase(out->usecase)) {
+        ssize_t ret = 0;
+        pthread_mutex_lock(&out->lock);
+        if (out->compr != NULL) {
+            ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
+                    &out->sample_rate);
+            if (ret < 0)
+                ret = -errno;
+            ALOGVV("%s rendered frames %d sample_rate %d",
+                   __func__, *dsp_frames, out->sample_rate);
+        }
+        pthread_mutex_unlock(&out->lock);
+        if (-ENETRESET == ret) {
+            ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver");
+            set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
+            return -EINVAL;
+        } else if(ret < 0) {
+            ALOGE(" ERROR: Unable to get time stamp from compress driver");
+            return -EINVAL;
+        } else if (get_snd_card_state(adev) == SND_CARD_STATE_OFFLINE){
+            /*
+             * Handle corner case where compress session is closed during SSR
+             * and timestamp is queried
+             */
+            ALOGE(" ERROR: sound card not active, return error");
+            return -EINVAL;
+        } else {
+            return 0;
+        }
+    } else if (audio_is_linear_pcm(out->format)) {
+        *dsp_frames = out->written;
+        return 0;
+    } else
+        return -EINVAL;
+}
+
+static int out_add_audio_effect(const struct audio_stream *stream __unused,
+                                effect_handle_t effect __unused)
+{
+    return 0;
+}
+
+static int out_remove_audio_effect(const struct audio_stream *stream __unused,
+                                   effect_handle_t effect __unused)
+{
+    return 0;
+}
+
+static int out_get_next_write_timestamp(const struct audio_stream_out *stream __unused,
+                                        int64_t *timestamp __unused)
+{
+    return -EINVAL;
+}
+
+static int out_get_presentation_position(const struct audio_stream_out *stream,
+                                   uint64_t *frames, struct timespec *timestamp)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int ret = -1;
+    unsigned long dsp_frames;
+
+    pthread_mutex_lock(&out->lock);
+
+    if (is_offload_usecase(out->usecase)) {
+        if (out->compr != NULL) {
+            ret = compress_get_tstamp(out->compr, &dsp_frames,
+                    &out->sample_rate);
+            ALOGVV("%s rendered frames %ld sample_rate %d",
+                   __func__, dsp_frames, out->sample_rate);
+            *frames = dsp_frames;
+            if (ret < 0)
+                ret = -errno;
+            if (-ENETRESET == ret) {
+                ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver");
+                set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
+                ret = -EINVAL;
+            } else
+                ret = 0;
+
+            /* this is the best we can do */
+            clock_gettime(CLOCK_MONOTONIC, timestamp);
+        }
+    } else {
+        if (out->pcm) {
+            unsigned int avail;
+            if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) {
+                size_t kernel_buffer_size = out->config.period_size * out->config.period_count;
+                int64_t signed_frames = out->written - kernel_buffer_size + avail;
+                // This adjustment accounts for buffering after app processor.
+                // It is based on estimated DSP latency per use case, rather than exact.
+                signed_frames -=
+                    (platform_render_latency(out->usecase) * out->sample_rate / 1000000LL);
+
+                // It would be unusual for this value to be negative, but check just in case ...
+                if (signed_frames >= 0) {
+                    *frames = signed_frames;
+                    ret = 0;
+                }
+            }
+        }
+    }
+
+    pthread_mutex_unlock(&out->lock);
+
+    return ret;
+}
+
+static int out_set_callback(struct audio_stream_out *stream,
+            stream_callback_t callback, void *cookie)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+
+    ALOGV("%s", __func__);
+    pthread_mutex_lock(&out->lock);
+    out->offload_callback = callback;
+    out->offload_cookie = cookie;
+    pthread_mutex_unlock(&out->lock);
+    return 0;
+}
+
+static int out_pause(struct audio_stream_out* stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int status = -ENOSYS;
+    ALOGV("%s", __func__);
+    if (is_offload_usecase(out->usecase)) {
+        ALOGD("copl(%p):pause compress driver", out);
+        pthread_mutex_lock(&out->lock);
+        if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) {
+            struct audio_device *adev = out->dev;
+            int snd_scard_state = get_snd_card_state(adev);
+
+            if (SND_CARD_STATE_ONLINE == snd_scard_state)
+                status = compress_pause(out->compr);
+
+            out->offload_state = OFFLOAD_STATE_PAUSED;
+        }
+        pthread_mutex_unlock(&out->lock);
+    }
+    return status;
+}
+
+static int out_resume(struct audio_stream_out* stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int status = -ENOSYS;
+    ALOGV("%s", __func__);
+    if (is_offload_usecase(out->usecase)) {
+        ALOGD("copl(%p):resume compress driver", out);
+        status = 0;
+        pthread_mutex_lock(&out->lock);
+        if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) {
+            struct audio_device *adev = out->dev;
+            int snd_scard_state = get_snd_card_state(adev);
+
+            if (SND_CARD_STATE_ONLINE == snd_scard_state)
+                status = compress_resume(out->compr);
+
+            out->offload_state = OFFLOAD_STATE_PLAYING;
+        }
+        pthread_mutex_unlock(&out->lock);
+    }
+    return status;
+}
+
+static int out_drain(struct audio_stream_out* stream, audio_drain_type_t type )
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int status = -ENOSYS;
+    ALOGV("%s", __func__);
+    if (is_offload_usecase(out->usecase)) {
+        pthread_mutex_lock(&out->lock);
+        if (type == AUDIO_DRAIN_EARLY_NOTIFY)
+            status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN);
+        else
+            status = send_offload_cmd_l(out, OFFLOAD_CMD_DRAIN);
+        pthread_mutex_unlock(&out->lock);
+    }
+    return status;
+}
+
+static int out_flush(struct audio_stream_out* stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    ALOGV("%s", __func__);
+    if (is_offload_usecase(out->usecase)) {
+        ALOGD("copl(%p):calling compress flush", out);
+        pthread_mutex_lock(&out->lock);
+        stop_compressed_output_l(out);
+        pthread_mutex_unlock(&out->lock);
+        ALOGD("copl(%p):out of compress flush", out);
+        return 0;
+    }
+    return -ENOSYS;
+}
+
+/** audio_stream_in implementation **/
+static uint32_t in_get_sample_rate(const struct audio_stream *stream)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+
+    return in->config.rate;
+}
+
+static int in_set_sample_rate(struct audio_stream *stream __unused,
+                              uint32_t rate __unused)
+{
+    return -ENOSYS;
+}
+
+static size_t in_get_buffer_size(const struct audio_stream *stream)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+
+    if(in->usecase == USECASE_COMPRESS_VOIP_CALL)
+        return voice_extn_compress_voip_in_get_buffer_size(in);
+    else if(audio_extn_compr_cap_usecase_supported(in->usecase))
+        return audio_extn_compr_cap_get_buffer_size(in->config.format);
+
+    return in->config.period_size *
+                audio_stream_in_frame_size((const struct audio_stream_in *)stream);
+}
+
+static uint32_t in_get_channels(const struct audio_stream *stream)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+
+    return in->channel_mask;
+}
+
+static audio_format_t in_get_format(const struct audio_stream *stream)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+
+    return in->format;
+}
+
+static int in_set_format(struct audio_stream *stream __unused,
+                         audio_format_t format __unused)
+{
+    return -ENOSYS;
+}
+
+static int in_standby(struct audio_stream *stream)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    struct audio_device *adev = in->dev;
+    int status = 0;
+    ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
+          stream, in->usecase, use_case_table[in->usecase]);
+
+    if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
+        /* Ignore standby in case of voip call because the voip input
+         * stream is closed in adev_close_input_stream()
+         */
+        ALOGV("%s: Ignore Standby in VOIP call", __func__);
+        return status;
+    }
+
+    pthread_mutex_lock(&in->lock);
+    if (!in->standby && in->is_st_session) {
+        ALOGD("%s: sound trigger pcm stop lab", __func__);
+        audio_extn_sound_trigger_stop_lab(in);
+        in->standby = 1;
+    }
+
+    if (!in->standby) {
+        pthread_mutex_lock(&adev->lock);
+        in->standby = true;
+        if (in->pcm) {
+            pcm_close(in->pcm);
+            in->pcm = NULL;
+        }
+        status = stop_input_stream(in);
+        pthread_mutex_unlock(&adev->lock);
+    }
+    pthread_mutex_unlock(&in->lock);
+    ALOGV("%s: exit:  status(%d)", __func__, status);
+    return status;
+}
+
+static int in_dump(const struct audio_stream *stream __unused,
+                   int fd __unused)
+{
+    return 0;
+}
+
+static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    struct audio_device *adev = in->dev;
+    struct str_parms *parms;
+    char *str;
+    char value[32];
+    int ret = 0, val = 0, err;
+
+    ALOGD("%s: enter: kvpairs=%s", __func__, kvpairs);
+    parms = str_parms_create_str(kvpairs);
+
+    if (!parms)
+        goto error;
+    pthread_mutex_lock(&in->lock);
+    pthread_mutex_lock(&adev->lock);
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof(value));
+    if (err >= 0) {
+        val = atoi(value);
+        /* no audio source uses val == 0 */
+        if ((in->source != val) && (val != 0)) {
+            in->source = val;
+            if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) &&
+                (in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
+                (voice_extn_compress_voip_is_format_supported(in->format)) &&
+                (in->config.rate == 8000 || in->config.rate == 16000) &&
+                (audio_channel_count_from_in_mask(in->channel_mask) == 1)) {
+                err = voice_extn_compress_voip_open_input_stream(in);
+                if (err != 0) {
+                    ALOGE("%s: Compress voip input cannot be opened, error:%d",
+                          __func__, err);
+                }
+            }
+        }
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
+    if (err >= 0) {
+        val = atoi(value);
+        if (((int)in->device != val) && (val != 0)) {
+            in->device = val;
+            /* If recording is in progress, change the tx device to new device */
+            if (!in->standby && !in->is_st_session)
+                ret = select_devices(adev, in->usecase);
+        }
+    }
+
+done:
+    pthread_mutex_unlock(&adev->lock);
+    pthread_mutex_unlock(&in->lock);
+
+    str_parms_destroy(parms);
+error:
+    ALOGV("%s: exit: status(%d)", __func__, ret);
+    return ret;
+}
+
+static char* in_get_parameters(const struct audio_stream *stream,
+                               const char *keys)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    struct str_parms *query = str_parms_create_str(keys);
+    char *str;
+    char value[256];
+    struct str_parms *reply = str_parms_create();
+
+    if (!query || !reply) {
+        ALOGE("in_get_parameters: failed to create query or reply");
+        return NULL;
+    }
+
+    ALOGV("%s: enter: keys - %s", __func__, keys);
+
+    voice_extn_in_get_parameters(in, query, reply);
+
+    str = str_parms_to_str(reply);
+    str_parms_destroy(query);
+    str_parms_destroy(reply);
+
+    ALOGV("%s: exit: returns - %s", __func__, str);
+    return str;
+}
+
+static int in_set_gain(struct audio_stream_in *stream __unused,
+                       float gain __unused)
+{
+    return 0;
+}
+
+static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
+                       size_t bytes)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    struct audio_device *adev = in->dev;
+    int i, ret = -1;
+    int snd_scard_state = get_snd_card_state(adev);
+
+    pthread_mutex_lock(&in->lock);
+
+    if (in->pcm) {
+        if(SND_CARD_STATE_OFFLINE == snd_scard_state) {
+            ALOGD(" %s: sound card is not active/SSR state", __func__);
+            ret= -EIO;;
+            goto exit;
+        }
+    }
+
+    if (in->standby) {
+        if (!in->is_st_session) {
+            pthread_mutex_lock(&adev->lock);
+            if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
+                ret = voice_extn_compress_voip_start_input_stream(in);
+            else
+                ret = start_input_stream(in);
+            pthread_mutex_unlock(&adev->lock);
+            if (ret != 0) {
+                goto exit;
+            }
+        }
+        in->standby = 0;
+    }
+
+    if (in->pcm) {
+        if (audio_extn_ssr_get_enabled() &&
+                audio_channel_count_from_in_mask(in->channel_mask) == 6)
+            ret = audio_extn_ssr_read(stream, buffer, bytes);
+        else if (audio_extn_compr_cap_usecase_supported(in->usecase))
+            ret = audio_extn_compr_cap_read(in, buffer, bytes);
+        else if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY)
+            ret = pcm_mmap_read(in->pcm, buffer, bytes);
+        else
+            ret = pcm_read(in->pcm, buffer, bytes);
+        if (ret < 0)
+            ret = -errno;
+    }
+
+    /*
+     * Instead of writing zeroes here, we could trust the hardware
+     * to always provide zeroes when muted.
+     */
+    if (ret == 0 && voice_get_mic_mute(adev) && !voice_is_in_call_rec_stream(in))
+        memset(buffer, 0, bytes);
+
+exit:
+    /* ToDo: There may be a corner case when SSR happens back to back during
+       start/stop. Need to post different error to handle that. */
+    if (-ENETRESET == ret) {
+        set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
+    }
+    pthread_mutex_unlock(&in->lock);
+
+    if (ret != 0) {
+        if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
+            pthread_mutex_lock(&adev->lock);
+            voice_extn_compress_voip_close_input_stream(&in->stream.common);
+            pthread_mutex_unlock(&adev->lock);
+            in->standby = true;
+        }
+        memset(buffer, 0, bytes);
+        in_standby(&in->stream.common);
+        ALOGV("%s: read failed status %d- sleeping for buffer duration", __func__, ret);
+        usleep(bytes * 1000000 / audio_stream_in_frame_size(stream) /
+                                   in_get_sample_rate(&in->stream.common));
+    }
+    return bytes;
+}
+
+static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream __unused)
+{
+    return 0;
+}
+
+static int add_remove_audio_effect(const struct audio_stream *stream,
+                                   effect_handle_t effect,
+                                   bool enable)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    int status = 0;
+    effect_descriptor_t desc;
+
+    status = (*effect)->get_descriptor(effect, &desc);
+    if (status != 0)
+        return status;
+
+    pthread_mutex_lock(&in->lock);
+    pthread_mutex_lock(&in->dev->lock);
+    if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) &&
+            in->enable_aec != enable &&
+            (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0)) {
+        in->enable_aec = enable;
+        if (!in->standby)
+            select_devices(in->dev, in->usecase);
+    }
+    if (in->enable_ns != enable &&
+            (memcmp(&desc.type, FX_IID_NS, sizeof(effect_uuid_t)) == 0)) {
+        in->enable_ns = enable;
+        if (!in->standby)
+            select_devices(in->dev, in->usecase);
+    }
+    pthread_mutex_unlock(&in->dev->lock);
+    pthread_mutex_unlock(&in->lock);
+
+    return 0;
+}
+
+static int in_add_audio_effect(const struct audio_stream *stream,
+                               effect_handle_t effect)
+{
+    ALOGV("%s: effect %p", __func__, effect);
+    return add_remove_audio_effect(stream, effect, true);
+}
+
+static int in_remove_audio_effect(const struct audio_stream *stream,
+                                  effect_handle_t effect)
+{
+    ALOGV("%s: effect %p", __func__, effect);
+    return add_remove_audio_effect(stream, effect, false);
+}
+
+static int adev_open_output_stream(struct audio_hw_device *dev,
+                                   audio_io_handle_t handle,
+                                   audio_devices_t devices,
+                                   audio_output_flags_t flags,
+                                   struct audio_config *config,
+                                   struct audio_stream_out **stream_out,
+                                   const char *address __unused)
+{
+    struct audio_device *adev = (struct audio_device *)dev;
+    struct stream_out *out;
+    int i, ret = 0;
+    audio_format_t format;
+
+    *stream_out = NULL;
+
+    if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
+             (SND_CARD_STATE_OFFLINE == get_snd_card_state(adev))) {
+        ALOGE(" sound card is not active rejecting compress output open request");
+        return -EINVAL;
+    }
+
+    out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
+
+    ALOGD("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)\
+        stream_handle(%p)",__func__, config->sample_rate, config->channel_mask,
+        devices, flags, &out->stream);
+
+
+    if (!out) {
+        return -ENOMEM;
+    }
+
+    if (devices == AUDIO_DEVICE_NONE)
+        devices = AUDIO_DEVICE_OUT_SPEAKER;
+
+    out->flags = flags;
+    out->devices = devices;
+    out->dev = adev;
+    format = out->format = config->format;
+    out->sample_rate = config->sample_rate;
+    out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+    out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO;
+    out->handle = handle;
+    out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+
+    /* Init use case and pcm_config */
+    if ((out->flags == AUDIO_OUTPUT_FLAG_DIRECT) &&
+        (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL ||
+        out->devices & AUDIO_DEVICE_OUT_PROXY)) {
+
+        pthread_mutex_lock(&adev->lock);
+        if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
+            ret = read_hdmi_channel_masks(out);
+
+        if (out->devices & AUDIO_DEVICE_OUT_PROXY)
+            ret = audio_extn_read_afe_proxy_channel_masks(out);
+        pthread_mutex_unlock(&adev->lock);
+        if (ret != 0)
+            goto error_open;
+
+        if (config->sample_rate == 0)
+            config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+        if (config->channel_mask == 0)
+            config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
+
+        out->channel_mask = config->channel_mask;
+        out->sample_rate = config->sample_rate;
+        out->usecase = USECASE_AUDIO_PLAYBACK_MULTI_CH;
+        out->config = pcm_config_hdmi_multi;
+        out->config.rate = config->sample_rate;
+        out->config.channels = audio_channel_count_from_out_mask(out->channel_mask);
+        out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2);
+    } else if ((out->dev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
+               (out->flags == (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_VOIP_RX)) &&
+               (voice_extn_compress_voip_is_config_supported(config))) {
+        ret = voice_extn_compress_voip_open_output_stream(out);
+        if (ret != 0) {
+            ALOGE("%s: Compress voip output cannot be opened, error:%d",
+                  __func__, ret);
+            goto error_open;
+        }
+    } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+        if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version ||
+            config->offload_info.size != AUDIO_INFO_INITIALIZER.size) {
+            ALOGE("%s: Unsupported Offload information", __func__);
+            ret = -EINVAL;
+            goto error_open;
+        }
+        if (!is_supported_format(config->offload_info.format) &&
+                !audio_extn_is_dolby_format(config->offload_info.format)) {
+            ALOGE("%s: Unsupported audio format", __func__);
+            ret = -EINVAL;
+            goto error_open;
+        }
+
+        out->compr_config.codec = (struct snd_codec *)
+                                    calloc(1, sizeof(struct snd_codec));
+
+        if (!out->compr_config.codec) {
+            ret = -ENOMEM;
+            goto error_open;
+        }
+
+        out->usecase = get_offload_usecase(adev);
+        if (config->offload_info.channel_mask)
+            out->channel_mask = config->offload_info.channel_mask;
+        else if (config->channel_mask) {
+            out->channel_mask = config->channel_mask;
+            config->offload_info.channel_mask = config->channel_mask;
+        }
+        format = out->format = config->offload_info.format;
+        out->sample_rate = config->offload_info.sample_rate;
+
+        out->stream.set_callback = out_set_callback;
+        out->stream.pause = out_pause;
+        out->stream.resume = out_resume;
+        out->stream.drain = out_drain;
+        out->stream.flush = out_flush;
+        out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+
+        if (audio_extn_is_dolby_format(config->offload_info.format))
+            out->compr_config.codec->id =
+                audio_extn_dolby_get_snd_codec_id(adev, out,
+                                                  config->offload_info.format);
+        else
+            out->compr_config.codec->id =
+                get_snd_codec_id(config->offload_info.format);
+        if (audio_is_offload_pcm(config->offload_info.format)) {
+            out->compr_config.fragment_size =
+                       platform_get_pcm_offload_buffer_size(&config->offload_info);
+        } else {
+            out->compr_config.fragment_size =
+                       platform_get_compress_offload_buffer_size(&config->offload_info);
+        }
+        out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
+        out->compr_config.codec->sample_rate =
+                    compress_get_alsa_rate(config->offload_info.sample_rate);
+        out->compr_config.codec->bit_rate =
+                    config->offload_info.bit_rate;
+        out->compr_config.codec->ch_in =
+                audio_channel_count_from_out_mask(config->channel_mask);
+        out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
+        out->bit_width = PCM_OUTPUT_BIT_WIDTH;
+
+        if (config->offload_info.format == AUDIO_FORMAT_AAC)
+            out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
+        if (config->offload_info.format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD)
+            out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE;
+        if(config->offload_info.format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD)
+            out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE;
+
+        if (out->bit_width == 24) {
+            out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE;
+        }
+
+        if (config->offload_info.format == AUDIO_FORMAT_FLAC)
+            out->compr_config.codec->options.flac_dec.sample_size = PCM_OUTPUT_BIT_WIDTH;
+
+        if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
+            out->non_blocking = 1;
+
+        out->send_new_metadata = 1;
+        out->offload_state = OFFLOAD_STATE_IDLE;
+        out->playback_started = 0;
+
+        create_offload_callback_thread(out);
+        ALOGV("%s: offloaded output offload_info version %04x bit rate %d",
+                __func__, config->offload_info.version,
+                config->offload_info.bit_rate);
+        //Decide if we need to use gapless mode by default
+        check_and_set_gapless_mode(adev);
+
+    } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) {
+        ret = voice_check_and_set_incall_music_usecase(adev, out);
+        if (ret != 0) {
+            ALOGE("%s: Incall music delivery usecase cannot be set error:%d",
+                  __func__, ret);
+            goto error_open;
+        }
+    } else  if (out->devices == AUDIO_DEVICE_OUT_TELEPHONY_TX) {
+        if (config->sample_rate == 0)
+            config->sample_rate = AFE_PROXY_SAMPLING_RATE;
+        if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
+                config->sample_rate != 8000) {
+            config->sample_rate = AFE_PROXY_SAMPLING_RATE;
+            ret = -EINVAL;
+            goto error_open;
+        }
+        out->sample_rate = config->sample_rate;
+        out->config.rate = config->sample_rate;
+        if (config->format == AUDIO_FORMAT_DEFAULT)
+            config->format = AUDIO_FORMAT_PCM_16_BIT;
+        if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
+            config->format = AUDIO_FORMAT_PCM_16_BIT;
+            ret = -EINVAL;
+            goto error_open;
+        }
+        out->format = config->format;
+        out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY;
+        out->config = pcm_config_afe_proxy_playback;
+        adev->voice_tx_output = out;
+    } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
+        format = AUDIO_FORMAT_PCM_16_BIT;
+        out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
+        out->config = pcm_config_low_latency;
+        out->sample_rate = out->config.rate;
+    } else {
+        /* primary path is the default path selected if no other outputs are available/suitable */
+        format = AUDIO_FORMAT_PCM_16_BIT;
+        out->usecase = USECASE_AUDIO_PLAYBACK_PRIMARY;
+        out->config = pcm_config_deep_buffer;
+        out->sample_rate = out->config.rate;
+    }
+
+    ALOGV("%s devices %d,flags %x, format %x, out->sample_rate %d, out->bit_width %d",
+           __func__, devices, flags, format, out->sample_rate, out->bit_width);
+    audio_extn_utils_update_stream_app_type_cfg(adev->platform,
+                                                &adev->streams_output_cfg_list,
+                                                devices, flags, format, out->sample_rate,
+                                                out->bit_width, &out->app_type_cfg);
+    if ((out->usecase == USECASE_AUDIO_PLAYBACK_PRIMARY) ||
+        (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
+        /* Ensure the default output is not selected twice */
+        if(adev->primary_output == NULL)
+            adev->primary_output = out;
+        else {
+            ALOGE("%s: Primary output is already opened", __func__);
+            ret = -EEXIST;
+            goto error_open;
+        }
+    }
+
+    /* Check if this usecase is already existing */
+    pthread_mutex_lock(&adev->lock);
+    if ((get_usecase_from_list(adev, out->usecase) != NULL) &&
+        (out->usecase != USECASE_COMPRESS_VOIP_CALL)) {
+        ALOGE("%s: Usecase (%d) is already present", __func__, out->usecase);
+        pthread_mutex_unlock(&adev->lock);
+        ret = -EEXIST;
+        goto error_open;
+    }
+    pthread_mutex_unlock(&adev->lock);
+
+    out->stream.common.get_sample_rate = out_get_sample_rate;
+    out->stream.common.set_sample_rate = out_set_sample_rate;
+    out->stream.common.get_buffer_size = out_get_buffer_size;
+    out->stream.common.get_channels = out_get_channels;
+    out->stream.common.get_format = out_get_format;
+    out->stream.common.set_format = out_set_format;
+    out->stream.common.standby = out_standby;
+    out->stream.common.dump = out_dump;
+    out->stream.common.set_parameters = out_set_parameters;
+    out->stream.common.get_parameters = out_get_parameters;
+    out->stream.common.add_audio_effect = out_add_audio_effect;
+    out->stream.common.remove_audio_effect = out_remove_audio_effect;
+    out->stream.get_latency = out_get_latency;
+    out->stream.set_volume = out_set_volume;
+    out->stream.write = out_write;
+    out->stream.get_render_position = out_get_render_position;
+    out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
+    out->stream.get_presentation_position = out_get_presentation_position;
+
+    out->standby = 1;
+    /* out->muted = false; by calloc() */
+    /* out->written = 0; by calloc() */
+
+    pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
+    pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL);
+
+    config->format = out->stream.common.get_format(&out->stream.common);
+    config->channel_mask = out->stream.common.get_channels(&out->stream.common);
+    config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common);
+
+    *stream_out = &out->stream;
+    ALOGD("%s: Stream (%p) picks up usecase (%s)", __func__, &out->stream,
+        use_case_table[out->usecase]);
+    ALOGV("%s: exit", __func__);
+    return 0;
+
+error_open:
+    free(out);
+    *stream_out = NULL;
+    ALOGD("%s: exit: ret %d", __func__, ret);
+    return ret;
+}
+
+static void adev_close_output_stream(struct audio_hw_device *dev __unused,
+                                     struct audio_stream_out *stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    struct audio_device *adev = out->dev;
+    int ret = 0;
+
+    ALOGD("%s: enter:stream_handle(%p)",__func__, out);
+
+    if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
+        pthread_mutex_lock(&adev->lock);
+        ret = voice_extn_compress_voip_close_output_stream(&stream->common);
+        pthread_mutex_unlock(&adev->lock);
+        if(ret != 0)
+            ALOGE("%s: Compress voip output cannot be closed, error:%d",
+                  __func__, ret);
+    } else
+        out_standby(&stream->common);
+
+    if (is_offload_usecase(out->usecase)) {
+        destroy_offload_callback_thread(out);
+        free_offload_usecase(adev, out->usecase);
+        if (out->compr_config.codec != NULL)
+            free(out->compr_config.codec);
+    }
+
+    if (adev->voice_tx_output == out)
+        adev->voice_tx_output = NULL;
+
+    pthread_cond_destroy(&out->cond);
+    pthread_mutex_destroy(&out->lock);
+    free(stream);
+    ALOGV("%s: exit", __func__);
+}
+
+static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
+{
+    struct audio_device *adev = (struct audio_device *)dev;
+    struct str_parms *parms;
+    char *str;
+    char value[32];
+    int val;
+    int ret;
+    int status = 0;
+
+    ALOGD("%s: enter: %s", __func__, kvpairs);
+    parms = str_parms_create_str(kvpairs);
+
+    if (!parms)
+        goto error;
+    ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value));
+    if (ret >= 0) {
+        char *snd_card_status = value+2;
+        if (strstr(snd_card_status, "OFFLINE")) {
+            struct listnode *node;
+            struct audio_usecase *usecase;
+
+            ALOGD("Received sound card OFFLINE status");
+            set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
+
+            pthread_mutex_lock(&adev->lock);
+            //close compress session on OFFLINE status
+            usecase = get_usecase_from_list(adev,USECASE_AUDIO_PLAYBACK_OFFLOAD);
+            if (usecase && usecase->stream.out) {
+                ALOGD(" %s closing compress session on OFFLINE state", __func__);
+
+                struct stream_out *out = usecase->stream.out;
+
+                pthread_mutex_unlock(&adev->lock);
+                out_standby(&out->stream.common);
+            } else
+                pthread_mutex_unlock(&adev->lock);
+        } else if (strstr(snd_card_status, "ONLINE")) {
+            ALOGD("Received sound card ONLINE status");
+            set_snd_card_state(adev,SND_CARD_STATE_ONLINE);
+            if (!platform_is_acdb_initialized(adev->platform)) {
+                ret = platform_acdb_init(adev->platform);
+                if(ret)
+                   ALOGE("acdb initialization is failed");
+
+            }
+        }
+    }
+
+    pthread_mutex_lock(&adev->lock);
+    status = voice_set_parameters(adev, parms);
+    if (status != 0)
+        goto done;
+
+    status = platform_set_parameters(adev->platform, parms);
+    if (status != 0)
+        goto done;
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value));
+    if (ret >= 0) {
+        /* When set to false, HAL should disable EC and NS */
+        if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
+            adev->bluetooth_nrec = true;
+        else
+            adev->bluetooth_nrec = false;
+    }
+
+    ret = str_parms_get_str(parms, "screen_state", value, sizeof(value));
+    if (ret >= 0) {
+        if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
+            adev->screen_off = false;
+        else
+            adev->screen_off = true;
+    }
+
+    ret = str_parms_get_int(parms, "rotation", &val);
+    if (ret >= 0) {
+        bool reverse_speakers = false;
+        switch(val) {
+        // FIXME: note that the code below assumes that the speakers are in the correct placement
+        //   relative to the user when the device is rotated 90deg from its default rotation. This
+        //   assumption is device-specific, not platform-specific like this code.
+        case 270:
+            reverse_speakers = true;
+            break;
+        case 0:
+        case 90:
+        case 180:
+            break;
+        default:
+            ALOGE("%s: unexpected rotation of %d", __func__, val);
+            status = -EINVAL;
+        }
+        if (status == 0) {
+            if (adev->speaker_lr_swap != reverse_speakers) {
+                adev->speaker_lr_swap = reverse_speakers;
+                // only update the selected device if there is active pcm playback
+                struct audio_usecase *usecase;
+                struct listnode *node;
+                list_for_each(node, &adev->usecase_list) {
+                    usecase = node_to_item(node, struct audio_usecase, list);
+                    if (usecase->type == PCM_PLAYBACK) {
+                        select_devices(adev, usecase->id);
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_SCO_WB, value, sizeof(value));
+    if (ret >= 0) {
+        if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
+            adev->bt_wb_speech_enabled = true;
+        else
+            adev->bt_wb_speech_enabled = false;
+    }
+
+    audio_extn_set_parameters(adev, parms);
+
+done:
+    str_parms_destroy(parms);
+    pthread_mutex_unlock(&adev->lock);
+error:
+    ALOGV("%s: exit with code(%d)", __func__, status);
+    return status;
+}
+
+static char* adev_get_parameters(const struct audio_hw_device *dev,
+                                 const char *keys)
+{
+    struct audio_device *adev = (struct audio_device *)dev;
+    struct str_parms *reply = str_parms_create();
+    struct str_parms *query = str_parms_create_str(keys);
+    char *str;
+    char value[256] = {0};
+    int ret = 0;
+
+    if (!query || !reply) {
+        ALOGE("adev_get_parameters: failed to create query or reply");
+        return NULL;
+    }
+
+    ret = str_parms_get_str(query, "SND_CARD_STATUS", value,
+                            sizeof(value));
+    if (ret >=0) {
+        int val = 1;
+        pthread_mutex_lock(&adev->snd_card_status.lock);
+        if (SND_CARD_STATE_OFFLINE == adev->snd_card_status.state)
+            val = 0;
+        pthread_mutex_unlock(&adev->snd_card_status.lock);
+        str_parms_add_int(reply, "SND_CARD_STATUS", val);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&adev->lock);
+    audio_extn_get_parameters(adev, query, reply);
+    voice_get_parameters(adev, query, reply);
+    platform_get_parameters(adev->platform, query, reply);
+    pthread_mutex_unlock(&adev->lock);
+
+exit:
+    str = str_parms_to_str(reply);
+    str_parms_destroy(query);
+    str_parms_destroy(reply);
+
+    ALOGV("%s: exit: returns - %s", __func__, str);
+    return str;
+}
+
+static int adev_init_check(const struct audio_hw_device *dev __unused)
+{
+    return 0;
+}
+
+static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
+{
+    int ret;
+    struct audio_device *adev = (struct audio_device *)dev;
+    pthread_mutex_lock(&adev->lock);
+    /* cache volume */
+    ret = voice_set_volume(adev, volume);
+    pthread_mutex_unlock(&adev->lock);
+    return ret;
+}
+
+static int adev_set_master_volume(struct audio_hw_device *dev __unused,
+                                  float volume __unused)
+{
+    return -ENOSYS;
+}
+
+static int adev_get_master_volume(struct audio_hw_device *dev __unused,
+                                  float *volume __unused)
+{
+    return -ENOSYS;
+}
+
+static int adev_set_master_mute(struct audio_hw_device *dev __unused,
+                                bool muted __unused)
+{
+    return -ENOSYS;
+}
+
+static int adev_get_master_mute(struct audio_hw_device *dev __unused,
+                                bool *muted __unused)
+{
+    return -ENOSYS;
+}
+
+static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
+{
+    struct audio_device *adev = (struct audio_device *)dev;
+
+    pthread_mutex_lock(&adev->lock);
+    if (adev->mode != mode) {
+        ALOGD("%s: mode %d\n", __func__, mode);
+        adev->mode = mode;
+        if ((mode == AUDIO_MODE_NORMAL || mode == AUDIO_MODE_IN_COMMUNICATION) &&
+                voice_is_in_call(adev)) {
+            voice_stop_call(adev);
+            adev->current_call_output = NULL;
+        }
+    }
+    pthread_mutex_unlock(&adev->lock);
+    return 0;
+}
+
+static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
+{
+    int ret;
+
+    pthread_mutex_lock(&adev->lock);
+    ALOGD("%s state %d\n", __func__, state);
+    ret = voice_set_mic_mute((struct audio_device *)dev, state);
+    pthread_mutex_unlock(&adev->lock);
+
+    return ret;
+}
+
+static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
+{
+    *state = voice_get_mic_mute((struct audio_device *)dev);
+    return 0;
+}
+
+static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev __unused,
+                                         const struct audio_config *config)
+{
+    int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
+
+    return get_input_buffer_size(config->sample_rate, config->format, channel_count,
+            false /* is_low_latency: since we don't know, be conservative */);
+}
+
+static int adev_open_input_stream(struct audio_hw_device *dev,
+                                  audio_io_handle_t handle __unused,
+                                  audio_devices_t devices,
+                                  struct audio_config *config,
+                                  struct audio_stream_in **stream_in,
+                                  audio_input_flags_t flags __unused,
+                                  const char *address __unused,
+                                  audio_source_t source __unused)
+{
+    struct audio_device *adev = (struct audio_device *)dev;
+    struct stream_in *in;
+    int ret = 0, buffer_size, frame_size;
+    int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
+    bool is_low_latency = false;
+
+    *stream_in = NULL;
+    if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0)
+        return -EINVAL;
+
+    in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
+
+    if (!in) {
+        ALOGE("failed to allocate input stream");
+        return -ENOMEM;
+    }
+
+    ALOGD("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x)\
+        stream_handle(%p) io_handle(%d)",__func__, config->sample_rate, config->channel_mask,
+        devices, &in->stream, handle);
+
+    pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL);
+
+    in->stream.common.get_sample_rate = in_get_sample_rate;
+    in->stream.common.set_sample_rate = in_set_sample_rate;
+    in->stream.common.get_buffer_size = in_get_buffer_size;
+    in->stream.common.get_channels = in_get_channels;
+    in->stream.common.get_format = in_get_format;
+    in->stream.common.set_format = in_set_format;
+    in->stream.common.standby = in_standby;
+    in->stream.common.dump = in_dump;
+    in->stream.common.set_parameters = in_set_parameters;
+    in->stream.common.get_parameters = in_get_parameters;
+    in->stream.common.add_audio_effect = in_add_audio_effect;
+    in->stream.common.remove_audio_effect = in_remove_audio_effect;
+    in->stream.set_gain = in_set_gain;
+    in->stream.read = in_read;
+    in->stream.get_input_frames_lost = in_get_input_frames_lost;
+
+    in->device = devices;
+    in->source = AUDIO_SOURCE_DEFAULT;
+    in->dev = adev;
+    in->standby = 1;
+    in->channel_mask = config->channel_mask;
+    in->capture_handle = handle;
+
+    /* Update config params with the requested sample rate and channels */
+    in->usecase = USECASE_AUDIO_RECORD;
+    if (config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE &&
+            (flags & AUDIO_INPUT_FLAG_FAST) != 0) {
+        is_low_latency = true;
+#if LOW_LATENCY_CAPTURE_USE_CASE
+        in->usecase = USECASE_AUDIO_RECORD_LOW_LATENCY;
+#endif
+    }
+    in->config = pcm_config_audio_capture;
+    in->config.rate = config->sample_rate;
+    in->format = config->format;
+
+    if (in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) {
+        if (config->sample_rate == 0)
+            config->sample_rate = AFE_PROXY_SAMPLING_RATE;
+        if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
+                config->sample_rate != 8000) {
+            config->sample_rate = AFE_PROXY_SAMPLING_RATE;
+            ret = -EINVAL;
+            goto err_open;
+        }
+        if (config->format == AUDIO_FORMAT_DEFAULT)
+            config->format = AUDIO_FORMAT_PCM_16_BIT;
+        if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
+            config->format = AUDIO_FORMAT_PCM_16_BIT;
+            ret = -EINVAL;
+            goto err_open;
+        }
+
+        in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY;
+        in->config = pcm_config_afe_proxy_record;
+        in->config.channels = channel_count;
+        in->config.rate = config->sample_rate;
+    } else if (channel_count == 6) {
+        if(audio_extn_ssr_get_enabled()) {
+            if(audio_extn_ssr_init(in)) {
+                ALOGE("%s: audio_extn_ssr_init failed", __func__);
+                ret = -EINVAL;
+                goto err_open;
+            }
+        } else {
+            ALOGW("%s: surround sound recording is not supported", __func__);
+        }
+    } else if (audio_extn_compr_cap_enabled() &&
+            audio_extn_compr_cap_format_supported(config->format) &&
+            (in->dev->mode != AUDIO_MODE_IN_COMMUNICATION)) {
+        audio_extn_compr_cap_init(in);
+    } else {
+        in->config.channels = channel_count;
+        frame_size = audio_stream_in_frame_size(&in->stream);
+        buffer_size = get_input_buffer_size(config->sample_rate,
+                                            config->format,
+                                            channel_count,
+                                            is_low_latency);
+        in->config.period_size = buffer_size / frame_size;
+    }
+
+    /* This stream could be for sound trigger lab,
+       get sound trigger pcm if present */
+    audio_extn_sound_trigger_check_and_get_session(in);
+    audio_extn_perf_lock_init();
+
+    *stream_in = &in->stream;
+    ALOGV("%s: exit", __func__);
+    return ret;
+
+err_open:
+    free(in);
+    *stream_in = NULL;
+    return ret;
+}
+
+static void adev_close_input_stream(struct audio_hw_device *dev,
+                                    struct audio_stream_in *stream)
+{
+    int ret;
+    struct stream_in *in = (struct stream_in *)stream;
+    struct audio_device *adev = (struct audio_device *)dev;
+
+    ALOGD("%s: enter:stream_handle(%p)",__func__, in);
+
+    /* Disable echo reference while closing input stream */
+    platform_set_echo_reference(adev->platform, false);
+
+    if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
+        pthread_mutex_lock(&adev->lock);
+        ret = voice_extn_compress_voip_close_input_stream(&stream->common);
+        pthread_mutex_unlock(&adev->lock);
+        if (ret != 0)
+            ALOGE("%s: Compress voip input cannot be closed, error:%d",
+                  __func__, ret);
+    } else
+        in_standby(&stream->common);
+
+    if (audio_extn_ssr_get_enabled() && 
+            (audio_channel_count_from_in_mask(in->channel_mask) == 6)) {
+        audio_extn_ssr_deinit();
+    }
+
+    if(audio_extn_compr_cap_enabled() &&
+            audio_extn_compr_cap_format_supported(in->config.format))
+        audio_extn_compr_cap_deinit();
+
+    free(stream);
+    return;
+}
+
+static int adev_dump(const audio_hw_device_t *device __unused,
+                     int fd __unused)
+{
+    return 0;
+}
+
+static int adev_close(hw_device_t *device)
+{
+    struct audio_device *adev = (struct audio_device *)device;
+
+    if (!adev)
+        return 0;
+
+    pthread_mutex_lock(&adev_init_lock);
+
+    if ((--audio_device_ref_count) == 0) {
+        audio_extn_sound_trigger_deinit(adev);
+        audio_extn_listen_deinit(adev);
+        audio_extn_utils_release_streams_output_cfg_list(&adev->streams_output_cfg_list);
+        audio_route_free(adev->audio_route);
+        free(adev->snd_dev_ref_cnt);
+        platform_deinit(adev->platform);
+        free(device);
+        adev = NULL;
+    }
+    pthread_mutex_unlock(&adev_init_lock);
+    return 0;
+}
+
+/* This returns 1 if the input parameter looks at all plausible as a low latency period size,
+ * or 0 otherwise.  A return value of 1 doesn't mean the value is guaranteed to work,
+ * just that it _might_ work.
+ */
+static int period_size_is_plausible_for_low_latency(int period_size)
+{
+    switch (period_size) {
+    case 160:
+    case 240:
+    case 320:
+    case 480:
+        return 1;
+    default:
+        return 0;
+    }
+}
+
+static int adev_open(const hw_module_t *module, const char *name,
+                     hw_device_t **device)
+{
+    int i, ret;
+
+    ALOGD("%s: enter", __func__);
+    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) return -EINVAL;
+
+    pthread_mutex_lock(&adev_init_lock);
+    if (audio_device_ref_count != 0){
+            *device = &adev->device.common;
+            audio_device_ref_count++;
+            ALOGD("%s: returning existing instance of adev", __func__);
+            ALOGD("%s: exit", __func__);
+            pthread_mutex_unlock(&adev_init_lock);
+            return 0;
+    }
+
+    adev = calloc(1, sizeof(struct audio_device));
+
+    if (!adev) {
+        pthread_mutex_unlock(&adev_init_lock);
+        return -ENOMEM;
+    }
+
+    pthread_mutex_init(&adev->lock, (const pthread_mutexattr_t *) NULL);
+
+    adev->device.common.tag = HARDWARE_DEVICE_TAG;
+    adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
+    adev->device.common.module = (struct hw_module_t *)module;
+    adev->device.common.close = adev_close;
+
+    adev->device.init_check = adev_init_check;
+    adev->device.set_voice_volume = adev_set_voice_volume;
+    adev->device.set_master_volume = adev_set_master_volume;
+    adev->device.get_master_volume = adev_get_master_volume;
+    adev->device.set_master_mute = adev_set_master_mute;
+    adev->device.get_master_mute = adev_get_master_mute;
+    adev->device.set_mode = adev_set_mode;
+    adev->device.set_mic_mute = adev_set_mic_mute;
+    adev->device.get_mic_mute = adev_get_mic_mute;
+    adev->device.set_parameters = adev_set_parameters;
+    adev->device.get_parameters = adev_get_parameters;
+    adev->device.get_input_buffer_size = adev_get_input_buffer_size;
+    adev->device.open_output_stream = adev_open_output_stream;
+    adev->device.close_output_stream = adev_close_output_stream;
+    adev->device.open_input_stream = adev_open_input_stream;
+    adev->device.close_input_stream = adev_close_input_stream;
+    adev->device.dump = adev_dump;
+
+    /* Set the default route before the PCM stream is opened */
+    adev->mode = AUDIO_MODE_NORMAL;
+    adev->active_input = NULL;
+    adev->primary_output = NULL;
+    adev->out_device = AUDIO_DEVICE_NONE;
+    adev->bluetooth_nrec = true;
+    adev->acdb_settings = TTY_MODE_OFF;
+    /* adev->cur_hdmi_channels = 0;  by calloc() */
+    adev->cur_codec_backend_samplerate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    adev->cur_codec_backend_bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+    adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int));
+    voice_init(adev);
+    list_init(&adev->usecase_list);
+    adev->cur_wfd_channels = 2;
+    adev->offload_usecases_state = 0;
+
+    pthread_mutex_init(&adev->snd_card_status.lock, (const pthread_mutexattr_t *) NULL);
+    adev->snd_card_status.state = SND_CARD_STATE_OFFLINE;
+    /* Loads platform specific libraries dynamically */
+    adev->platform = platform_init(adev);
+    if (!adev->platform) {
+        free(adev->snd_dev_ref_cnt);
+        free(adev);
+        ALOGE("%s: Failed to init platform data, aborting.", __func__);
+        *device = NULL;
+        pthread_mutex_unlock(&adev_init_lock);
+        return -EINVAL;
+    }
+
+    adev->snd_card_status.state = SND_CARD_STATE_ONLINE;
+
+    if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) {
+        adev->visualizer_lib = dlopen(VISUALIZER_LIBRARY_PATH, RTLD_NOW);
+        if (adev->visualizer_lib == NULL) {
+            ALOGE("%s: DLOPEN failed for %s", __func__, VISUALIZER_LIBRARY_PATH);
+        } else {
+            ALOGV("%s: DLOPEN successful for %s", __func__, VISUALIZER_LIBRARY_PATH);
+            adev->visualizer_start_output =
+                        (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
+                                                        "visualizer_hal_start_output");
+            adev->visualizer_stop_output =
+                        (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
+                                                        "visualizer_hal_stop_output");
+        }
+    }
+    audio_extn_listen_init(adev, adev->snd_card);
+    audio_extn_sound_trigger_init(adev);
+
+    if (access(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, R_OK) == 0) {
+        adev->offload_effects_lib = dlopen(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, RTLD_NOW);
+        if (adev->offload_effects_lib == NULL) {
+            ALOGE("%s: DLOPEN failed for %s", __func__,
+                  OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
+        } else {
+            ALOGV("%s: DLOPEN successful for %s", __func__,
+                  OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
+            adev->offload_effects_start_output =
+                        (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
+                                         "offload_effects_bundle_hal_start_output");
+            adev->offload_effects_stop_output =
+                        (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
+                                         "offload_effects_bundle_hal_stop_output");
+        }
+    }
+
+    adev->bt_wb_speech_enabled = false;
+
+    audio_extn_ds2_enable(adev);
+    *device = &adev->device.common;
+
+    audio_extn_utils_update_streams_output_cfg_list(adev->platform, adev->mixer,
+                                                    &adev->streams_output_cfg_list);
+
+    audio_device_ref_count++;
+
+    char value[PROPERTY_VALUE_MAX];
+    int trial;
+    if (property_get("audio_hal.period_size", value, NULL) > 0) {
+        trial = atoi(value);
+        if (period_size_is_plausible_for_low_latency(trial)) {
+            pcm_config_low_latency.period_size = trial;
+            pcm_config_low_latency.start_threshold = trial / 4;
+            pcm_config_low_latency.avail_min = trial / 4;
+            configured_low_latency_capture_period_size = trial;
+        }
+    }
+    if (property_get("audio_hal.in_period_size", value, NULL) > 0) {
+        trial = atoi(value);
+        if (period_size_is_plausible_for_low_latency(trial)) {
+            configured_low_latency_capture_period_size = trial;
+        }
+    }
+
+    pthread_mutex_unlock(&adev_init_lock);
+
+    ALOGV("%s: exit", __func__);
+    return 0;
+}
+
+static struct hw_module_methods_t hal_module_methods = {
+    .open = adev_open,
+};
+
+struct audio_module HAL_MODULE_INFO_SYM = {
+    .common = {
+        .tag = HARDWARE_MODULE_TAG,
+        .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
+        .hal_api_version = HARDWARE_HAL_API_VERSION,
+        .id = AUDIO_HARDWARE_MODULE_ID,
+        .name = "QCOM Audio HAL",
+        .author = "The Linux Foundation",
+        .methods = &hal_module_methods,
+    },
+};
diff --git a/msm8909/hal/audio_hw.h b/msm8909/hal/audio_hw.h
new file mode 100644
index 0000000..d05f743
--- /dev/null
+++ b/msm8909/hal/audio_hw.h
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef QCOM_AUDIO_HW_H
+#define QCOM_AUDIO_HW_H
+
+#include <cutils/list.h>
+#include <hardware/audio.h>
+#include <tinyalsa/asoundlib.h>
+#include <tinycompress/tinycompress.h>
+
+#include <audio_route/audio_route.h>
+#include "audio_defs.h"
+#include "voice.h"
+
+#define VISUALIZER_LIBRARY_PATH "/system/lib/soundfx/libqcomvisualizer.so"
+#define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/system/lib/soundfx/libqcompostprocbundle.so"
+
+/* Flags used to initialize acdb_settings variable that goes to ACDB library */
+#define NONE_FLAG            0x00000000
+#define ANC_FLAG	     0x00000001
+#define DMIC_FLAG            0x00000002
+#define QMIC_FLAG            0x00000004
+#define TTY_MODE_OFF         0x00000010
+#define TTY_MODE_FULL        0x00000020
+#define TTY_MODE_VCO         0x00000040
+#define TTY_MODE_HCO         0x00000080
+#define TTY_MODE_CLEAR       0xFFFFFF0F
+#define FLUENCE_MODE_CLEAR   0xFFFFFFF0
+
+#define ACDB_DEV_TYPE_OUT 1
+#define ACDB_DEV_TYPE_IN 2
+
+#define MAX_SUPPORTED_CHANNEL_MASKS 2
+#define DEFAULT_HDMI_OUT_CHANNELS   2
+
+#define SND_CARD_STATE_OFFLINE 0
+#define SND_CARD_STATE_ONLINE 1
+typedef int snd_device_t;
+
+/* These are the supported use cases by the hardware.
+ * Each usecase is mapped to a specific PCM device.
+ * Refer to pcm_device_table[].
+ */
+enum {
+    USECASE_INVALID = -1,
+    /* Playback usecases */
+    USECASE_AUDIO_PLAYBACK_DEEP_BUFFER = 0,
+    USECASE_AUDIO_PLAYBACK_LOW_LATENCY,
+    USECASE_AUDIO_PLAYBACK_MULTI_CH,
+    USECASE_AUDIO_PLAYBACK_OFFLOAD,
+#ifdef MULTIPLE_OFFLOAD_ENABLED
+    USECASE_AUDIO_PLAYBACK_OFFLOAD2,
+    USECASE_AUDIO_PLAYBACK_OFFLOAD3,
+    USECASE_AUDIO_PLAYBACK_OFFLOAD4,
+    USECASE_AUDIO_PLAYBACK_OFFLOAD5,
+    USECASE_AUDIO_PLAYBACK_OFFLOAD6,
+    USECASE_AUDIO_PLAYBACK_OFFLOAD7,
+    USECASE_AUDIO_PLAYBACK_OFFLOAD8,
+    USECASE_AUDIO_PLAYBACK_OFFLOAD9,
+#endif
+
+    /* FM usecase */
+    USECASE_AUDIO_PLAYBACK_FM,
+
+    /* HFP Use case*/
+    USECASE_AUDIO_HFP_SCO,
+    USECASE_AUDIO_HFP_SCO_WB,
+
+    /* Capture usecases */
+    USECASE_AUDIO_RECORD,
+    USECASE_AUDIO_RECORD_COMPRESS,
+    USECASE_AUDIO_RECORD_LOW_LATENCY,
+    USECASE_AUDIO_RECORD_FM_VIRTUAL,
+
+    /* Voice usecase */
+    USECASE_VOICE_CALL,
+
+    /* Voice extension usecases */
+    USECASE_VOICE2_CALL,
+    USECASE_VOLTE_CALL,
+    USECASE_QCHAT_CALL,
+    USECASE_VOWLAN_CALL,
+    USECASE_COMPRESS_VOIP_CALL,
+
+    USECASE_INCALL_REC_UPLINK,
+    USECASE_INCALL_REC_DOWNLINK,
+    USECASE_INCALL_REC_UPLINK_AND_DOWNLINK,
+    USECASE_INCALL_REC_UPLINK_COMPRESS,
+    USECASE_INCALL_REC_DOWNLINK_COMPRESS,
+    USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS,
+
+    USECASE_INCALL_MUSIC_UPLINK,
+    USECASE_INCALL_MUSIC_UPLINK2,
+
+    USECASE_AUDIO_SPKR_CALIB_RX,
+    USECASE_AUDIO_SPKR_CALIB_TX,
+
+    USECASE_AUDIO_PLAYBACK_AFE_PROXY,
+    USECASE_AUDIO_RECORD_AFE_PROXY,
+
+    AUDIO_USECASE_MAX
+};
+
+const char * const use_case_table[AUDIO_USECASE_MAX];
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+/*
+ * tinyAlsa library interprets period size as number of frames
+ * one frame = channel_count * sizeof (pcm sample)
+ * so if format = 16-bit PCM and channels = Stereo, frame size = 2 ch * 2 = 4 bytes
+ * DEEP_BUFFER_OUTPUT_PERIOD_SIZE = 1024 means 1024 * 4 = 4096 bytes
+ * We should take care of returning proper size when AudioFlinger queries for
+ * the buffer size of an input/output stream
+ */
+
+enum {
+    OFFLOAD_CMD_EXIT,               /* exit compress offload thread loop*/
+    OFFLOAD_CMD_DRAIN,              /* send a full drain request to DSP */
+    OFFLOAD_CMD_PARTIAL_DRAIN,      /* send a partial drain request to DSP */
+    OFFLOAD_CMD_WAIT_FOR_BUFFER,    /* wait for buffer released by DSP */
+};
+
+enum {
+    OFFLOAD_STATE_IDLE,
+    OFFLOAD_STATE_PLAYING,
+    OFFLOAD_STATE_PAUSED,
+};
+
+struct offload_cmd {
+    struct listnode node;
+    int cmd;
+    int data[];
+};
+
+struct stream_app_type_cfg {
+    int sample_rate;
+    uint32_t bit_width;
+    int app_type;
+};
+
+struct stream_out {
+    struct audio_stream_out stream;
+    pthread_mutex_t lock; /* see note below on mutex acquisition order */
+    pthread_cond_t  cond;
+    struct pcm_config config;
+    struct compr_config compr_config;
+    struct pcm *pcm;
+    struct compress *compr;
+    int standby;
+    int pcm_device_id;
+    unsigned int sample_rate;
+    audio_channel_mask_t channel_mask;
+    audio_format_t format;
+    audio_devices_t devices;
+    audio_output_flags_t flags;
+    audio_usecase_t usecase;
+    /* Array of supported channel mask configurations. +1 so that the last entry is always 0 */
+    audio_channel_mask_t supported_channel_masks[MAX_SUPPORTED_CHANNEL_MASKS + 1];
+    bool muted;
+    uint64_t written; /* total frames written, not cleared when entering standby */
+    audio_io_handle_t handle;
+    struct stream_app_type_cfg app_type_cfg;
+
+    int non_blocking;
+    int playback_started;
+    int offload_state;
+    pthread_cond_t offload_cond;
+    pthread_t offload_thread;
+    struct listnode offload_cmd_list;
+    bool offload_thread_blocked;
+
+    stream_callback_t offload_callback;
+    void *offload_cookie;
+    struct compr_gapless_mdata gapless_mdata;
+    int send_new_metadata;
+    unsigned int bit_width;
+
+    struct audio_device *dev;
+};
+
+struct stream_in {
+    struct audio_stream_in stream;
+    pthread_mutex_t lock; /* see note below on mutex acquisition order */
+    struct pcm_config config;
+    struct pcm *pcm;
+    int standby;
+    int source;
+    int pcm_device_id;
+    audio_devices_t device;
+    audio_channel_mask_t channel_mask;
+    audio_usecase_t usecase;
+    bool enable_aec;
+    bool enable_ns;
+    audio_format_t format;
+    audio_io_handle_t capture_handle;
+    bool is_st_session;
+
+    struct audio_device *dev;
+};
+
+typedef enum {
+    PCM_PLAYBACK,
+    PCM_CAPTURE,
+    VOICE_CALL,
+    VOIP_CALL,
+    PCM_HFP_CALL
+} usecase_type_t;
+
+union stream_ptr {
+    struct stream_in *in;
+    struct stream_out *out;
+};
+
+struct audio_usecase {
+    struct listnode list;
+    audio_usecase_t id;
+    usecase_type_t  type;
+    audio_devices_t devices;
+    snd_device_t out_snd_device;
+    snd_device_t in_snd_device;
+    union stream_ptr stream;
+};
+
+struct sound_card_status {
+    pthread_mutex_t lock;
+    int state;
+};
+
+struct stream_format {
+    struct listnode list;
+    audio_format_t format;
+};
+
+struct stream_sample_rate {
+    struct listnode list;
+    uint32_t sample_rate;
+};
+
+struct streams_output_cfg {
+    struct listnode list;
+    audio_output_flags_t flags;
+    struct listnode format_list;
+    struct listnode sample_rate_list;
+    struct stream_app_type_cfg app_type_cfg;
+};
+
+struct audio_device {
+    struct audio_hw_device device;
+    pthread_mutex_t lock; /* see note below on mutex acquisition order */
+    struct mixer *mixer;
+    audio_mode_t mode;
+    audio_devices_t out_device;
+    struct stream_in *active_input;
+    struct stream_out *primary_output;
+    struct stream_out *voice_tx_output;
+    struct stream_out *current_call_output;
+    bool bluetooth_nrec;
+    bool screen_off;
+    int *snd_dev_ref_cnt;
+    struct listnode usecase_list;
+    struct listnode streams_output_cfg_list;
+    struct audio_route *audio_route;
+    int acdb_settings;
+    bool speaker_lr_swap;
+    struct voice voice;
+    unsigned int cur_hdmi_channels;
+    unsigned int cur_wfd_channels;
+    bool bt_wb_speech_enabled;
+
+    int snd_card;
+    unsigned int cur_codec_backend_samplerate;
+    unsigned int cur_codec_backend_bit_width;
+    void *platform;
+    unsigned int offload_usecases_state;
+    void *visualizer_lib;
+    int (*visualizer_start_output)(audio_io_handle_t, int);
+    int (*visualizer_stop_output)(audio_io_handle_t, int);
+    void *offload_effects_lib;
+    int (*offload_effects_start_output)(audio_io_handle_t, int);
+    int (*offload_effects_stop_output)(audio_io_handle_t, int);
+
+    struct sound_card_status snd_card_status;
+};
+
+int select_devices(struct audio_device *adev,
+                          audio_usecase_t uc_id);
+int disable_audio_route(struct audio_device *adev,
+                        struct audio_usecase *usecase);
+int disable_snd_device(struct audio_device *adev,
+                       snd_device_t snd_device);
+int enable_snd_device(struct audio_device *adev,
+                      snd_device_t snd_device);
+
+int enable_audio_route(struct audio_device *adev,
+                       struct audio_usecase *usecase);
+
+struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
+                                                   audio_usecase_t uc_id);
+
+bool is_offload_usecase(audio_usecase_t uc_id);
+
+int pcm_ioctl(struct pcm *pcm, int request, ...);
+
+int get_snd_card_state(struct audio_device *adev);
+
+#define LITERAL_TO_STRING(x) #x
+#define CHECK(condition) LOG_ALWAYS_FATAL_IF(!(condition), "%s",\
+            __FILE__ ":" LITERAL_TO_STRING(__LINE__)\
+            " ASSERT_FATAL(" #condition ") failed.")
+
+/*
+ * NOTE: when multiple mutexes have to be acquired, always take the
+ * stream_in or stream_out mutex first, followed by the audio_device mutex.
+ */
+
+#endif // QCOM_AUDIO_HW_H
diff --git a/msm8909/hal/msm8916/hw_info.c b/msm8909/hal/msm8916/hw_info.c
new file mode 100644
index 0000000..6778e65
--- /dev/null
+++ b/msm8909/hal/msm8916/hw_info.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2014, 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 "hardware_info"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+
+
+struct hardware_info {
+    char name[HW_INFO_ARRAY_MAX_SIZE];
+    char type[HW_INFO_ARRAY_MAX_SIZE];
+    /* variables for handling target variants */
+    uint32_t num_snd_devices;
+    char dev_extn[HW_INFO_ARRAY_MAX_SIZE];
+    snd_device_t  *snd_devices;
+};
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+static const snd_device_t taiko_fluid_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+};
+
+static const snd_device_t taiko_CDP_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+    SND_DEVICE_IN_QUAD_MIC,
+};
+
+static const snd_device_t taiko_apq8084_CDP_variant_devices[] = {
+    SND_DEVICE_IN_HANDSET_MIC,
+};
+
+static const snd_device_t taiko_liquid_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+    SND_DEVICE_IN_SPEAKER_MIC,
+    SND_DEVICE_IN_HEADSET_MIC,
+    SND_DEVICE_IN_VOICE_DMIC,
+    SND_DEVICE_IN_VOICE_SPEAKER_DMIC,
+    SND_DEVICE_IN_VOICE_REC_DMIC_STEREO,
+    SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
+    SND_DEVICE_IN_QUAD_MIC,
+    SND_DEVICE_IN_HANDSET_STEREO_DMIC,
+    SND_DEVICE_IN_SPEAKER_STEREO_DMIC,
+};
+
+static const snd_device_t taiko_DB_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+    SND_DEVICE_IN_SPEAKER_MIC,
+    SND_DEVICE_IN_HEADSET_MIC,
+    SND_DEVICE_IN_QUAD_MIC,
+};
+
+static const snd_device_t tapan_lite_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
+};
+
+static const snd_device_t tapan_skuf_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+    /*SND_DEVICE_OUT_SPEAKER_AND_ANC_FB_HEADSET,*/
+};
+
+static const snd_device_t tapan_lite_skuf_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
+};
+
+static const snd_device_t helicon_skuab_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+};
+
+static void update_hardware_info_8x16(struct hardware_info *hw_info, const char *snd_card_name)
+{
+    if (!strcmp(snd_card_name, "msm8x16-snd-card")) {
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8x16", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8x16-snd-card-mtp")) {
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8x16", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8x16-snd-card-sbc")) {
+        strlcpy(hw_info->type, "sbc", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8x16", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+    } else if (!strcmp(snd_card_name, "msm8x16-skuh-snd-card")) {
+        strlcpy(hw_info->type, "skuh", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8x16", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8x16-skui-snd-card")) {
+        strlcpy(hw_info->type, "skui", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8x16", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8x16-skuhf-snd-card")) {
+        strlcpy(hw_info->type, "skuhf", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8x16", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8939-snd-card")) {
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8939", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8939-snd-card-mtp")) {
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8939", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8939-snd-card-skuk")) {
+        strlcpy(hw_info->type, "skuk", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8939", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8939-tapan-snd-card") ||
+               !strcmp(snd_card_name, "msm8939-tapan9302-snd-card")) {
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8939", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8909-snd-card")) {
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8909", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8909-skua-snd-card")) {
+        strlcpy(hw_info->type, "skua", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8909", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8909-skuc-snd-card")) {
+        strlcpy(hw_info->type, "skuc", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8909", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8909-pm8916-snd-card")) {
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8909", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8909-skue-snd-card")) {
+        strlcpy(hw_info->type, "skue", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8909", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8939-snd-card-skul")) {
+        strlcpy(hw_info->type, "skul", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8939", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8909-skut-snd-card")) {
+        strlcpy(hw_info->type, "skut", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8909", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+   } else if (!strcmp(snd_card_name, "msm8x09-tasha9326-snd-card")) {
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8909", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else {
+        ALOGW("%s: Not an  8x16/8939/8909 device", __func__);
+    }
+}
+
+void *hw_info_init(const char *snd_card_name)
+{
+    struct hardware_info *hw_info;
+
+    hw_info = malloc(sizeof(struct hardware_info));
+    if (!hw_info) {
+        ALOGE("failed to allocate mem for hardware info");
+        return NULL;
+    }
+
+    if (strstr(snd_card_name, "msm8x16") || strstr(snd_card_name, "msm8939") ||
+        strstr(snd_card_name, "msm8909") || strstr(snd_card_name, "msm8x09")) {
+        ALOGV("8x16 - variant soundcard");
+        update_hardware_info_8x16(hw_info, snd_card_name);
+    } else {
+        ALOGE("%s: Unsupported target %s:",__func__, snd_card_name);
+        free(hw_info);
+        hw_info = NULL;
+    }
+
+    return hw_info;
+}
+
+void hw_info_deinit(void *hw_info)
+{
+    struct hardware_info *my_data = (struct hardware_info*) hw_info;
+
+    if(!my_data)
+        free(my_data);
+}
+
+void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device,
+                            char *device_name)
+{
+    struct hardware_info *my_data = (struct hardware_info*) hw_info;
+    uint32_t i = 0;
+
+    snd_device_t *snd_devices =
+            (snd_device_t *) my_data->snd_devices;
+
+    if(snd_devices != NULL) {
+        for (i = 0; i <  my_data->num_snd_devices; i++) {
+            if (snd_device == (snd_device_t)snd_devices[i]) {
+                ALOGV("extract dev_extn device %d, extn = %s",
+                        (snd_device_t)snd_devices[i],  my_data->dev_extn);
+                CHECK(strlcat(device_name,  my_data->dev_extn,
+                        DEVICE_NAME_MAX_SIZE) < DEVICE_NAME_MAX_SIZE);
+                break;
+            }
+        }
+    }
+    ALOGD("%s : device_name = %s", __func__,device_name);
+}
diff --git a/msm8909/hal/msm8916/platform.c b/msm8909/hal/msm8916/platform.c
new file mode 100644
index 0000000..ea75a4a
--- /dev/null
+++ b/msm8909/hal/msm8916/platform.c
@@ -0,0 +1,2964 @@
+/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "msm8916_platform"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <cutils/str_parms.h>
+#include <audio_hw.h>
+#include <platform_api.h>
+#include "platform.h"
+#include "audio_extn.h"
+#include "voice_extn.h"
+#include "sound/msmcal-hwdep.h"
+#include <dirent.h>
+#define SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID (100)
+#define MAX_MIXER_XML_PATH  100
+#define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
+#define MIXER_XML_PATH_MTP "/system/etc/mixer_paths_mtp.xml"
+#define MIXER_XML_PATH_SBC "/system/etc/mixer_paths_sbc.xml"
+#define MIXER_XML_PATH_MSM8909_PM8916 "/system/etc/mixer_paths_msm8909_pm8916.xml"
+#define MIXER_XML_PATH_QRD_SKUH "/system/etc/mixer_paths_qrd_skuh.xml"
+#define MIXER_XML_PATH_QRD_SKUI "/system/etc/mixer_paths_qrd_skui.xml"
+#define MIXER_XML_PATH_QRD_SKUHF "/system/etc/mixer_paths_qrd_skuhf.xml"
+#define MIXER_XML_PATH_QRD_SKUT "/system/etc/mixer_paths_qrd_skut.xml"
+#define MIXER_XML_PATH_SKUK "/system/etc/mixer_paths_skuk.xml"
+#define MIXER_XML_PATH_SKUA "/system/etc/mixer_paths_skua.xml"
+#define MIXER_XML_PATH_SKUC "/system/etc/mixer_paths_skuc.xml"
+#define MIXER_XML_PATH_SKUE "/system/etc/mixer_paths_skue.xml"
+#define MIXER_XML_PATH_SKUL "/system/etc/mixer_paths_skul.xml"
+#define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml"
+#define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml"
+#define MIXER_XML_PATH_WCD9306 "/system/etc/mixer_paths_wcd9306.xml"
+#define MIXER_XML_PATH_WCD9330 "/system/etc/mixer_paths_wcd9330.xml"
+#define MIXER_XML_PATH_WCD9326 "/system/etc/mixer_paths_wcd9326_i2s.xml"
+#define PLATFORM_INFO_XML_PATH      "/system/etc/audio_platform_info.xml"
+#define LIB_ACDB_LOADER "libacdbloader.so"
+#define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID"
+#define CVD_VERSION_MIXER_CTL "CVD Version"
+
+#define MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE (256 * 1024)
+#define MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE (2 * 1024)
+#define COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING (2 * 1024)
+#define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024)
+/* Used in calculating fragment size for pcm offload */
+#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV 2000 /* 2 secs */
+#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING 100 /* 100 millisecs */
+
+/* MAX PCM fragment size cannot be increased  further due
+ * to flinger's cblk size of 1mb,and it has to be a multiple of
+ * 24 - lcm of channels supported by DSP
+ */
+#define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024)
+#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE (32 * 1024)
+
+#define ALIGN( num, to ) (((num) + (to-1)) & (~(to-1)))
+/*
+ * This file will have a maximum of 38 bytes:
+ *
+ * 4 bytes: number of audio blocks
+ * 4 bytes: total length of Short Audio Descriptor (SAD) blocks
+ * Maximum 10 * 3 bytes: SAD blocks
+ */
+#define MAX_SAD_BLOCKS      10
+#define SAD_BLOCK_SIZE      3
+#define MAX_CVD_VERSION_STRING_SIZE    100
+
+/* EDID format ID for LPCM audio */
+#define EDID_FORMAT_LPCM    1
+
+/* fallback app type if the default app type from acdb loader fails */
+#define DEFAULT_APP_TYPE  0x11130
+
+/* Retry for delay in FW loading*/
+#define RETRY_NUMBER 20
+#define RETRY_US 500000
+#define MAX_SND_CARD 8
+
+#define SAMPLE_RATE_8KHZ  8000
+#define SAMPLE_RATE_16KHZ 16000
+
+#define AUDIO_PARAMETER_KEY_FLUENCE_TYPE  "fluence"
+#define AUDIO_PARAMETER_KEY_SLOWTALK      "st_enable"
+#define AUDIO_PARAMETER_KEY_HD_VOICE      "hd_voice"
+#define AUDIO_PARAMETER_KEY_VOLUME_BOOST  "volume_boost"
+#define MAX_CAL_NAME 20
+#define APP_TYPE_SYSTEM_SOUNDS 0x00011131
+#define APP_TYPE_GENERAL_RECORDING 0x00011132
+
+char cal_name_info[WCD9XXX_MAX_CAL][MAX_CAL_NAME] = {
+        [WCD9XXX_ANC_CAL] = "anc_cal",
+        [WCD9XXX_MBHC_CAL] = "mbhc_cal",
+        [WCD9XXX_MAD_CAL] = "mad_cal",
+};
+
+#define AUDIO_PARAMETER_KEY_REC_PLAY_CONC "rec_play_conc_on"
+
+#define  AUDIO_PARAMETER_IS_HW_DECODER_SESSION_ALLOWED  "is_hw_dec_session_allowed"
+
+char * dsp_only_decoders_mime[] = {
+    "audio/x-ms-wma" /* wma*/ ,
+    "audio/x-ms-wma-lossless" /* wma lossless */ ,
+    "audio/x-ms-wma-pro" /* wma prop */ ,
+    "audio/amr-wb-plus" /* amr wb plus */ ,
+    "audio/alac"  /*alac */ ,
+    "audio/x-ape" /*ape */,
+};
+
+enum {
+	VOICE_FEATURE_SET_DEFAULT,
+	VOICE_FEATURE_SET_VOLUME_BOOST
+};
+
+struct audio_block_header
+{
+    int reserved;
+    int length;
+};
+
+/* Audio calibration related functions */
+typedef void (*acdb_deallocate_t)();
+typedef int  (*acdb_init_t)(char *, char *, int);
+typedef void (*acdb_send_audio_cal_t)(int, int, int, int);
+typedef void (*acdb_send_voice_cal_t)(int, int);
+typedef int (*acdb_reload_vocvoltable_t)(int);
+typedef int  (*acdb_get_default_app_type_t)(void);
+typedef int (*acdb_loader_get_calibration_t)(char *attr, int size, void *data);
+acdb_loader_get_calibration_t acdb_loader_get_calibration;
+
+struct platform_data {
+    struct audio_device *adev;
+    bool fluence_in_spkr_mode;
+    bool fluence_in_voice_call;
+    bool fluence_in_voice_rec;
+    bool fluence_in_audio_rec;
+    int  fluence_type;
+    char fluence_cap[PROPERTY_VALUE_MAX];
+    int  fluence_mode;
+    bool slowtalk;
+    bool hd_voice;
+    bool ec_ref_enabled;
+    bool is_acdb_initialized;
+    bool is_wsa_speaker;
+    /* Audio calibration related functions */
+    void                       *acdb_handle;
+    int                        voice_feature_set;
+    acdb_init_t                acdb_init;
+    acdb_deallocate_t          acdb_deallocate;
+    acdb_send_audio_cal_t      acdb_send_audio_cal;
+    acdb_send_voice_cal_t      acdb_send_voice_cal;
+    acdb_reload_vocvoltable_t  acdb_reload_vocvoltable;
+    acdb_get_default_app_type_t acdb_get_default_app_type;
+#ifdef RECORD_PLAY_CONCURRENCY
+    bool rec_play_conc_set;
+#endif
+    void *hw_info;
+    struct csd_data *csd;
+};
+
+static bool is_external_codec = false;
+static const int pcm_device_table_of_ext_codec[AUDIO_USECASE_MAX][2] = {
+   [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE_OF_EXT_CODEC, QCHAT_CALL_PCM_DEVICE_OF_EXT_CODEC}
+};
+
+/* List of use cases that has different PCM device ID's for internal and external codecs */
+static const int misc_usecase[AUDIO_USECASE_MAX] = { USECASE_QCHAT_CALL };
+
+static const int pcm_device_table[AUDIO_USECASE_MAX][2] = {
+    [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {DEEP_BUFFER_PCM_DEVICE,
+                                            DEEP_BUFFER_PCM_DEVICE},
+    [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
+                                           LOWLATENCY_PCM_DEVICE},
+    [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTIMEDIA2_PCM_DEVICE,
+                                        MULTIMEDIA2_PCM_DEVICE},
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD] =
+                     {PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE},
+    [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE},
+    [USECASE_AUDIO_RECORD_COMPRESS] = {COMPRESS_CAPTURE_DEVICE, COMPRESS_CAPTURE_DEVICE},
+    [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
+                                          LOWLATENCY_PCM_DEVICE},
+    [USECASE_AUDIO_RECORD_FM_VIRTUAL] = {MULTIMEDIA2_PCM_DEVICE,
+                                  MULTIMEDIA2_PCM_DEVICE},
+    [USECASE_AUDIO_PLAYBACK_FM] = {FM_PLAYBACK_PCM_DEVICE, FM_CAPTURE_PCM_DEVICE},
+    [USECASE_AUDIO_HFP_SCO] = {HFP_PCM_RX, HFP_SCO_RX},
+    [USECASE_AUDIO_HFP_SCO_WB] = {HFP_PCM_RX, HFP_SCO_RX},
+    [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE},
+    [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE},
+    [USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE},
+    [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE, QCHAT_CALL_PCM_DEVICE},
+    [USECASE_VOWLAN_CALL] = {VOWLAN_CALL_PCM_DEVICE, VOWLAN_CALL_PCM_DEVICE},
+    [USECASE_COMPRESS_VOIP_CALL] = {COMPRESS_VOIP_CALL_PCM_DEVICE, COMPRESS_VOIP_CALL_PCM_DEVICE},
+    [USECASE_INCALL_REC_UPLINK] = {AUDIO_RECORD_PCM_DEVICE,
+                                   AUDIO_RECORD_PCM_DEVICE},
+    [USECASE_INCALL_REC_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE,
+                                     AUDIO_RECORD_PCM_DEVICE},
+    [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE,
+                                                AUDIO_RECORD_PCM_DEVICE},
+    [USECASE_INCALL_REC_UPLINK_COMPRESS] = {COMPRESS_CAPTURE_DEVICE,
+                                            COMPRESS_CAPTURE_DEVICE},
+    [USECASE_INCALL_REC_DOWNLINK_COMPRESS] = {COMPRESS_CAPTURE_DEVICE,
+                                              COMPRESS_CAPTURE_DEVICE},
+    [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS] = {COMPRESS_CAPTURE_DEVICE,
+                                                         COMPRESS_CAPTURE_DEVICE},
+    [USECASE_INCALL_MUSIC_UPLINK] = {INCALL_MUSIC_UPLINK_PCM_DEVICE,
+                                     INCALL_MUSIC_UPLINK_PCM_DEVICE},
+    [USECASE_INCALL_MUSIC_UPLINK2] = {INCALL_MUSIC_UPLINK2_PCM_DEVICE,
+                                      INCALL_MUSIC_UPLINK2_PCM_DEVICE},
+    [USECASE_AUDIO_SPKR_CALIB_RX] = {SPKR_PROT_CALIB_RX_PCM_DEVICE, -1},
+    [USECASE_AUDIO_SPKR_CALIB_TX] = {-1, SPKR_PROT_CALIB_TX_PCM_DEVICE},
+};
+
+/* Array to store sound devices */
+static const char * const device_table[SND_DEVICE_MAX] = {
+    [SND_DEVICE_NONE] = "none",
+    /* Playback sound devices */
+    [SND_DEVICE_OUT_HANDSET] = "handset",
+    [SND_DEVICE_OUT_SPEAKER] = "speaker",
+    [SND_DEVICE_OUT_SPEAKER_WSA] = "wsa-speaker",
+    [SND_DEVICE_OUT_SPEAKER_REVERSE] = "speaker-reverse",
+    [SND_DEVICE_OUT_HEADPHONES] = "headphones",
+    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = "speaker-and-headphones",
+    [SND_DEVICE_OUT_VOICE_HANDSET] = "voice-handset",
+    [SND_DEVICE_OUT_VOICE_SPEAKER] = "voice-speaker",
+    [SND_DEVICE_OUT_VOICE_SPEAKER_WSA] = "wsa-voice-speaker",
+    [SND_DEVICE_OUT_VOICE_HEADPHONES] = "voice-headphones",
+    [SND_DEVICE_OUT_HDMI] = "hdmi",
+    [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi",
+    [SND_DEVICE_OUT_BT_SCO] = "bt-sco-headset",
+    [SND_DEVICE_OUT_BT_SCO_WB] = "bt-sco-headset-wb",
+    [SND_DEVICE_OUT_BT_A2DP] = "bt-a2dp",
+    [SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP] = "speaker-and-bt-a2dp",
+    [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones",
+    [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones",
+    [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset",
+    [SND_DEVICE_OUT_AFE_PROXY] = "afe-proxy",
+    [SND_DEVICE_OUT_USB_HEADSET] = "usb-headphones",
+    [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = "speaker-and-usb-headphones",
+    [SND_DEVICE_OUT_TRANSMISSION_FM] = "transmission-fm",
+    [SND_DEVICE_OUT_ANC_HEADSET] = "anc-headphones",
+    [SND_DEVICE_OUT_ANC_FB_HEADSET] = "anc-fb-headphones",
+    [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = "voice-anc-headphones",
+    [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = "voice-anc-fb-headphones",
+    [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = "speaker-and-anc-headphones",
+    [SND_DEVICE_OUT_ANC_HANDSET] = "anc-handset",
+    [SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected",
+#ifdef RECORD_PLAY_CONCURRENCY
+    [SND_DEVICE_OUT_VOIP_HANDSET] = "voip-handset",
+    [SND_DEVICE_OUT_VOIP_SPEAKER] = "voip-speaker",
+    [SND_DEVICE_OUT_VOIP_HEADPHONES] = "voip-headphones",
+#endif
+
+    /* Capture sound devices */
+    [SND_DEVICE_IN_HANDSET_MIC] = "handset-mic",
+    [SND_DEVICE_IN_HANDSET_MIC_AEC] = "handset-mic",
+    [SND_DEVICE_IN_HANDSET_MIC_NS] = "handset-mic",
+    [SND_DEVICE_IN_HANDSET_MIC_AEC_NS] = "handset-mic",
+    [SND_DEVICE_IN_HANDSET_DMIC] = "dmic-endfire",
+    [SND_DEVICE_IN_HANDSET_DMIC_AEC] = "dmic-endfire",
+    [SND_DEVICE_IN_HANDSET_DMIC_NS] = "dmic-endfire",
+    [SND_DEVICE_IN_HANDSET_DMIC_AEC_NS] = "dmic-endfire",
+    [SND_DEVICE_IN_SPEAKER_MIC] = "speaker-mic",
+    [SND_DEVICE_IN_SPEAKER_MIC_AEC] = "speaker-mic",
+    [SND_DEVICE_IN_SPEAKER_MIC_NS] = "speaker-mic",
+    [SND_DEVICE_IN_SPEAKER_MIC_AEC_NS] = "speaker-mic",
+    [SND_DEVICE_IN_SPEAKER_DMIC] = "speaker-dmic-endfire",
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC] = "speaker-dmic-endfire",
+    [SND_DEVICE_IN_SPEAKER_DMIC_NS] = "speaker-dmic-endfire",
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS] = "speaker-dmic-endfire",
+    [SND_DEVICE_IN_HEADSET_MIC] = "headset-mic",
+    [SND_DEVICE_IN_HEADSET_MIC_FLUENCE] = "headset-mic",
+    [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = "voice-speaker-mic",
+    [SND_DEVICE_IN_VOICE_HEADSET_MIC] = "voice-headset-mic",
+    [SND_DEVICE_IN_HDMI_MIC] = "hdmi-mic",
+    [SND_DEVICE_IN_BT_SCO_MIC] = "bt-sco-mic",
+    [SND_DEVICE_IN_BT_SCO_MIC_NREC] = "bt-sco-mic",
+    [SND_DEVICE_IN_BT_SCO_MIC_WB] = "bt-sco-mic-wb",
+    [SND_DEVICE_IN_BT_SCO_MIC_WB_NREC] = "bt-sco-mic-wb",
+    [SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic",
+    [SND_DEVICE_IN_VOICE_DMIC] = "voice-dmic-ef",
+    [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = "voice-speaker-dmic-ef",
+    [SND_DEVICE_IN_VOICE_SPEAKER_QMIC] = "voice-speaker-qmic",
+    [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic",
+    [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic",
+    [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic",
+    [SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic",
+    [SND_DEVICE_IN_VOICE_REC_MIC_NS] = "voice-rec-mic",
+    [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = "voice-rec-dmic-ef",
+    [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence",
+    [SND_DEVICE_IN_USB_HEADSET_MIC] = "usb-headset-mic",
+    [SND_DEVICE_IN_CAPTURE_FM] = "capture-fm",
+    [SND_DEVICE_IN_AANC_HANDSET_MIC] = "aanc-handset-mic",
+    [SND_DEVICE_IN_QUAD_MIC] = "quad-mic",
+    [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = "handset-stereo-dmic-ef",
+    [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = "speaker-stereo-dmic-ef",
+    [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = "vi-feedback",
+    [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE] = "voice-speaker-dmic-broadside",
+    [SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE] = "speaker-dmic-broadside",
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE] = "speaker-dmic-broadside",
+    [SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE] = "speaker-dmic-broadside",
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE] = "speaker-dmic-broadside",
+    [SND_DEVICE_IN_VOICE_FLUENCE_DMIC_AANC] = "aanc-fluence-dmic-handset",
+    [SND_DEVICE_IN_HANDSET_QMIC] = "quad-mic",
+    [SND_DEVICE_IN_SPEAKER_QMIC_AEC] = "quad-mic",
+    [SND_DEVICE_IN_SPEAKER_QMIC_NS] = "quad-mic",
+    [SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS] = "quad-mic",
+};
+
+/* ACDB IDs (audio DSP path configuration IDs) for each sound device */
+static int acdb_device_table[SND_DEVICE_MAX] = {
+    [SND_DEVICE_NONE] = -1,
+    [SND_DEVICE_OUT_HANDSET] = 7,
+    [SND_DEVICE_OUT_SPEAKER] = 14,
+    [SND_DEVICE_OUT_SPEAKER_WSA] = 135,
+    [SND_DEVICE_OUT_SPEAKER_REVERSE] = 14,
+    [SND_DEVICE_OUT_HEADPHONES] = 10,
+    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10,
+    [SND_DEVICE_OUT_VOICE_HANDSET] = 7,
+    [SND_DEVICE_OUT_VOICE_SPEAKER] = 14,
+    [SND_DEVICE_OUT_VOICE_SPEAKER_WSA] = 135,
+    [SND_DEVICE_OUT_VOICE_HEADPHONES] = 10,
+    [SND_DEVICE_OUT_HDMI] = 18,
+    [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14,
+    [SND_DEVICE_OUT_BT_SCO] = 22,
+    [SND_DEVICE_OUT_BT_SCO_WB] = 39,
+    [SND_DEVICE_OUT_BT_A2DP] = 20,
+    [SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP] = 14,
+    [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17,
+    [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
+    [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37,
+    [SND_DEVICE_OUT_AFE_PROXY] = 0,
+    [SND_DEVICE_OUT_USB_HEADSET] = 45,
+    [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 14,
+    [SND_DEVICE_OUT_TRANSMISSION_FM] = 0,
+    [SND_DEVICE_OUT_ANC_HEADSET] = 26,
+    [SND_DEVICE_OUT_ANC_FB_HEADSET] = 27,
+    [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = 26,
+    [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = 27,
+    [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = 26,
+    [SND_DEVICE_OUT_ANC_HANDSET] = 103,
+    [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 101,
+#ifdef RECORD_PLAY_CONCURRENCY
+    [SND_DEVICE_OUT_VOIP_HANDSET] = 133,
+    [SND_DEVICE_OUT_VOIP_SPEAKER] = 132,
+    [SND_DEVICE_OUT_VOIP_HEADPHONES] = 134,
+#endif
+
+    [SND_DEVICE_IN_HANDSET_MIC] = 4,
+    [SND_DEVICE_IN_HANDSET_MIC_AEC] = 106,
+    [SND_DEVICE_IN_HANDSET_MIC_NS] = 107,
+    [SND_DEVICE_IN_HANDSET_MIC_AEC_NS] = 108,
+    [SND_DEVICE_IN_HANDSET_DMIC] = 41,
+    [SND_DEVICE_IN_HANDSET_DMIC_AEC] = 109,
+    [SND_DEVICE_IN_HANDSET_DMIC_NS] = 110,
+    [SND_DEVICE_IN_HANDSET_DMIC_AEC_NS] = 111,
+    [SND_DEVICE_IN_SPEAKER_MIC] = 11,
+    [SND_DEVICE_IN_SPEAKER_MIC_AEC] = 112,
+    [SND_DEVICE_IN_SPEAKER_MIC_NS] = 113,
+    [SND_DEVICE_IN_SPEAKER_MIC_AEC_NS] = 114,
+    [SND_DEVICE_IN_SPEAKER_DMIC] = 43,
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC] = 115,
+    [SND_DEVICE_IN_SPEAKER_DMIC_NS] = 116,
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS] = 117,
+    [SND_DEVICE_IN_HEADSET_MIC] = 8,
+    [SND_DEVICE_IN_HEADSET_MIC_FLUENCE] = 47,
+    [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = 11,
+    [SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8,
+    [SND_DEVICE_IN_HDMI_MIC] = 4,
+    [SND_DEVICE_IN_BT_SCO_MIC] = 21,
+    [SND_DEVICE_IN_BT_SCO_MIC_NREC] = 122,
+    [SND_DEVICE_IN_BT_SCO_MIC_WB] = 38,
+    [SND_DEVICE_IN_BT_SCO_MIC_WB_NREC] = 123,
+    [SND_DEVICE_IN_CAMCORDER_MIC] = 4,
+    [SND_DEVICE_IN_VOICE_DMIC] = 41,
+    [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = 43,
+    [SND_DEVICE_IN_VOICE_SPEAKER_QMIC] = 19,
+    [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16,
+    [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36,
+    [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16,
+    [SND_DEVICE_IN_VOICE_REC_MIC] = 4,
+    [SND_DEVICE_IN_VOICE_REC_MIC_NS] = 107,
+    [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = 34,
+    [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 41,
+    [SND_DEVICE_IN_USB_HEADSET_MIC] = 44,
+    [SND_DEVICE_IN_CAPTURE_FM] = 0,
+    [SND_DEVICE_IN_AANC_HANDSET_MIC] = 104,
+    [SND_DEVICE_IN_QUAD_MIC] = 46,
+    [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = 34,
+    [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = 35,
+    [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = 102,
+    [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE] = 12,
+    [SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE] = 12,
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE] = 119,
+    [SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE] = 121,
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE] = 120,
+    [SND_DEVICE_IN_VOICE_FLUENCE_DMIC_AANC] = 135,
+    [SND_DEVICE_IN_HANDSET_QMIC] = 125,
+    [SND_DEVICE_IN_SPEAKER_QMIC_AEC] = 126,
+    [SND_DEVICE_IN_SPEAKER_QMIC_NS] = 127,
+    [SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS] = 129,
+};
+
+struct snd_device_index {
+    char name[100];
+    unsigned int index;
+};
+
+#define TO_NAME_INDEX(X)   #X, X
+
+/* Used to get index from parsed sting */
+struct snd_device_index snd_device_name_index[SND_DEVICE_MAX] = {
+    {TO_NAME_INDEX(SND_DEVICE_OUT_HANDSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_WSA)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_REVERSE)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_HEADPHONES)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HANDSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_WSA)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HEADPHONES)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_HDMI)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HDMI)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_BT_SCO)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_BT_SCO_WB)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_BT_A2DP)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_AFE_PROXY)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_USB_HEADSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_TRANSMISSION_FM)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_ANC_HEADSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_ANC_FB_HEADSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_ANC_HEADSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_ANC_HANDSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED)},
+#ifdef RECORD_PLAY_CONCURRENCY
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_HANDSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_SPEAKER)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_HEADPHONES)},
+#endif
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_AEC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_AEC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_DMIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_DMIC_AEC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_DMIC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_DMIC_AEC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_MIC_AEC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_MIC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_MIC_AEC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HEADSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HEADSET_MIC_FLUENCE)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_HEADSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HDMI_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_BT_SCO_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_BT_SCO_MIC_NREC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_BT_SCO_MIC_WB)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_BT_SCO_MIC_WB_NREC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_CAMCORDER_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_DMIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_DMIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_QMIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_MIC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_DMIC_STEREO)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_USB_HEADSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_FM)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_AANC_HANDSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_QUAD_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_STEREO_DMIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_STEREO_DMIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_VI_FEEDBACK)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_FLUENCE_DMIC_AANC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_QMIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_AEC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS)},
+};
+
+#define NO_COLS 2
+static int msm_be_id_array_len;
+static int (*msm_device_to_be_id)[];
+
+/* Below table lists output device to BE_ID mapping*/
+/* Update the table based on the board configuration*/
+
+static int msm_device_to_be_id_internal_codec [][NO_COLS] = {
+       {AUDIO_DEVICE_OUT_EARPIECE                       ,       34},
+       {AUDIO_DEVICE_OUT_SPEAKER                        ,       34},
+       {AUDIO_DEVICE_OUT_WIRED_HEADSET                  ,       34},
+       {AUDIO_DEVICE_OUT_WIRED_HEADPHONE                ,       34},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO                  ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET          ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT           ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP                 ,       -1},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES      ,       -1},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER         ,       -1},
+       {AUDIO_DEVICE_OUT_AUX_DIGITAL                    ,       4},
+       {AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET              ,       9},
+       {AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET              ,       9},
+       {AUDIO_DEVICE_OUT_USB_ACCESSORY                  ,       -1},
+       {AUDIO_DEVICE_OUT_USB_DEVICE                     ,       -1},
+       {AUDIO_DEVICE_OUT_REMOTE_SUBMIX                  ,       9},
+       {AUDIO_DEVICE_OUT_PROXY                          ,       9},
+       {AUDIO_DEVICE_OUT_FM                             ,       7},
+       {AUDIO_DEVICE_OUT_FM_TX                          ,       8},
+       {AUDIO_DEVICE_OUT_ALL                            ,      -1},
+       {AUDIO_DEVICE_NONE                               ,      -1},
+       {AUDIO_DEVICE_OUT_DEFAULT                        ,      -1},
+};
+
+static int msm_device_to_be_id_external_codec [][NO_COLS] = {
+       {AUDIO_DEVICE_OUT_EARPIECE                       ,       2},
+       {AUDIO_DEVICE_OUT_SPEAKER                        ,       2},
+       {AUDIO_DEVICE_OUT_WIRED_HEADSET                  ,       2},
+       {AUDIO_DEVICE_OUT_WIRED_HEADPHONE                ,       2},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO                  ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET          ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT           ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP                 ,       -1},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES      ,       -1},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER         ,       -1},
+       {AUDIO_DEVICE_OUT_AUX_DIGITAL                    ,       4},
+       {AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET              ,       9},
+       {AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET              ,       9},
+       {AUDIO_DEVICE_OUT_USB_ACCESSORY                  ,       -1},
+       {AUDIO_DEVICE_OUT_USB_DEVICE                     ,       -1},
+       {AUDIO_DEVICE_OUT_REMOTE_SUBMIX                  ,       9},
+       {AUDIO_DEVICE_OUT_PROXY                          ,       9},
+       {AUDIO_DEVICE_OUT_FM                             ,       7},
+       {AUDIO_DEVICE_OUT_FM_TX                          ,       8},
+       {AUDIO_DEVICE_OUT_ALL                            ,      -1},
+       {AUDIO_DEVICE_NONE                               ,      -1},
+       {AUDIO_DEVICE_OUT_DEFAULT                        ,      -1},
+};
+
+
+#define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
+#define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
+
+static bool is_misc_usecase(audio_usecase_t usecase) {
+     bool ret = false;
+     int i;
+
+     for (i = 0; i < AUDIO_USECASE_MAX; i++) {
+          if(usecase == misc_usecase[i]) {
+             ret = true;
+             break;
+          }
+     }
+     return ret;
+}
+
+
+static void update_codec_type(const char *snd_card_name) {
+
+     if (!strncmp(snd_card_name, "msm8939-tapan-snd-card",
+                  sizeof("msm8939-tapan-snd-card")) ||
+         !strncmp(snd_card_name, "msm8939-tapan9302-snd-card",
+                  sizeof("msm8939-tapan9302-snd-card"))||
+         !strncmp(snd_card_name, "msm8939-tomtom9330-snd-card",
+                  sizeof("msm8939-tomtom9330-snd-card")) ||
+        !strncmp(snd_card_name, "msm8x09-tasha9326-snd-card",
+                  sizeof("msm8x09-tasha9326-snd-card")))
+     {
+         ALOGI("%s: snd_card_name: %s",__func__,snd_card_name);
+         is_external_codec = true;
+     }
+}
+static void query_platform(const char *snd_card_name,
+                                      char *mixer_xml_path)
+{
+    if (!strncmp(snd_card_name, "msm8x16-snd-card-mtp",
+                 sizeof("msm8x16-snd-card-mtp"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_MTP,
+                sizeof(MIXER_XML_PATH_MTP));
+
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
+    } else if (!strncmp(snd_card_name, "msm8x16-snd-card-sbc",
+                 sizeof("msm8x16-snd-card-sbc"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_SBC,
+                sizeof(MIXER_XML_PATH_SBC));
+
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
+    } else if (!strncmp(snd_card_name, "msm8x16-skuh-snd-card",
+                 sizeof("msm8x16-skuh-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_QRD_SKUH,
+                sizeof(MIXER_XML_PATH_QRD_SKUH));
+
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
+    } else if (!strncmp(snd_card_name, "msm8x16-skui-snd-card",
+                 sizeof("msm8x16-skui-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_QRD_SKUI,
+                sizeof(MIXER_XML_PATH_QRD_SKUI));
+
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
+    } else if (!strncmp(snd_card_name, "msm8x16-skuhf-snd-card",
+                 sizeof("msm8x16-skuhf-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_QRD_SKUHF,
+                sizeof(MIXER_XML_PATH_QRD_SKUHF));
+
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
+    } else if (!strncmp(snd_card_name, "msm8939-snd-card-mtp",
+                 sizeof("msm8939-snd-card-mtp"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_MTP,
+                sizeof(MIXER_XML_PATH_MTP));
+
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
+    } else if (!strncmp(snd_card_name, "msm8939-snd-card-skuk",
+                 sizeof("msm8939-snd-card-skuk"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_SKUK,
+                sizeof(MIXER_XML_PATH_SKUK));
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
+    } else if (!strncmp(snd_card_name, "msm8939-tapan-snd-card",
+                 sizeof("msm8939-tapan-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_WCD9306,
+                sizeof(MIXER_XML_PATH_WCD9306));
+        msm_device_to_be_id = msm_device_to_be_id_external_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_external_codec[0]);
+
+    } else if (!strncmp(snd_card_name, "msm8939-tapan9302-snd-card",
+                 sizeof("msm8939-tapan9302-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_WCD9306,
+                sizeof(MIXER_XML_PATH_WCD9306));
+
+        msm_device_to_be_id = msm_device_to_be_id_external_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_external_codec[0]);
+
+    } else if (!strncmp(snd_card_name, "msm8939-tomtom9330-snd-card",
+                 sizeof("msm8939-tomtom9330-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_WCD9330,
+                sizeof(MIXER_XML_PATH_WCD9330));
+        msm_device_to_be_id = msm_device_to_be_id_external_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_external_codec[0]);
+    } else if (!strncmp(snd_card_name, "msm8x09-tasha9326-snd-card",
+                 sizeof("msm8x09-tasha9326-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_WCD9326,
+               MAX_MIXER_XML_PATH);
+        msm_device_to_be_id = msm_device_to_be_id_external_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_external_codec[0]);
+    } else if (!strncmp(snd_card_name, "msm8909-skua-snd-card",
+                sizeof("msm8909-skua-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_SKUA,
+                sizeof(MIXER_XML_PATH_SKUA));
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
+    } else if (!strncmp(snd_card_name, "msm8909-skuc-snd-card",
+                 sizeof("msm8909-skuc-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_SKUC,
+                sizeof(MIXER_XML_PATH_SKUC));
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
+    } else if (!strncmp(snd_card_name, "msm8909-skut-snd-card",
+                 sizeof("msm8909-skut-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_QRD_SKUT,
+                sizeof(MIXER_XML_PATH_QRD_SKUT));
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
+    } else if (!strncmp(snd_card_name, "msm8909-pm8916-snd-card",
+                 sizeof("msm8909-pm8916-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_MSM8909_PM8916,
+                sizeof(MIXER_XML_PATH_MSM8909_PM8916));
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
+    } else if (!strncmp(snd_card_name, "msm8909-skue-snd-card",
+                 sizeof("msm8909-skue-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_SKUE,
+                sizeof(MIXER_XML_PATH_SKUE));
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
+    } else if (!strncmp(snd_card_name, "msm8939-snd-card-skul",
+                 sizeof("msm8939-snd-card-skul"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_SKUL,
+                sizeof(MIXER_XML_PATH_SKUL));
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+    } else {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH,
+                sizeof(MIXER_XML_PATH));
+
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
+    }
+}
+
+void platform_set_echo_reference(void *platform, bool enable)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+
+    if (my_data->ec_ref_enabled) {
+        my_data->ec_ref_enabled = false;
+        ALOGD("%s: disabling echo-reference", __func__);
+        audio_route_reset_and_update_path(adev->audio_route, "echo-reference");
+    }
+
+    if (enable) {
+        my_data->ec_ref_enabled = true;
+        ALOGD("%s: enabling echo-reference", __func__);
+        audio_route_apply_and_update_path(adev->audio_route, "echo-reference");
+    }
+
+}
+
+static struct csd_data *open_csd_client()
+{
+    struct csd_data *csd = calloc(1, sizeof(struct csd_data));
+    if (!csd) {
+        ALOGE("failed to allocate csd_data mem");
+        return NULL;
+    }
+
+    csd->csd_client = dlopen(LIB_CSD_CLIENT, RTLD_NOW);
+    if (csd->csd_client == NULL) {
+        ALOGE("%s: DLOPEN failed for %s", __func__, LIB_CSD_CLIENT);
+        goto error;
+    } else {
+        ALOGV("%s: DLOPEN successful for %s", __func__, LIB_CSD_CLIENT);
+
+        csd->deinit = (deinit_t)dlsym(csd->csd_client,
+                                             "csd_client_deinit");
+        if (csd->deinit == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_deinit", __func__,
+                  dlerror());
+            goto error;
+        }
+        csd->disable_device = (disable_device_t)dlsym(csd->csd_client,
+                                             "csd_client_disable_device");
+        if (csd->disable_device == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_disable_device",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->enable_device_config = (enable_device_config_t)dlsym(csd->csd_client,
+                                               "csd_client_enable_device_config");
+        if (csd->enable_device_config == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_enable_device_config",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->enable_device = (enable_device_t)dlsym(csd->csd_client,
+                                             "csd_client_enable_device");
+        if (csd->enable_device == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_enable_device",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->start_voice = (start_voice_t)dlsym(csd->csd_client,
+                                             "csd_client_start_voice");
+        if (csd->start_voice == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_start_voice",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->stop_voice = (stop_voice_t)dlsym(csd->csd_client,
+                                             "csd_client_stop_voice");
+        if (csd->stop_voice == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_stop_voice",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->volume = (volume_t)dlsym(csd->csd_client,
+                                             "csd_client_volume");
+        if (csd->volume == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_volume",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->mic_mute = (mic_mute_t)dlsym(csd->csd_client,
+                                             "csd_client_mic_mute");
+        if (csd->mic_mute == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_mic_mute",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->slow_talk = (slow_talk_t)dlsym(csd->csd_client,
+                                             "csd_client_slow_talk");
+        if (csd->slow_talk == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_slow_talk",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->start_playback = (start_playback_t)dlsym(csd->csd_client,
+                                             "csd_client_start_playback");
+        if (csd->start_playback == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_start_playback",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->stop_playback = (stop_playback_t)dlsym(csd->csd_client,
+                                             "csd_client_stop_playback");
+        if (csd->stop_playback == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_stop_playback",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->set_lch = (set_lch_t)dlsym(csd->csd_client, "csd_client_set_lch");
+        if (csd->set_lch == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_set_lch",
+                  __func__, dlerror());
+            /* Ignore the error as this is not mandatory function for
+             * basic voice call to work.
+             */
+        }
+        csd->start_record = (start_record_t)dlsym(csd->csd_client,
+                                             "csd_client_start_record");
+        if (csd->start_record == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_start_record",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->stop_record = (stop_record_t)dlsym(csd->csd_client,
+                                             "csd_client_stop_record");
+        if (csd->stop_record == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_stop_record",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->init = (init_t)dlsym(csd->csd_client, "csd_client_init");
+
+        if (csd->init == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_init",
+                  __func__, dlerror());
+            goto error;
+        } else {
+            csd->init();
+        }
+    }
+    return csd;
+
+error:
+    free(csd);
+    csd = NULL;
+    return csd;
+}
+
+void close_csd_client(struct csd_data *csd)
+{
+    if (csd != NULL) {
+        csd->deinit();
+        dlclose(csd->csd_client);
+        free(csd);
+        csd = NULL;
+    }
+}
+
+void get_cvd_version(char *cvd_version, struct audio_device *adev)
+{
+    struct mixer_ctl *ctl;
+    int count;
+    int ret = 0;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, CVD_VERSION_MIXER_CTL);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",  __func__, CVD_VERSION_MIXER_CTL);
+        goto done;
+    }
+    mixer_ctl_update(ctl);
+
+    count = mixer_ctl_get_num_values(ctl);
+    if (count > MAX_CVD_VERSION_STRING_SIZE)
+        count = MAX_CVD_VERSION_STRING_SIZE;
+
+    ret = mixer_ctl_get_array(ctl, cvd_version, count);
+    if (ret != 0) {
+        ALOGE("%s: ERROR! mixer_ctl_get_array() failed to get CVD Version", __func__);
+        goto done;
+    }
+
+done:
+    return;
+}
+
+static int hw_util_open(int card_no)
+{
+    int fd = -1;
+    char dev_name[256];
+
+    snprintf(dev_name, sizeof(dev_name), "/dev/snd/hwC%uD%u",
+                               card_no, WCD9XXX_CODEC_HWDEP_NODE);
+    ALOGD("%s Opening device %s\n", __func__, dev_name);
+    fd = open(dev_name, O_WRONLY);
+    if (fd < 0) {
+        ALOGE("%s: cannot open device '%s'\n", __func__, dev_name);
+        return fd;
+    }
+    ALOGD("%s success", __func__);
+    return fd;
+}
+
+struct param_data {
+    int    use_case;
+    int    acdb_id;
+    int    get_size;
+    int    buff_size;
+    int    data_size;
+    void   *buff;
+};
+
+static int send_codec_cal(acdb_loader_get_calibration_t acdb_loader_get_calibration, int fd)
+{
+    int ret = 0, type;
+
+    for (type = WCD9XXX_ANC_CAL; type < WCD9XXX_MAX_CAL; type++) {
+        struct wcdcal_ioctl_buffer codec_buffer;
+        struct param_data calib;
+
+        if (!strcmp(cal_name_info[type], "mad_cal"))
+            calib.acdb_id = SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID;
+        calib.get_size = 1;
+        ret = acdb_loader_get_calibration(cal_name_info[type], sizeof(struct param_data),
+                                                                 &calib);
+        if (ret < 0) {
+            ALOGE("%s get_calibration failed\n", __func__);
+            return ret;
+        }
+        calib.get_size = 0;
+        calib.buff = malloc(calib.buff_size);
+        if(calib.buff == NULL) {
+            ALOGE("%s mem allocation for %d bytes for %s failed\n"
+                , __func__, calib.buff_size, cal_name_info[type]);
+            return -1;
+        }
+        ret = acdb_loader_get_calibration(cal_name_info[type],
+                              sizeof(struct param_data), &calib);
+        if (ret < 0) {
+            ALOGE("%s get_calibration failed type=%s calib.size=%d\n"
+                , __func__, cal_name_info[type], codec_buffer.size);
+            free(calib.buff);
+            return ret;
+        }
+        codec_buffer.buffer = calib.buff;
+        codec_buffer.size = calib.data_size;
+        codec_buffer.cal_type = type;
+        if (ioctl(fd, SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE, &codec_buffer) < 0)
+            ALOGE("Failed to call ioctl  for %s err=%d calib.size=%d",
+                cal_name_info[type], errno, codec_buffer.size);
+        ALOGD("%s cal sent for %s calib.size=%d"
+            , __func__, cal_name_info[type], codec_buffer.size);
+        free(calib.buff);
+    }
+    return ret;
+}
+
+static void audio_hwdep_send_cal(struct platform_data *plat_data)
+{
+    int fd;
+
+    fd = hw_util_open(plat_data->adev->snd_card);
+    if (fd == -1) {
+        ALOGE("%s error open\n", __func__);
+        return;
+    }
+
+    acdb_loader_get_calibration = (acdb_loader_get_calibration_t)
+          dlsym(plat_data->acdb_handle, "acdb_loader_get_calibration");
+
+    if (acdb_loader_get_calibration == NULL) {
+        ALOGE("%s: ERROR. dlsym Error:%s acdb_loader_get_calibration", __func__,
+           dlerror());
+        return;
+    }
+    if (send_codec_cal(acdb_loader_get_calibration, fd) < 0)
+        ALOGE("%s: Could not send anc cal", __FUNCTION__);
+}
+
+int platform_acdb_init(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    char *cvd_version = NULL;
+    int key = 0;
+    const char *snd_card_name;
+    int result;
+    char value[PROPERTY_VALUE_MAX];
+    cvd_version = calloc(1, MAX_CVD_VERSION_STRING_SIZE);
+    if (!cvd_version)
+        ALOGE("Failed to allocate cvd version");
+    else
+        get_cvd_version(cvd_version, my_data->adev);
+
+    property_get("audio.ds1.metainfo.key",value,"0");
+    key = atoi(value);
+    snd_card_name = mixer_get_name(my_data->adev->mixer);
+    result = my_data->acdb_init(snd_card_name, cvd_version, key);
+    if (cvd_version)
+        free(cvd_version);
+    if (!result) {
+        my_data->is_acdb_initialized = true;
+        ALOGD("ACDB initialized");
+        audio_hwdep_send_cal(my_data);
+    } else {
+        my_data->is_acdb_initialized = false;
+        ALOGD("ACDB initialization failed");
+    }
+    return result;
+}
+
+#define MAX_PATH             (256)
+#define THERMAL_SYSFS "/sys/class/thermal"
+#define TZ_TYPE "/sys/class/thermal/thermal_zone%d/type"
+#define TZ_WSA "/sys/class/thermal/thermal_zone%d/temp"
+
+static bool is_wsa_found(int *wsaCount)
+{
+    DIR *tdir = NULL;
+    struct dirent *tdirent = NULL;
+    int tzn = 0;
+    char name[MAX_PATH] = {0};
+    char cwd[MAX_PATH] = {0};
+    char file[10] = "wsa";
+    bool found = false;
+    int wsa_count = 0;
+
+    if (!getcwd(cwd, sizeof(cwd)))
+        return false;
+
+    chdir(THERMAL_SYSFS); /* Change dir to read the entries. Doesnt work
+                             otherwise */
+    tdir = opendir(THERMAL_SYSFS);
+    if (!tdir) {
+        ALOGE("Unable to open %s\n", THERMAL_SYSFS);
+        return false;
+    }
+
+    while ((tdirent = readdir(tdir))) {
+        char buf[50];
+        struct dirent *tzdirent;
+        DIR *tzdir = NULL;
+
+        tzdir = opendir(tdirent->d_name);
+        if (!tzdir)
+            continue;
+        while ((tzdirent = readdir(tzdir))) {
+            if (strcmp(tzdirent->d_name, "type"))
+                continue;
+            snprintf(name, MAX_PATH, TZ_TYPE, tzn);
+            ALOGD("Opening %s\n", name);
+            read_line_from_file(name, buf, sizeof(buf));
+            if (strstr(buf, file)) {
+                wsa_count++;
+                /*We support max only two WSA speakers*/
+                if (wsa_count == 2)
+                    break;
+            }
+            tzn++;
+        }
+        closedir(tzdir);
+    }
+    if (wsa_count > 0){
+         ALOGD("Found %d WSA present on the platform", wsa_count);
+         found = true;
+         *wsaCount = wsa_count;
+    }
+    closedir(tdir);
+    chdir(cwd); /* Restore current working dir */
+    return found;
+}
+
+void *platform_init(struct audio_device *adev)
+{
+    char platform[PROPERTY_VALUE_MAX];
+    char baseband[PROPERTY_VALUE_MAX];
+    char value[PROPERTY_VALUE_MAX];
+    struct platform_data *my_data = NULL;
+    int retry_num = 0, snd_card_num = 0, key = 0;
+    const char *snd_card_name;
+    char mixer_xml_path[100],ffspEnable[PROPERTY_VALUE_MAX];
+    char *cvd_version = NULL;
+    int wsaCount =0;
+
+    my_data = calloc(1, sizeof(struct platform_data));
+    if (!my_data) {
+        ALOGE("failed to allocate platform data");
+        return NULL;
+    }
+
+    while (snd_card_num < MAX_SND_CARD) {
+        adev->mixer = mixer_open(snd_card_num);
+
+        while (!adev->mixer && retry_num < RETRY_NUMBER) {
+            usleep(RETRY_US);
+            adev->mixer = mixer_open(snd_card_num);
+            retry_num++;
+        }
+
+        if (!adev->mixer) {
+            ALOGE("%s: Unable to open the mixer card: %d", __func__,
+                   snd_card_num);
+            retry_num = 0;
+            snd_card_num++;
+            continue;
+        }
+
+        snd_card_name = mixer_get_name(adev->mixer);
+        ALOGV("%s: snd_card_name: %s", __func__, snd_card_name);
+
+        my_data->hw_info = hw_info_init(snd_card_name);
+        if (!my_data->hw_info) {
+            ALOGE("%s: Failed to init hardware info", __func__);
+        } else {
+            query_platform(snd_card_name, mixer_xml_path);
+            ALOGD("%s: mixer path file is %s", __func__,
+                                    mixer_xml_path);
+            if (audio_extn_read_xml(adev, snd_card_num, mixer_xml_path,
+                                    MIXER_XML_PATH_AUXPCM) == -ENOSYS) {
+                adev->audio_route = audio_route_init(snd_card_num,
+                                                 mixer_xml_path);
+            }
+            if (!adev->audio_route) {
+                ALOGE("%s: Failed to init audio route controls, aborting.",
+                       __func__);
+                free(my_data);
+                return NULL;
+            }
+            adev->snd_card = snd_card_num;
+            update_codec_type(snd_card_name);
+            ALOGD("%s: Opened sound card:%d", __func__, snd_card_num);
+            break;
+        }
+        retry_num = 0;
+        snd_card_num++;
+    }
+
+    if (snd_card_num >= MAX_SND_CARD) {
+        ALOGE("%s: Unable to find correct sound card, aborting.", __func__);
+        free(my_data);
+        return NULL;
+    }
+
+    my_data->adev = adev;
+    my_data->fluence_in_spkr_mode = false;
+    my_data->fluence_in_voice_call = false;
+    my_data->fluence_in_voice_rec = false;
+    my_data->fluence_in_audio_rec = false;
+    my_data->fluence_type = FLUENCE_NONE;
+    my_data->fluence_mode = FLUENCE_ENDFIRE;
+    my_data->slowtalk = false;
+    my_data->hd_voice = false;
+    my_data->is_wsa_speaker = false;
+
+    property_get("ro.qc.sdk.audio.fluencetype", my_data->fluence_cap, "");
+    if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro"))) {
+        my_data->fluence_type = FLUENCE_QUAD_MIC | FLUENCE_DUAL_MIC;
+    } else if (!strncmp("fluence", my_data->fluence_cap, sizeof("fluence"))) {
+        my_data->fluence_type = FLUENCE_DUAL_MIC;
+    } else {
+        my_data->fluence_type = FLUENCE_NONE;
+    }
+
+    if (my_data->fluence_type != FLUENCE_NONE) {
+        property_get("persist.audio.fluence.voicecall",value,"");
+        if (!strncmp("true", value, sizeof("true"))) {
+            my_data->fluence_in_voice_call = true;
+        }
+
+        property_get("persist.audio.fluence.voicerec",value,"");
+        if (!strncmp("true", value, sizeof("true"))) {
+            my_data->fluence_in_voice_rec = true;
+        }
+
+        property_get("persist.audio.fluence.audiorec",value,"");
+        if (!strncmp("true", value, sizeof("true"))) {
+            my_data->fluence_in_audio_rec = true;
+        }
+
+        property_get("persist.audio.fluence.speaker",value,"");
+        if (!strncmp("true", value, sizeof("true"))) {
+            my_data->fluence_in_spkr_mode = true;
+        }
+
+        property_get("persist.audio.fluence.mode",value,"");
+        if (!strncmp("broadside", value, sizeof("broadside"))) {
+            my_data->fluence_mode = FLUENCE_BROADSIDE;
+        }
+    }
+
+    if (is_wsa_found(&wsaCount)) {
+        /*Set ACDB ID of Stereo speaker if two WSAs are present*/
+        /*Default ACDB ID for wsa speaker is that for mono*/
+        if (wsaCount == 2) {
+            platform_set_snd_device_acdb_id(SND_DEVICE_OUT_SPEAKER_WSA, 15);
+        }
+        my_data->is_wsa_speaker = true;
+    }
+
+    property_get("persist.audio.FFSP.enable", ffspEnable, "");
+    if (!strncmp("true", ffspEnable, sizeof("true"))) {
+        acdb_device_table[SND_DEVICE_OUT_SPEAKER] = 131;
+        acdb_device_table[SND_DEVICE_OUT_SPEAKER_WSA] = 131;
+        acdb_device_table[SND_DEVICE_OUT_SPEAKER_REVERSE] = 131;
+        acdb_device_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 131;
+        acdb_device_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 131;
+    }
+
+    my_data->voice_feature_set = VOICE_FEATURE_SET_DEFAULT;
+    my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
+    if (my_data->acdb_handle == NULL) {
+        ALOGE("%s: DLOPEN failed for %s", __func__, LIB_ACDB_LOADER);
+    } else {
+        ALOGV("%s: DLOPEN successful for %s", __func__, LIB_ACDB_LOADER);
+        my_data->acdb_deallocate = (acdb_deallocate_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_deallocate_ACDB");
+        if (!my_data->acdb_deallocate)
+            ALOGE("%s: Could not find the symbol acdb_loader_deallocate_ACDB from %s",
+                  __func__, LIB_ACDB_LOADER);
+
+        my_data->acdb_send_audio_cal = (acdb_send_audio_cal_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_send_audio_cal_v2");
+        if (!my_data->acdb_send_audio_cal)
+            ALOGE("%s: Could not find the symbol acdb_send_audio_cal from %s",
+                  __func__, LIB_ACDB_LOADER);
+
+        my_data->acdb_send_voice_cal = (acdb_send_voice_cal_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_send_voice_cal");
+        if (!my_data->acdb_send_voice_cal)
+            ALOGE("%s: Could not find the symbol acdb_loader_send_voice_cal from %s",
+                  __func__, LIB_ACDB_LOADER);
+
+        my_data->acdb_reload_vocvoltable = (acdb_reload_vocvoltable_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_reload_vocvoltable");
+        if (!my_data->acdb_reload_vocvoltable)
+            ALOGE("%s: Could not find the symbol acdb_loader_reload_vocvoltable from %s",
+                  __func__, LIB_ACDB_LOADER);
+
+        my_data->acdb_get_default_app_type = (acdb_get_default_app_type_t)dlsym(
+                                                    my_data->acdb_handle,
+                                                    "acdb_loader_get_default_app_type");
+        if (!my_data->acdb_get_default_app_type)
+            ALOGE("%s: Could not find the symbol acdb_get_default_app_type from %s",
+                  __func__, LIB_ACDB_LOADER);
+
+        my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_init_v2");
+        if (my_data->acdb_init == NULL) {
+            ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__, dlerror());
+            goto acdb_init_fail;
+        }
+        platform_acdb_init(my_data);
+    }
+    audio_extn_pm_vote();
+
+acdb_init_fail:
+    /* Initialize ACDB ID's */
+    platform_info_init(PLATFORM_INFO_XML_PATH);
+
+    /* init usb */
+    audio_extn_usb_init(adev);
+
+    /*init a2dp*/
+    audio_extn_a2dp_init();
+
+    /* update sound cards appropriately */
+    audio_extn_usb_set_proxy_sound_card(adev->snd_card);
+
+    /* Read one time ssr property */
+    audio_extn_ssr_update_enabled();
+    audio_extn_spkr_prot_init(adev);
+
+    /* init dap hal */
+    audio_extn_dap_hal_init(adev->snd_card);
+
+    audio_extn_dolby_set_license(adev);
+    audio_hwdep_send_cal(my_data);
+
+    return my_data;
+}
+
+void platform_deinit(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    hw_info_deinit(my_data->hw_info);
+    close_csd_client(my_data->csd);
+
+    free(platform);
+    /* deinit usb */
+    audio_extn_usb_deinit();
+    audio_extn_dap_hal_deinit();
+}
+
+int platform_is_acdb_initialized(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    ALOGD("%s: acdb initialized %d\n", __func__, my_data->is_acdb_initialized);
+    return my_data->is_acdb_initialized;
+}
+
+const char *platform_get_snd_device_name(snd_device_t snd_device)
+{
+    if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX)
+        return device_table[snd_device];
+    else
+        return "";
+}
+
+int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device,
+                                      char *device_name)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) {
+        strlcpy(device_name, device_table[snd_device], DEVICE_NAME_MAX_SIZE);
+        hw_info_append_hw_type(my_data->hw_info, snd_device, device_name);
+    } else {
+        strlcpy(device_name, "", DEVICE_NAME_MAX_SIZE);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+void platform_add_backend_name(char *mixer_path, snd_device_t snd_device)
+{
+    if ((snd_device == SND_DEVICE_IN_BT_SCO_MIC) ||
+         (snd_device == SND_DEVICE_IN_BT_SCO_MIC_NREC))
+        strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
+    else if ((snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB) ||
+              (snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB_NREC))
+        strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH);
+    else if(snd_device == SND_DEVICE_OUT_BT_SCO)
+        strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
+    else if(snd_device == SND_DEVICE_OUT_BT_A2DP)
+        strlcat(mixer_path, " bt-a2dp", MIXER_PATH_MAX_LENGTH);
+    else if(snd_device == SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP)
+        strlcat(mixer_path, " speaker-and-bt-a2dp", MIXER_PATH_MAX_LENGTH);
+    else if(snd_device == SND_DEVICE_OUT_BT_SCO_WB)
+        strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH);
+    else if (snd_device == SND_DEVICE_OUT_HDMI)
+        strlcat(mixer_path, " hdmi", MIXER_PATH_MAX_LENGTH);
+    else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI)
+        strlcat(mixer_path, " speaker-and-hdmi", MIXER_PATH_MAX_LENGTH);
+    else if (snd_device == SND_DEVICE_OUT_AFE_PROXY)
+        strlcat(mixer_path, " afe-proxy", MIXER_PATH_MAX_LENGTH);
+    else if (snd_device == SND_DEVICE_OUT_USB_HEADSET)
+        strlcat(mixer_path, " usb-headphones", MIXER_PATH_MAX_LENGTH);
+    else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET)
+        strlcat(mixer_path, " speaker-and-usb-headphones",
+                MIXER_PATH_MAX_LENGTH);
+    else if (snd_device == SND_DEVICE_IN_USB_HEADSET_MIC)
+        strlcat(mixer_path, " usb-headset-mic", MIXER_PATH_MAX_LENGTH);
+    else if (snd_device == SND_DEVICE_IN_CAPTURE_FM)
+        strlcat(mixer_path, " capture-fm", MIXER_PATH_MAX_LENGTH);
+    else if (snd_device == SND_DEVICE_OUT_TRANSMISSION_FM)
+        strlcat(mixer_path, " transmission-fm", MIXER_PATH_MAX_LENGTH);
+}
+
+int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type)
+{
+    int device_id = -1;
+
+    if (is_external_codec && is_misc_usecase(usecase)) {
+        if (device_type == PCM_PLAYBACK)
+            device_id = pcm_device_table_of_ext_codec[usecase][0];
+        else
+            device_id = pcm_device_table_of_ext_codec[usecase][1];
+    } else {
+        if (device_type == PCM_PLAYBACK)
+            device_id = pcm_device_table[usecase][0];
+        else
+            device_id = pcm_device_table[usecase][1];
+    }
+    return device_id;
+}
+
+int platform_get_snd_device_index(char *snd_device_index_name)
+{
+    int ret = 0;
+    int i;
+
+    if (snd_device_index_name == NULL) {
+        ALOGE("%s: snd_device_index_name is NULL", __func__);
+        ret = -ENODEV;
+        goto done;
+    }
+
+    for (i=0; i < SND_DEVICE_MAX; i++) {
+        if(strcmp(snd_device_name_index[i].name, snd_device_index_name) == 0) {
+            ret = snd_device_name_index[i].index;
+            goto done;
+        }
+    }
+    ALOGE("%s: Could not find index for snd_device_index_name = %s",
+            __func__, snd_device_index_name);
+    ret = -ENODEV;
+done:
+    return ret;
+}
+
+int platform_set_fluence_type(void *platform, char *value)
+{
+    int ret = 0;
+    int fluence_type = FLUENCE_NONE;
+    int fluence_flag = NONE_FLAG;
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+
+    ALOGV("%s: fluence type:%d", __func__, my_data->fluence_type);
+
+    /* only dual mic turn on and off is supported as of now through setparameters */
+    if (!strncmp(AUDIO_PARAMETER_VALUE_DUALMIC,value, sizeof(AUDIO_PARAMETER_VALUE_DUALMIC))) {
+        if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro")) ||
+            !strncmp("fluence", my_data->fluence_cap, sizeof("fluence"))) {
+            ALOGV("fluence dualmic feature enabled \n");
+            fluence_type = FLUENCE_DUAL_MIC;
+            fluence_flag = DMIC_FLAG;
+        } else {
+            ALOGE("%s: Failed to set DUALMIC", __func__);
+            ret = -1;
+            goto done;
+        }
+    } else if (!strncmp(AUDIO_PARAMETER_KEY_NO_FLUENCE, value, sizeof(AUDIO_PARAMETER_KEY_NO_FLUENCE))) {
+        ALOGV("fluence disabled");
+        fluence_type = FLUENCE_NONE;
+    } else {
+        ALOGE("Invalid fluence value : %s",value);
+        ret = -1;
+        goto done;
+    }
+
+    if (fluence_type != my_data->fluence_type) {
+        ALOGV("%s: Updating fluence_type to :%d", __func__, fluence_type);
+        my_data->fluence_type = fluence_type;
+        adev->acdb_settings = (adev->acdb_settings & FLUENCE_MODE_CLEAR) | fluence_flag;
+    }
+done:
+    return ret;
+}
+
+int platform_get_fluence_type(void *platform, char *value, uint32_t len)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if (my_data->fluence_type == FLUENCE_QUAD_MIC) {
+        strlcpy(value, "quadmic", len);
+    } else if (my_data->fluence_type == FLUENCE_DUAL_MIC) {
+        strlcpy(value, "dualmic", len);
+    } else if (my_data->fluence_type == FLUENCE_NONE) {
+        strlcpy(value, "none", len);
+    } else
+        ret = -1;
+
+    return ret;
+}
+
+int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id)
+{
+    int ret = 0;
+
+    if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
+        ALOGE("%s: Invalid snd_device = %d",
+            __func__, snd_device);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    acdb_device_table[snd_device] = acdb_id;
+done:
+    return ret;
+}
+
+int platform_get_default_app_type(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if (my_data->acdb_get_default_app_type)
+        return my_data->acdb_get_default_app_type();
+    else
+        return DEFAULT_APP_TYPE;
+}
+
+int platform_get_snd_device_acdb_id(snd_device_t snd_device)
+{
+    if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
+        ALOGE("%s: Invalid snd_device = %d", __func__, snd_device);
+        return -EINVAL;
+    }
+    return acdb_device_table[snd_device];
+}
+
+int platform_send_audio_calibration(void *platform, struct audio_usecase *usecase,
+                                    int app_type, int sample_rate)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int acdb_dev_id, acdb_dev_type;
+    struct audio_device *adev = my_data->adev;
+    int snd_device = SND_DEVICE_OUT_SPEAKER;
+
+    if (usecase->type == PCM_PLAYBACK) {
+        snd_device = usecase->out_snd_device;
+        if(usecase->id != USECASE_AUDIO_PLAYBACK_OFFLOAD)
+            app_type = APP_TYPE_SYSTEM_SOUNDS;
+    } else if ((usecase->type == PCM_HFP_CALL) || (usecase->type == PCM_CAPTURE)) {
+        snd_device = usecase->in_snd_device;
+        app_type = APP_TYPE_GENERAL_RECORDING;
+    }
+
+    acdb_dev_id = acdb_device_table[snd_device];
+    if (acdb_dev_id < 0) {
+        ALOGE("%s: Could not find acdb id for device(%d)",
+              __func__, snd_device);
+        return -EINVAL;
+    }
+    if (my_data->acdb_send_audio_cal) {
+        ALOGV("%s: sending audio calibration for snd_device(%d) acdb_id(%d)",
+              __func__, snd_device, acdb_dev_id);
+        if (snd_device >= SND_DEVICE_OUT_BEGIN &&
+                snd_device < SND_DEVICE_OUT_END)
+            acdb_dev_type = ACDB_DEV_TYPE_OUT;
+        else
+            acdb_dev_type = ACDB_DEV_TYPE_IN;
+        my_data->acdb_send_audio_cal(acdb_dev_id, acdb_dev_type, app_type,
+                                     sample_rate);
+    }
+    return 0;
+}
+
+int platform_switch_voice_call_device_pre(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int ret = 0;
+
+    if (my_data->csd != NULL &&
+        my_data->adev->mode == AUDIO_MODE_IN_CALL) {
+        /* This must be called before disabling mixer controls on APQ side */
+        ret = my_data->csd->disable_device();
+        if (ret < 0) {
+            ALOGE("%s: csd_client_disable_device, failed, error %d",
+                  __func__, ret);
+        }
+    }
+    return ret;
+}
+int platform_switch_voice_call_enable_device_config(void *platform,
+                                                    snd_device_t out_snd_device,
+                                                    snd_device_t in_snd_device)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int acdb_rx_id, acdb_tx_id;
+    int ret = 0;
+
+    acdb_rx_id = acdb_device_table[out_snd_device];
+    acdb_tx_id = acdb_device_table[in_snd_device];
+
+    if (my_data->csd != NULL) {
+        if (acdb_rx_id > 0 && acdb_tx_id > 0) {
+            ret = my_data->csd->enable_device_config(acdb_rx_id, acdb_tx_id);
+            if (ret < 0) {
+                ALOGE("%s: csd_enable_device_config, failed, error %d",
+                      __func__, ret);
+            }
+        } else {
+            ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+                  acdb_rx_id, acdb_tx_id);
+        }
+    }
+    return ret;
+}
+
+
+int platform_switch_voice_call_device_post(void *platform,
+                                           snd_device_t out_snd_device,
+                                           snd_device_t in_snd_device)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int acdb_rx_id, acdb_tx_id;
+
+    if (my_data->acdb_send_voice_cal == NULL) {
+        ALOGE("%s: dlsym error for acdb_send_voice_call", __func__);
+    } else {
+        acdb_rx_id = acdb_device_table[out_snd_device];
+        acdb_tx_id = acdb_device_table[in_snd_device];
+
+        if (acdb_rx_id > 0 && acdb_tx_id > 0)
+            my_data->acdb_send_voice_cal(acdb_rx_id, acdb_tx_id);
+        else
+            ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+                  acdb_rx_id, acdb_tx_id);
+    }
+
+    return 0;
+}
+
+int platform_switch_voice_call_usecase_route_post(void *platform,
+                                                  snd_device_t out_snd_device,
+                                                  snd_device_t in_snd_device)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int acdb_rx_id, acdb_tx_id;
+    int ret = 0;
+
+    acdb_rx_id = acdb_device_table[out_snd_device];
+    acdb_tx_id = acdb_device_table[in_snd_device];
+
+    if (my_data->csd != NULL) {
+        if (acdb_rx_id > 0 && acdb_tx_id > 0) {
+            ret = my_data->csd->enable_device(acdb_rx_id, acdb_tx_id,
+                                              my_data->adev->acdb_settings);
+            if (ret < 0) {
+                ALOGE("%s: csd_enable_device, failed, error %d",
+                      __func__, ret);
+            }
+        } else {
+            ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+                  acdb_rx_id, acdb_tx_id);
+        }
+    }
+    return ret;
+}
+
+int platform_start_voice_call(void *platform, uint32_t vsid)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int ret = 0;
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->start_voice(vsid);
+        if (ret < 0) {
+            ALOGE("%s: csd_start_voice error %d\n", __func__, ret);
+        }
+    }
+    return ret;
+}
+
+int platform_stop_voice_call(void *platform, uint32_t vsid)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int ret = 0;
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->stop_voice(vsid);
+        if (ret < 0) {
+            ALOGE("%s: csd_stop_voice error %d\n", __func__, ret);
+        }
+    }
+    return ret;
+}
+
+int platform_get_sample_rate(void *platform __unused, uint32_t *rate __unused)
+{
+    return 0;
+}
+
+int platform_set_voice_volume(void *platform, int volume)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Voice Rx Gain";
+    int vol_index = 0, ret = 0;
+    uint32_t set_values[ ] = {0,
+                              ALL_SESSION_VSID,
+                              DEFAULT_VOLUME_RAMP_DURATION_MS};
+
+    // Voice volume levels are mapped to adsp volume levels as follows.
+    // 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1  0 -> 0
+    // But this values don't changed in kernel. So, below change is need.
+    vol_index = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX);
+    set_values[0] = vol_index;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    ALOGV("Setting voice volume index: %d", set_values[0]);
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->volume(ALL_SESSION_VSID, volume);
+        if (ret < 0) {
+            ALOGE("%s: csd_volume error %d", __func__, ret);
+        }
+    }
+    return ret;
+}
+
+int platform_set_mic_mute(void *platform, bool state)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Voice Tx Mute";
+    int ret = 0;
+    uint32_t set_values[ ] = {0,
+                              ALL_SESSION_VSID,
+                              DEFAULT_VOLUME_RAMP_DURATION_MS};
+
+    set_values[0] = state;
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    ALOGV("Setting voice mute state: %d", state);
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->mic_mute(ALL_SESSION_VSID, state);
+        if (ret < 0) {
+            ALOGE("%s: csd_mic_mute error %d", __func__, ret);
+        }
+    }
+    return ret;
+}
+
+int platform_set_device_mute(void *platform, bool state, char *dir)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    char *mixer_ctl_name = NULL;
+    int ret = 0;
+    uint32_t set_values[ ] = {0,
+                              ALL_SESSION_VSID,
+                              0};
+    if(dir == NULL) {
+        ALOGE("%s: Invalid direction:%s", __func__, dir);
+        return -EINVAL;
+    }
+
+    if (!strncmp("rx", dir, sizeof("rx"))) {
+        mixer_ctl_name = "Voice Rx Device Mute";
+    } else if (!strncmp("tx", dir, sizeof("tx"))) {
+        mixer_ctl_name = "Voice Tx Device Mute";
+    } else {
+        return -EINVAL;
+    }
+
+    set_values[0] = state;
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+
+    ALOGV("%s: Setting device mute state: %d, mixer ctrl:%s",
+          __func__,state, mixer_ctl_name);
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+    return ret;
+}
+
+snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    audio_mode_t mode = adev->mode;
+    snd_device_t snd_device = SND_DEVICE_NONE;
+#ifdef RECORD_PLAY_CONCURRENCY
+    bool use_voip_out_devices = false;
+    bool prop_rec_play_enabled = false;
+    char recConcPropValue[PROPERTY_VALUE_MAX];
+
+    if (property_get("rec.playback.conc.disabled", recConcPropValue, NULL)) {
+        prop_rec_play_enabled = atoi(recConcPropValue) || !strncmp("true", recConcPropValue, 4);
+    }
+    use_voip_out_devices =  prop_rec_play_enabled &&
+                        (my_data->rec_play_conc_set || adev->mode == AUDIO_MODE_IN_COMMUNICATION);
+    ALOGV("platform_get_output_snd_device use_voip_out_devices : %d",use_voip_out_devices);
+#endif
+
+    audio_channel_mask_t channel_mask = (adev->active_input == NULL) ?
+                                AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask;
+    int channel_count = popcount(channel_mask);
+
+    ALOGV("%s: enter: output devices(%#x)", __func__, devices);
+    if (devices == AUDIO_DEVICE_NONE ||
+        devices & AUDIO_DEVICE_BIT_IN) {
+        ALOGV("%s: Invalid output devices (%#x)", __func__, devices);
+        goto exit;
+    }
+
+    if (popcount(devices) == 2 && !voice_is_in_call(adev)) {
+        if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+                        AUDIO_DEVICE_OUT_SPEAKER)) {
+            snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
+        } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET |
+                               AUDIO_DEVICE_OUT_SPEAKER)) {
+            if (audio_extn_get_anc_enabled())
+                snd_device = SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET;
+            else
+                snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
+        } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL |
+                               AUDIO_DEVICE_OUT_SPEAKER)) {
+            snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI;
+        } else if (devices == (AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
+                               AUDIO_DEVICE_OUT_SPEAKER)) {
+            snd_device = SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET;
+        } else if ((devices & AUDIO_DEVICE_OUT_SPEAKER) &&
+                   (devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+            snd_device = SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP;
+        } else {
+            ALOGE("%s: Invalid combo device(%#x)", __func__, devices);
+            goto exit;
+        }
+        if (snd_device != SND_DEVICE_NONE) {
+            goto exit;
+        }
+    }
+
+    if (popcount(devices) != 1) {
+        ALOGE("%s: Invalid output devices(%#x)", __func__, devices);
+        goto exit;
+    }
+
+    if ((mode == AUDIO_MODE_IN_CALL) ||
+        voice_extn_compress_voip_is_active(adev)) {
+        if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+            devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+            if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
+                !voice_extn_compress_voip_is_active(adev)) {
+                switch (adev->voice.tty_mode) {
+                case TTY_MODE_FULL:
+                    snd_device = SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES;
+                    break;
+                case TTY_MODE_VCO:
+                    snd_device = SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES;
+                    break;
+                case TTY_MODE_HCO:
+                    snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET;
+                    break;
+                default:
+                    ALOGE("%s: Invalid TTY mode (%#x)",
+                          __func__, adev->voice.tty_mode);
+                }
+            } else if (audio_extn_get_anc_enabled()) {
+                if (audio_extn_should_use_fb_anc())
+                    snd_device = SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET;
+                else
+                    snd_device = SND_DEVICE_OUT_VOICE_ANC_HEADSET;
+            } else {
+                snd_device = SND_DEVICE_OUT_VOICE_HEADPHONES;
+            }
+        } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
+            if (adev->bt_wb_speech_enabled)
+                snd_device = SND_DEVICE_OUT_BT_SCO_WB;
+            else
+                snd_device = SND_DEVICE_OUT_BT_SCO;
+        } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
+                if (my_data->is_wsa_speaker)
+                    snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_WSA;
+                else
+                    snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
+        } else if (devices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ||
+                   devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+            snd_device = SND_DEVICE_OUT_USB_HEADSET;
+        } else if (devices & AUDIO_DEVICE_OUT_FM_TX) {
+            snd_device = SND_DEVICE_OUT_TRANSMISSION_FM;
+        } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
+            if (audio_extn_should_use_handset_anc(channel_count))
+                snd_device = SND_DEVICE_OUT_ANC_HANDSET;
+            else
+                snd_device = SND_DEVICE_OUT_VOICE_HANDSET;
+        }
+        if (snd_device != SND_DEVICE_NONE) {
+            goto exit;
+        }
+    }
+
+    if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+        devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+        if (devices & AUDIO_DEVICE_OUT_WIRED_HEADSET
+            && audio_extn_get_anc_enabled()) {
+#ifdef RECORD_PLAY_CONCURRENCY
+            if (use_voip_out_devices) {
+                // ANC should be disabled for voip concurrency
+                snd_device = SND_DEVICE_OUT_VOIP_HEADPHONES;
+            } else
+#endif
+            {
+                if (audio_extn_should_use_fb_anc())
+                    snd_device = SND_DEVICE_OUT_ANC_FB_HEADSET;
+                else
+                    snd_device = SND_DEVICE_OUT_ANC_HEADSET;
+            }
+        } else {
+#ifdef RECORD_PLAY_CONCURRENCY
+            if (use_voip_out_devices)
+                snd_device = SND_DEVICE_OUT_VOIP_HEADPHONES;
+            else
+#endif
+                snd_device = SND_DEVICE_OUT_HEADPHONES;
+        }
+    } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
+#ifdef RECORD_PLAY_CONCURRENCY
+        if (use_voip_out_devices) {
+            snd_device = SND_DEVICE_OUT_VOIP_SPEAKER;
+        } else
+#endif
+        {
+            if (adev->speaker_lr_swap)
+                snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE;
+            else
+            {
+                if (my_data->is_wsa_speaker)
+                    snd_device = SND_DEVICE_OUT_SPEAKER_WSA;
+                else
+                    snd_device = SND_DEVICE_OUT_SPEAKER;
+            }
+        }
+    } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
+        if (adev->bt_wb_speech_enabled)
+            snd_device = SND_DEVICE_OUT_BT_SCO_WB;
+        else
+            snd_device = SND_DEVICE_OUT_BT_SCO;
+    } else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+        snd_device = SND_DEVICE_OUT_HDMI ;
+    } else if (devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+        snd_device = SND_DEVICE_OUT_BT_A2DP;
+    } else if (devices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ||
+               devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+        ALOGD("%s: setting USB hadset channel capability(2) for Proxy", __func__);
+        audio_extn_set_afe_proxy_channel_mixer(adev, 2);
+        snd_device = SND_DEVICE_OUT_USB_HEADSET;
+    } else if (devices & AUDIO_DEVICE_OUT_FM_TX) {
+        snd_device = SND_DEVICE_OUT_TRANSMISSION_FM;
+    } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
+#ifdef RECORD_PLAY_CONCURRENCY
+        if (use_voip_out_devices)
+            snd_device = SND_DEVICE_OUT_VOIP_HANDSET;
+        else
+#endif
+            snd_device = SND_DEVICE_OUT_HANDSET;
+    } else if (devices & AUDIO_DEVICE_OUT_PROXY) {
+        channel_count = audio_extn_get_afe_proxy_channel_count();
+        ALOGD("%s: setting sink capability(%d) for Proxy", __func__, channel_count);
+        audio_extn_set_afe_proxy_channel_mixer(adev, channel_count);
+        snd_device = SND_DEVICE_OUT_AFE_PROXY;
+    } else {
+        ALOGE("%s: Unknown device(s) %#x", __func__, devices);
+    }
+exit:
+    ALOGV("%s: exit: snd_device(%s)", __func__, device_table[snd_device]);
+    return snd_device;
+}
+
+snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    audio_source_t  source = (adev->active_input == NULL) ?
+                                AUDIO_SOURCE_DEFAULT : adev->active_input->source;
+
+    audio_mode_t    mode   = adev->mode;
+    audio_devices_t in_device = ((adev->active_input == NULL) ?
+                                    AUDIO_DEVICE_NONE : adev->active_input->device)
+                                & ~AUDIO_DEVICE_BIT_IN;
+    audio_channel_mask_t channel_mask = (adev->active_input == NULL) ?
+                                AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask;
+    snd_device_t snd_device = SND_DEVICE_NONE;
+    int channel_count = popcount(channel_mask);
+
+    ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
+          __func__, out_device, in_device);
+    if ((out_device != AUDIO_DEVICE_NONE) && ((mode == AUDIO_MODE_IN_CALL) ||
+        voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev))) {
+        if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
+            !voice_extn_compress_voip_is_active(adev)) {
+            if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+                out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+                switch (adev->voice.tty_mode) {
+                case TTY_MODE_FULL:
+                    snd_device = SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC;
+                    break;
+                case TTY_MODE_VCO:
+                    snd_device = SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC;
+                    break;
+                case TTY_MODE_HCO:
+                    snd_device = SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC;
+                    break;
+                default:
+                    ALOGE("%s: Invalid TTY mode (%#x)",
+                          __func__, adev->voice.tty_mode);
+                }
+                goto exit;
+            }
+        }
+        if (out_device & AUDIO_DEVICE_OUT_EARPIECE ||
+            out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+            if (out_device & AUDIO_DEVICE_OUT_EARPIECE &&
+                audio_extn_should_use_handset_anc(channel_count) &&
+                my_data->fluence_type != FLUENCE_NONE) {
+                snd_device = SND_DEVICE_IN_VOICE_FLUENCE_DMIC_AANC;
+                adev->acdb_settings |= DMIC_FLAG;
+                ALOGD("Selecting AANC, Fluence combo device");
+            } else if (out_device & AUDIO_DEVICE_OUT_EARPIECE &&
+                audio_extn_should_use_handset_anc(channel_count)) {
+                snd_device = SND_DEVICE_IN_AANC_HANDSET_MIC;
+            } else if (my_data->fluence_type == FLUENCE_NONE ||
+                my_data->fluence_in_voice_call == false) {
+                snd_device = SND_DEVICE_IN_HANDSET_MIC;
+                if (audio_extn_hfp_is_active(adev))
+                    platform_set_echo_reference(adev->platform, true);
+            } else {
+                snd_device = SND_DEVICE_IN_VOICE_DMIC;
+                adev->acdb_settings |= DMIC_FLAG;
+            }
+        } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+            snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC;
+               if (audio_extn_hfp_is_active(adev))
+                   platform_set_echo_reference(adev->platform, true);
+        } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
+            if (adev->bt_wb_speech_enabled) {
+                if (adev->bluetooth_nrec)
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB_NREC;
+                else
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+            } else {
+                if (adev->bluetooth_nrec)
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC_NREC;
+                else
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+            }
+        } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
+            if (my_data->fluence_type != FLUENCE_NONE &&
+                my_data->fluence_in_voice_call &&
+                my_data->fluence_in_spkr_mode) {
+                if(my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                    adev->acdb_settings |= QMIC_FLAG;
+                    snd_device = SND_DEVICE_IN_VOICE_SPEAKER_QMIC;
+                } else {
+                    adev->acdb_settings |= DMIC_FLAG;
+                    if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                       snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE;
+                    else
+                       snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC;
+                }
+            } else {
+                snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC;
+                if (audio_extn_hfp_is_active(adev))
+                    platform_set_echo_reference(adev->platform, true);
+            }
+        }
+    } else if (source == AUDIO_SOURCE_CAMCORDER) {
+        if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC ||
+            in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+            if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
+                channel_count == 2)
+                snd_device = SND_DEVICE_IN_HANDSET_STEREO_DMIC;
+            else
+                snd_device = SND_DEVICE_IN_CAMCORDER_MIC;
+        }
+    } else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) {
+        if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+           if (channel_count == 2) {
+                snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_STEREO;
+                adev->acdb_settings |= DMIC_FLAG;
+            } else if (adev->active_input->enable_ns)
+                snd_device = SND_DEVICE_IN_VOICE_REC_MIC_NS;
+            else if (my_data->fluence_type != FLUENCE_NONE &&
+                     my_data->fluence_in_voice_rec) {
+                snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE;
+                adev->acdb_settings |= DMIC_FLAG;
+            } else {
+                snd_device = SND_DEVICE_IN_VOICE_REC_MIC;
+            }
+        }
+    } else if ((source == AUDIO_SOURCE_VOICE_COMMUNICATION) ||
+              (mode == AUDIO_MODE_IN_COMMUNICATION)) {
+        if (out_device & AUDIO_DEVICE_OUT_SPEAKER)
+            in_device = AUDIO_DEVICE_IN_BACK_MIC;
+        if (adev->active_input) {
+            if (adev->active_input->enable_aec &&
+                    adev->active_input->enable_ns) {
+                if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+                    if (my_data->fluence_in_spkr_mode) {
+                        if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                            snd_device = SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS;
+                        } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                            if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE;
+                            else
+                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS;
+                        }
+                        adev->acdb_settings |= DMIC_FLAG;
+                    } else
+                        snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC_NS;
+                } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+                    if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                        snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC_NS;
+                        adev->acdb_settings |= DMIC_FLAG;
+                    } else
+                        snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC_NS;
+                } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+                    snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
+                }
+                platform_set_echo_reference(adev->platform, true);
+            } else if (adev->active_input->enable_aec) {
+                if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+                    if (my_data->fluence_in_spkr_mode) {
+                        if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                            snd_device = SND_DEVICE_IN_SPEAKER_QMIC_AEC;
+                        } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                            if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE;
+                            else
+                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC;
+                        }
+                        adev->acdb_settings |= DMIC_FLAG;
+                    } else
+                        snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC;
+                } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+                    if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                        snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC;
+                        adev->acdb_settings |= DMIC_FLAG;
+                    } else
+                        snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC;
+                } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+                    snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
+                }
+                platform_set_echo_reference(adev->platform, true);
+            } else if (adev->active_input->enable_ns) {
+                if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+                    if (my_data->fluence_in_spkr_mode) {
+                        if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                            snd_device = SND_DEVICE_IN_SPEAKER_QMIC_NS;
+                        } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                            if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE;
+                            else
+                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS;
+                        }
+                        adev->acdb_settings |= DMIC_FLAG;
+                    } else
+                        snd_device = SND_DEVICE_IN_SPEAKER_MIC_NS;
+                } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+                    if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                        snd_device = SND_DEVICE_IN_HANDSET_DMIC_NS;
+                        adev->acdb_settings |= DMIC_FLAG;
+                    } else
+                        snd_device = SND_DEVICE_IN_HANDSET_MIC_NS;
+                } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+                    snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
+                }
+                platform_set_echo_reference(adev->platform,false);
+            } else
+                platform_set_echo_reference(adev->platform, false);
+        }
+    } else if (source == AUDIO_SOURCE_MIC) {
+        if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC &&
+                channel_count == 1 ) {
+            ALOGD("Record path active");
+            if(my_data->fluence_in_audio_rec) {
+                if(my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                    ALOGD(" snd_device = SND_DEVICE_IN_HANDSET_QMIC");
+                    snd_device = SND_DEVICE_IN_HANDSET_QMIC;
+                    platform_set_echo_reference(adev->platform, true);
+                } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                    snd_device = SND_DEVICE_IN_HANDSET_DMIC;
+                    platform_set_echo_reference(adev->platform, true);
+                }
+            }
+        }
+    } else if (source == AUDIO_SOURCE_FM_TUNER) {
+        snd_device = SND_DEVICE_IN_CAPTURE_FM;
+    } else if (source == AUDIO_SOURCE_DEFAULT) {
+        goto exit;
+    }
+
+
+    if (snd_device != SND_DEVICE_NONE) {
+        goto exit;
+    }
+
+    if (in_device != AUDIO_DEVICE_NONE &&
+            !(in_device & AUDIO_DEVICE_IN_VOICE_CALL) &&
+            !(in_device & AUDIO_DEVICE_IN_COMMUNICATION)) {
+        if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            if (audio_extn_ssr_get_enabled() && channel_count == 6)
+                snd_device = SND_DEVICE_IN_QUAD_MIC;
+            else if (channel_count == 2)
+                snd_device = SND_DEVICE_IN_HANDSET_STEREO_DMIC;
+            else
+                snd_device = SND_DEVICE_IN_HANDSET_MIC;
+        } else if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+            snd_device = SND_DEVICE_IN_SPEAKER_MIC;
+        } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+            snd_device = SND_DEVICE_IN_HEADSET_MIC;
+        } else if (in_device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+            if (adev->bt_wb_speech_enabled) {
+                if (adev->bluetooth_nrec)
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB_NREC;
+                else
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+            } else {
+                if (adev->bluetooth_nrec)
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC_NREC;
+                else
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+            }
+        } else if (in_device & AUDIO_DEVICE_IN_AUX_DIGITAL) {
+            snd_device = SND_DEVICE_IN_HDMI_MIC;
+        } else if (in_device & AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET ||
+                   in_device & AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET) {
+            snd_device = SND_DEVICE_IN_USB_HEADSET_MIC;
+        } else if (in_device & AUDIO_DEVICE_IN_FM_TUNER) {
+            snd_device = SND_DEVICE_IN_CAPTURE_FM;
+        } else {
+            ALOGE("%s: Unknown input device(s) %#x", __func__, in_device);
+            ALOGW("%s: Using default handset-mic", __func__);
+            snd_device = SND_DEVICE_IN_HANDSET_MIC;
+        }
+    } else {
+        if (out_device & AUDIO_DEVICE_OUT_EARPIECE) {
+            snd_device = SND_DEVICE_IN_HANDSET_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+            snd_device = SND_DEVICE_IN_HEADSET_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
+            if (channel_count > 1)
+                snd_device = SND_DEVICE_IN_SPEAKER_STEREO_DMIC;
+            else
+                snd_device = SND_DEVICE_IN_SPEAKER_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+            snd_device = SND_DEVICE_IN_HANDSET_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) {
+            if (adev->bt_wb_speech_enabled) {
+                if (adev->bluetooth_nrec)
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB_NREC;
+                else
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+            } else {
+                if (adev->bluetooth_nrec)
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC_NREC;
+                else
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+            }
+        } else if (out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+            snd_device = SND_DEVICE_IN_HDMI_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ||
+                   out_device & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+            snd_device = SND_DEVICE_IN_USB_HEADSET_MIC;
+        } else {
+            ALOGE("%s: Unknown output device(s) %#x", __func__, out_device);
+            ALOGW("%s: Using default handset-mic", __func__);
+            snd_device = SND_DEVICE_IN_HANDSET_MIC;
+        }
+    }
+exit:
+    ALOGV("%s: exit: in_snd_device(%s)", __func__, device_table[snd_device]);
+    return snd_device;
+}
+
+int platform_set_hdmi_channels(void *platform,  int channel_count)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    const char *channel_cnt_str = NULL;
+    const char *mixer_ctl_name = "HDMI_RX Channels";
+    switch (channel_count) {
+    case 8:
+        channel_cnt_str = "Eight"; break;
+    case 7:
+        channel_cnt_str = "Seven"; break;
+    case 6:
+        channel_cnt_str = "Six"; break;
+    case 5:
+        channel_cnt_str = "Five"; break;
+    case 4:
+        channel_cnt_str = "Four"; break;
+    case 3:
+        channel_cnt_str = "Three"; break;
+    default:
+        channel_cnt_str = "Two"; break;
+    }
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    ALOGV("HDMI channel count: %s", channel_cnt_str);
+    mixer_ctl_set_enum_by_string(ctl, channel_cnt_str);
+    return 0;
+}
+
+int platform_edid_get_max_channels(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE];
+    char *sad = block;
+    int num_audio_blocks;
+    int channel_count;
+    int max_channels = 0;
+    int i, ret, count;
+
+    struct mixer_ctl *ctl;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, AUDIO_DATA_BLOCK_MIXER_CTL);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, AUDIO_DATA_BLOCK_MIXER_CTL);
+        return 0;
+    }
+
+    mixer_ctl_update(ctl);
+
+    count = mixer_ctl_get_num_values(ctl);
+
+    /* Read SAD blocks, clamping the maximum size for safety */
+    if (count > (int)sizeof(block))
+        count = (int)sizeof(block);
+
+    ret = mixer_ctl_get_array(ctl, block, count);
+    if (ret != 0) {
+        ALOGE("%s: mixer_ctl_get_array() failed to get EDID info", __func__);
+        return 0;
+    }
+
+    /* Calculate the number of SAD blocks */
+    num_audio_blocks = count / SAD_BLOCK_SIZE;
+
+    for (i = 0; i < num_audio_blocks; i++) {
+        /* Only consider LPCM blocks */
+        if ((sad[0] >> 3) != EDID_FORMAT_LPCM) {
+            sad += 3;
+            continue;
+        }
+
+        channel_count = (sad[0] & 0x7) + 1;
+        if (channel_count > max_channels)
+            max_channels = channel_count;
+
+        /* Advance to next block */
+        sad += 3;
+    }
+
+    return max_channels;
+}
+
+static int platform_set_slowtalk(struct platform_data *my_data, bool state)
+{
+    int ret = 0;
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Slowtalk Enable";
+    uint32_t set_values[ ] = {0,
+                              ALL_SESSION_VSID};
+
+    set_values[0] = state;
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        ret = -EINVAL;
+    } else {
+        ALOGV("Setting slowtalk state: %d", state);
+        ret = mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+        my_data->slowtalk = state;
+    }
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->slow_talk(ALL_SESSION_VSID, state);
+        if (ret < 0) {
+            ALOGE("%s: csd_client_disable_device, failed, error %d",
+                  __func__, ret);
+        }
+    }
+    return ret;
+}
+
+static int set_hd_voice(struct platform_data *my_data, bool state)
+{
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "HD Voice Enable";
+    int ret = 0;
+    uint32_t set_values[ ] = {0,
+                              ALL_SESSION_VSID};
+
+    set_values[0] = state;
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        ret = -EINVAL;
+    } else {
+        ALOGV("Setting HD Voice state: %d", state);
+        ret = mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+        my_data->hd_voice = state;
+    }
+
+    return ret;
+}
+
+int platform_set_parameters(void *platform, struct str_parms *parms)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    char *str;
+    char value[256] = {0};
+    int val;
+    int ret = 0, err;
+    char *kv_pairs = NULL;
+
+    kv_pairs = str_parms_to_str(parms);
+    ALOGV("%s: enter: - %s", __func__, kv_pairs);
+    free(kv_pairs);
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SLOWTALK, value, sizeof(value));
+    if (err >= 0) {
+        bool state = false;
+        if (!strncmp("true", value, sizeof("true"))) {
+            state = true;
+        }
+
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_SLOWTALK);
+        ret = platform_set_slowtalk(my_data, state);
+        if (ret)
+            ALOGE("%s: Failed to set slow talk err: %d", __func__, ret);
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HD_VOICE, value, sizeof(value));
+    if (err >= 0) {
+        bool state = false;
+        if (!strncmp("true", value, sizeof("true"))) {
+            state = true;
+        }
+
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_HD_VOICE);
+        if (my_data->hd_voice != state) {
+            ret = set_hd_voice(my_data, state);
+            if (ret)
+                ALOGE("%s: Failed to set HD voice err: %d", __func__, ret);
+        } else {
+            ALOGV("%s: HD Voice already set to %d", __func__, state);
+        }
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOLUME_BOOST,
+                            value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_VOLUME_BOOST);
+
+        if (my_data->acdb_reload_vocvoltable == NULL) {
+            ALOGE("%s: acdb_reload_vocvoltable is NULL", __func__);
+        } else if (!strcmp(value, "on")) {
+            if (!my_data->acdb_reload_vocvoltable(VOICE_FEATURE_SET_VOLUME_BOOST)) {
+                my_data->voice_feature_set = 1;
+            }
+        } else {
+            if (!my_data->acdb_reload_vocvoltable(VOICE_FEATURE_SET_DEFAULT)) {
+                my_data->voice_feature_set = 0;
+            }
+        }
+    }
+
+#ifdef RECORD_PLAY_CONCURRENCY
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_REC_PLAY_CONC, value, sizeof(value));
+    if (err >= 0) {
+        if (!strncmp("true", value, sizeof("true"))) {
+            ALOGD("setting record playback concurrency to true");
+            my_data->rec_play_conc_set = true;
+        } else {
+            ALOGD("setting record playback concurrency to false");
+            my_data->rec_play_conc_set = false;
+        }
+    }
+#endif
+    ALOGV("%s: exit with code(%d)", __func__, ret);
+    return ret;
+}
+
+int platform_set_incall_recording_session_id(void *platform,
+                                             uint32_t session_id, int rec_mode)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Voc VSID";
+    int num_ctl_values;
+    int i;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        ret = -EINVAL;
+    } else {
+        num_ctl_values = mixer_ctl_get_num_values(ctl);
+        for (i = 0; i < num_ctl_values; i++) {
+            if (mixer_ctl_set_value(ctl, i, session_id)) {
+                ALOGV("Error: invalid session_id: %x", session_id);
+                ret = -EINVAL;
+                break;
+            }
+        }
+    }
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->start_record(ALL_SESSION_VSID, rec_mode);
+        if (ret < 0) {
+            ALOGE("%s: csd_client_start_record failed, error %d",
+                  __func__, ret);
+        }
+    }
+
+    return ret;
+}
+
+int platform_stop_incall_recording_usecase(void *platform)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->stop_record(ALL_SESSION_VSID);
+        if (ret < 0) {
+            ALOGE("%s: csd_client_stop_record failed, error %d",
+                  __func__, ret);
+        }
+    }
+
+    return ret;
+}
+
+int platform_start_incall_music_usecase(void *platform)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->start_playback(ALL_SESSION_VSID);
+        if (ret < 0) {
+            ALOGE("%s: csd_client_start_playback failed, error %d",
+                  __func__, ret);
+        }
+    }
+
+    return ret;
+}
+
+int platform_stop_incall_music_usecase(void *platform)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->stop_playback(ALL_SESSION_VSID);
+        if (ret < 0) {
+            ALOGE("%s: csd_client_stop_playback failed, error %d",
+                  __func__, ret);
+        }
+    }
+
+    return ret;
+}
+
+int platform_update_lch(void *platform, struct voice_session *session,
+                        enum voice_lch_mode lch_mode)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if ((my_data->csd != NULL) && (my_data->csd->set_lch != NULL))
+        ret = my_data->csd->set_lch(session->vsid, lch_mode);
+    else
+        ret = pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode);
+
+    return ret;
+}
+
+void platform_get_parameters(void *platform,
+                            struct str_parms *query,
+                            struct str_parms *reply)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    char *str = NULL;
+    char value[256] = {0};
+    int ret;
+    char *kv_pairs = NULL;
+    char propValue[PROPERTY_VALUE_MAX]={0};
+    bool prop_playback_enabled = false;
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_SLOWTALK,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_SLOWTALK,
+                          my_data->slowtalk?"true":"false");
+    }
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_HD_VOICE,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_HD_VOICE,
+                          my_data->hd_voice?"true":"false");
+    }
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOLUME_BOOST,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        if (my_data->voice_feature_set == VOICE_FEATURE_SET_VOLUME_BOOST) {
+            strlcpy(value, "on", sizeof(value));
+        } else {
+            strlcpy(value, "off", sizeof(value));
+        }
+
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VOLUME_BOOST, value);
+    }
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_IS_HW_DECODER_SESSION_ALLOWED,
+                                    value, sizeof(value));
+    if (ret >= 0) {
+        int isallowed = 1; /*true*/
+
+        if (property_get("voice.playback.conc.disabled", propValue, NULL)) {
+            prop_playback_enabled = atoi(propValue) ||
+                !strncmp("true", propValue, 4);
+        }
+
+        if (prop_playback_enabled && (voice_is_in_call(my_data->adev) ||
+             (SND_CARD_STATE_OFFLINE == get_snd_card_state(my_data->adev)))) {
+            char *decoder_mime_type = value;
+
+            //check if unsupported mime type or not
+            if(decoder_mime_type) {
+                int i = 0;
+                for (i = 0; i < sizeof(dsp_only_decoders_mime)/sizeof(dsp_only_decoders_mime[0]); i++) {
+                    if (!strncmp(decoder_mime_type, dsp_only_decoders_mime[i],
+                    strlen(dsp_only_decoders_mime[i]))) {
+                       ALOGD("Rejecting request for DSP only session from HAL during voice call/SSR state");
+                       isallowed = 0;
+                       break;
+                    }
+                }
+            }
+        }
+        str_parms_add_int(reply, AUDIO_PARAMETER_IS_HW_DECODER_SESSION_ALLOWED, isallowed);
+    }
+
+
+    /* Handle audio calibration keys */
+    kv_pairs = str_parms_to_str(reply);
+    ALOGV("%s: exit: returns - %s", __func__, kv_pairs);
+    free(kv_pairs);
+}
+
+/* Delay in Us */
+int64_t platform_render_latency(audio_usecase_t usecase)
+{
+    switch (usecase) {
+        case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER:
+            return DEEP_BUFFER_PLATFORM_DELAY;
+        case USECASE_AUDIO_PLAYBACK_LOW_LATENCY:
+            return LOW_LATENCY_PLATFORM_DELAY;
+        default:
+            return 0;
+    }
+}
+
+int platform_update_usecase_from_source(int source, int usecase)
+{
+    ALOGV("%s: input source :%d", __func__, source);
+    if(source == AUDIO_SOURCE_FM_TUNER)
+        usecase = USECASE_AUDIO_RECORD_FM_VIRTUAL;
+    return usecase;
+}
+
+bool platform_listen_device_needs_event(snd_device_t snd_device)
+{
+    bool needs_event = false;
+
+    if ((snd_device >= SND_DEVICE_IN_BEGIN) &&
+        (snd_device < SND_DEVICE_IN_END) &&
+        (snd_device != SND_DEVICE_IN_CAPTURE_FM) &&
+        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK))
+        needs_event = true;
+
+    return needs_event;
+}
+
+bool platform_listen_usecase_needs_event(audio_usecase_t uc_id)
+{
+    bool needs_event = false;
+
+    switch(uc_id){
+    /* concurrent playback usecases needs event */
+    case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER:
+    case USECASE_AUDIO_PLAYBACK_MULTI_CH:
+    case USECASE_AUDIO_PLAYBACK_OFFLOAD:
+        needs_event = true;
+        break;
+    /* concurrent playback in low latency allowed */
+    case USECASE_AUDIO_PLAYBACK_LOW_LATENCY:
+        break;
+    /* concurrent playback FM needs event */
+    case USECASE_AUDIO_PLAYBACK_FM:
+        needs_event = true;
+        break;
+
+    /* concurrent capture usecases, no event, capture handled by device
+    *  USECASE_AUDIO_RECORD:
+    *  USECASE_AUDIO_RECORD_COMPRESS:
+    *  USECASE_AUDIO_RECORD_LOW_LATENCY:
+
+    *  USECASE_VOICE_CALL:
+    *  USECASE_VOICE2_CALL:
+    *  USECASE_VOLTE_CALL:
+    *  USECASE_QCHAT_CALL:
+    *  USECASE_VOWLAN_CALL:
+    *  USECASE_COMPRESS_VOIP_CALL:
+    *  USECASE_AUDIO_RECORD_FM_VIRTUAL:
+    *  USECASE_INCALL_REC_UPLINK:
+    *  USECASE_INCALL_REC_DOWNLINK:
+    *  USECASE_INCALL_REC_UPLINK_AND_DOWNLINK:
+    *  USECASE_INCALL_REC_UPLINK_COMPRESS:
+    *  USECASE_INCALL_REC_DOWNLINK_COMPRESS:
+    *  USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS:
+    *  USECASE_INCALL_MUSIC_UPLINK:
+    *  USECASE_INCALL_MUSIC_UPLINK2:
+    *  USECASE_AUDIO_SPKR_CALIB_RX:
+    *  USECASE_AUDIO_SPKR_CALIB_TX:
+    */
+    default:
+        ALOGV("%s:usecase_id[%d} no need to raise event.", __func__, uc_id);
+    }
+    return needs_event;
+}
+
+bool platform_sound_trigger_device_needs_event(snd_device_t snd_device)
+{
+    bool needs_event = false;
+
+    if ((snd_device >= SND_DEVICE_IN_BEGIN) &&
+        (snd_device < SND_DEVICE_IN_END) &&
+        (snd_device != SND_DEVICE_IN_CAPTURE_FM) &&
+        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK))
+        needs_event = true;
+
+    return needs_event;
+}
+
+bool platform_sound_trigger_usecase_needs_event(audio_usecase_t uc_id)
+{
+    bool needs_event = false;
+
+    switch(uc_id){
+    /* concurrent playback usecases needs event */
+    case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER:
+    case USECASE_AUDIO_PLAYBACK_MULTI_CH:
+    case USECASE_AUDIO_PLAYBACK_OFFLOAD:
+        needs_event = true;
+        break;
+    /* concurrent playback in low latency allowed */
+    case USECASE_AUDIO_PLAYBACK_LOW_LATENCY:
+        break;
+    /* concurrent playback FM needs event */
+    case USECASE_AUDIO_PLAYBACK_FM:
+        needs_event = true;
+        break;
+
+    /* concurrent capture usecases, no event, capture handled by device
+    *  USECASE_AUDIO_RECORD:
+    *  USECASE_AUDIO_RECORD_COMPRESS:
+    *  USECASE_AUDIO_RECORD_LOW_LATENCY:
+
+    *  USECASE_VOICE_CALL:
+    *  USECASE_VOICE2_CALL:
+    *  USECASE_VOLTE_CALL:
+    *  USECASE_QCHAT_CALL:
+    *  USECASE_VOWLAN_CALL:
+    *  USECASE_COMPRESS_VOIP_CALL:
+    *  USECASE_AUDIO_RECORD_FM_VIRTUAL:
+    *  USECASE_INCALL_REC_UPLINK:
+    *  USECASE_INCALL_REC_DOWNLINK:
+    *  USECASE_INCALL_REC_UPLINK_AND_DOWNLINK:
+    *  USECASE_INCALL_REC_UPLINK_COMPRESS:
+    *  USECASE_INCALL_REC_DOWNLINK_COMPRESS:
+    *  USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS:
+    *  USECASE_INCALL_MUSIC_UPLINK:
+    *  USECASE_INCALL_MUSIC_UPLINK2:
+    *  USECASE_AUDIO_SPKR_CALIB_RX:
+    *  USECASE_AUDIO_SPKR_CALIB_TX:
+    */
+    default:
+        ALOGV("%s:usecase_id[%d] no need to raise event.", __func__, uc_id);
+    }
+    return needs_event;
+}
+
+/* Read  offload buffer size from a property.
+ * If value is not power of 2  round it to
+ * power of 2.
+ */
+uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info)
+{
+    char value[PROPERTY_VALUE_MAX] = {0};
+    uint32_t fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE;
+    if((property_get("audio.offload.buffer.size.kb", value, "")) &&
+            atoi(value)) {
+        fragment_size =  atoi(value) * 1024;
+    }
+
+    if (info != NULL && info->has_video && info->is_streaming) {
+        fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING;
+        ALOGV("%s: offload fragment size reduced for AV streaming to %d",
+               __func__, fragment_size);
+    }
+
+    fragment_size = ALIGN( fragment_size, 1024);
+
+    if(fragment_size < MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE)
+        fragment_size = MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE;
+    else if(fragment_size > MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE)
+        fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE;
+    ALOGV("%s: fragment_size %d", __func__, fragment_size);
+    return fragment_size;
+}
+
+uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info)
+{
+    uint32_t fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
+    uint32_t bits_per_sample = 16;
+
+    if (info->format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) {
+        bits_per_sample = 32;
+    }
+
+    if (!info->has_video) {
+        fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
+
+    } else if (info->has_video && info->is_streaming) {
+        fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING
+                                     * info->sample_rate
+                                     * bits_per_sample
+                                     * popcount(info->channel_mask))/1000;
+
+    } else if (info->has_video) {
+        fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV
+                                     * info->sample_rate
+                                     * bits_per_sample
+                                     * popcount(info->channel_mask))/1000;
+    }
+
+    fragment_size = ALIGN( fragment_size, 1024);
+
+    if(fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE)
+        fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
+    else if(fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE)
+        fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
+
+    ALOGV("%s: fragment_size %d", __func__, fragment_size);
+    return fragment_size;
+}
+
+void platform_get_device_to_be_id_map(int **device_to_be_id, int *length)
+{
+     *device_to_be_id = msm_device_to_be_id;
+     *length = msm_be_id_array_len;
+}
+
+bool platform_check_24_bit_support() {
+    return false;
+}
+
+bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev __unused,
+                                              struct audio_usecase *usecase __unused)
+{
+    return false;
+}
+
+int platform_get_usecase_index(const char * usecase __unused)
+{
+    return -ENOSYS;
+}
+
+int platform_set_usecase_pcm_id(audio_usecase_t usecase __unused, int32_t type __unused,
+                                int32_t pcm_id __unused)
+{
+    return -ENOSYS;
+}
+
+int platform_set_snd_device_backend(snd_device_t snd_device __unused,
+                                    const char * backend __unused)
+{
+    return -ENOSYS;
+}
+
+int platform_get_subsys_image_name(char *buf)
+{
+    strlcpy(buf, PLATFORM_IMAGE_NAME, sizeof(PLATFORM_IMAGE_NAME));
+    return 0;
+}
diff --git a/msm8909/hal/msm8916/platform.h b/msm8909/hal/msm8916/platform.h
new file mode 100644
index 0000000..80852b5
--- /dev/null
+++ b/msm8909/hal/msm8916/platform.h
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef QCOM_AUDIO_PLATFORM_H
+#define QCOM_AUDIO_PLATFORM_H
+#include <sound/voice_params.h>
+
+enum {
+    FLUENCE_NONE,
+    FLUENCE_DUAL_MIC = 0x1,
+    FLUENCE_QUAD_MIC = 0x2,
+};
+
+enum {
+    FLUENCE_ENDFIRE = 0x1,
+    FLUENCE_BROADSIDE = 0x2,
+};
+
+#define PLATFORM_IMAGE_NAME "modem"
+
+/*
+ * Below are the devices for which is back end is same, SLIMBUS_0_RX.
+ * All these devices are handled by the internal HW codec. We can
+ * enable any one of these devices at any time.
+ */
+#define AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND \
+    (AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER | \
+     AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE)
+
+/* Sound devices specific to the platform
+ * The DEVICE_OUT_* and DEVICE_IN_* should be mapped to these sound
+ * devices to enable corresponding mixer paths
+ */
+enum {
+    SND_DEVICE_NONE = 0,
+
+    /* Playback devices */
+    SND_DEVICE_MIN,
+    SND_DEVICE_OUT_BEGIN = SND_DEVICE_MIN,
+    SND_DEVICE_OUT_HANDSET = SND_DEVICE_OUT_BEGIN,
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_REVERSE,
+    SND_DEVICE_OUT_SPEAKER_WSA,
+    SND_DEVICE_OUT_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_HANDSET,
+    SND_DEVICE_OUT_VOICE_SPEAKER,
+    SND_DEVICE_OUT_VOICE_SPEAKER_WSA,
+    SND_DEVICE_OUT_VOICE_HEADPHONES,
+    SND_DEVICE_OUT_HDMI,
+    SND_DEVICE_OUT_SPEAKER_AND_HDMI,
+    SND_DEVICE_OUT_BT_SCO,
+    SND_DEVICE_OUT_BT_SCO_WB,
+    SND_DEVICE_OUT_BT_A2DP,
+    SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP,
+    SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET,
+    SND_DEVICE_OUT_AFE_PROXY,
+    SND_DEVICE_OUT_USB_HEADSET,
+    SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET,
+    SND_DEVICE_OUT_TRANSMISSION_FM,
+    SND_DEVICE_OUT_ANC_HEADSET,
+    SND_DEVICE_OUT_ANC_FB_HEADSET,
+    SND_DEVICE_OUT_VOICE_ANC_HEADSET,
+    SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET,
+    SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+    SND_DEVICE_OUT_ANC_HANDSET,
+    SND_DEVICE_OUT_SPEAKER_PROTECTED,
+#ifdef RECORD_PLAY_CONCURRENCY
+    SND_DEVICE_OUT_VOIP_HANDSET,
+    SND_DEVICE_OUT_VOIP_SPEAKER,
+    SND_DEVICE_OUT_VOIP_HEADPHONES,
+#endif
+    SND_DEVICE_OUT_END,
+
+    /*
+     * Note: IN_BEGIN should be same as OUT_END because total number of devices
+     * SND_DEVICES_MAX should not exceed MAX_RX + MAX_TX devices.
+     */
+    /* Capture devices */
+    SND_DEVICE_IN_BEGIN = SND_DEVICE_OUT_END,
+    SND_DEVICE_IN_HANDSET_MIC  = SND_DEVICE_IN_BEGIN,
+    SND_DEVICE_IN_HANDSET_MIC_AEC,
+    SND_DEVICE_IN_HANDSET_MIC_NS,
+    SND_DEVICE_IN_HANDSET_MIC_AEC_NS,
+    SND_DEVICE_IN_HANDSET_DMIC,
+    SND_DEVICE_IN_HANDSET_DMIC_AEC,
+    SND_DEVICE_IN_HANDSET_DMIC_NS,
+    SND_DEVICE_IN_HANDSET_DMIC_AEC_NS,
+    SND_DEVICE_IN_SPEAKER_MIC,
+    SND_DEVICE_IN_SPEAKER_MIC_AEC,
+    SND_DEVICE_IN_SPEAKER_MIC_NS,
+    SND_DEVICE_IN_SPEAKER_MIC_AEC_NS,
+    SND_DEVICE_IN_SPEAKER_DMIC,
+    SND_DEVICE_IN_SPEAKER_DMIC_AEC,
+    SND_DEVICE_IN_SPEAKER_DMIC_NS,
+    SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS,
+    SND_DEVICE_IN_HEADSET_MIC,
+    SND_DEVICE_IN_HEADSET_MIC_FLUENCE,
+    SND_DEVICE_IN_VOICE_SPEAKER_MIC,
+    SND_DEVICE_IN_VOICE_HEADSET_MIC,
+    SND_DEVICE_IN_HDMI_MIC,
+    SND_DEVICE_IN_BT_SCO_MIC,
+    SND_DEVICE_IN_BT_SCO_MIC_NREC,
+    SND_DEVICE_IN_BT_SCO_MIC_WB,
+    SND_DEVICE_IN_BT_SCO_MIC_WB_NREC,
+    SND_DEVICE_IN_CAMCORDER_MIC,
+    SND_DEVICE_IN_VOICE_DMIC,
+    SND_DEVICE_IN_VOICE_SPEAKER_DMIC,
+    SND_DEVICE_IN_VOICE_SPEAKER_QMIC,
+    SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC,
+    SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC,
+    SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC,
+    SND_DEVICE_IN_VOICE_REC_MIC,
+    SND_DEVICE_IN_VOICE_REC_MIC_NS,
+    SND_DEVICE_IN_VOICE_REC_DMIC_STEREO,
+    SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
+    SND_DEVICE_IN_USB_HEADSET_MIC,
+    SND_DEVICE_IN_CAPTURE_FM,
+    SND_DEVICE_IN_AANC_HANDSET_MIC,
+    SND_DEVICE_IN_QUAD_MIC,
+    SND_DEVICE_IN_HANDSET_STEREO_DMIC,
+    SND_DEVICE_IN_SPEAKER_STEREO_DMIC,
+    SND_DEVICE_IN_CAPTURE_VI_FEEDBACK,
+    SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE,
+    SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE,
+    SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE,
+    SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE,
+    SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE,
+    SND_DEVICE_IN_VOICE_FLUENCE_DMIC_AANC,
+    SND_DEVICE_IN_HANDSET_QMIC,
+    SND_DEVICE_IN_SPEAKER_QMIC_AEC,
+    SND_DEVICE_IN_SPEAKER_QMIC_NS,
+    SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS,
+    SND_DEVICE_IN_END,
+
+    SND_DEVICE_MAX = SND_DEVICE_IN_END,
+
+};
+
+#define DEFAULT_OUTPUT_SAMPLING_RATE 48000
+
+#define ALL_SESSION_VSID                0xFFFFFFFF
+#define DEFAULT_MUTE_RAMP_DURATION      500
+#define DEFAULT_VOLUME_RAMP_DURATION_MS 20
+#define MIXER_PATH_MAX_LENGTH 100
+
+#define MAX_VOL_INDEX 5
+#define MIN_VOL_INDEX 0
+#define percent_to_index(val, min, max) \
+            ((val) * ((max) - (min)) * 0.01 + (min) + .5)
+
+/*
+ * tinyAlsa library interprets period size as number of frames
+ * one frame = channel_count * sizeof (pcm sample)
+ * so if format = 16-bit PCM and channels = Stereo, frame size = 2 ch * 2 = 4 bytes
+ * DEEP_BUFFER_OUTPUT_PERIOD_SIZE = 1024 means 1024 * 4 = 4096 bytes
+ * We should take care of returning proper size when AudioFlinger queries for
+ * the buffer size of an input/output stream
+ */
+#define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 960
+#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 4
+#define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240
+#define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2
+
+#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
+#define LOW_LATENCY_CAPTURE_PERIOD_SIZE 240
+#define LOW_LATENCY_CAPTURE_USE_CASE 1
+
+#define HDMI_MULTI_PERIOD_SIZE  336
+#define HDMI_MULTI_PERIOD_COUNT 8
+#define HDMI_MULTI_DEFAULT_CHANNEL_COUNT 6
+#define HDMI_MULTI_PERIOD_BYTES (HDMI_MULTI_PERIOD_SIZE * HDMI_MULTI_DEFAULT_CHANNEL_COUNT * 2)
+
+#define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
+#define AUDIO_CAPTURE_PERIOD_COUNT 2
+
+#define DEVICE_NAME_MAX_SIZE 128
+#define HW_INFO_ARRAY_MAX_SIZE 32
+
+#define DEEP_BUFFER_PCM_DEVICE 0
+#define AUDIO_RECORD_PCM_DEVICE 0
+#define MULTIMEDIA2_PCM_DEVICE 1
+#define FM_PLAYBACK_PCM_DEVICE 5
+#define FM_CAPTURE_PCM_DEVICE  6
+#define HFP_PCM_RX 5
+#define HFP_SCO_RX 17
+#define HFP_ASM_RX_TX 18
+
+#define INCALL_MUSIC_UPLINK_PCM_DEVICE 1
+#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16
+#define SPKR_PROT_CALIB_RX_PCM_DEVICE 5
+#define SPKR_PROT_CALIB_TX_PCM_DEVICE 22
+#define PLAYBACK_OFFLOAD_DEVICE 9
+#define COMPRESS_VOIP_CALL_PCM_DEVICE 3
+
+/* Define macro for Internal FM volume mixer */
+#define FM_RX_VOLUME "Internal FM RX Volume"
+
+#define LOWLATENCY_PCM_DEVICE 12
+#define EC_REF_RX "I2S_RX"
+#define COMPRESS_CAPTURE_DEVICE 19
+
+#define VOICE_CALL_PCM_DEVICE 2
+#define VOICE2_CALL_PCM_DEVICE 13
+#define VOLTE_CALL_PCM_DEVICE 15
+#define QCHAT_CALL_PCM_DEVICE 26
+#define QCHAT_CALL_PCM_DEVICE_OF_EXT_CODEC 28
+#define VOWLAN_CALL_PCM_DEVICE 16
+
+#define LIB_CSD_CLIENT "libcsd-client.so"
+/* CSD-CLIENT related functions */
+typedef int (*init_t)();
+typedef int (*deinit_t)();
+typedef int (*disable_device_t)();
+typedef int (*enable_device_config_t)(int, int);
+typedef int (*enable_device_t)(int, int, uint32_t);
+typedef int (*volume_t)(uint32_t, int);
+typedef int (*mic_mute_t)(uint32_t, int);
+typedef int (*slow_talk_t)(uint32_t, uint8_t);
+typedef int (*start_voice_t)(uint32_t);
+typedef int (*stop_voice_t)(uint32_t);
+typedef int (*start_playback_t)(uint32_t);
+typedef int (*stop_playback_t)(uint32_t);
+typedef int (*set_lch_t)(uint32_t, enum voice_lch_mode);
+typedef int (*start_record_t)(uint32_t, int);
+typedef int (*stop_record_t)(uint32_t);
+/* CSD Client structure */
+struct csd_data {
+    void *csd_client;
+    init_t init;
+    deinit_t deinit;
+    disable_device_t disable_device;
+    enable_device_config_t enable_device_config;
+    enable_device_t enable_device;
+    volume_t volume;
+    mic_mute_t mic_mute;
+    slow_talk_t slow_talk;
+    start_voice_t start_voice;
+    stop_voice_t stop_voice;
+    start_playback_t start_playback;
+    stop_playback_t stop_playback;
+    set_lch_t set_lch;
+    start_record_t start_record;
+    stop_record_t stop_record;
+};
+
+int platform_get_subsys_image_name (char *buf);
+
+#endif // QCOM_AUDIO_PLATFORM_H
diff --git a/msm8909/hal/msm8960/platform.c b/msm8909/hal/msm8960/platform.c
new file mode 100644
index 0000000..593b66a
--- /dev/null
+++ b/msm8909/hal/msm8960/platform.c
@@ -0,0 +1,1088 @@
+/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "msm8960_platform"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <audio_hw.h>
+#include <platform_api.h>
+#include "platform.h"
+
+#define LIB_ACDB_LOADER "libacdbloader.so"
+#define LIB_CSD_CLIENT "libcsd-client.so"
+
+/*
+ * This is the sysfs path for the HDMI audio data block
+ */
+#define AUDIO_DATA_BLOCK_PATH "/sys/class/graphics/fb1/audio_data_block"
+#define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
+
+/*
+ * This file will have a maximum of 38 bytes:
+ *
+ * 4 bytes: number of audio blocks
+ * 4 bytes: total length of Short Audio Descriptor (SAD) blocks
+ * Maximum 10 * 3 bytes: SAD blocks
+ */
+#define MAX_SAD_BLOCKS      10
+#define SAD_BLOCK_SIZE      3
+
+/* EDID format ID for LPCM audio */
+#define EDID_FORMAT_LPCM    1
+
+struct audio_block_header
+{
+    int reserved;
+    int length;
+};
+
+
+typedef void (*acdb_deallocate_t)();
+typedef int  (*acdb_init_t)();
+typedef void (*acdb_send_audio_cal_t)(int, int);
+typedef void (*acdb_send_voice_cal_t)(int, int);
+
+typedef int (*csd_client_init_t)();
+typedef int (*csd_client_deinit_t)();
+typedef int (*csd_disable_device_t)();
+typedef int (*csd_enable_device_t)(int, int, uint32_t);
+typedef int (*csd_volume_t)(int);
+typedef int (*csd_mic_mute_t)(int);
+typedef int (*csd_start_voice_t)();
+typedef int (*csd_stop_voice_t)();
+
+
+struct platform_data {
+    struct audio_device *adev;
+    bool fluence_in_spkr_mode;
+    bool fluence_in_voice_call;
+    bool fluence_in_voice_rec;
+    int  fluence_type;
+    int  dualmic_config;
+    bool ec_ref_enabled;
+
+    /* Audio calibration related functions */
+    void *acdb_handle;
+    acdb_init_t acdb_init;
+    acdb_deallocate_t acdb_deallocate;
+    acdb_send_audio_cal_t acdb_send_audio_cal;
+    acdb_send_voice_cal_t acdb_send_voice_cal;
+
+    /* CSD Client related functions for voice call */
+    void *csd_client;
+    csd_client_init_t csd_client_init;
+    csd_client_deinit_t csd_client_deinit;
+    csd_disable_device_t csd_disable_device;
+    csd_enable_device_t csd_enable_device;
+    csd_volume_t csd_volume;
+    csd_mic_mute_t csd_mic_mute;
+    csd_start_voice_t csd_start_voice;
+    csd_stop_voice_t csd_stop_voice;
+};
+
+static const int pcm_device_table[AUDIO_USECASE_MAX][2] = {
+    [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0},
+    [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {14, 14},
+    [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {1, 1},
+    [USECASE_AUDIO_RECORD] = {0, 0},
+    [USECASE_AUDIO_RECORD_LOW_LATENCY] = {14, 14},
+    [USECASE_VOICE_CALL] = {12, 12},
+};
+
+/* Array to store sound devices */
+static const char * const device_table[SND_DEVICE_MAX] = {
+    [SND_DEVICE_NONE] = "none",
+    /* Playback sound devices */
+    [SND_DEVICE_OUT_HANDSET] = "handset",
+    [SND_DEVICE_OUT_SPEAKER] = "speaker",
+    [SND_DEVICE_OUT_SPEAKER_REVERSE] = "speaker-reverse",
+    [SND_DEVICE_OUT_HEADPHONES] = "headphones",
+    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = "speaker-and-headphones",
+    [SND_DEVICE_OUT_VOICE_SPEAKER] = "voice-speaker",
+    [SND_DEVICE_OUT_VOICE_HEADPHONES] = "voice-headphones",
+    [SND_DEVICE_OUT_HDMI] = "hdmi",
+    [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi",
+    [SND_DEVICE_OUT_BT_SCO] = "bt-sco-headset",
+    [SND_DEVICE_OUT_BT_SCO_WB] = "bt-sco-headset-wb",
+    [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones",
+    [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones",
+    [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset",
+    [SND_DEVICE_OUT_USB_HEADSET] = "usb-headphones",
+    [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = "speaker-and-usb-headphones",
+
+    /* Capture sound devices */
+    [SND_DEVICE_IN_HANDSET_MIC] = "handset-mic",
+    [SND_DEVICE_IN_SPEAKER_MIC] = "speaker-mic",
+    [SND_DEVICE_IN_HEADSET_MIC] = "headset-mic",
+    [SND_DEVICE_IN_HANDSET_MIC_AEC] = "handset-mic",
+    [SND_DEVICE_IN_SPEAKER_MIC_AEC] = "voice-speaker-mic",
+    [SND_DEVICE_IN_HEADSET_MIC_AEC] = "headset-mic",
+    [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = "voice-speaker-mic",
+    [SND_DEVICE_IN_VOICE_HEADSET_MIC] = "voice-headset-mic",
+    [SND_DEVICE_IN_HDMI_MIC] = "hdmi-mic",
+    [SND_DEVICE_IN_BT_SCO_MIC] = "bt-sco-mic",
+    [SND_DEVICE_IN_BT_SCO_MIC_WB] = "bt-sco-mic-wb",
+    [SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic",
+    [SND_DEVICE_IN_VOICE_DMIC] = "voice-dmic-ef",
+    [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = "voice-speaker-dmic-ef",
+    [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic",
+    [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic",
+    [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic",
+    [SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic",
+    [SND_DEVICE_IN_VOICE_REC_DMIC] = "voice-rec-dmic-ef",
+    [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence",
+    [SND_DEVICE_IN_USB_HEADSET_MIC] = "usb-headset-mic",
+};
+
+/* ACDB IDs (audio DSP path configuration IDs) for each sound device */
+static const int acdb_device_table[SND_DEVICE_MAX] = {
+    [SND_DEVICE_NONE] = -1,
+    [SND_DEVICE_OUT_HANDSET] = 7,
+    [SND_DEVICE_OUT_SPEAKER] = 14,
+    [SND_DEVICE_OUT_SPEAKER_REVERSE] = 14,
+    [SND_DEVICE_OUT_HEADPHONES] = 10,
+    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10,
+    [SND_DEVICE_OUT_VOICE_SPEAKER] = 14,
+    [SND_DEVICE_OUT_VOICE_HEADPHONES] = 10,
+    [SND_DEVICE_OUT_HDMI] = 18,
+    [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14,
+    [SND_DEVICE_OUT_BT_SCO] = 22,
+    [SND_DEVICE_OUT_BT_SCO_WB] = 39,
+    [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17,
+    [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
+    [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37,
+    [SND_DEVICE_OUT_USB_HEADSET] = 45,
+    [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 14,
+
+    [SND_DEVICE_IN_HANDSET_MIC] = 4,
+    [SND_DEVICE_IN_SPEAKER_MIC] = 4,
+    [SND_DEVICE_IN_HEADSET_MIC] = 8,
+    [SND_DEVICE_IN_HANDSET_MIC_AEC] = 40,
+    [SND_DEVICE_IN_SPEAKER_MIC_AEC] = 42,
+    [SND_DEVICE_IN_HEADSET_MIC_AEC] = 47,
+    [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = 11,
+    [SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8,
+    [SND_DEVICE_IN_HDMI_MIC] = 4,
+    [SND_DEVICE_IN_BT_SCO_MIC] = 21,
+    [SND_DEVICE_IN_BT_SCO_MIC_WB] = 38,
+    [SND_DEVICE_IN_CAMCORDER_MIC] = 61,
+    [SND_DEVICE_IN_VOICE_DMIC] = 6,
+    [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = 13,
+    [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16,
+    [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36,
+    [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16,
+    [SND_DEVICE_IN_VOICE_REC_MIC] = 62,
+    [SND_DEVICE_IN_USB_HEADSET_MIC] = 44,
+    /* TODO: Update with proper acdb ids */
+    [SND_DEVICE_IN_VOICE_REC_DMIC] = 62,
+    [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 6,
+};
+
+#define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
+#define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
+
+void platform_set_echo_reference(void *platform, bool enable)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+
+    if (enable) {
+        my_data->ec_ref_enabled = enable;
+        audio_route_apply_and_update_path(adev->audio_route, "echo-reference");
+    } else {
+        if (my_data->ec_ref_enabled) {
+            audio_route_reset_and_update_path(adev->audio_route, "echo-reference");
+            my_data->ec_ref_enabled = enable;
+        } else {
+            ALOGV("EC Reference is already disabled: %d", my_data->ec_ref_enabled);
+        }
+    }
+
+    ALOGV("Setting EC Reference: %d", enable);
+}
+
+void *platform_init(struct audio_device *adev)
+{
+    char platform[PROPERTY_VALUE_MAX];
+    char baseband[PROPERTY_VALUE_MAX];
+    char value[PROPERTY_VALUE_MAX];
+    struct platform_data *my_data;
+    const char *snd_card_name;
+
+    adev->mixer = mixer_open(MIXER_CARD);
+
+    if (!adev->mixer) {
+        ALOGE("Unable to open the mixer, aborting.");
+        return NULL;
+    }
+
+    adev->audio_route = audio_route_init(MIXER_CARD, MIXER_XML_PATH);
+    if (!adev->audio_route) {
+        ALOGE("%s: Failed to init audio route controls, aborting.", __func__);
+        return NULL;
+    }
+
+    my_data = calloc(1, sizeof(struct platform_data));
+
+    snd_card_name = mixer_get_name(adev->mixer);
+
+    my_data->adev = adev;
+    my_data->fluence_in_spkr_mode = false;
+    my_data->fluence_in_voice_call = false;
+    my_data->fluence_in_voice_rec = false;
+    my_data->fluence_type = FLUENCE_NONE;
+
+    property_get("ro.qc.sdk.audio.fluencetype", value, "");
+    if (!strncmp("fluencepro", value, sizeof("fluencepro"))) {
+        my_data->fluence_type = FLUENCE_QUAD_MIC;
+    } else if (!strncmp("fluence", value, sizeof("fluence"))) {
+        my_data->fluence_type = FLUENCE_DUAL_MIC;
+    } else {
+        my_data->fluence_type = FLUENCE_NONE;
+    }
+
+    if (my_data->fluence_type != FLUENCE_NONE) {
+        property_get("persist.audio.fluence.voicecall",value,"");
+        if (!strncmp("true", value, sizeof("true"))) {
+            my_data->fluence_in_voice_call = true;
+        }
+
+        property_get("persist.audio.fluence.voicerec",value,"");
+        if (!strncmp("true", value, sizeof("true"))) {
+            my_data->fluence_in_voice_rec = true;
+        }
+
+        property_get("persist.audio.fluence.speaker",value,"");
+        if (!strncmp("true", value, sizeof("true"))) {
+            my_data->fluence_in_spkr_mode = true;
+        }
+    }
+
+    my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
+    if (my_data->acdb_handle == NULL) {
+        ALOGE("%s: DLOPEN failed for %s", __func__, LIB_ACDB_LOADER);
+    } else {
+        ALOGV("%s: DLOPEN successful for %s", __func__, LIB_ACDB_LOADER);
+        my_data->acdb_deallocate = (acdb_deallocate_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_deallocate_ACDB");
+        my_data->acdb_send_audio_cal = (acdb_send_audio_cal_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_send_audio_cal");
+        if (!my_data->acdb_send_audio_cal)
+            ALOGW("%s: Could not find the symbol acdb_send_audio_cal from %s",
+                  __func__, LIB_ACDB_LOADER);
+        my_data->acdb_send_voice_cal = (acdb_send_voice_cal_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_send_voice_cal");
+        my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_init_ACDB");
+        if (my_data->acdb_init == NULL)
+            ALOGE("%s: dlsym error %s for acdb_loader_init_ACDB", __func__, dlerror());
+        else
+            my_data->acdb_init();
+    }
+
+    /* If platform is Fusion3, load CSD Client specific symbols
+     * Voice call is handled by MDM and apps processor talks to
+     * MDM through CSD Client
+     */
+    property_get("ro.board.platform", platform, "");
+    property_get("ro.baseband", baseband, "");
+    if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband)) {
+        my_data->csd_client = dlopen(LIB_CSD_CLIENT, RTLD_NOW);
+        if (my_data->csd_client == NULL)
+            ALOGE("%s: DLOPEN failed for %s", __func__, LIB_CSD_CLIENT);
+    }
+
+    if (my_data->csd_client) {
+        ALOGV("%s: DLOPEN successful for %s", __func__, LIB_CSD_CLIENT);
+        my_data->csd_client_deinit = (csd_client_deinit_t)dlsym(my_data->csd_client,
+                                                    "csd_client_deinit");
+        my_data->csd_disable_device = (csd_disable_device_t)dlsym(my_data->csd_client,
+                                                    "csd_client_disable_device");
+        my_data->csd_enable_device = (csd_enable_device_t)dlsym(my_data->csd_client,
+                                                    "csd_client_enable_device");
+        my_data->csd_start_voice = (csd_start_voice_t)dlsym(my_data->csd_client,
+                                                    "csd_client_start_voice");
+        my_data->csd_stop_voice = (csd_stop_voice_t)dlsym(my_data->csd_client,
+                                                    "csd_client_stop_voice");
+        my_data->csd_volume = (csd_volume_t)dlsym(my_data->csd_client,
+                                                    "csd_client_volume");
+        my_data->csd_mic_mute = (csd_mic_mute_t)dlsym(my_data->csd_client,
+                                                    "csd_client_mic_mute");
+        my_data->csd_client_init = (csd_client_init_t)dlsym(my_data->csd_client,
+                                                    "csd_client_init");
+
+        if (my_data->csd_client_init == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_init", __func__, dlerror());
+        } else {
+            my_data->csd_client_init();
+        }
+    }
+
+    return my_data;
+}
+
+void platform_deinit(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    free(platform);
+}
+
+const char *platform_get_snd_device_name(snd_device_t snd_device)
+{
+    if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX)
+        return device_table[snd_device];
+    else
+        return "";
+}
+
+int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device,
+                                      char *device_name)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) {
+        strlcpy(device_name, device_table[snd_device], DEVICE_NAME_MAX_SIZE);
+    } else {
+        strlcpy(device_name, "", DEVICE_NAME_MAX_SIZE);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+void platform_add_backend_name(char *mixer_path, snd_device_t snd_device)
+{
+    if (snd_device == SND_DEVICE_IN_BT_SCO_MIC)
+        strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
+    else if (snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB)
+        strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH);
+    else if(snd_device == SND_DEVICE_OUT_BT_SCO)
+        strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
+    else if(snd_device == SND_DEVICE_OUT_BT_SCO_WB)
+        strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH);
+    else if (snd_device == SND_DEVICE_OUT_HDMI)
+        strlcat(mixer_path, " hdmi", MIXER_PATH_MAX_LENGTH);
+    else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI)
+        strlcat(mixer_path, " speaker-and-hdmi", MIXER_PATH_MAX_LENGTH);
+}
+
+int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type)
+{
+    int device_id;
+    if (device_type == PCM_PLAYBACK)
+        device_id = pcm_device_table[usecase][0];
+    else
+        device_id = pcm_device_table[usecase][1];
+    return device_id;
+}
+
+int platform_get_snd_device_index(char *snd_device_index_name __unused)
+{
+    return -ENODEV;
+}
+
+int platform_set_snd_device_acdb_id(snd_device_t snd_device __unused,
+                                    unsigned int acdb_id __unused)
+{
+    return -ENODEV;
+}
+
+uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
+int platform_get_snd_device_acdb_id(snd_device_t snd_device __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
+int platform_switch_voice_call_enable_device_config(void *platform __unused,
+                                                    snd_device_t out_snd_device __unused,
+                                                    snd_device_t in_snd_device __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
+int platform_switch_voice_call_usecase_route_post(void *platform __unused,
+                                                  snd_device_t out_snd_device __unused,
+                                                  snd_device_t in_snd_device __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
+int platform_set_incall_recording_session_id(void *platform __unused,
+                                             uint32_t session_id __unused,
+                                             int rec_mode __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
+int platform_stop_incall_recording_usecase(void *platform __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
+int platform_get_sample_rate(void *platform __unused, uint32_t *rate __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
+int platform_get_default_app_type(void *platform __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
+int platform_send_audio_calibration(void *platform, struct audio_usecase *usecase,
+                                    int app_type __unused, int sample_rate __unused)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int acdb_dev_id, acdb_dev_type;
+    struct audio_device *adev = my_data->adev;
+    int snd_device = SND_DEVICE_OUT_SPEAKER;
+
+    if (usecase->type == PCM_PLAYBACK)
+        snd_device = platform_get_output_snd_device(adev->platform,
+                                            usecase->stream.out->devices);
+    else if ((usecase->type == PCM_HFP_CALL) || (usecase->type == PCM_CAPTURE))
+        snd_device = platform_get_input_snd_device(adev->platform,
+                                            adev->primary_output->devices);
+    acdb_dev_id = acdb_device_table[snd_device];
+    if (acdb_dev_id < 0) {
+        ALOGE("%s: Could not find acdb id for device(%d)",
+              __func__, snd_device);
+        return -EINVAL;
+    }
+    if (my_data->acdb_send_audio_cal) {
+        ("%s: sending audio calibration for snd_device(%d) acdb_id(%d)",
+              __func__, snd_device, acdb_dev_id);
+        if (snd_device >= SND_DEVICE_OUT_BEGIN &&
+                snd_device < SND_DEVICE_OUT_END)
+            acdb_dev_type = ACDB_DEV_TYPE_OUT;
+        else
+            acdb_dev_type = ACDB_DEV_TYPE_IN;
+        my_data->acdb_send_audio_cal(acdb_dev_id, acdb_dev_type);
+    }
+    return 0;
+}
+
+int platform_switch_voice_call_device_pre(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int ret = 0;
+
+    if (my_data->csd_client != NULL) {
+        /* This must be called before disabling the mixer controls on APQ side */
+        if (my_data->csd_disable_device == NULL) {
+            ALOGE("%s: dlsym error for csd_disable_device", __func__);
+        } else {
+            ret = my_data->csd_disable_device();
+            if (ret < 0) {
+                ALOGE("%s: csd_client_disable_device, failed, error %d",
+                      __func__, ret);
+            }
+        }
+    }
+    return ret;
+}
+
+int platform_switch_voice_call_device_post(void *platform,
+                                           snd_device_t out_snd_device,
+                                           snd_device_t in_snd_device)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int acdb_rx_id, acdb_tx_id;
+    int ret = 0;
+
+    if (my_data->csd_client) {
+        if (my_data->csd_enable_device == NULL) {
+            ALOGE("%s: dlsym error for csd_enable_device",
+                  __func__);
+        } else {
+            acdb_rx_id = acdb_device_table[out_snd_device];
+            acdb_tx_id = acdb_device_table[in_snd_device];
+
+            if (acdb_rx_id > 0 || acdb_tx_id > 0) {
+                ret = my_data->csd_enable_device(acdb_rx_id, acdb_tx_id,
+                                                    my_data->adev->acdb_settings);
+                if (ret < 0) {
+                    ALOGE("%s: csd_enable_device, failed, error %d",
+                          __func__, ret);
+                }
+            } else {
+                ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+                      acdb_rx_id, acdb_tx_id);
+            }
+        }
+    }
+
+    return ret;
+}
+
+int platform_start_voice_call(void *platform, uint32_t vsid __unused)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int ret = 0;
+
+    if (my_data->csd_client) {
+        if (my_data->csd_start_voice == NULL) {
+            ALOGE("dlsym error for csd_client_start_voice");
+            ret = -ENOSYS;
+        } else {
+            ret = my_data->csd_start_voice();
+            if (ret < 0) {
+                ALOGE("%s: csd_start_voice error %d\n", __func__, ret);
+            }
+        }
+    }
+
+    return ret;
+}
+
+int platform_stop_voice_call(void *platform, uint32_t vsid __unused)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int ret = 0;
+
+    if (my_data->csd_client) {
+        if (my_data->csd_stop_voice == NULL) {
+            ALOGE("dlsym error for csd_stop_voice");
+        } else {
+            ret = my_data->csd_stop_voice();
+            if (ret < 0) {
+                ALOGE("%s: csd_stop_voice error %d\n", __func__, ret);
+            }
+        }
+    }
+
+    return ret;
+}
+
+int platform_set_voice_volume(void *platform, int volume)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int ret = 0;
+
+    if (my_data->csd_client) {
+        if (my_data->csd_volume == NULL) {
+            ALOGE("%s: dlsym error for csd_volume", __func__);
+        } else {
+            ret = my_data->csd_volume(volume);
+            if (ret < 0) {
+                ALOGE("%s: csd_volume error %d", __func__, ret);
+            }
+        }
+    } else {
+        ALOGE("%s: No CSD Client present", __func__);
+    }
+
+    return ret;
+}
+
+int platform_set_mic_mute(void *platform, bool state)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int ret = 0;
+
+    if (my_data->adev->mode == AUDIO_MODE_IN_CALL) {
+        if (my_data->csd_client) {
+            if (my_data->csd_mic_mute == NULL) {
+                ALOGE("%s: dlsym error for csd_mic_mute", __func__);
+            } else {
+                ret = my_data->csd_mic_mute(state);
+                if (ret < 0) {
+                    ALOGE("%s: csd_mic_mute error %d", __func__, ret);
+                }
+            }
+        } else {
+            ALOGE("%s: No CSD Client present", __func__);
+        }
+    }
+
+    return ret;
+}
+
+int platform_set_device_mute(void *platform __unused, bool state __unused, char *dir __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
+snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    audio_mode_t mode = adev->mode;
+    snd_device_t snd_device = SND_DEVICE_NONE;
+
+    ALOGV("%s: enter: output devices(%#x)", __func__, devices);
+    if (devices == AUDIO_DEVICE_NONE ||
+        devices & AUDIO_DEVICE_BIT_IN) {
+        ALOGV("%s: Invalid output devices (%#x)", __func__, devices);
+        goto exit;
+    }
+
+    if (mode == AUDIO_MODE_IN_CALL) {
+        if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+            devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+            if (adev->voice.tty_mode == TTY_MODE_FULL)
+                snd_device = SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES;
+            else if (adev->voice.tty_mode == TTY_MODE_VCO)
+                snd_device = SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES;
+            else if (adev->voice.tty_mode == TTY_MODE_HCO)
+                snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET;
+            else
+                snd_device = SND_DEVICE_OUT_VOICE_HEADPHONES;
+        } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
+            if (adev->bt_wb_speech_enabled)
+                snd_device = SND_DEVICE_OUT_BT_SCO_WB;
+            else
+                snd_device = SND_DEVICE_OUT_BT_SCO;
+        } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
+            snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
+        } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
+            snd_device = SND_DEVICE_OUT_HANDSET;
+        }
+        if (snd_device != SND_DEVICE_NONE) {
+            goto exit;
+        }
+    }
+
+    if (popcount(devices) == 2) {
+        if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+                        AUDIO_DEVICE_OUT_SPEAKER)) {
+            snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
+        } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET |
+                               AUDIO_DEVICE_OUT_SPEAKER)) {
+            snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
+        } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL |
+                               AUDIO_DEVICE_OUT_SPEAKER)) {
+            snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI;
+        } else {
+            ALOGE("%s: Invalid combo device(%#x)", __func__, devices);
+            goto exit;
+        }
+        if (snd_device != SND_DEVICE_NONE) {
+            goto exit;
+        }
+    }
+
+    if (popcount(devices) != 1) {
+        ALOGE("%s: Invalid output devices(%#x)", __func__, devices);
+        goto exit;
+    }
+
+    if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+        devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+        snd_device = SND_DEVICE_OUT_HEADPHONES;
+    } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
+        if (adev->speaker_lr_swap)
+            snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE;
+        else
+            snd_device = SND_DEVICE_OUT_SPEAKER;
+    } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
+        if (adev->bt_wb_speech_enabled)
+            snd_device = SND_DEVICE_OUT_BT_SCO_WB;
+        else
+            snd_device = SND_DEVICE_OUT_BT_SCO;
+    } else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+        snd_device = SND_DEVICE_OUT_HDMI ;
+    } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
+        snd_device = SND_DEVICE_OUT_HANDSET;
+    } else {
+        ALOGE("%s: Unknown device(s) %#x", __func__, devices);
+    }
+exit:
+    ALOGV("%s: exit: snd_device(%s)", __func__, device_table[snd_device]);
+    return snd_device;
+}
+
+snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    audio_source_t  source = (adev->active_input == NULL) ?
+                                AUDIO_SOURCE_DEFAULT : adev->active_input->source;
+
+    audio_mode_t    mode   = adev->mode;
+    audio_devices_t in_device = ((adev->active_input == NULL) ?
+                                    AUDIO_DEVICE_NONE : adev->active_input->device)
+                                & ~AUDIO_DEVICE_BIT_IN;
+    audio_channel_mask_t channel_mask = (adev->active_input == NULL) ?
+                                AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask;
+    snd_device_t snd_device = SND_DEVICE_NONE;
+
+    ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
+          __func__, out_device, in_device);
+    if (mode == AUDIO_MODE_IN_CALL) {
+        if (out_device == AUDIO_DEVICE_NONE) {
+            ALOGE("%s: No output device set for voice call", __func__);
+            goto exit;
+        }
+        if (adev->voice.tty_mode != TTY_MODE_OFF) {
+            if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+                out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+                switch (adev->voice.tty_mode) {
+                case TTY_MODE_FULL:
+                    snd_device = SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC;
+                    break;
+                case TTY_MODE_VCO:
+                    snd_device = SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC;
+                    break;
+                case TTY_MODE_HCO:
+                    snd_device = SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC;
+                    break;
+                default:
+                    ALOGE("%s: Invalid TTY mode (%#x)", __func__, adev->voice.tty_mode);
+                }
+                goto exit;
+            }
+        }
+        if (out_device & AUDIO_DEVICE_OUT_EARPIECE ||
+            out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+            if (my_data->fluence_type == FLUENCE_NONE ||
+                my_data->fluence_in_voice_call == false) {
+                snd_device = SND_DEVICE_IN_HANDSET_MIC;
+            } else {
+                snd_device = SND_DEVICE_IN_VOICE_DMIC;
+                adev->acdb_settings |= DMIC_FLAG;
+            }
+        } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+            snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
+            if (adev->bt_wb_speech_enabled)
+                snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+            else
+                snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
+            if (my_data->fluence_type != FLUENCE_NONE &&
+                my_data->fluence_in_voice_call &&
+                my_data->fluence_in_spkr_mode) {
+                if(my_data->fluence_type == FLUENCE_DUAL_MIC) {
+                    adev->acdb_settings |= DMIC_FLAG;
+                    snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC;
+                } else {
+                    adev->acdb_settings |= QMIC_FLAG;
+                    snd_device = SND_DEVICE_IN_VOICE_SPEAKER_QMIC;
+                }
+            } else {
+                snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC;
+            }
+        }
+    } else if (source == AUDIO_SOURCE_CAMCORDER) {
+        if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC ||
+            in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+            snd_device = SND_DEVICE_IN_CAMCORDER_MIC;
+        }
+    } else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) {
+        if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK)
+                snd_device = SND_DEVICE_IN_VOICE_REC_DMIC;
+            else if (my_data->fluence_in_voice_rec)
+                snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE;
+
+            if (snd_device == SND_DEVICE_NONE)
+                snd_device = SND_DEVICE_IN_VOICE_REC_MIC;
+            else
+                adev->acdb_settings |= DMIC_FLAG;
+        }
+    } else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
+        if (out_device & AUDIO_DEVICE_OUT_SPEAKER)
+            in_device = AUDIO_DEVICE_IN_BACK_MIC;
+        if (adev->active_input) {
+            if (adev->active_input->enable_aec) {
+                if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+                    snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC;
+                } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+                    snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC;
+                } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+                    snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC;
+                }
+                platform_set_echo_reference(adev->platform, true);
+            } else
+                platform_set_echo_reference(adev->platform, false);
+        }
+    } else if (source == AUDIO_SOURCE_DEFAULT) {
+        goto exit;
+    }
+
+
+    if (snd_device != SND_DEVICE_NONE) {
+        goto exit;
+    }
+
+    if (in_device != AUDIO_DEVICE_NONE &&
+            !(in_device & AUDIO_DEVICE_IN_VOICE_CALL) &&
+            !(in_device & AUDIO_DEVICE_IN_COMMUNICATION)) {
+        if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            snd_device = SND_DEVICE_IN_HANDSET_MIC;
+        } else if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+            snd_device = SND_DEVICE_IN_SPEAKER_MIC;
+        } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+            snd_device = SND_DEVICE_IN_HEADSET_MIC;
+        } else if (in_device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+            if (adev->bt_wb_speech_enabled)
+                snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+            else
+                snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+        } else if (in_device & AUDIO_DEVICE_IN_AUX_DIGITAL) {
+            snd_device = SND_DEVICE_IN_HDMI_MIC;
+        } else {
+            ALOGE("%s: Unknown input device(s) %#x", __func__, in_device);
+            ALOGW("%s: Using default handset-mic", __func__);
+            snd_device = SND_DEVICE_IN_HANDSET_MIC;
+        }
+    } else {
+        if (out_device & AUDIO_DEVICE_OUT_EARPIECE) {
+            snd_device = SND_DEVICE_IN_HANDSET_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+            snd_device = SND_DEVICE_IN_HEADSET_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
+            snd_device = SND_DEVICE_IN_SPEAKER_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+            snd_device = SND_DEVICE_IN_HANDSET_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) {
+            if (adev->bt_wb_speech_enabled)
+                snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+            else
+                snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+            snd_device = SND_DEVICE_IN_HDMI_MIC;
+        } else {
+            ALOGE("%s: Unknown output device(s) %#x", __func__, out_device);
+            ALOGW("%s: Using default handset-mic", __func__);
+            snd_device = SND_DEVICE_IN_HANDSET_MIC;
+        }
+    }
+exit:
+    ALOGV("%s: exit: in_snd_device(%s)", __func__, device_table[snd_device]);
+    return snd_device;
+}
+
+int platform_set_hdmi_channels(void *platform,  int channel_count)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    const char *channel_cnt_str = NULL;
+    const char *mixer_ctl_name = "HDMI_RX Channels";
+    switch (channel_count) {
+    case 8:
+        channel_cnt_str = "Eight"; break;
+    case 7:
+        channel_cnt_str = "Seven"; break;
+    case 6:
+        channel_cnt_str = "Six"; break;
+    case 5:
+        channel_cnt_str = "Five"; break;
+    case 4:
+        channel_cnt_str = "Four"; break;
+    case 3:
+        channel_cnt_str = "Three"; break;
+    default:
+        channel_cnt_str = "Two"; break;
+    }
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    ALOGV("HDMI channel count: %s", channel_cnt_str);
+    mixer_ctl_set_enum_by_string(ctl, channel_cnt_str);
+    return 0;
+}
+
+int platform_edid_get_max_channels(void *platform __unused)
+{
+    FILE *file;
+    struct audio_block_header header;
+    char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE];
+    char *sad = block;
+    int num_audio_blocks;
+    int channel_count;
+    int max_channels = 0;
+    int i;
+
+    file = fopen(AUDIO_DATA_BLOCK_PATH, "rb");
+    if (file == NULL) {
+        ALOGE("Unable to open '%s'", AUDIO_DATA_BLOCK_PATH);
+        return 0;
+    }
+
+    /* Read audio block header */
+    fread(&header, 1, sizeof(header), file);
+
+    /* Read SAD blocks, clamping the maximum size for safety */
+    if (header.length > (int)sizeof(block))
+        header.length = (int)sizeof(block);
+    fread(&block, header.length, 1, file);
+
+    fclose(file);
+
+    /* Calculate the number of SAD blocks */
+    num_audio_blocks = header.length / SAD_BLOCK_SIZE;
+
+    for (i = 0; i < num_audio_blocks; i++) {
+        /* Only consider LPCM blocks */
+        if ((sad[0] >> 3) != EDID_FORMAT_LPCM)
+            continue;
+
+        channel_count = (sad[0] & 0x7) + 1;
+        if (channel_count > max_channels)
+            max_channels = channel_count;
+
+        /* Advance to next block */
+        sad += 3;
+    }
+
+    return max_channels;
+}
+
+void platform_get_parameters(void *platform __unused,
+                             struct str_parms *query __unused,
+                             struct str_parms *reply __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+}
+
+int platform_set_parameters(void *platform __unused, struct str_parms *parms __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
+int platform_set_incall_recoding_session_id(void *platform __unused,
+                                            uint32_t session_id __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
+int platform_update_lch(void *platform __unused,
+                        struct voice_session *session __unused,
+                        enum voice_lch_mode lch_mode __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
+int platform_start_incall_music_usecase(void *platform __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
+int platform_stop_incall_music_usecase(void *platform __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
+/* Delay in Us */
+int64_t platform_render_latency(audio_usecase_t usecase)
+{
+    switch (usecase) {
+        case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER:
+            return DEEP_BUFFER_PLATFORM_DELAY;
+        case USECASE_AUDIO_PLAYBACK_LOW_LATENCY:
+            return LOW_LATENCY_PLATFORM_DELAY;
+        default:
+            return 0;
+    }
+}
+
+int platform_update_usecase_from_source(int source, int usecase)
+{
+    ALOGV("%s: input source :%d", __func__, source);
+    return usecase;
+}
+
+bool platform_listen_device_needs_event(snd_device_t snd_device __unused)
+{
+    return false;
+}
+
+bool platform_listen_usecase_needs_event(audio_usecase_t uc_id __unused)
+{
+    return false;
+}
+
+bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev __unused,
+                                              struct audio_usecase *usecase __unused)
+{
+    return false;
+}
+
+int platform_get_usecase_index(const char * usecase __unused)
+{
+    return -ENOSYS;
+}
+
+int platform_set_usecase_pcm_id(audio_usecase_t usecase __unused, int32_t type __unused,
+                                int32_t pcm_id __unused)
+{
+    return -ENOSYS;
+}
+
+int platform_set_snd_device_backend(snd_device_t snd_device __unused,
+                                    const char * backend __unused)
+{
+    return -ENOSYS;
+}
+
+bool platform_sound_trigger_device_needs_event(snd_device_t snd_device __unused)
+{
+    return false;
+}
+
+bool platform_sound_trigger_usecase_needs_event(audio_usecase_t uc_id  __unused)
+{
+    return false;
+}
+
+int platform_set_fluence_type(void *platform __unused, char *value __unused)
+{
+    return -ENOSYS;
+}
+
+int platform_get_fluence_type(void *platform __unused, char *value __unused,
+                              uint32_t len __unused)
+{
+    return -ENOSYS;
+}
+
+uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info __unused)
+{
+    return 0;
+}
diff --git a/msm8909/hal/msm8960/platform.h b/msm8909/hal/msm8960/platform.h
new file mode 100644
index 0000000..123a630
--- /dev/null
+++ b/msm8909/hal/msm8960/platform.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef QCOM_AUDIO_PLATFORM_H
+#define QCOM_AUDIO_PLATFORM_H
+
+enum {
+    FLUENCE_NONE,
+    FLUENCE_DUAL_MIC,
+    FLUENCE_QUAD_MIC
+};
+
+/*
+ * Below are the devices for which is back end is same, SLIMBUS_0_RX.
+ * All these devices are handled by the internal HW codec. We can
+ * enable any one of these devices at any time
+ */
+#define AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND \
+    (AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER | \
+     AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE)
+
+/* Sound devices specific to the platform
+ * The DEVICE_OUT_* and DEVICE_IN_* should be mapped to these sound
+ * devices to enable corresponding mixer paths
+ */
+enum {
+    SND_DEVICE_NONE = 0,
+
+    /* Playback devices */
+    SND_DEVICE_MIN,
+    SND_DEVICE_OUT_BEGIN = SND_DEVICE_MIN,
+    SND_DEVICE_OUT_HANDSET = SND_DEVICE_OUT_BEGIN,
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_REVERSE,
+    SND_DEVICE_OUT_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_SPEAKER,
+    SND_DEVICE_OUT_VOICE_HEADPHONES,
+    SND_DEVICE_OUT_HDMI,
+    SND_DEVICE_OUT_SPEAKER_AND_HDMI,
+    SND_DEVICE_OUT_BT_SCO,
+    SND_DEVICE_OUT_BT_A2DP,
+    SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP,
+    SND_DEVICE_OUT_BT_SCO_WB,
+    SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET,
+    SND_DEVICE_OUT_USB_HEADSET,
+    SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET,
+    SND_DEVICE_OUT_END,
+
+    /*
+     * Note: IN_BEGIN should be same as OUT_END because total number of devices
+     * SND_DEVICES_MAX should not exceed MAX_RX + MAX_TX devices.
+     */
+    /* Capture devices */
+    SND_DEVICE_IN_BEGIN = SND_DEVICE_OUT_END,
+    SND_DEVICE_IN_HANDSET_MIC  = SND_DEVICE_IN_BEGIN,
+    SND_DEVICE_IN_SPEAKER_MIC,
+    SND_DEVICE_IN_HEADSET_MIC,
+    SND_DEVICE_IN_HANDSET_MIC_AEC,
+    SND_DEVICE_IN_SPEAKER_MIC_AEC,
+    SND_DEVICE_IN_HEADSET_MIC_AEC,
+    SND_DEVICE_IN_VOICE_SPEAKER_MIC,
+    SND_DEVICE_IN_VOICE_HEADSET_MIC,
+    SND_DEVICE_IN_HDMI_MIC,
+    SND_DEVICE_IN_BT_SCO_MIC,
+    SND_DEVICE_IN_BT_SCO_MIC_WB,
+    SND_DEVICE_IN_CAMCORDER_MIC,
+    SND_DEVICE_IN_VOICE_DMIC,
+    SND_DEVICE_IN_VOICE_SPEAKER_DMIC,
+    SND_DEVICE_IN_VOICE_SPEAKER_QMIC,
+    SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC,
+    SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC,
+    SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC,
+    SND_DEVICE_IN_VOICE_REC_MIC,
+    SND_DEVICE_IN_VOICE_REC_DMIC,
+    SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
+    SND_DEVICE_IN_USB_HEADSET_MIC,
+    SND_DEVICE_IN_END,
+
+    SND_DEVICE_MAX = SND_DEVICE_IN_END,
+
+};
+
+#define MIXER_CARD 0
+#define SOUND_CARD 0
+
+#define DEFAULT_OUTPUT_SAMPLING_RATE 48000
+
+#define ALL_SESSION_VSID                0xFFFFFFFF
+#define DEFAULT_MUTE_RAMP_DURATION_MS   20
+#define DEFAULT_VOLUME_RAMP_DURATION_MS 20
+#define MIXER_PATH_MAX_LENGTH 100
+
+#define MAX_VOL_INDEX 5
+#define MIN_VOL_INDEX 0
+#define percent_to_index(val, min, max) \
+            ((val) * ((max) - (min)) * 0.01 + (min) + .5)
+
+/*
+ * tinyAlsa library interprets period size as number of frames
+ * one frame = channel_count * sizeof (pcm sample)
+ * so if format = 16-bit PCM and channels = Stereo, frame size = 2 ch * 2 = 4 bytes
+ * DEEP_BUFFER_OUTPUT_PERIOD_SIZE = 1024 means 1024 * 4 = 4096 bytes
+ * We should take care of returning proper size when AudioFlinger queries for
+ * the buffer size of an input/output stream
+ */
+#define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 960
+#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 4
+#define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240
+#define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2
+
+#define HDMI_MULTI_PERIOD_SIZE  336
+#define HDMI_MULTI_PERIOD_COUNT 8
+#define HDMI_MULTI_DEFAULT_CHANNEL_COUNT 6
+#define HDMI_MULTI_PERIOD_BYTES (HDMI_MULTI_PERIOD_SIZE * HDMI_MULTI_DEFAULT_CHANNEL_COUNT * 2)
+
+#define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
+#define AUDIO_CAPTURE_PERIOD_COUNT 2
+
+#define DEVICE_NAME_MAX_SIZE 128
+
+/* Define macro for Internal FM volume mixer */
+#define FM_RX_VOLUME "Internal FM RX Volume"
+
+#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
+#define LOW_LATENCY_CAPTURE_PERIOD_SIZE 240
+#define LOW_LATENCY_CAPTURE_USE_CASE 0
+
+#define AFE_PROXY_PLAYBACK_PCM_DEVICE 7
+#define AFE_PROXY_RECORD_PCM_DEVICE 8
+
+#endif // QCOM_AUDIO_PLATFORM_H
diff --git a/msm8909/hal/msm8974/hw_info.c b/msm8909/hal/msm8974/hw_info.c
new file mode 100644
index 0000000..f7d19f4
--- /dev/null
+++ b/msm8909/hal/msm8974/hw_info.c
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2013, 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 "hardware_info"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+
+
+struct hardware_info {
+    char name[HW_INFO_ARRAY_MAX_SIZE];
+    char type[HW_INFO_ARRAY_MAX_SIZE];
+    /* variables for handling target variants */
+    uint32_t num_snd_devices;
+    char dev_extn[HW_INFO_ARRAY_MAX_SIZE];
+    snd_device_t  *snd_devices;
+};
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+static const snd_device_t taiko_fluid_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+};
+
+static const snd_device_t taiko_CDP_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+    SND_DEVICE_IN_QUAD_MIC,
+};
+
+static const snd_device_t taiko_apq8084_CDP_variant_devices[] = {
+    SND_DEVICE_IN_HANDSET_MIC,
+};
+
+static const snd_device_t taiko_liquid_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+    SND_DEVICE_IN_SPEAKER_MIC,
+    SND_DEVICE_IN_HEADSET_MIC,
+    SND_DEVICE_IN_VOICE_DMIC,
+    SND_DEVICE_IN_VOICE_SPEAKER_DMIC,
+    SND_DEVICE_IN_VOICE_REC_DMIC_STEREO,
+    SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
+    SND_DEVICE_IN_QUAD_MIC,
+    SND_DEVICE_IN_HANDSET_STEREO_DMIC,
+    SND_DEVICE_IN_SPEAKER_STEREO_DMIC,
+};
+
+static const snd_device_t tomtom_msm8994_CDP_variant_devices[] = {
+    SND_DEVICE_IN_HANDSET_MIC,
+};
+
+static const snd_device_t tomtom_liquid_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_EXTERNAL_1,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+    SND_DEVICE_IN_SPEAKER_MIC,
+    SND_DEVICE_IN_HEADSET_MIC,
+    SND_DEVICE_IN_VOICE_DMIC,
+    SND_DEVICE_IN_VOICE_SPEAKER_DMIC,
+    SND_DEVICE_IN_VOICE_REC_DMIC_STEREO,
+    SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
+    SND_DEVICE_IN_QUAD_MIC,
+    SND_DEVICE_IN_HANDSET_STEREO_DMIC,
+    SND_DEVICE_IN_SPEAKER_STEREO_DMIC,
+};
+
+static const snd_device_t tomtom_stp_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+};
+
+static const snd_device_t taiko_DB_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+    SND_DEVICE_IN_SPEAKER_MIC,
+    SND_DEVICE_IN_HEADSET_MIC,
+    SND_DEVICE_IN_QUAD_MIC,
+};
+
+static const snd_device_t taiko_apq8084_sbc_variant_devices[] = {
+    SND_DEVICE_IN_HANDSET_MIC,
+    SND_DEVICE_IN_SPEAKER_MIC,
+};
+
+static const snd_device_t tapan_lite_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
+};
+
+static const snd_device_t tapan_skuf_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+    /*SND_DEVICE_OUT_SPEAKER_AND_ANC_FB_HEADSET,*/
+};
+
+static const snd_device_t tapan_lite_skuf_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
+};
+
+static const snd_device_t helicon_skuab_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+    SND_DEVICE_OUT_VOICE_SPEAKER,
+};
+
+static void  update_hardware_info_8084(struct hardware_info *hw_info, const char *snd_card_name)
+{
+    if (!strcmp(snd_card_name, "apq8084-taiko-mtp-snd-card") ||
+        !strncmp(snd_card_name, "apq8084-taiko-i2s-mtp-snd-card",
+                 sizeof("apq8084-taiko-i2s-mtp-snd-card")) ||
+        !strncmp(snd_card_name, "apq8084-tomtom-mtp-snd-card",
+                 sizeof("apq8084-tomtom-mtp-snd-card"))) {
+        strlcpy(hw_info->type, "mtp", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "apq8084", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if ((!strcmp(snd_card_name, "apq8084-taiko-cdp-snd-card")) ||
+        !strncmp(snd_card_name, "apq8084-tomtom-cdp-snd-card",
+                 sizeof("apq8084-tomtom-cdp-snd-card"))) {
+        strlcpy(hw_info->type, " cdp", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "apq8084", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)taiko_apq8084_CDP_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(taiko_apq8084_CDP_variant_devices);
+        strlcpy(hw_info->dev_extn, "-cdp", sizeof(hw_info->dev_extn));
+    } else if (!strncmp(snd_card_name, "apq8084-taiko-i2s-cdp-snd-card",
+                        sizeof("apq8084-taiko-i2s-cdp-snd-card"))) {
+        strlcpy(hw_info->type, " cdp", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "apq8084", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "apq8084-taiko-liquid-snd-card")) {
+        strlcpy(hw_info->type , " liquid", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "apq8084", sizeof(hw_info->type));
+        hw_info->snd_devices = (snd_device_t *)taiko_liquid_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(taiko_liquid_variant_devices);
+        strlcpy(hw_info->dev_extn, "-liquid", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "apq8084-taiko-sbc-snd-card")) {
+        strlcpy(hw_info->type, " sbc", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "apq8084", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)taiko_apq8084_sbc_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(taiko_apq8084_sbc_variant_devices);
+        strlcpy(hw_info->dev_extn, "-sbc", sizeof(hw_info->dev_extn));
+    } else {
+        ALOGW("%s: Not an 8084 device", __func__);
+    }
+}
+
+static void  update_hardware_info_8994(struct hardware_info *hw_info, const char *snd_card_name)
+{
+    if (!strcmp(snd_card_name, "msm8994-tomtom-mtp-snd-card")) {
+        strlcpy(hw_info->type, " mtp", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8994", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8994-tomtom-cdp-snd-card")) {
+        strlcpy(hw_info->type, " cdp", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8994", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)tomtom_msm8994_CDP_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(tomtom_msm8994_CDP_variant_devices);
+        strlcpy(hw_info->dev_extn, "-cdp", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8994-tomtom-stp-snd-card")) {
+        strlcpy(hw_info->type, " stp", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8994", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)tomtom_stp_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(tomtom_stp_variant_devices);
+        strlcpy(hw_info->dev_extn, "-stp", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8994-tomtom-liquid-snd-card")) {
+        strlcpy(hw_info->type, " liquid", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8994", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)tomtom_liquid_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(tomtom_liquid_variant_devices);
+        strlcpy(hw_info->dev_extn, "-liquid", sizeof(hw_info->dev_extn));
+    } else {
+        ALOGW("%s: Not an 8994 device", __func__);
+    }
+}
+
+static void  update_hardware_info_8974(struct hardware_info *hw_info, const char *snd_card_name)
+{
+    if (!strcmp(snd_card_name, "msm8974-taiko-mtp-snd-card")) {
+        strlcpy(hw_info->type, " mtp", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8974-taiko-cdp-snd-card")) {
+        strlcpy(hw_info->type, " cdp", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)taiko_CDP_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(taiko_CDP_variant_devices);
+        strlcpy(hw_info->dev_extn, "-cdp", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8974-taiko-fluid-snd-card")) {
+        strlcpy(hw_info->type, " fluid", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *) taiko_fluid_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(taiko_fluid_variant_devices);
+        strlcpy(hw_info->dev_extn, "-fluid", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8974-taiko-liquid-snd-card")) {
+        strlcpy(hw_info->type, " liquid", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)taiko_liquid_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(taiko_liquid_variant_devices);
+        strlcpy(hw_info->dev_extn, "-liquid", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "apq8074-taiko-db-snd-card")) {
+        strlcpy(hw_info->type, " dragon-board", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)taiko_DB_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(taiko_DB_variant_devices);
+        strlcpy(hw_info->dev_extn, "-DB", sizeof(hw_info->dev_extn));
+    } else {
+        ALOGW("%s: Not an 8974 device", __func__);
+    }
+}
+
+static void update_hardware_info_8610(struct hardware_info *hw_info, const char *snd_card_name)
+{
+    if (!strcmp(snd_card_name, "msm8x10-snd-card")) {
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8x10", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8x10-skuab-snd-card")) {
+        strlcpy(hw_info->type, "skuab", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8x10", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)helicon_skuab_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(helicon_skuab_variant_devices);
+        strlcpy(hw_info->dev_extn, "-skuab", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8x10-skuaa-snd-card")) {
+        strlcpy(hw_info->type, " skuaa", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8x10", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else {
+        ALOGW("%s: Not an  8x10 device", __func__);
+    }
+}
+
+static void update_hardware_info_8226(struct hardware_info *hw_info, const char *snd_card_name)
+{
+    if (!strcmp(snd_card_name, "msm8226-tapan-snd-card")) {
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8226-tapan9302-snd-card")) {
+        strlcpy(hw_info->type, "tapan_lite", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)tapan_lite_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(tapan_lite_variant_devices);
+        strlcpy(hw_info->dev_extn, "-lite", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8226-tapan-skuf-snd-card")) {
+        strlcpy(hw_info->type, " skuf", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *) tapan_skuf_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(tapan_skuf_variant_devices);
+        strlcpy(hw_info->dev_extn, "-skuf", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8226-tapan9302-skuf-snd-card")) {
+        strlcpy(hw_info->type, " tapan9302-skuf", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)tapan_lite_skuf_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(tapan_lite_skuf_variant_devices);
+        strlcpy(hw_info->dev_extn, "-skuf-lite", sizeof(hw_info->dev_extn));
+    } else {
+        ALOGW("%s: Not an  8x26 device", __func__);
+    }
+}
+
+void *hw_info_init(const char *snd_card_name)
+{
+    struct hardware_info *hw_info;
+
+    hw_info = malloc(sizeof(struct hardware_info));
+    if (!hw_info) {
+        ALOGE("failed to allocate mem for hardware info");
+        return NULL;
+    }
+
+    hw_info->snd_devices = NULL;
+    hw_info->num_snd_devices = 0;
+    strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    strlcpy(hw_info->type, "", sizeof(hw_info->type));
+    strlcpy(hw_info->name, "", sizeof(hw_info->name));
+
+    if(strstr(snd_card_name, "msm8974") ||
+              strstr(snd_card_name, "apq8074")) {
+        ALOGV("8974 - variant soundcard");
+        update_hardware_info_8974(hw_info, snd_card_name);
+    } else if(strstr(snd_card_name, "msm8226")) {
+        ALOGV("8x26 - variant soundcard");
+        update_hardware_info_8226(hw_info, snd_card_name);
+    } else if(strstr(snd_card_name, "msm8x10")) {
+        ALOGV("8x10 - variant soundcard");
+        update_hardware_info_8610(hw_info, snd_card_name);
+    } else if(strstr(snd_card_name, "apq8084")) {
+        ALOGV("8084 - variant soundcard");
+        update_hardware_info_8084(hw_info, snd_card_name);
+    } else if(strstr(snd_card_name, "msm8994")) {
+        ALOGV("8994 - variant soundcard");
+        update_hardware_info_8994(hw_info, snd_card_name);
+    } else {
+        ALOGE("%s: Unsupported target %s:",__func__, snd_card_name);
+        free(hw_info);
+        hw_info = NULL;
+    }
+
+    return hw_info;
+}
+
+void hw_info_deinit(void *hw_info)
+{
+    struct hardware_info *my_data = (struct hardware_info*) hw_info;
+
+    if(!my_data)
+        free(my_data);
+}
+
+void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device,
+                            char *device_name)
+{
+    struct hardware_info *my_data = (struct hardware_info*) hw_info;
+    uint32_t i = 0;
+
+    snd_device_t *snd_devices =
+            (snd_device_t *) my_data->snd_devices;
+
+    if(snd_devices != NULL) {
+        for (i = 0; i <  my_data->num_snd_devices; i++) {
+            if (snd_device == (snd_device_t)snd_devices[i]) {
+                ALOGV("extract dev_extn device %d, extn = %s",
+                        (snd_device_t)snd_devices[i],  my_data->dev_extn);
+                CHECK(strlcat(device_name,  my_data->dev_extn,
+                        DEVICE_NAME_MAX_SIZE) < DEVICE_NAME_MAX_SIZE);
+                break;
+            }
+        }
+    }
+    ALOGD("%s : device_name = %s", __func__,device_name);
+}
diff --git a/msm8909/hal/msm8974/platform.c b/msm8909/hal/msm8974/platform.c
new file mode 100644
index 0000000..59a4af1
--- /dev/null
+++ b/msm8909/hal/msm8974/platform.c
@@ -0,0 +1,2919 @@
+/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "msm8974_platform"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <cutils/str_parms.h>
+#include <audio_hw.h>
+#include <platform_api.h>
+#include "platform.h"
+#include "audio_extn.h"
+#include "voice_extn.h"
+#include "sound/compress_params.h"
+#include "sound/msmcal-hwdep.h"
+
+#define SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID (100)
+#define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
+#define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml"
+#define MIXER_XML_PATH_I2S "/system/etc/mixer_paths_i2s.xml"
+
+#define PLATFORM_INFO_XML_PATH      "/system/etc/audio_platform_info.xml"
+#define PLATFORM_INFO_XML_PATH_I2S  "/system/etc/audio_platform_info_i2s.xml"
+
+#define LIB_ACDB_LOADER "libacdbloader.so"
+#define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID"
+#define CVD_VERSION_MIXER_CTL "CVD Version"
+
+#define MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE (256 * 1024)
+#define MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE (2 * 1024)
+#define COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING (2 * 1024)
+#define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024)
+
+/* Used in calculating fragment size for pcm offload */
+#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV 1000 /* 1 sec */
+#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING 80 /* 80 millisecs */
+
+/* MAX PCM fragment size cannot be increased  further due
+ * to flinger's cblk size of 1mb,and it has to be a multiple of
+ * 24 - lcm of channels supported by DSP
+ */
+#define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024)
+#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE (4 * 1024)
+
+#define ALIGN( num, to ) (((num) + (to-1)) & (~(to-1)))
+/*
+ * This file will have a maximum of 38 bytes:
+ *
+ * 4 bytes: number of audio blocks
+ * 4 bytes: total length of Short Audio Descriptor (SAD) blocks
+ * Maximum 10 * 3 bytes: SAD blocks
+ */
+#define MAX_SAD_BLOCKS      10
+#define SAD_BLOCK_SIZE      3
+
+#define MAX_CVD_VERSION_STRING_SIZE    100
+
+/* EDID format ID for LPCM audio */
+#define EDID_FORMAT_LPCM    1
+
+/* fallback app type if the default app type from acdb loader fails */
+#define DEFAULT_APP_TYPE  0x11130
+
+/* Retry for delay in FW loading*/
+#define RETRY_NUMBER 10
+#define RETRY_US 500000
+#define MAX_SND_CARD 8
+
+#define SAMPLE_RATE_8KHZ  8000
+#define SAMPLE_RATE_16KHZ 16000
+
+#define AUDIO_PARAMETER_KEY_FLUENCE_TYPE  "fluence"
+#define AUDIO_PARAMETER_KEY_SLOWTALK      "st_enable"
+#define AUDIO_PARAMETER_KEY_HD_VOICE      "hd_voice"
+#define AUDIO_PARAMETER_KEY_VOLUME_BOOST  "volume_boost"
+/* Query external audio device connection status */
+#define AUDIO_PARAMETER_KEY_EXT_AUDIO_DEVICE "ext_audio_device"
+
+#define EVENT_EXTERNAL_SPK_1 "qc_ext_spk_1"
+#define EVENT_EXTERNAL_SPK_2 "qc_ext_spk_2"
+#define EVENT_EXTERNAL_MIC   "qc_ext_mic"
+#define MAX_CAL_NAME 20
+
+char cal_name_info[WCD9XXX_MAX_CAL][MAX_CAL_NAME] = {
+        [WCD9XXX_ANC_CAL] = "anc_cal",
+        [WCD9XXX_MBHC_CAL] = "mbhc_cal",
+        [WCD9XXX_MAD_CAL] = "mad_cal",
+};
+
+#define  AUDIO_PARAMETER_IS_HW_DECODER_SESSION_ALLOWED  "is_hw_dec_session_allowed"
+
+char * dsp_only_decoders_mime[] = {
+    "audio/x-ms-wma" /* wma*/ ,
+    "audio/x-ms-wma-lossless" /* wma lossless */ ,
+    "audio/x-ms-wma-pro" /* wma prop */ ,
+    "audio/amr-wb-plus" /* amr wb plus */ ,
+    "audio/alac"  /*alac */ ,
+    "audio/x-ape" /*ape */,
+};
+
+
+enum {
+	VOICE_FEATURE_SET_DEFAULT,
+	VOICE_FEATURE_SET_VOLUME_BOOST
+};
+
+struct audio_block_header
+{
+    int reserved;
+    int length;
+};
+
+/* Audio calibration related functions */
+typedef void (*acdb_deallocate_t)();
+typedef int  (*acdb_init_t)(const char *, char *, int);
+typedef void (*acdb_send_audio_cal_t)(int, int, int , int);
+typedef void (*acdb_send_voice_cal_t)(int, int);
+typedef int (*acdb_reload_vocvoltable_t)(int);
+typedef int  (*acdb_get_default_app_type_t)(void);
+typedef int (*acdb_loader_get_calibration_t)(char *attr, int size, void *data);
+acdb_loader_get_calibration_t acdb_loader_get_calibration;
+
+struct platform_data {
+    struct audio_device *adev;
+    bool fluence_in_spkr_mode;
+    bool fluence_in_voice_call;
+    bool fluence_in_voice_rec;
+    bool fluence_in_audio_rec;
+    bool external_spk_1;
+    bool external_spk_2;
+    bool external_mic;
+    int  fluence_type;
+    int  fluence_mode;
+    char fluence_cap[PROPERTY_VALUE_MAX];
+    bool slowtalk;
+    bool hd_voice;
+    bool ec_ref_enabled;
+    bool is_i2s_ext_modem;
+    bool is_acdb_initialized;
+    /* Audio calibration related functions */
+    void                       *acdb_handle;
+    int                        voice_feature_set;
+    acdb_init_t                acdb_init;
+    acdb_deallocate_t          acdb_deallocate;
+    acdb_send_audio_cal_t      acdb_send_audio_cal;
+    acdb_send_voice_cal_t      acdb_send_voice_cal;
+    acdb_reload_vocvoltable_t  acdb_reload_vocvoltable;
+    acdb_get_default_app_type_t acdb_get_default_app_type;
+
+    void *hw_info;
+    struct csd_data *csd;
+};
+
+static int pcm_device_table[AUDIO_USECASE_MAX][2] = {
+    [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {DEEP_BUFFER_PCM_DEVICE,
+                                            DEEP_BUFFER_PCM_DEVICE},
+    [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
+                                           LOWLATENCY_PCM_DEVICE},
+    [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTIMEDIA2_PCM_DEVICE,
+                                        MULTIMEDIA2_PCM_DEVICE},
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD] =
+                     {PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE},
+#ifdef MULTIPLE_OFFLOAD_ENABLED
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD2] =
+                     {PLAYBACK_OFFLOAD_DEVICE2, PLAYBACK_OFFLOAD_DEVICE2},
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD3] =
+                     {PLAYBACK_OFFLOAD_DEVICE3, PLAYBACK_OFFLOAD_DEVICE3},
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD4] =
+                     {PLAYBACK_OFFLOAD_DEVICE4, PLAYBACK_OFFLOAD_DEVICE4},
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD5] =
+                     {PLAYBACK_OFFLOAD_DEVICE5, PLAYBACK_OFFLOAD_DEVICE5},
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD6] =
+                     {PLAYBACK_OFFLOAD_DEVICE6, PLAYBACK_OFFLOAD_DEVICE6},
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD7] =
+                     {PLAYBACK_OFFLOAD_DEVICE7, PLAYBACK_OFFLOAD_DEVICE7},
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD8] =
+                     {PLAYBACK_OFFLOAD_DEVICE8, PLAYBACK_OFFLOAD_DEVICE8},
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD9] =
+                     {PLAYBACK_OFFLOAD_DEVICE9, PLAYBACK_OFFLOAD_DEVICE9},
+#endif
+    [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE},
+    [USECASE_AUDIO_RECORD_COMPRESS] = {COMPRESS_CAPTURE_DEVICE, COMPRESS_CAPTURE_DEVICE},
+    [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
+                                          LOWLATENCY_PCM_DEVICE},
+    [USECASE_AUDIO_RECORD_FM_VIRTUAL] = {MULTIMEDIA2_PCM_DEVICE,
+                                  MULTIMEDIA2_PCM_DEVICE},
+    [USECASE_AUDIO_PLAYBACK_FM] = {FM_PLAYBACK_PCM_DEVICE, FM_CAPTURE_PCM_DEVICE},
+    [USECASE_AUDIO_HFP_SCO] = {HFP_PCM_RX, HFP_SCO_RX},
+    [USECASE_AUDIO_HFP_SCO_WB] = {HFP_PCM_RX, HFP_SCO_RX},
+    [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE},
+    [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE},
+    [USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE},
+    [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE, QCHAT_CALL_PCM_DEVICE},
+    [USECASE_VOWLAN_CALL] = {VOWLAN_CALL_PCM_DEVICE, VOWLAN_CALL_PCM_DEVICE},
+    [USECASE_COMPRESS_VOIP_CALL] = {COMPRESS_VOIP_CALL_PCM_DEVICE, COMPRESS_VOIP_CALL_PCM_DEVICE},
+    [USECASE_INCALL_REC_UPLINK] = {AUDIO_RECORD_PCM_DEVICE,
+                                   AUDIO_RECORD_PCM_DEVICE},
+    [USECASE_INCALL_REC_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE,
+                                     AUDIO_RECORD_PCM_DEVICE},
+    [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE,
+                                                AUDIO_RECORD_PCM_DEVICE},
+    [USECASE_INCALL_REC_UPLINK_COMPRESS] = {COMPRESS_CAPTURE_DEVICE,
+                                            COMPRESS_CAPTURE_DEVICE},
+    [USECASE_INCALL_REC_DOWNLINK_COMPRESS] = {COMPRESS_CAPTURE_DEVICE,
+                                              COMPRESS_CAPTURE_DEVICE},
+    [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS] = {COMPRESS_CAPTURE_DEVICE,
+                                                         COMPRESS_CAPTURE_DEVICE},
+    [USECASE_INCALL_MUSIC_UPLINK] = {INCALL_MUSIC_UPLINK_PCM_DEVICE,
+                                     INCALL_MUSIC_UPLINK_PCM_DEVICE},
+    [USECASE_INCALL_MUSIC_UPLINK2] = {INCALL_MUSIC_UPLINK2_PCM_DEVICE,
+                                      INCALL_MUSIC_UPLINK2_PCM_DEVICE},
+    [USECASE_AUDIO_SPKR_CALIB_RX] = {SPKR_PROT_CALIB_RX_PCM_DEVICE, -1},
+    [USECASE_AUDIO_SPKR_CALIB_TX] = {-1, SPKR_PROT_CALIB_TX_PCM_DEVICE},
+
+    [USECASE_AUDIO_PLAYBACK_AFE_PROXY] = {AFE_PROXY_PLAYBACK_PCM_DEVICE,
+                                          AFE_PROXY_RECORD_PCM_DEVICE},
+    [USECASE_AUDIO_RECORD_AFE_PROXY] = {AFE_PROXY_PLAYBACK_PCM_DEVICE,
+                                        AFE_PROXY_RECORD_PCM_DEVICE},
+
+};
+
+/* Array to store sound devices */
+static const char * const device_table[SND_DEVICE_MAX] = {
+    [SND_DEVICE_NONE] = "none",
+    /* Playback sound devices */
+    [SND_DEVICE_OUT_HANDSET] = "handset",
+    [SND_DEVICE_OUT_SPEAKER] = "speaker",
+    [SND_DEVICE_OUT_SPEAKER_EXTERNAL_1] = "speaker-ext-1",
+    [SND_DEVICE_OUT_SPEAKER_EXTERNAL_2] = "speaker-ext-2",
+    [SND_DEVICE_OUT_SPEAKER_REVERSE] = "speaker-reverse",
+    [SND_DEVICE_OUT_HEADPHONES] = "headphones",
+    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = "speaker-and-headphones",
+    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1] = "speaker-and-headphones-ext-1",
+    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2] = "speaker-and-headphones-ext-2",
+    [SND_DEVICE_OUT_VOICE_HANDSET] = "voice-handset",
+    [SND_DEVICE_OUT_VOICE_SPEAKER] = "voice-speaker",
+    [SND_DEVICE_OUT_VOICE_HEADPHONES] = "voice-headphones",
+    [SND_DEVICE_OUT_HDMI] = "hdmi",
+    [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi",
+    [SND_DEVICE_OUT_BT_SCO] = "bt-sco-headset",
+    [SND_DEVICE_OUT_BT_SCO_WB] = "bt-sco-headset-wb",
+    [SND_DEVICE_OUT_BT_A2DP] = "bt-a2dp",
+    [SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP] = "speaker-and-bt-a2dp",
+    [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones",
+    [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones",
+    [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset",
+    [SND_DEVICE_OUT_VOICE_TX] = "voice-tx",
+    [SND_DEVICE_OUT_AFE_PROXY] = "afe-proxy",
+    [SND_DEVICE_OUT_USB_HEADSET] = "usb-headphones",
+    [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = "speaker-and-usb-headphones",
+    [SND_DEVICE_OUT_TRANSMISSION_FM] = "transmission-fm",
+    [SND_DEVICE_OUT_ANC_HEADSET] = "anc-headphones",
+    [SND_DEVICE_OUT_ANC_FB_HEADSET] = "anc-fb-headphones",
+    [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = "voice-anc-headphones",
+    [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = "voice-anc-fb-headphones",
+    [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = "speaker-and-anc-headphones",
+    [SND_DEVICE_OUT_ANC_HANDSET] = "anc-handset",
+    [SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected",
+    [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = "voice-speaker-protected",
+
+    /* Capture sound devices */
+    [SND_DEVICE_IN_HANDSET_MIC] = "handset-mic",
+    [SND_DEVICE_IN_HANDSET_MIC_EXTERNAL] = "handset-mic-ext",
+    [SND_DEVICE_IN_HANDSET_MIC_AEC] = "handset-mic",
+    [SND_DEVICE_IN_HANDSET_MIC_NS] = "handset-mic",
+    [SND_DEVICE_IN_HANDSET_MIC_AEC_NS] = "handset-mic",
+    [SND_DEVICE_IN_HANDSET_DMIC] = "dmic-endfire",
+    [SND_DEVICE_IN_HANDSET_DMIC_AEC] = "dmic-endfire",
+    [SND_DEVICE_IN_HANDSET_DMIC_NS] = "dmic-endfire",
+    [SND_DEVICE_IN_HANDSET_DMIC_AEC_NS] = "dmic-endfire",
+    [SND_DEVICE_IN_SPEAKER_MIC] = "speaker-mic",
+    [SND_DEVICE_IN_SPEAKER_MIC_AEC] = "speaker-mic",
+    [SND_DEVICE_IN_SPEAKER_MIC_NS] = "speaker-mic",
+    [SND_DEVICE_IN_SPEAKER_MIC_AEC_NS] = "speaker-mic",
+    [SND_DEVICE_IN_SPEAKER_DMIC] = "speaker-dmic-endfire",
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC] = "speaker-dmic-endfire",
+    [SND_DEVICE_IN_SPEAKER_DMIC_NS] = "speaker-dmic-endfire",
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS] = "speaker-dmic-endfire",
+    [SND_DEVICE_IN_HEADSET_MIC] = "headset-mic",
+    [SND_DEVICE_IN_HEADSET_MIC_FLUENCE] = "headset-mic",
+    [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = "voice-speaker-mic",
+    [SND_DEVICE_IN_VOICE_HEADSET_MIC] = "voice-headset-mic",
+    [SND_DEVICE_IN_HDMI_MIC] = "hdmi-mic",
+    [SND_DEVICE_IN_BT_SCO_MIC] = "bt-sco-mic",
+    [SND_DEVICE_IN_BT_SCO_MIC_NREC] = "bt-sco-mic",
+    [SND_DEVICE_IN_BT_SCO_MIC_WB] = "bt-sco-mic-wb",
+    [SND_DEVICE_IN_BT_SCO_MIC_WB_NREC] = "bt-sco-mic-wb",
+    [SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic",
+    [SND_DEVICE_IN_VOICE_DMIC] = "voice-dmic-ef",
+    [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = "voice-speaker-dmic-ef",
+    [SND_DEVICE_IN_VOICE_SPEAKER_QMIC] = "voice-speaker-qmic",
+    [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic",
+    [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic",
+    [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic",
+    [SND_DEVICE_IN_VOICE_RX] = "voice-rx",
+
+    [SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic",
+    [SND_DEVICE_IN_VOICE_REC_MIC_NS] = "voice-rec-mic",
+    [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = "voice-rec-dmic-ef",
+    [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence",
+    [SND_DEVICE_IN_USB_HEADSET_MIC] = "usb-headset-mic",
+    [SND_DEVICE_IN_CAPTURE_FM] = "capture-fm",
+    [SND_DEVICE_IN_AANC_HANDSET_MIC] = "aanc-handset-mic",
+    [SND_DEVICE_IN_QUAD_MIC] = "quad-mic",
+    [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = "handset-stereo-dmic-ef",
+    [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = "speaker-stereo-dmic-ef",
+    [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = "vi-feedback",
+    [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE] = "voice-speaker-dmic-broadside",
+    [SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE] = "speaker-dmic-broadside",
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE] = "speaker-dmic-broadside",
+    [SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE] = "speaker-dmic-broadside",
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE] = "speaker-dmic-broadside",
+};
+
+/* ACDB IDs (audio DSP path configuration IDs) for each sound device */
+static int acdb_device_table[SND_DEVICE_MAX] = {
+    [SND_DEVICE_NONE] = -1,
+    [SND_DEVICE_OUT_HANDSET] = 7,
+    [SND_DEVICE_OUT_SPEAKER] = 14,
+    [SND_DEVICE_OUT_SPEAKER_EXTERNAL_1] = 14,
+    [SND_DEVICE_OUT_SPEAKER_EXTERNAL_2] = 14,
+    [SND_DEVICE_OUT_SPEAKER_REVERSE] = 14,
+    [SND_DEVICE_OUT_HEADPHONES] = 10,
+    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10,
+    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1] = 10,
+    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2] = 10,
+    [SND_DEVICE_OUT_VOICE_HANDSET] = 7,
+    [SND_DEVICE_OUT_VOICE_SPEAKER] = 14,
+    [SND_DEVICE_OUT_VOICE_HEADPHONES] = 10,
+    [SND_DEVICE_OUT_HDMI] = 18,
+    [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14,
+    [SND_DEVICE_OUT_BT_SCO] = 22,
+    [SND_DEVICE_OUT_BT_SCO_WB] = 39,
+    [SND_DEVICE_OUT_BT_A2DP] = 20,
+    [SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP] = 14,
+    [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17,
+    [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
+    [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37,
+    [SND_DEVICE_OUT_VOICE_TX] = 45,
+    [SND_DEVICE_OUT_AFE_PROXY] = 0,
+    [SND_DEVICE_OUT_USB_HEADSET] = 45,
+    [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 14,
+    [SND_DEVICE_OUT_TRANSMISSION_FM] = 0,
+    [SND_DEVICE_OUT_ANC_HEADSET] = 26,
+    [SND_DEVICE_OUT_ANC_FB_HEADSET] = 27,
+    [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = 26,
+    [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = 27,
+    [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = 26,
+    [SND_DEVICE_OUT_ANC_HANDSET] = 103,
+    [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 124,
+    [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = 101,
+
+    [SND_DEVICE_IN_HANDSET_MIC] = 4,
+    [SND_DEVICE_IN_HANDSET_MIC_EXTERNAL] = 4,
+    [SND_DEVICE_IN_HANDSET_MIC_AEC] = 106,
+    [SND_DEVICE_IN_HANDSET_MIC_NS] = 107,
+    [SND_DEVICE_IN_HANDSET_MIC_AEC_NS] = 108,
+    [SND_DEVICE_IN_HANDSET_DMIC] = 41,
+    [SND_DEVICE_IN_HANDSET_DMIC_AEC] = 109,
+    [SND_DEVICE_IN_HANDSET_DMIC_NS] = 110,
+    [SND_DEVICE_IN_HANDSET_DMIC_AEC_NS] = 111,
+    [SND_DEVICE_IN_SPEAKER_MIC] = 11,
+    [SND_DEVICE_IN_SPEAKER_MIC_AEC] = 112,
+    [SND_DEVICE_IN_SPEAKER_MIC_NS] = 113,
+    [SND_DEVICE_IN_SPEAKER_MIC_AEC_NS] = 114,
+    [SND_DEVICE_IN_SPEAKER_DMIC] = 43,
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC] = 115,
+    [SND_DEVICE_IN_SPEAKER_DMIC_NS] = 116,
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS] = 117,
+    [SND_DEVICE_IN_HEADSET_MIC] = 8,
+    [SND_DEVICE_IN_HEADSET_MIC_FLUENCE] = 47,
+    [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = 11,
+    [SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8,
+    [SND_DEVICE_IN_HDMI_MIC] = 4,
+    [SND_DEVICE_IN_BT_SCO_MIC] = 21,
+    [SND_DEVICE_IN_BT_SCO_MIC_NREC] = 122,
+    [SND_DEVICE_IN_BT_SCO_MIC_WB] = 38,
+    [SND_DEVICE_IN_BT_SCO_MIC_WB_NREC] = 123,
+    [SND_DEVICE_IN_CAMCORDER_MIC] = 4,
+    [SND_DEVICE_IN_VOICE_DMIC] = 41,
+    [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = 43,
+    [SND_DEVICE_IN_VOICE_SPEAKER_QMIC] = 19,
+    [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16,
+    [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36,
+    [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16,
+    [SND_DEVICE_IN_VOICE_RX] = 44,
+
+    [SND_DEVICE_IN_VOICE_REC_MIC] = 4,
+    [SND_DEVICE_IN_VOICE_REC_MIC_NS] = 107,
+    [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = 34,
+    [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 41,
+    [SND_DEVICE_IN_USB_HEADSET_MIC] = 44,
+    [SND_DEVICE_IN_CAPTURE_FM] = 0,
+    [SND_DEVICE_IN_AANC_HANDSET_MIC] = 104,
+    [SND_DEVICE_IN_QUAD_MIC] = 46,
+    [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = 34,
+    [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = 35,
+    [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = 102,
+    [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE] = 12,
+    [SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE] = 12,
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE] = 119,
+    [SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE] = 121,
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE] = 120,
+};
+
+struct name_to_index {
+    char name[100];
+    unsigned int index;
+};
+
+#define TO_NAME_INDEX(X)   #X, X
+
+/* Used to get index from parsed sting */
+static struct name_to_index snd_device_name_index[SND_DEVICE_MAX] = {
+    {TO_NAME_INDEX(SND_DEVICE_OUT_HANDSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_EXTERNAL_1)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_EXTERNAL_2)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_REVERSE)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_HEADPHONES)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HANDSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HEADPHONES)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_HDMI)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HDMI)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_BT_SCO)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_BT_SCO_WB)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_BT_A2DP)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_AFE_PROXY)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_USB_HEADSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_TRANSMISSION_FM)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_ANC_HEADSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_ANC_FB_HEADSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_ANC_HEADSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_ANC_HANDSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_EXTERNAL)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_AEC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_AEC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_DMIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_DMIC_AEC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_DMIC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_DMIC_AEC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_MIC_AEC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_MIC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_MIC_AEC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HEADSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HEADSET_MIC_FLUENCE)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_HEADSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HDMI_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_BT_SCO_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_BT_SCO_MIC_NREC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_BT_SCO_MIC_WB)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_BT_SCO_MIC_WB_NREC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_CAMCORDER_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_DMIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_DMIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_QMIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_MIC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_DMIC_STEREO)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_USB_HEADSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_FM)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_AANC_HANDSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_QUAD_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_STEREO_DMIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_STEREO_DMIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_VI_FEEDBACK)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE)},
+};
+
+static char * backend_table[SND_DEVICE_MAX] = {0};
+
+static struct name_to_index usecase_name_index[AUDIO_USECASE_MAX] = {
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_DEEP_BUFFER)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_LOW_LATENCY)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_MULTI_CH)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD)},
+    {TO_NAME_INDEX(USECASE_AUDIO_RECORD)},
+    {TO_NAME_INDEX(USECASE_AUDIO_RECORD_LOW_LATENCY)},
+    {TO_NAME_INDEX(USECASE_VOICE_CALL)},
+    {TO_NAME_INDEX(USECASE_VOICE2_CALL)},
+    {TO_NAME_INDEX(USECASE_VOLTE_CALL)},
+    {TO_NAME_INDEX(USECASE_QCHAT_CALL)},
+    {TO_NAME_INDEX(USECASE_VOWLAN_CALL)},
+    {TO_NAME_INDEX(USECASE_INCALL_REC_UPLINK)},
+    {TO_NAME_INDEX(USECASE_INCALL_REC_DOWNLINK)},
+    {TO_NAME_INDEX(USECASE_INCALL_REC_UPLINK_AND_DOWNLINK)},
+    {TO_NAME_INDEX(USECASE_AUDIO_HFP_SCO)},
+};
+
+#define NO_COLS 2
+#ifdef PLATFORM_APQ8084
+static int msm_device_to_be_id [][NO_COLS] = {
+       {AUDIO_DEVICE_OUT_EARPIECE                       ,       2},
+       {AUDIO_DEVICE_OUT_SPEAKER                        ,       2},
+       {AUDIO_DEVICE_OUT_WIRED_HEADSET                  ,       2},
+       {AUDIO_DEVICE_OUT_WIRED_HEADPHONE                ,       2},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO                  ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET          ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT           ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP                 ,       -1},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES      ,       -1},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER         ,       -1},
+       {AUDIO_DEVICE_OUT_AUX_DIGITAL                    ,       4},
+       {AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET              ,       9},
+       {AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET              ,       9},
+       {AUDIO_DEVICE_OUT_USB_ACCESSORY                  ,       -1},
+       {AUDIO_DEVICE_OUT_USB_DEVICE                     ,       -1},
+       {AUDIO_DEVICE_OUT_REMOTE_SUBMIX                  ,       9},
+       {AUDIO_DEVICE_OUT_PROXY                          ,       9},
+       {AUDIO_DEVICE_OUT_FM                             ,       7},
+       {AUDIO_DEVICE_OUT_FM_TX                          ,       8},
+       {AUDIO_DEVICE_OUT_ALL                            ,      -1},
+       {AUDIO_DEVICE_NONE                               ,      -1},
+       {AUDIO_DEVICE_OUT_DEFAULT                        ,      -1},
+};
+#elif PLATFORM_MSM8994
+static int msm_device_to_be_id [][NO_COLS] = {
+       {AUDIO_DEVICE_OUT_EARPIECE                       ,       2},
+       {AUDIO_DEVICE_OUT_SPEAKER                        ,       2},
+       {AUDIO_DEVICE_OUT_WIRED_HEADSET                  ,       2},
+       {AUDIO_DEVICE_OUT_WIRED_HEADPHONE                ,       2},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO                  ,       38},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET          ,       38},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT           ,       38},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP                 ,       -1},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES      ,       -1},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER         ,       -1},
+       {AUDIO_DEVICE_OUT_AUX_DIGITAL                    ,       4},
+       {AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET              ,       9},
+       {AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET              ,       9},
+       {AUDIO_DEVICE_OUT_USB_ACCESSORY                  ,       -1},
+       {AUDIO_DEVICE_OUT_USB_DEVICE                     ,       -1},
+       {AUDIO_DEVICE_OUT_REMOTE_SUBMIX                  ,       9},
+       {AUDIO_DEVICE_OUT_PROXY                          ,       9},
+/* Add the correct be ids */
+       {AUDIO_DEVICE_OUT_FM                             ,       7},
+       {AUDIO_DEVICE_OUT_FM_TX                          ,       8},
+       {AUDIO_DEVICE_OUT_ALL                            ,      -1},
+       {AUDIO_DEVICE_NONE                               ,      -1},
+       {AUDIO_DEVICE_OUT_DEFAULT                        ,      -1},
+};
+#else
+static int msm_device_to_be_id [][NO_COLS] = {
+    {AUDIO_DEVICE_NONE, -1},
+};
+#endif
+static int msm_be_id_array_len  =
+    sizeof(msm_device_to_be_id) / sizeof(msm_device_to_be_id[0]);
+
+
+#define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
+#define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
+
+void platform_set_echo_reference(void *platform, bool enable)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+
+    if (my_data->ec_ref_enabled) {
+        my_data->ec_ref_enabled = false;
+        ALOGV("%s: disabling echo-reference", __func__);
+        audio_route_reset_and_update_path(adev->audio_route, "echo-reference");
+    }
+
+    if (enable) {
+         my_data->ec_ref_enabled = true;
+         ALOGD("%s: enabling echo-reference", __func__);
+         audio_route_apply_and_update_path(adev->audio_route, "echo-reference");
+    }
+
+}
+
+static struct csd_data *open_csd_client(bool i2s_ext_modem)
+{
+    struct csd_data *csd = calloc(1, sizeof(struct csd_data));
+
+    if (!csd) {
+        ALOGE("failed to allocate csd_data mem");
+        return NULL;
+    }
+
+    csd->csd_client = dlopen(LIB_CSD_CLIENT, RTLD_NOW);
+    if (csd->csd_client == NULL) {
+        ALOGE("%s: DLOPEN failed for %s", __func__, LIB_CSD_CLIENT);
+        goto error;
+    } else {
+        ALOGV("%s: DLOPEN successful for %s", __func__, LIB_CSD_CLIENT);
+
+        csd->deinit = (deinit_t)dlsym(csd->csd_client,
+                                             "csd_client_deinit");
+        if (csd->deinit == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_deinit", __func__,
+                  dlerror());
+            goto error;
+        }
+        csd->disable_device = (disable_device_t)dlsym(csd->csd_client,
+                                             "csd_client_disable_device");
+        if (csd->disable_device == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_disable_device",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->enable_device_config = (enable_device_config_t)dlsym(csd->csd_client,
+                                               "csd_client_enable_device_config");
+        if (csd->enable_device_config == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_enable_device_config",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->enable_device = (enable_device_t)dlsym(csd->csd_client,
+                                             "csd_client_enable_device");
+        if (csd->enable_device == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_enable_device",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->start_voice = (start_voice_t)dlsym(csd->csd_client,
+                                             "csd_client_start_voice");
+        if (csd->start_voice == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_start_voice",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->stop_voice = (stop_voice_t)dlsym(csd->csd_client,
+                                             "csd_client_stop_voice");
+        if (csd->stop_voice == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_stop_voice",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->volume = (volume_t)dlsym(csd->csd_client,
+                                             "csd_client_volume");
+        if (csd->volume == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_volume",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->mic_mute = (mic_mute_t)dlsym(csd->csd_client,
+                                             "csd_client_mic_mute");
+        if (csd->mic_mute == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_mic_mute",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->slow_talk = (slow_talk_t)dlsym(csd->csd_client,
+                                             "csd_client_slow_talk");
+        if (csd->slow_talk == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_slow_talk",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->start_playback = (start_playback_t)dlsym(csd->csd_client,
+                                             "csd_client_start_playback");
+        if (csd->start_playback == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_start_playback",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->stop_playback = (stop_playback_t)dlsym(csd->csd_client,
+                                             "csd_client_stop_playback");
+        if (csd->stop_playback == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_stop_playback",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->set_lch = (set_lch_t)dlsym(csd->csd_client, "csd_client_set_lch");
+        if (csd->set_lch == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_set_lch",
+                  __func__, dlerror());
+            /* Ignore the error as this is not mandatory function for
+             * basic voice call to work.
+             */
+        }
+        csd->start_record = (start_record_t)dlsym(csd->csd_client,
+                                             "csd_client_start_record");
+        if (csd->start_record == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_start_record",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->stop_record = (stop_record_t)dlsym(csd->csd_client,
+                                             "csd_client_stop_record");
+        if (csd->stop_record == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_stop_record",
+                  __func__, dlerror());
+            goto error;
+        }
+
+        csd->get_sample_rate = (get_sample_rate_t)dlsym(csd->csd_client,
+                                             "csd_client_get_sample_rate");
+        if (csd->get_sample_rate == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_get_sample_rate",
+                  __func__, dlerror());
+
+            goto error;
+        }
+
+        csd->init = (init_t)dlsym(csd->csd_client, "csd_client_init");
+
+        if (csd->init == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_init",
+                  __func__, dlerror());
+            goto error;
+        } else {
+            csd->init(i2s_ext_modem);
+        }
+    }
+    return csd;
+
+error:
+    free(csd);
+    csd = NULL;
+    return csd;
+}
+
+void close_csd_client(struct csd_data *csd)
+{
+    if (csd != NULL) {
+        csd->deinit();
+        dlclose(csd->csd_client);
+        free(csd);
+        csd = NULL;
+    }
+}
+
+static bool platform_is_i2s_ext_modem(const char *snd_card_name,
+                                      struct platform_data *plat_data)
+{
+    plat_data->is_i2s_ext_modem = false;
+
+    if (!strncmp(snd_card_name, "apq8084-taiko-i2s-mtp-snd-card",
+                 sizeof("apq8084-taiko-i2s-mtp-snd-card")) ||
+        !strncmp(snd_card_name, "apq8084-taiko-i2s-cdp-snd-card",
+                 sizeof("apq8084-taiko-i2s-cdp-snd-card"))) {
+        plat_data->is_i2s_ext_modem = true;
+    }
+    ALOGV("%s, is_i2s_ext_modem:%d",__func__, plat_data->is_i2s_ext_modem);
+
+    return plat_data->is_i2s_ext_modem;
+}
+
+static void set_platform_defaults()
+{
+    int32_t dev;
+    for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
+        backend_table[dev] = NULL;
+    }
+
+    // TBD - do these go to the platform-info.xml file.
+    // will help in avoiding strdups here
+    backend_table[SND_DEVICE_IN_BT_SCO_MIC] = strdup("bt-sco");
+    backend_table[SND_DEVICE_IN_BT_SCO_MIC_WB] = strdup("bt-sco-wb");
+    backend_table[SND_DEVICE_IN_BT_SCO_MIC_NREC] = strdup("bt-sco");
+    backend_table[SND_DEVICE_IN_BT_SCO_MIC_WB_NREC] = strdup("bt-sco-wb");
+    backend_table[SND_DEVICE_OUT_BT_SCO] = strdup("bt-sco");
+    backend_table[SND_DEVICE_OUT_BT_SCO_WB] = strdup("bt-sco-wb");
+    backend_table[SND_DEVICE_OUT_BT_A2DP] = strdup("bt-a2dp");
+    backend_table[SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP] = strdup("speaker-and-bt-a2dp");
+    backend_table[SND_DEVICE_OUT_HDMI] = strdup("hdmi");
+    backend_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = strdup("speaker-and-hdmi");
+    backend_table[SND_DEVICE_OUT_VOICE_TX] = strdup("afe-proxy");
+    backend_table[SND_DEVICE_IN_VOICE_RX] = strdup("afe-proxy");
+
+    backend_table[SND_DEVICE_OUT_AFE_PROXY] = strdup("afe-proxy");
+    backend_table[SND_DEVICE_OUT_USB_HEADSET] = strdup("usb-headphones");
+    backend_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] =
+        strdup("speaker-and-usb-headphones");
+    backend_table[SND_DEVICE_IN_USB_HEADSET_MIC] = strdup("usb-headset-mic");
+    backend_table[SND_DEVICE_IN_CAPTURE_FM] = strdup("capture-fm");
+    backend_table[SND_DEVICE_OUT_TRANSMISSION_FM] = strdup("transmission-fm");
+}
+
+void get_cvd_version(char *cvd_version, struct audio_device *adev)
+{
+    struct mixer_ctl *ctl;
+    int count;
+    int ret = 0;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, CVD_VERSION_MIXER_CTL);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",  __func__, CVD_VERSION_MIXER_CTL);
+        goto done;
+    }
+    mixer_ctl_update(ctl);
+
+    count = mixer_ctl_get_num_values(ctl);
+    if (count > MAX_CVD_VERSION_STRING_SIZE)
+        count = MAX_CVD_VERSION_STRING_SIZE;
+
+    ret = mixer_ctl_get_array(ctl, cvd_version, count);
+    if (ret != 0) {
+        ALOGE("%s: ERROR! mixer_ctl_get_array() failed to get CVD Version", __func__);
+        goto done;
+    }
+
+done:
+    return;
+}
+
+static int hw_util_open(int card_no)
+{
+    int fd = -1;
+    char dev_name[256];
+
+    snprintf(dev_name, sizeof(dev_name), "/dev/snd/hwC%uD%u",
+                               card_no, WCD9XXX_CODEC_HWDEP_NODE);
+    ALOGD("%s Opening device %s\n", __func__, dev_name);
+    fd = open(dev_name, O_WRONLY);
+    if (fd < 0) {
+        ALOGE("%s: cannot open device '%s'\n", __func__, dev_name);
+        return fd;
+    }
+    ALOGD("%s success", __func__);
+    return fd;
+}
+
+struct param_data {
+    int    use_case;
+    int    acdb_id;
+    int    get_size;
+    int    buff_size;
+    int    data_size;
+    void   *buff;
+};
+
+static int send_codec_cal(acdb_loader_get_calibration_t acdb_loader_get_calibration, int fd)
+{
+    int ret = 0, type;
+
+    for (type = WCD9XXX_ANC_CAL; type < WCD9XXX_MAX_CAL; type++) {
+        struct wcdcal_ioctl_buffer codec_buffer;
+        struct param_data calib;
+
+        if (!strcmp(cal_name_info[type], "mad_cal"))
+            calib.acdb_id = SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID;
+        calib.get_size = 1;
+        ret = acdb_loader_get_calibration(cal_name_info[type], sizeof(struct param_data),
+                                                                 &calib);
+        if (ret < 0) {
+            ALOGE("%s get_calibration failed\n", __func__);
+            return ret;
+        }
+        calib.get_size = 0;
+        calib.buff = malloc(calib.buff_size);
+        ret = acdb_loader_get_calibration(cal_name_info[type],
+                              sizeof(struct param_data), &calib);
+        if (ret < 0) {
+            ALOGE("%s get_calibration failed\n", __func__);
+            free(calib.buff);
+            return ret;
+        }
+        codec_buffer.buffer = calib.buff;
+        codec_buffer.size = calib.data_size;
+        codec_buffer.cal_type = type;
+        if (ioctl(fd, SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE, &codec_buffer) < 0)
+            ALOGE("Failed to call ioctl  for %s err=%d",
+                                  cal_name_info[type], errno);
+        ALOGD("%s cal sent for %s", __func__, cal_name_info[type]);
+        free(calib.buff);
+    }
+    return ret;
+}
+
+static void audio_hwdep_send_cal(struct platform_data *plat_data)
+{
+    int fd;
+
+    fd = hw_util_open(plat_data->adev->snd_card);
+    if (fd == -1) {
+        ALOGE("%s error open\n", __func__);
+        return;
+    }
+
+    acdb_loader_get_calibration = (acdb_loader_get_calibration_t)
+          dlsym(plat_data->acdb_handle, "acdb_loader_get_calibration");
+
+    if (acdb_loader_get_calibration == NULL) {
+        ALOGE("%s: ERROR. dlsym Error:%s acdb_loader_get_calibration", __func__,
+           dlerror());
+        return;
+    }
+    if (send_codec_cal(acdb_loader_get_calibration, fd) < 0)
+        ALOGE("%s: Could not send anc cal", __FUNCTION__);
+}
+
+int platform_acdb_init(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    char *cvd_version = NULL;
+    int key = 0;
+    const char *snd_card_name;
+    int result;
+    char value[PROPERTY_VALUE_MAX];
+    cvd_version = calloc(1, MAX_CVD_VERSION_STRING_SIZE);
+    if (!cvd_version)
+        ALOGE("Failed to allocate cvd version");
+    else
+        get_cvd_version(cvd_version, my_data->adev);
+
+    property_get("audio.ds1.metainfo.key",value,"0");
+    key = atoi(value);
+    snd_card_name = mixer_get_name(my_data->adev->mixer);
+    result = my_data->acdb_init(snd_card_name, cvd_version, key);
+    if (cvd_version)
+        free(cvd_version);
+    if (!result) {
+        my_data->is_acdb_initialized = true;
+        ALOGD("ACDB initialized");
+        audio_hwdep_send_cal(my_data);
+    } else {
+        my_data->is_acdb_initialized = false;
+        ALOGD("ACDB initialization failed");
+    }
+    return result;
+}
+
+void *platform_init(struct audio_device *adev)
+{
+    char platform[PROPERTY_VALUE_MAX];
+    char baseband[PROPERTY_VALUE_MAX];
+    char value[PROPERTY_VALUE_MAX];
+    struct platform_data *my_data = NULL;
+    int retry_num = 0, snd_card_num = 0, key = 0;
+    const char *snd_card_name;
+    char *cvd_version = NULL;
+
+    my_data = calloc(1, sizeof(struct platform_data));
+
+    if (!my_data) {
+        ALOGE("failed to allocate platform data");
+        return NULL;
+    }
+
+    while (snd_card_num < MAX_SND_CARD) {
+        adev->mixer = mixer_open(snd_card_num);
+
+        while (!adev->mixer && retry_num < RETRY_NUMBER) {
+            usleep(RETRY_US);
+            adev->mixer = mixer_open(snd_card_num);
+            retry_num++;
+        }
+
+        if (!adev->mixer) {
+            ALOGE("%s: Unable to open the mixer card: %d", __func__,
+                   snd_card_num);
+            retry_num = 0;
+            snd_card_num++;
+            continue;
+        }
+
+        snd_card_name = mixer_get_name(adev->mixer);
+        ALOGV("%s: snd_card_name: %s", __func__, snd_card_name);
+
+        my_data->hw_info = hw_info_init(snd_card_name);
+        if (!my_data->hw_info) {
+            ALOGE("%s: Failed to init hardware info", __func__);
+        } else {
+            if (platform_is_i2s_ext_modem(snd_card_name, my_data)) {
+                ALOGD("%s: Call MIXER_XML_PATH_I2S", __func__);
+
+                adev->audio_route = audio_route_init(snd_card_num,
+                                                     MIXER_XML_PATH_I2S);
+            } else if (audio_extn_read_xml(adev, snd_card_num, MIXER_XML_PATH,
+                                    MIXER_XML_PATH_AUXPCM) == -ENOSYS) {
+                adev->audio_route = audio_route_init(snd_card_num,
+                                                 MIXER_XML_PATH);
+            }
+            if (!adev->audio_route) {
+                ALOGE("%s: Failed to init audio route controls, aborting.",
+                       __func__);
+                free(my_data);
+                return NULL;
+            }
+            adev->snd_card = snd_card_num;
+            ALOGD("%s: Opened sound card:%d", __func__, snd_card_num);
+            break;
+        }
+        retry_num = 0;
+        snd_card_num++;
+    }
+
+    if (snd_card_num >= MAX_SND_CARD) {
+        ALOGE("%s: Unable to find correct sound card, aborting.", __func__);
+        free(my_data);
+        return NULL;
+    }
+
+    my_data->adev = adev;
+    my_data->fluence_in_spkr_mode = false;
+    my_data->fluence_in_voice_call = false;
+    my_data->fluence_in_voice_rec = false;
+    my_data->fluence_in_audio_rec = false;
+    my_data->external_spk_1 = false;
+    my_data->external_spk_2 = false;
+    my_data->external_mic = false;
+    my_data->fluence_type = FLUENCE_NONE;
+    my_data->fluence_mode = FLUENCE_ENDFIRE;
+    my_data->slowtalk = false;
+    my_data->hd_voice = false;
+
+    property_get("ro.qc.sdk.audio.fluencetype", my_data->fluence_cap, "");
+    if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro"))) {
+        my_data->fluence_type = FLUENCE_QUAD_MIC | FLUENCE_DUAL_MIC;
+    } else if (!strncmp("fluence", my_data->fluence_cap, sizeof("fluence"))) {
+        my_data->fluence_type = FLUENCE_DUAL_MIC;
+    } else {
+        my_data->fluence_type = FLUENCE_NONE;
+    }
+
+    if (my_data->fluence_type != FLUENCE_NONE) {
+        property_get("persist.audio.fluence.voicecall",value,"");
+        if (!strncmp("true", value, sizeof("true"))) {
+            my_data->fluence_in_voice_call = true;
+        }
+
+        property_get("persist.audio.fluence.voicerec",value,"");
+        if (!strncmp("true", value, sizeof("true"))) {
+            my_data->fluence_in_voice_rec = true;
+        }
+
+        property_get("persist.audio.fluence.audiorec",value,"");
+        if (!strncmp("true", value, sizeof("true"))) {
+            my_data->fluence_in_audio_rec = true;
+        }
+
+        property_get("persist.audio.fluence.speaker",value,"");
+        if (!strncmp("true", value, sizeof("true"))) {
+            my_data->fluence_in_spkr_mode = true;
+        }
+
+        property_get("persist.audio.fluence.mode",value,"");
+        if (!strncmp("broadside", value, sizeof("broadside"))) {
+            my_data->fluence_mode = FLUENCE_BROADSIDE;
+        }
+    }
+
+    my_data->voice_feature_set = VOICE_FEATURE_SET_DEFAULT;
+    my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
+    if (my_data->acdb_handle == NULL) {
+        ALOGE("%s: DLOPEN failed for %s", __func__, LIB_ACDB_LOADER);
+    } else {
+        ALOGV("%s: DLOPEN successful for %s", __func__, LIB_ACDB_LOADER);
+        my_data->acdb_deallocate = (acdb_deallocate_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_deallocate_ACDB");
+        if (!my_data->acdb_deallocate)
+            ALOGE("%s: Could not find the symbol acdb_loader_deallocate_ACDB from %s",
+                  __func__, LIB_ACDB_LOADER);
+
+        my_data->acdb_send_audio_cal = (acdb_send_audio_cal_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_send_audio_cal_v2");
+        if (!my_data->acdb_send_audio_cal)
+            ALOGE("%s: Could not find the symbol acdb_send_audio_cal from %s",
+                  __func__, LIB_ACDB_LOADER);
+
+        my_data->acdb_send_voice_cal = (acdb_send_voice_cal_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_send_voice_cal");
+        if (!my_data->acdb_send_voice_cal)
+            ALOGE("%s: Could not find the symbol acdb_loader_send_voice_cal from %s",
+                  __func__, LIB_ACDB_LOADER);
+
+        my_data->acdb_reload_vocvoltable = (acdb_reload_vocvoltable_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_reload_vocvoltable");
+        if (!my_data->acdb_reload_vocvoltable)
+            ALOGE("%s: Could not find the symbol acdb_loader_reload_vocvoltable from %s",
+                  __func__, LIB_ACDB_LOADER);
+
+        my_data->acdb_get_default_app_type = (acdb_get_default_app_type_t)dlsym(
+                                                    my_data->acdb_handle,
+                                                    "acdb_loader_get_default_app_type");
+        if (!my_data->acdb_get_default_app_type)
+            ALOGE("%s: Could not find the symbol acdb_get_default_app_type from %s",
+                  __func__, LIB_ACDB_LOADER);
+
+        my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_init_v2");
+        if (my_data->acdb_init == NULL) {
+            ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__, dlerror());
+            goto acdb_init_fail;
+        }
+
+        platform_acdb_init(my_data);
+    }
+
+acdb_init_fail:
+
+    set_platform_defaults();
+
+    /* Initialize ACDB ID's */
+    if (my_data->is_i2s_ext_modem)
+        platform_info_init(PLATFORM_INFO_XML_PATH_I2S);
+    else
+        platform_info_init(PLATFORM_INFO_XML_PATH);
+
+    /* If platform is apq8084 and baseband is MDM, load CSD Client specific
+     * symbols. Voice call is handled by MDM and apps processor talks to
+     * MDM through CSD Client
+     */
+    property_get("ro.board.platform", platform, "");
+    property_get("ro.baseband", baseband, "");
+    if (!strncmp("apq8084", platform, sizeof("apq8084")) &&
+        !strncmp("mdm", baseband, (sizeof("mdm")-1))) {
+         my_data->csd = open_csd_client(my_data->is_i2s_ext_modem);
+    } else {
+         my_data->csd = NULL;
+    }
+
+    /* init usb */
+    audio_extn_usb_init(adev);
+
+    /*init a2dp*/
+    audio_extn_a2dp_init();
+
+    /* update sound cards appropriately */
+    audio_extn_usb_set_proxy_sound_card(adev->snd_card);
+
+    /* init dap hal */
+    audio_extn_dap_hal_init(adev->snd_card);
+
+    /* Read one time ssr property */
+    audio_extn_ssr_update_enabled();
+    audio_extn_spkr_prot_init(adev);
+
+    audio_extn_dolby_set_license(adev);
+    audio_hwdep_send_cal(my_data);
+
+    /* init audio device arbitration */
+    audio_extn_dev_arbi_init();
+
+    return my_data;
+}
+
+void platform_deinit(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    hw_info_deinit(my_data->hw_info);
+    close_csd_client(my_data->csd);
+
+    int32_t dev;
+    for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
+        if (backend_table[dev]) {
+            free(backend_table[dev]);
+            backend_table[dev]= NULL;
+        }
+    }
+
+    /* deinit audio device arbitration */
+    audio_extn_dev_arbi_deinit();
+
+    free(platform);
+    /* deinit usb */
+    audio_extn_usb_deinit();
+    audio_extn_dap_hal_deinit();
+}
+
+int platform_is_acdb_initialized(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    ALOGD("%s: acdb initialized %d\n", __func__, my_data->is_acdb_initialized);
+    return my_data->is_acdb_initialized;
+}
+
+const char *platform_get_snd_device_name(snd_device_t snd_device)
+{
+    if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX)
+        return device_table[snd_device];
+    else
+        return "";
+}
+
+int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device,
+                                      char *device_name)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) {
+        strlcpy(device_name, device_table[snd_device], DEVICE_NAME_MAX_SIZE);
+        hw_info_append_hw_type(my_data->hw_info, snd_device, device_name);
+    } else {
+        strlcpy(device_name, "", DEVICE_NAME_MAX_SIZE);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+void platform_add_backend_name(char *mixer_path, snd_device_t snd_device)
+{
+    if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
+        ALOGE("%s: Invalid snd_device = %d", __func__, snd_device);
+        return;
+    }
+
+    const char * suffix = backend_table[snd_device];
+
+    if (suffix != NULL) {
+        strlcat(mixer_path, " ", MIXER_PATH_MAX_LENGTH);
+        strlcat(mixer_path, suffix, MIXER_PATH_MAX_LENGTH);
+    }
+}
+
+int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type)
+{
+    int device_id;
+    if (device_type == PCM_PLAYBACK)
+        device_id = pcm_device_table[usecase][0];
+    else
+        device_id = pcm_device_table[usecase][1];
+    return device_id;
+}
+
+static int find_index(struct name_to_index * table, int32_t len, const char * name)
+{
+    int ret = 0;
+    int32_t i;
+
+    if (table == NULL) {
+        ALOGE("%s: table is NULL", __func__);
+        ret = -ENODEV;
+        goto done;
+    }
+
+    if (name == NULL) {
+        ALOGE("null key");
+        ret = -ENODEV;
+        goto done;
+    }
+
+    for (i=0; i < len; i++) {
+        const char* tn = table[i].name;
+        size_t len = strlen(tn);
+        if (strncmp(tn, name, len) == 0) {
+            if (strlen(name) != len) {
+                continue; // substring
+            }
+            ret = table[i].index;
+            goto done;
+        }
+    }
+    ALOGE("%s: Could not find index for name = %s",
+            __func__, name);
+    ret = -ENODEV;
+done:
+    return ret;
+}
+
+int platform_set_fluence_type(void *platform, char *value)
+{
+    int ret = 0;
+    int fluence_type = FLUENCE_NONE;
+    int fluence_flag = NONE_FLAG;
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+
+    ALOGV("%s: fluence type:%d", __func__, my_data->fluence_type);
+
+    /* only dual mic turn on and off is supported as of now through setparameters */
+    if (!strncmp(AUDIO_PARAMETER_VALUE_DUALMIC,value, sizeof(AUDIO_PARAMETER_VALUE_DUALMIC))) {
+        if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro")) ||
+            !strncmp("fluence", my_data->fluence_cap, sizeof("fluence"))) {
+            ALOGV("fluence dualmic feature enabled \n");
+            fluence_type = FLUENCE_DUAL_MIC;
+            fluence_flag = DMIC_FLAG;
+        } else {
+            ALOGE("%s: Failed to set DUALMIC", __func__);
+            ret = -1;
+            goto done;
+        }
+    } else if (!strncmp(AUDIO_PARAMETER_KEY_NO_FLUENCE, value, sizeof(AUDIO_PARAMETER_KEY_NO_FLUENCE))) {
+        ALOGV("fluence disabled");
+        fluence_type = FLUENCE_NONE;
+    } else {
+        ALOGE("Invalid fluence value : %s",value);
+        ret = -1;
+        goto done;
+    }
+
+    if (fluence_type != my_data->fluence_type) {
+        ALOGV("%s: Updating fluence_type to :%d", __func__, fluence_type);
+        my_data->fluence_type = fluence_type;
+        adev->acdb_settings = (adev->acdb_settings & FLUENCE_MODE_CLEAR) | fluence_flag;
+    }
+done:
+    return ret;
+}
+
+int platform_get_fluence_type(void *platform, char *value, uint32_t len)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if (my_data->fluence_type == FLUENCE_QUAD_MIC) {
+        strlcpy(value, "quadmic", len);
+    } else if (my_data->fluence_type == FLUENCE_DUAL_MIC) {
+        strlcpy(value, "dualmic", len);
+    } else if (my_data->fluence_type == FLUENCE_NONE) {
+        strlcpy(value, "none", len);
+    } else
+        ret = -1;
+
+    return ret;
+}
+
+int platform_get_snd_device_index(char *device_name)
+{
+    return find_index(snd_device_name_index, SND_DEVICE_MAX, device_name);
+}
+
+int platform_get_usecase_index(const char *usecase_name)
+{
+    return find_index(usecase_name_index, AUDIO_USECASE_MAX, usecase_name);
+}
+
+int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id)
+{
+    int ret = 0;
+
+    if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
+        ALOGE("%s: Invalid snd_device = %d",
+            __func__, snd_device);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    acdb_device_table[snd_device] = acdb_id;
+done:
+    return ret;
+}
+
+int platform_get_default_app_type(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if (my_data->acdb_get_default_app_type)
+        return my_data->acdb_get_default_app_type();
+    else
+        return DEFAULT_APP_TYPE;
+}
+
+int platform_get_snd_device_acdb_id(snd_device_t snd_device)
+{
+    if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
+        ALOGE("%s: Invalid snd_device = %d", __func__, snd_device);
+        return -EINVAL;
+    }
+    return acdb_device_table[snd_device];
+}
+
+int platform_send_audio_calibration(void *platform, struct audio_usecase *usecase,
+                                    int app_type, int sample_rate)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int acdb_dev_id, acdb_dev_type;
+    struct audio_device *adev = my_data->adev;
+    int snd_device = SND_DEVICE_OUT_SPEAKER;
+
+    if (usecase->type == PCM_PLAYBACK)
+        snd_device = platform_get_output_snd_device(adev->platform,
+                                            usecase->stream.out->devices);
+    else if ((usecase->type == PCM_HFP_CALL) || (usecase->type == PCM_CAPTURE))
+        snd_device = platform_get_input_snd_device(adev->platform,
+                                            adev->primary_output->devices);
+    acdb_dev_id = acdb_device_table[audio_extn_get_spkr_prot_snd_device(snd_device)];
+    if (acdb_dev_id < 0) {
+        ALOGE("%s: Could not find acdb id for device(%d)",
+              __func__, snd_device);
+        return -EINVAL;
+    }
+    if (my_data->acdb_send_audio_cal) {
+        ALOGV("%s: sending audio calibration for snd_device(%d) acdb_id(%d)",
+              __func__, snd_device, acdb_dev_id);
+        if (snd_device >= SND_DEVICE_OUT_BEGIN &&
+                snd_device < SND_DEVICE_OUT_END)
+            acdb_dev_type = ACDB_DEV_TYPE_OUT;
+        else
+            acdb_dev_type = ACDB_DEV_TYPE_IN;
+        my_data->acdb_send_audio_cal(acdb_dev_id, acdb_dev_type, app_type,
+                                     sample_rate);
+    }
+    return 0;
+}
+
+int platform_switch_voice_call_device_pre(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int ret = 0;
+
+    if (my_data->csd != NULL &&
+        my_data->adev->mode == AUDIO_MODE_IN_CALL) {
+        /* This must be called before disabling mixer controls on APQ side */
+        ret = my_data->csd->disable_device();
+        if (ret < 0) {
+            ALOGE("%s: csd_client_disable_device, failed, error %d",
+                  __func__, ret);
+        }
+    }
+    return ret;
+}
+
+int platform_switch_voice_call_enable_device_config(void *platform,
+                                                    snd_device_t out_snd_device,
+                                                    snd_device_t in_snd_device)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int acdb_rx_id, acdb_tx_id;
+    int ret = 0;
+
+    if (my_data->csd == NULL)
+        return ret;
+
+    if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER &&
+        audio_extn_spkr_prot_is_enabled())
+        acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED];
+    else
+        acdb_rx_id = acdb_device_table[out_snd_device];
+
+    acdb_tx_id = acdb_device_table[in_snd_device];
+
+    if (acdb_rx_id > 0 && acdb_tx_id > 0) {
+        ret = my_data->csd->enable_device_config(acdb_rx_id, acdb_tx_id);
+        if (ret < 0) {
+            ALOGE("%s: csd_enable_device_config, failed, error %d",
+                  __func__, ret);
+        }
+    } else {
+        ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+              acdb_rx_id, acdb_tx_id);
+    }
+
+    return ret;
+}
+
+int platform_switch_voice_call_device_post(void *platform,
+                                           snd_device_t out_snd_device,
+                                           snd_device_t in_snd_device)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int acdb_rx_id, acdb_tx_id;
+
+    if (my_data->acdb_send_voice_cal == NULL) {
+        ALOGE("%s: dlsym error for acdb_send_voice_call", __func__);
+    } else {
+        if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER &&
+            audio_extn_spkr_prot_is_enabled())
+            out_snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED;
+
+        acdb_rx_id = acdb_device_table[out_snd_device];
+        acdb_tx_id = acdb_device_table[in_snd_device];
+
+        if (acdb_rx_id > 0 && acdb_tx_id > 0)
+            my_data->acdb_send_voice_cal(acdb_rx_id, acdb_tx_id);
+        else
+            ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+                  acdb_rx_id, acdb_tx_id);
+    }
+
+    return 0;
+}
+
+int platform_switch_voice_call_usecase_route_post(void *platform,
+                                                  snd_device_t out_snd_device,
+                                                  snd_device_t in_snd_device)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int acdb_rx_id, acdb_tx_id;
+    int ret = 0;
+
+    if (my_data->csd == NULL)
+        return ret;
+
+    if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER &&
+        audio_extn_spkr_prot_is_enabled())
+        acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED];
+    else
+        acdb_rx_id = acdb_device_table[out_snd_device];
+
+    acdb_tx_id = acdb_device_table[in_snd_device];
+
+    if (acdb_rx_id > 0 && acdb_tx_id > 0) {
+        ret = my_data->csd->enable_device(acdb_rx_id, acdb_tx_id,
+                                          my_data->adev->acdb_settings);
+        if (ret < 0) {
+            ALOGE("%s: csd_enable_device, failed, error %d", __func__, ret);
+        }
+    } else {
+        ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+              acdb_rx_id, acdb_tx_id);
+    }
+
+    return ret;
+}
+
+int platform_start_voice_call(void *platform, uint32_t vsid)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int ret = 0;
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->start_voice(vsid);
+        if (ret < 0) {
+            ALOGE("%s: csd_start_voice error %d\n", __func__, ret);
+        }
+    }
+    return ret;
+}
+
+int platform_stop_voice_call(void *platform, uint32_t vsid)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int ret = 0;
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->stop_voice(vsid);
+        if (ret < 0) {
+            ALOGE("%s: csd_stop_voice error %d\n", __func__, ret);
+        }
+    }
+    return ret;
+}
+
+int platform_get_sample_rate(void *platform, uint32_t *rate)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int ret = 0;
+
+    if ((my_data->csd != NULL) && my_data->is_i2s_ext_modem) {
+        ret = my_data->csd->get_sample_rate(rate);
+        if (ret < 0) {
+            ALOGE("%s: csd_get_sample_rate error %d\n", __func__, ret);
+        }
+    }
+    return ret;
+}
+
+int platform_set_voice_volume(void *platform, int volume)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Voice Rx Gain";
+    int vol_index = 0, ret = 0;
+    uint32_t set_values[ ] = {0,
+                              ALL_SESSION_VSID,
+                              DEFAULT_VOLUME_RAMP_DURATION_MS};
+
+    // Voice volume levels are mapped to adsp volume levels as follows.
+    // 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1  0 -> 0
+    // But this values don't changed in kernel. So, below change is need.
+    vol_index = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX);
+    set_values[0] = vol_index;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    ALOGV("Setting voice volume index: %d", set_values[0]);
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->volume(ALL_SESSION_VSID, volume,
+                                   DEFAULT_VOLUME_RAMP_DURATION_MS);
+        if (ret < 0) {
+            ALOGE("%s: csd_volume error %d", __func__, ret);
+        }
+    }
+    return ret;
+}
+
+int platform_set_mic_mute(void *platform, bool state)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Voice Tx Mute";
+    int ret = 0;
+    uint32_t set_values[ ] = {0,
+                              ALL_SESSION_VSID,
+                              DEFAULT_MUTE_RAMP_DURATION_MS};
+
+    set_values[0] = state;
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    ALOGV("Setting voice mute state: %d", state);
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->mic_mute(ALL_SESSION_VSID, state,
+                                     DEFAULT_MUTE_RAMP_DURATION_MS);
+        if (ret < 0) {
+            ALOGE("%s: csd_mic_mute error %d", __func__, ret);
+        }
+    }
+    return ret;
+}
+
+int platform_set_device_mute(void *platform, bool state, char *dir)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    char *mixer_ctl_name = NULL;
+    int ret = 0;
+    uint32_t set_values[ ] = {0,
+                              ALL_SESSION_VSID,
+                              0};
+    if(dir == NULL) {
+        ALOGE("%s: Invalid direction:%s", __func__, dir);
+        return -EINVAL;
+    }
+
+    if (!strncmp("rx", dir, sizeof("rx"))) {
+        mixer_ctl_name = "Voice Rx Device Mute";
+    } else if (!strncmp("tx", dir, sizeof("tx"))) {
+        mixer_ctl_name = "Voice Tx Device Mute";
+    } else {
+        return -EINVAL;
+    }
+
+    set_values[0] = state;
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+
+    ALOGV("%s: Setting device mute state: %d, mixer ctrl:%s",
+          __func__,state, mixer_ctl_name);
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+    return ret;
+}
+
+snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    audio_mode_t mode = adev->mode;
+    snd_device_t snd_device = SND_DEVICE_NONE;
+
+    audio_channel_mask_t channel_mask = (adev->active_input == NULL) ?
+                                AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask;
+    int channel_count = popcount(channel_mask);
+
+    ALOGV("%s: enter: output devices(%#x)", __func__, devices);
+    if (devices == AUDIO_DEVICE_NONE ||
+        devices & AUDIO_DEVICE_BIT_IN) {
+        ALOGV("%s: Invalid output devices (%#x)", __func__, devices);
+        goto exit;
+    }
+
+    if (popcount(devices) == 2 && !voice_is_in_call(adev)) {
+        if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+                        AUDIO_DEVICE_OUT_SPEAKER)) {
+            if (my_data->external_spk_1)
+                snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1;
+            else if (my_data->external_spk_2)
+                snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2;
+            else
+                snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
+        } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET |
+                               AUDIO_DEVICE_OUT_SPEAKER)) {
+            if (audio_extn_get_anc_enabled())
+                snd_device = SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET;
+            else if (my_data->external_spk_1)
+                snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1;
+            else if (my_data->external_spk_2)
+                snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2;
+            else
+                snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
+        } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL |
+                               AUDIO_DEVICE_OUT_SPEAKER)) {
+            snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI;
+        } else if (devices == (AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
+                               AUDIO_DEVICE_OUT_SPEAKER)) {
+            snd_device = SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET;
+        } else if ((devices & AUDIO_DEVICE_OUT_SPEAKER) &&
+                   (devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+            snd_device = SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP;
+        } else {
+            ALOGE("%s: Invalid combo device(%#x)", __func__, devices);
+            goto exit;
+        }
+        if (snd_device != SND_DEVICE_NONE) {
+            goto exit;
+        }
+    }
+
+    if (popcount(devices) != 1) {
+        ALOGE("%s: Invalid output devices(%#x)", __func__, devices);
+        goto exit;
+    }
+
+    if ((mode == AUDIO_MODE_IN_CALL) ||
+        voice_extn_compress_voip_is_active(adev)) {
+        if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+            devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+            if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
+                !voice_extn_compress_voip_is_active(adev)) {
+                switch (adev->voice.tty_mode) {
+                case TTY_MODE_FULL:
+                    snd_device = SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES;
+                    break;
+                case TTY_MODE_VCO:
+                    snd_device = SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES;
+                    break;
+                case TTY_MODE_HCO:
+                    snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET;
+                    break;
+                default:
+                    ALOGE("%s: Invalid TTY mode (%#x)",
+                          __func__, adev->voice.tty_mode);
+                }
+            } else if (audio_extn_get_anc_enabled()) {
+                if (audio_extn_should_use_fb_anc())
+                    snd_device = SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET;
+                else
+                    snd_device = SND_DEVICE_OUT_VOICE_ANC_HEADSET;
+            } else {
+                snd_device = SND_DEVICE_OUT_VOICE_HEADPHONES;
+            }
+        } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
+            if (adev->bt_wb_speech_enabled)
+                snd_device = SND_DEVICE_OUT_BT_SCO_WB;
+            else
+                snd_device = SND_DEVICE_OUT_BT_SCO;
+        } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
+            snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
+        } else if (devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+            snd_device = SND_DEVICE_OUT_BT_A2DP;
+        } else if (devices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ||
+                   devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+            snd_device = SND_DEVICE_OUT_USB_HEADSET;
+        } else if (devices & AUDIO_DEVICE_OUT_FM_TX) {
+            snd_device = SND_DEVICE_OUT_TRANSMISSION_FM;
+        } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
+            if (audio_extn_should_use_handset_anc(channel_count))
+                snd_device = SND_DEVICE_OUT_ANC_HANDSET;
+            else
+                snd_device = SND_DEVICE_OUT_VOICE_HANDSET;
+        } else if (devices & AUDIO_DEVICE_OUT_TELEPHONY_TX)
+            snd_device = SND_DEVICE_OUT_VOICE_TX;
+
+        if (snd_device != SND_DEVICE_NONE) {
+            goto exit;
+        }
+    }
+
+    if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+        devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+        if (devices & AUDIO_DEVICE_OUT_WIRED_HEADSET
+            && audio_extn_get_anc_enabled()) {
+            if (audio_extn_should_use_fb_anc())
+                snd_device = SND_DEVICE_OUT_ANC_FB_HEADSET;
+            else
+                snd_device = SND_DEVICE_OUT_ANC_HEADSET;
+        } else
+            snd_device = SND_DEVICE_OUT_HEADPHONES;
+    } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
+        if (my_data->external_spk_1)
+            snd_device = SND_DEVICE_OUT_SPEAKER_EXTERNAL_1;
+        else if (my_data->external_spk_2)
+            snd_device = SND_DEVICE_OUT_SPEAKER_EXTERNAL_2;
+        else if (adev->speaker_lr_swap)
+            snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE;
+        else
+            snd_device = SND_DEVICE_OUT_SPEAKER;
+    } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
+        if (adev->bt_wb_speech_enabled)
+            snd_device = SND_DEVICE_OUT_BT_SCO_WB;
+        else
+            snd_device = SND_DEVICE_OUT_BT_SCO;
+    } else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+        snd_device = SND_DEVICE_OUT_HDMI ;
+    } else if (devices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ||
+               devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+        ALOGD("%s: setting USB hadset channel capability(2) for Proxy", __func__);
+        audio_extn_set_afe_proxy_channel_mixer(adev, 2);
+        snd_device = SND_DEVICE_OUT_USB_HEADSET;
+    } else if (devices & AUDIO_DEVICE_OUT_FM_TX) {
+        snd_device = SND_DEVICE_OUT_TRANSMISSION_FM;
+    } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
+        snd_device = SND_DEVICE_OUT_HANDSET;
+    } else if (devices & AUDIO_DEVICE_OUT_PROXY) {
+        channel_count = audio_extn_get_afe_proxy_channel_count();
+        ALOGD("%s: setting sink capability(%d) for Proxy", __func__, channel_count);
+        audio_extn_set_afe_proxy_channel_mixer(adev, channel_count);
+        snd_device = SND_DEVICE_OUT_AFE_PROXY;
+    } else {
+        ALOGE("%s: Unknown device(s) %#x", __func__, devices);
+    }
+exit:
+    ALOGV("%s: exit: snd_device(%s)", __func__, device_table[snd_device]);
+    return snd_device;
+}
+
+snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    audio_source_t  source = (adev->active_input == NULL) ?
+                                AUDIO_SOURCE_DEFAULT : adev->active_input->source;
+
+    audio_mode_t    mode   = adev->mode;
+    audio_devices_t in_device = ((adev->active_input == NULL) ?
+                                    AUDIO_DEVICE_NONE : adev->active_input->device)
+                                & ~AUDIO_DEVICE_BIT_IN;
+    audio_channel_mask_t channel_mask = (adev->active_input == NULL) ?
+                                AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask;
+    snd_device_t snd_device = SND_DEVICE_NONE;
+    int channel_count = popcount(channel_mask);
+
+    ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
+          __func__, out_device, in_device);
+    if (my_data->external_mic) {
+        if (((out_device != AUDIO_DEVICE_NONE) && (mode == AUDIO_MODE_IN_CALL)) ||
+            voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev)) {
+            if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+               out_device & AUDIO_DEVICE_OUT_EARPIECE ||
+               out_device & AUDIO_DEVICE_OUT_SPEAKER )
+                snd_device = SND_DEVICE_IN_HANDSET_MIC_EXTERNAL;
+        } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC ||
+                   in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+            snd_device = SND_DEVICE_IN_HANDSET_MIC_EXTERNAL;
+        }
+    }
+
+    if (snd_device != AUDIO_DEVICE_NONE)
+        goto exit;
+
+    if ((out_device != AUDIO_DEVICE_NONE) && ((mode == AUDIO_MODE_IN_CALL) ||
+        voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev))) {
+        if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
+            !voice_extn_compress_voip_is_active(adev)) {
+            if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+                out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+                switch (adev->voice.tty_mode) {
+                case TTY_MODE_FULL:
+                    snd_device = SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC;
+                    break;
+                case TTY_MODE_VCO:
+                    snd_device = SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC;
+                    break;
+                case TTY_MODE_HCO:
+                    snd_device = SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC;
+                    break;
+                default:
+                    ALOGE("%s: Invalid TTY mode (%#x)", __func__, adev->voice.tty_mode);
+                }
+                goto exit;
+            }
+        }
+        if (out_device & AUDIO_DEVICE_OUT_EARPIECE ||
+            out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+            if (out_device & AUDIO_DEVICE_OUT_EARPIECE &&
+                audio_extn_should_use_handset_anc(channel_count)) {
+                snd_device = SND_DEVICE_IN_AANC_HANDSET_MIC;
+                adev->acdb_settings |= ANC_FLAG;
+            } else if (my_data->fluence_type == FLUENCE_NONE ||
+                my_data->fluence_in_voice_call == false) {
+                snd_device = SND_DEVICE_IN_HANDSET_MIC;
+                if (audio_extn_hfp_is_active(adev))
+                    platform_set_echo_reference(adev->platform, true);
+            } else {
+                snd_device = SND_DEVICE_IN_VOICE_DMIC;
+            }
+        } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+            snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC;
+            if (audio_extn_hfp_is_active(adev))
+                platform_set_echo_reference(adev->platform, true);
+        } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
+            if (adev->bt_wb_speech_enabled) {
+                if (adev->bluetooth_nrec)
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB_NREC;
+                else
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+            } else {
+                if (adev->bluetooth_nrec)
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC_NREC;
+                else
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+            }
+        } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
+            if (my_data->fluence_type != FLUENCE_NONE &&
+                my_data->fluence_in_voice_call &&
+                my_data->fluence_in_spkr_mode) {
+                if(my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                    snd_device = SND_DEVICE_IN_VOICE_SPEAKER_QMIC;
+                } else {
+                    if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                       snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE;
+                    else
+                       snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC;
+                }
+            } else {
+                snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC;
+                if (audio_extn_hfp_is_active(adev))
+                    platform_set_echo_reference(adev->platform, true);
+            }
+        } else if (out_device & AUDIO_DEVICE_OUT_TELEPHONY_TX)
+            snd_device = SND_DEVICE_IN_VOICE_RX;
+    } else if (source == AUDIO_SOURCE_CAMCORDER) {
+        if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC ||
+            in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+            snd_device = SND_DEVICE_IN_CAMCORDER_MIC;
+        }
+    } else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) {
+        if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            if (channel_count == 2) {
+                snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_STEREO;
+            } else if (adev->active_input->enable_ns)
+                snd_device = SND_DEVICE_IN_VOICE_REC_MIC_NS;
+            else if (my_data->fluence_type != FLUENCE_NONE &&
+                     my_data->fluence_in_voice_rec) {
+                snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE;
+            } else {
+                snd_device = SND_DEVICE_IN_VOICE_REC_MIC;
+            }
+        }
+    } else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
+        if (out_device & AUDIO_DEVICE_OUT_SPEAKER)
+            in_device = AUDIO_DEVICE_IN_BACK_MIC;
+        if (adev->active_input) {
+            if (adev->active_input->enable_aec &&
+                    adev->active_input->enable_ns) {
+                if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+                    if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
+                       my_data->fluence_in_spkr_mode) {
+                        if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE;
+                        else
+                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS;
+                    } else
+                        snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC_NS;
+                } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+                    if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                        snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC_NS;
+                    } else
+                        snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC_NS;
+                } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+                    snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
+                }
+                platform_set_echo_reference(adev->platform, true);
+            } else if (adev->active_input->enable_aec) {
+                if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+                    if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
+                        my_data->fluence_in_spkr_mode) {
+                        if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE;
+                        else
+                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC;
+                    } else
+                        snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC;
+                } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+                    if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                        snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC;
+                    } else
+                        snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC;
+                } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+                    snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
+                }
+                platform_set_echo_reference(adev->platform, true);
+            } else if (adev->active_input->enable_ns) {
+                if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+                    if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
+                        my_data->fluence_in_spkr_mode) {
+                        if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE;
+                        else
+                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS;
+                    } else
+                        snd_device = SND_DEVICE_IN_SPEAKER_MIC_NS;
+                } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+                    if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                        snd_device = SND_DEVICE_IN_HANDSET_DMIC_NS;
+                    } else
+                        snd_device = SND_DEVICE_IN_HANDSET_MIC_NS;
+                } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+                    snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
+                }
+                platform_set_echo_reference(adev->platform, false);
+            } else
+                platform_set_echo_reference(adev->platform, false);
+        }
+    } else if (source == AUDIO_SOURCE_MIC) {
+        if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC &&
+                channel_count == 1 ) {
+            if(my_data->fluence_type & FLUENCE_DUAL_MIC &&
+                    my_data->fluence_in_audio_rec) {
+                snd_device = SND_DEVICE_IN_HANDSET_DMIC;
+                platform_set_echo_reference(adev->platform, true);
+            }
+        }
+    } else if (source == AUDIO_SOURCE_FM_TUNER) {
+        snd_device = SND_DEVICE_IN_CAPTURE_FM;
+    } else if (source == AUDIO_SOURCE_DEFAULT) {
+        goto exit;
+    }
+
+
+    if (snd_device != SND_DEVICE_NONE) {
+        goto exit;
+    }
+
+    if (in_device != AUDIO_DEVICE_NONE &&
+            !(in_device & AUDIO_DEVICE_IN_VOICE_CALL) &&
+            !(in_device & AUDIO_DEVICE_IN_COMMUNICATION)) {
+        if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            if (audio_extn_ssr_get_enabled() && channel_count == 6)
+                snd_device = SND_DEVICE_IN_QUAD_MIC;
+            else if (my_data->fluence_type & (FLUENCE_DUAL_MIC | FLUENCE_QUAD_MIC) &&
+                    channel_count == 2)
+                snd_device = SND_DEVICE_IN_HANDSET_STEREO_DMIC;
+            else
+                snd_device = SND_DEVICE_IN_HANDSET_MIC;
+        } else if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+            snd_device = SND_DEVICE_IN_SPEAKER_MIC;
+        } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+            snd_device = SND_DEVICE_IN_HEADSET_MIC;
+        } else if (in_device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+            if (adev->bt_wb_speech_enabled) {
+                if (adev->bluetooth_nrec)
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB_NREC;
+                else
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+            } else {
+                if (adev->bluetooth_nrec)
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC_NREC;
+                else
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+            }
+        } else if (in_device & AUDIO_DEVICE_IN_AUX_DIGITAL) {
+            snd_device = SND_DEVICE_IN_HDMI_MIC;
+        } else if (in_device & AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET ||
+                   in_device & AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET) {
+            snd_device = SND_DEVICE_IN_USB_HEADSET_MIC;
+        } else if (in_device & AUDIO_DEVICE_IN_FM_TUNER) {
+            snd_device = SND_DEVICE_IN_CAPTURE_FM;
+        } else {
+            ALOGE("%s: Unknown input device(s) %#x", __func__, in_device);
+            ALOGW("%s: Using default handset-mic", __func__);
+            snd_device = SND_DEVICE_IN_HANDSET_MIC;
+        }
+    } else {
+        if (out_device & AUDIO_DEVICE_OUT_EARPIECE) {
+            snd_device = SND_DEVICE_IN_HANDSET_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+            snd_device = SND_DEVICE_IN_HEADSET_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
+            if (channel_count == 2)
+                snd_device = SND_DEVICE_IN_SPEAKER_STEREO_DMIC;
+            else
+                snd_device = SND_DEVICE_IN_SPEAKER_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+            snd_device = SND_DEVICE_IN_HANDSET_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) {
+            if (adev->bt_wb_speech_enabled) {
+                if (adev->bluetooth_nrec)
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB_NREC;
+                else
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+            } else {
+                if (adev->bluetooth_nrec)
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC_NREC;
+                else
+                    snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+            }
+        } else if (out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+            snd_device = SND_DEVICE_IN_HDMI_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ||
+                   out_device & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+            snd_device = SND_DEVICE_IN_USB_HEADSET_MIC;
+        } else {
+            ALOGE("%s: Unknown output device(s) %#x", __func__, out_device);
+            ALOGW("%s: Using default handset-mic", __func__);
+            snd_device = SND_DEVICE_IN_HANDSET_MIC;
+        }
+    }
+exit:
+    ALOGV("%s: exit: in_snd_device(%s)", __func__, device_table[snd_device]);
+    return snd_device;
+}
+
+int platform_set_hdmi_channels(void *platform,  int channel_count)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    const char *channel_cnt_str = NULL;
+    const char *mixer_ctl_name = "HDMI_RX Channels";
+    switch (channel_count) {
+    case 8:
+        channel_cnt_str = "Eight"; break;
+    case 7:
+        channel_cnt_str = "Seven"; break;
+    case 6:
+        channel_cnt_str = "Six"; break;
+    case 5:
+        channel_cnt_str = "Five"; break;
+    case 4:
+        channel_cnt_str = "Four"; break;
+    case 3:
+        channel_cnt_str = "Three"; break;
+    default:
+        channel_cnt_str = "Two"; break;
+    }
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    ALOGV("HDMI channel count: %s", channel_cnt_str);
+    mixer_ctl_set_enum_by_string(ctl, channel_cnt_str);
+    return 0;
+}
+
+int platform_edid_get_max_channels(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE];
+    char *sad = block;
+    int num_audio_blocks;
+    int channel_count;
+    int max_channels = 0;
+    int i, ret, count;
+
+    struct mixer_ctl *ctl;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, AUDIO_DATA_BLOCK_MIXER_CTL);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, AUDIO_DATA_BLOCK_MIXER_CTL);
+        return 0;
+    }
+
+    mixer_ctl_update(ctl);
+
+    count = mixer_ctl_get_num_values(ctl);
+
+    /* Read SAD blocks, clamping the maximum size for safety */
+    if (count > (int)sizeof(block))
+        count = (int)sizeof(block);
+
+    ret = mixer_ctl_get_array(ctl, block, count);
+    if (ret != 0) {
+        ALOGE("%s: mixer_ctl_get_array() failed to get EDID info", __func__);
+        return 0;
+    }
+
+    /* Calculate the number of SAD blocks */
+    num_audio_blocks = count / SAD_BLOCK_SIZE;
+
+    for (i = 0; i < num_audio_blocks; i++) {
+        /* Only consider LPCM blocks */
+        if ((sad[0] >> 3) != EDID_FORMAT_LPCM) {
+            sad += 3;
+            continue;
+        }
+
+        channel_count = (sad[0] & 0x7) + 1;
+        if (channel_count > max_channels)
+            max_channels = channel_count;
+
+        /* Advance to next block */
+        sad += 3;
+    }
+
+    return max_channels;
+}
+
+static int platform_set_slowtalk(struct platform_data *my_data, bool state)
+{
+    int ret = 0;
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Slowtalk Enable";
+    uint32_t set_values[ ] = {0,
+                              ALL_SESSION_VSID};
+
+    set_values[0] = state;
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        ret = -EINVAL;
+    } else {
+        ALOGV("Setting slowtalk state: %d", state);
+        ret = mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+        my_data->slowtalk = state;
+    }
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->slow_talk(ALL_SESSION_VSID, state);
+        if (ret < 0) {
+            ALOGE("%s: csd_client_disable_device, failed, error %d",
+                  __func__, ret);
+        }
+    }
+    return ret;
+}
+
+static int set_hd_voice(struct platform_data *my_data, bool state)
+{
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    char *mixer_ctl_name = "HD Voice Enable";
+    int ret = 0;
+    uint32_t set_values[ ] = {0,
+                              ALL_SESSION_VSID};
+
+    set_values[0] = state;
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    } else {
+        ALOGV("Setting HD Voice state: %d", state);
+        ret = mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+        my_data->hd_voice = state;
+    }
+
+    return ret;
+}
+
+static int update_external_device_status(struct platform_data *my_data,
+                                 char* event_name, bool status)
+{
+    int ret = 0;
+    struct audio_usecase *usecase;
+    struct listnode *node;
+
+    ALOGD("Recieved  external event switch %s", event_name);
+
+    if (!strcmp(event_name, EVENT_EXTERNAL_SPK_1))
+        my_data->external_spk_1 = status;
+    else if (!strcmp(event_name, EVENT_EXTERNAL_SPK_2))
+        my_data->external_spk_2 = status;
+    else if (!strcmp(event_name, EVENT_EXTERNAL_MIC))
+        my_data->external_mic = status;
+    else {
+        ALOGE("The audio event type is not found");
+        return -EINVAL;
+    }
+
+    list_for_each(node, &my_data->adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        select_devices(my_data->adev, usecase->id);
+    }
+
+    return ret;
+}
+
+int platform_set_parameters(void *platform, struct str_parms *parms)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    char *str;
+    char value[256] = {0};
+    int val;
+    int ret = 0, err;
+    char *kv_pairs = str_parms_to_str(parms);
+
+    ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SLOWTALK, value, sizeof(value));
+    if (err >= 0) {
+        bool state = false;
+        if (!strncmp("true", value, sizeof("true"))) {
+            state = true;
+        }
+
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_SLOWTALK);
+        ret = platform_set_slowtalk(my_data, state);
+        if (ret)
+            ALOGE("%s: Failed to set slow talk err: %d", __func__, ret);
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HD_VOICE, value, sizeof(value));
+    if (err >= 0) {
+        bool state = false;
+        if (!strncmp("true", value, sizeof("true"))) {
+            state = true;
+        }
+
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_HD_VOICE);
+        if (my_data->hd_voice != state) {
+            ret = set_hd_voice(my_data, state);
+            if (ret)
+                ALOGE("%s: Failed to set HD voice err: %d", __func__, ret);
+        } else {
+            ALOGV("%s: HD Voice already set to %d", __func__, state);
+        }
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOLUME_BOOST,
+                            value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_VOLUME_BOOST);
+
+        if (my_data->acdb_reload_vocvoltable == NULL) {
+            ALOGE("%s: acdb_reload_vocvoltable is NULL", __func__);
+        } else if (!strcmp(value, "on")) {
+            if (!my_data->acdb_reload_vocvoltable(VOICE_FEATURE_SET_VOLUME_BOOST)) {
+                my_data->voice_feature_set = 1;
+            }
+        } else {
+            if (!my_data->acdb_reload_vocvoltable(VOICE_FEATURE_SET_DEFAULT)) {
+                my_data->voice_feature_set = 0;
+            }
+        }
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_EXT_AUDIO_DEVICE,
+                            value, sizeof(value));
+    if (err >= 0) {
+        char *event_name, *status_str;
+        bool status = false;
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_EXT_AUDIO_DEVICE);
+        event_name = strtok_r(value, ",", &status_str);
+        ALOGV("%s: recieved update of external audio device %s %s",
+                         __func__,
+                         event_name, status_str);
+        if (!strncmp(status_str, "ON", sizeof("ON")))
+            status = true;
+        else if (!strncmp(status_str, "OFF", sizeof("OFF")))
+            status = false;
+        update_external_device_status(my_data, event_name, status);
+    }
+
+    ALOGV("%s: exit with code(%d)", __func__, ret);
+    free(kv_pairs);
+    return ret;
+}
+
+int platform_set_incall_recording_session_id(void *platform,
+                                             uint32_t session_id, int rec_mode)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Voc VSID";
+    int num_ctl_values;
+    int i;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        ret = -EINVAL;
+    } else {
+        num_ctl_values = mixer_ctl_get_num_values(ctl);
+        for (i = 0; i < num_ctl_values; i++) {
+            if (mixer_ctl_set_value(ctl, i, session_id)) {
+                ALOGV("Error: invalid session_id: %x", session_id);
+                ret = -EINVAL;
+                break;
+            }
+        }
+    }
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->start_record(ALL_SESSION_VSID, rec_mode);
+        if (ret < 0) {
+            ALOGE("%s: csd_client_start_record failed, error %d",
+                  __func__, ret);
+        }
+    }
+
+    return ret;
+}
+
+int platform_stop_incall_recording_usecase(void *platform)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->stop_record(ALL_SESSION_VSID);
+        if (ret < 0) {
+            ALOGE("%s: csd_client_stop_record failed, error %d",
+                  __func__, ret);
+        }
+    }
+
+    return ret;
+}
+
+int platform_start_incall_music_usecase(void *platform)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->start_playback(ALL_SESSION_VSID);
+        if (ret < 0) {
+            ALOGE("%s: csd_client_start_playback failed, error %d",
+                  __func__, ret);
+        }
+    }
+
+    return ret;
+}
+
+int platform_stop_incall_music_usecase(void *platform)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->stop_playback(ALL_SESSION_VSID);
+        if (ret < 0) {
+            ALOGE("%s: csd_client_stop_playback failed, error %d",
+                  __func__, ret);
+        }
+    }
+
+    return ret;
+}
+
+int platform_update_lch(void *platform, struct voice_session *session,
+                        enum voice_lch_mode lch_mode)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if ((my_data->csd != NULL) && (my_data->csd->set_lch != NULL))
+        ret = my_data->csd->set_lch(session->vsid, lch_mode);
+    else
+        ret = pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode);
+
+    return ret;
+}
+
+void platform_get_parameters(void *platform,
+                            struct str_parms *query,
+                            struct str_parms *reply)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    char *str = NULL;
+    char value[256] = {0};
+    int ret;
+    char *kv_pairs = NULL;
+    char propValue[PROPERTY_VALUE_MAX]={0};
+    bool prop_playback_enabled = false;
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_SLOWTALK,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_SLOWTALK,
+                          my_data->slowtalk?"true":"false");
+    }
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_HD_VOICE,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_HD_VOICE,
+                          my_data->hd_voice?"true":"false");
+    }
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOLUME_BOOST,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        if (my_data->voice_feature_set == VOICE_FEATURE_SET_VOLUME_BOOST) {
+            strlcpy(value, "on", sizeof(value));
+        } else {
+            strlcpy(value, "off", sizeof(value));
+        }
+
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VOLUME_BOOST, value);
+    }
+
+    /* Handle audio calibration keys */
+    get_audiocal(platform, query, reply);
+    native_audio_get_params(query, reply, value, sizeof(value));
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_IS_HW_DECODER_SESSION_ALLOWED,
+                                    value, sizeof(value));
+    if (ret >= 0) {
+        int isallowed = 1; /*true*/
+
+        if (property_get("voice.playback.conc.disabled", propValue, NULL)) {
+            prop_playback_enabled = atoi(propValue) ||
+                !strncmp("true", propValue, 4);
+        }
+
+        if (prop_playback_enabled && (voice_is_in_call(my_data->adev) ||
+             (SND_CARD_STATE_OFFLINE == get_snd_card_state(my_data->adev)))) {
+            char *decoder_mime_type = value;
+
+            //check if unsupported mime type or not
+            if(decoder_mime_type) {
+                int i = 0;
+                for (i = 0; i < sizeof(dsp_only_decoders_mime)/sizeof(dsp_only_decoders_mime[0]); i++) {
+                    if (!strncmp(decoder_mime_type, dsp_only_decoders_mime[i],
+                    strlen(dsp_only_decoders_mime[i]))) {
+                       ALOGD("Rejecting request for DSP only session from HAL during voice call/SSR state");
+                       isallowed = 0;
+                       break;
+                    }
+                }
+            }
+        }
+        str_parms_add_int(reply, AUDIO_PARAMETER_IS_HW_DECODER_SESSION_ALLOWED, isallowed);
+    }
+
+done:
+    kv_pairs = str_parms_to_str(reply);
+    ALOGV_IF(kv_pairs != NULL, "%s: exit: returns - %s", __func__, kv_pairs);
+    free(kv_pairs);
+}
+
+/* Delay in Us */
+int64_t platform_render_latency(audio_usecase_t usecase)
+{
+    switch (usecase) {
+        case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER:
+            return DEEP_BUFFER_PLATFORM_DELAY;
+        case USECASE_AUDIO_PLAYBACK_LOW_LATENCY:
+            return LOW_LATENCY_PLATFORM_DELAY;
+        default:
+            return 0;
+    }
+}
+
+int platform_update_usecase_from_source(int source, int usecase)
+{
+    ALOGV("%s: input source :%d", __func__, source);
+    if(source == AUDIO_SOURCE_FM_TUNER)
+        usecase = USECASE_AUDIO_RECORD_FM_VIRTUAL;
+    return usecase;
+}
+
+bool platform_listen_device_needs_event(snd_device_t snd_device)
+{
+    bool needs_event = false;
+
+    if ((snd_device >= SND_DEVICE_IN_BEGIN) &&
+        (snd_device < SND_DEVICE_IN_END) &&
+        (snd_device != SND_DEVICE_IN_CAPTURE_FM) &&
+        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK))
+        needs_event = true;
+
+    return needs_event;
+}
+
+bool platform_listen_usecase_needs_event(audio_usecase_t uc_id __unused)
+{
+    return false;
+}
+
+bool platform_sound_trigger_device_needs_event(snd_device_t snd_device)
+{
+    bool needs_event = false;
+
+    if ((snd_device >= SND_DEVICE_IN_BEGIN) &&
+        (snd_device < SND_DEVICE_IN_END) &&
+        (snd_device != SND_DEVICE_IN_CAPTURE_FM) &&
+        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK))
+        needs_event = true;
+
+    return needs_event;
+}
+
+bool platform_sound_trigger_usecase_needs_event(audio_usecase_t uc_id __unused)
+{
+    return false;
+}
+
+/* Read  offload buffer size from a property.
+ * If value is not power of 2  round it to
+ * power of 2.
+ */
+uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info)
+{
+    char value[PROPERTY_VALUE_MAX] = {0};
+    uint32_t fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE;
+    if((property_get("audio.offload.buffer.size.kb", value, "")) &&
+            atoi(value)) {
+        fragment_size =  atoi(value) * 1024;
+    }
+
+    // For FLAC use max size since it is loss less, and has sampling rates
+    // upto 192kHZ
+    if (info != NULL && !info->has_video &&
+        info->format == AUDIO_FORMAT_FLAC) {
+       fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE;
+       ALOGV("FLAC fragment size %d", fragment_size);
+    }
+
+    if (info != NULL && info->has_video && info->is_streaming) {
+        fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING;
+        ALOGV("%s: offload fragment size reduced for AV streaming to %d",
+               __func__, fragment_size);
+    }
+
+    fragment_size = ALIGN( fragment_size, 1024);
+
+    if(fragment_size < MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE)
+        fragment_size = MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE;
+    else if(fragment_size > MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE)
+        fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE;
+    ALOGV("%s: fragment_size %d", __func__, fragment_size);
+    return fragment_size;
+}
+
+uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info)
+{
+    uint32_t fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
+    uint32_t bits_per_sample = 16;
+
+    if (info->format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) {
+        bits_per_sample = 32;
+    }
+
+    if (!info->has_video) {
+        fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
+
+    } else if (info->has_video && info->is_streaming) {
+        fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING
+                                     * info->sample_rate
+                                     * (bits_per_sample >> 3)
+                                     * popcount(info->channel_mask))/1000;
+
+    } else if (info->has_video) {
+        fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV
+                                     * info->sample_rate
+                                     * (bits_per_sample >> 3)
+                                     * popcount(info->channel_mask))/1000;
+    }
+
+    char value[PROPERTY_VALUE_MAX] = {0};
+    if((property_get("audio.offload.pcm.buffer.size", value, "")) &&
+            atoi(value)) {
+        fragment_size =  atoi(value) * 1024;
+        ALOGV("Using buffer size from sys prop %d", fragment_size);
+    }
+
+    fragment_size = ALIGN( fragment_size, 1024);
+
+    if(fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE)
+        fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
+    else if(fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE)
+        fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
+
+    ALOGV("%s: fragment_size %d", __func__, fragment_size);
+    return fragment_size;
+}
+
+int platform_set_codec_backend_cfg(struct audio_device* adev,
+                         unsigned int bit_width, unsigned int sample_rate)
+{
+    ALOGV("%s bit width: %d, sample rate: %d", __func__, bit_width, sample_rate);
+
+    int ret = 0;
+    if (bit_width != adev->cur_codec_backend_bit_width) {
+        const char * mixer_ctl_name = "SLIM_0_RX Format";
+        struct  mixer_ctl *ctl;
+        ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+        if (!ctl) {
+            ALOGE("%s: Could not get ctl for mixer command - %s",
+                    __func__, mixer_ctl_name);
+            return -EINVAL;
+        }
+
+        if (bit_width == 24) {
+                mixer_ctl_set_enum_by_string(ctl, "S24_LE");
+        } else {
+            mixer_ctl_set_enum_by_string(ctl, "S16_LE");
+            sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+        }
+        adev->cur_codec_backend_bit_width = bit_width;
+        ALOGE("Backend bit width is set to %d ", bit_width);
+    }
+
+    /*
+     * Backend sample rate configuration follows:
+     * 16 bit playback - 48khz for streams at any valid sample rate
+     * 24 bit playback - 48khz for stream sample rate less than 48khz
+     * 24 bit playback - 96khz for sample rate range of 48khz to 96khz
+     * 24 bit playback - 192khz for sample rate range of 96khz to 192 khz
+     * Upper limit is inclusive in the sample rate range.
+     */
+    // TODO: This has to be more dynamic based on policy file
+    if (sample_rate != adev->cur_codec_backend_samplerate) {
+            char *rate_str = NULL;
+            const char * mixer_ctl_name = "SLIM_0_RX SampleRate";
+            struct  mixer_ctl *ctl;
+
+            switch (sample_rate) {
+            case 8000:
+            case 11025:
+            case 16000:
+            case 22050:
+            case 32000:
+            case 44100:
+            case 48000:
+                rate_str = "KHZ_48";
+                break;
+            case 64000:
+            case 88200:
+            case 96000:
+                rate_str = "KHZ_96";
+                break;
+            case 176400:
+            case 192000:
+                rate_str = "KHZ_192";
+                break;
+            default:
+                rate_str = "KHZ_48";
+                break;
+            }
+
+            ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+            if(!ctl) {
+                ALOGE("%s: Could not get ctl for mixer command - %s",
+                    __func__, mixer_ctl_name);
+                return -EINVAL;
+            }
+
+            ALOGV("Set sample rate as rate_str = %s", rate_str);
+            mixer_ctl_set_enum_by_string(ctl, rate_str);
+            adev->cur_codec_backend_samplerate = sample_rate;
+    }
+
+    return ret;
+}
+
+bool platform_check_codec_backend_cfg(struct audio_device* adev,
+                                   struct audio_usecase* usecase __unused,
+                                   unsigned int* new_bit_width,
+                                   unsigned int* new_sample_rate)
+{
+    bool backend_change = false;
+    struct listnode *node;
+    struct stream_out *out = NULL;
+    unsigned int bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+    unsigned int sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+
+    // For voice calls use default configuration
+    // force routing is not required here, caller will do it anyway
+    if (adev->mode == AUDIO_MODE_IN_CALL ||
+        adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
+        ALOGW("%s:Use default bw and sr for voice/voip calls ",__func__);
+        *new_bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+        *new_sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+        backend_change = true;
+    }
+
+    /*
+     * The backend should be configured at highest bit width and/or
+     * sample rate amongst all playback usecases.
+     * If the selected sample rate and/or bit width differ with
+     * current backend sample rate and/or bit width, then, we set the
+     * backend re-configuration flag.
+     *
+     * Exception: 16 bit playbacks is allowed through 16 bit/48 khz backend only
+     */
+    if (!backend_change) {
+        list_for_each(node, &adev->usecase_list) {
+            struct audio_usecase *curr_usecase;
+            curr_usecase = node_to_item(node, struct audio_usecase, list);
+            if (curr_usecase->type == PCM_PLAYBACK) {
+                struct stream_out *out =
+                           (struct stream_out*) curr_usecase->stream.out;
+                if (out != NULL ) {
+                    ALOGV("Offload playback running bw %d sr %d",
+                              out->bit_width, out->sample_rate);
+                        if (bit_width < out->bit_width)
+                            bit_width = out->bit_width;
+                        if (sample_rate < out->sample_rate)
+                            sample_rate = out->sample_rate;
+                }
+            }
+        }
+    }
+
+    // 24 bit playback on speakers and all 16 bit playbacks is allowed through
+    // 16 bit/48 khz backend only
+    if ((16 == bit_width) ||
+        ((24 == bit_width) &&
+         (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER))) {
+        sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    }
+    // Force routing if the expected bitwdith or samplerate
+    // is not same as current backend comfiguration
+    if ((bit_width != adev->cur_codec_backend_bit_width) ||
+        (sample_rate != adev->cur_codec_backend_samplerate)) {
+        *new_bit_width = bit_width;
+        *new_sample_rate = sample_rate;
+        backend_change = true;
+        ALOGI("%s Codec backend needs to be updated. new bit width: %d new sample rate: %d",
+               __func__, *new_bit_width, *new_sample_rate);
+    }
+
+    return backend_change;
+}
+
+bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase)
+{
+    ALOGV("platform_check_and_set_codec_backend_cfg usecase = %d",usecase->id );
+
+    unsigned int new_bit_width, old_bit_width;
+    unsigned int new_sample_rate, old_sample_rate;
+
+    new_bit_width = old_bit_width = adev->cur_codec_backend_bit_width;
+    new_sample_rate = old_sample_rate = adev->cur_codec_backend_samplerate;
+
+    ALOGW("Codec backend bitwidth %d, samplerate %d", old_bit_width, old_sample_rate);
+    if (platform_check_codec_backend_cfg(adev, usecase,
+                                      &new_bit_width, &new_sample_rate)) {
+        platform_set_codec_backend_cfg(adev, new_bit_width, new_sample_rate);
+        return true;
+    }
+
+    return false;
+}
+
+int platform_set_snd_device_backend(snd_device_t device, const char *backend)
+{
+    int ret = 0;
+
+    if ((device < SND_DEVICE_MIN) || (device >= SND_DEVICE_MAX)) {
+        ALOGE("%s: Invalid snd_device = %d",
+            __func__, device);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    if (backend_table[device]) {
+        free(backend_table[device]);
+    }
+    backend_table[device] = strdup(backend);
+done:
+    return ret;
+}
+
+int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id)
+{
+    int ret = 0;
+    if ((usecase <= USECASE_INVALID) || (usecase >= AUDIO_USECASE_MAX)) {
+        ALOGE("%s: invalid usecase case idx %d", __func__, usecase);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    if ((type != 0) && (type != 1)) {
+        ALOGE("%s: invalid usecase type", __func__);
+        ret = -EINVAL;
+    }
+    pcm_device_table[usecase][type] = pcm_id;
+done:
+    return ret;
+}
+
+void platform_get_device_to_be_id_map(int **device_to_be_id, int *length)
+{
+     *device_to_be_id = msm_device_to_be_id;
+     *length = msm_be_id_array_len;
+}
diff --git a/msm8909/hal/msm8974/platform.h b/msm8909/hal/msm8974/platform.h
new file mode 100644
index 0000000..6358e9d
--- /dev/null
+++ b/msm8909/hal/msm8974/platform.h
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef QCOM_AUDIO_PLATFORM_H
+#define QCOM_AUDIO_PLATFORM_H
+#include <sound/voice_params.h>
+
+enum {
+    FLUENCE_NONE,
+    FLUENCE_DUAL_MIC = 0x1,
+    FLUENCE_QUAD_MIC = 0x2,
+};
+
+enum {
+    FLUENCE_ENDFIRE = 0x1,
+    FLUENCE_BROADSIDE = 0x2,
+};
+
+/*
+ * Below are the devices for which is back end is same, SLIMBUS_0_RX.
+ * All these devices are handled by the internal HW codec. We can
+ * enable any one of these devices at any time
+ */
+#define AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND \
+    (AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER | \
+     AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE)
+
+/* Sound devices specific to the platform
+ * The DEVICE_OUT_* and DEVICE_IN_* should be mapped to these sound
+ * devices to enable corresponding mixer paths
+ */
+enum {
+    SND_DEVICE_NONE = 0,
+
+    /* Playback devices */
+    SND_DEVICE_MIN,
+    SND_DEVICE_OUT_BEGIN = SND_DEVICE_MIN,
+    SND_DEVICE_OUT_HANDSET = SND_DEVICE_OUT_BEGIN,
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_EXTERNAL_1,
+    SND_DEVICE_OUT_SPEAKER_EXTERNAL_2,
+    SND_DEVICE_OUT_SPEAKER_REVERSE,
+    SND_DEVICE_OUT_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2,
+    SND_DEVICE_OUT_VOICE_HANDSET,
+    SND_DEVICE_OUT_VOICE_SPEAKER,
+    SND_DEVICE_OUT_VOICE_HEADPHONES,
+    SND_DEVICE_OUT_HDMI,
+    SND_DEVICE_OUT_SPEAKER_AND_HDMI,
+    SND_DEVICE_OUT_BT_SCO,
+    SND_DEVICE_OUT_BT_SCO_WB,
+    SND_DEVICE_OUT_BT_A2DP,
+    SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP,
+    SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET,
+    SND_DEVICE_OUT_VOICE_TX,
+    SND_DEVICE_OUT_AFE_PROXY,
+    SND_DEVICE_OUT_USB_HEADSET,
+    SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET,
+    SND_DEVICE_OUT_TRANSMISSION_FM,
+    SND_DEVICE_OUT_ANC_HEADSET,
+    SND_DEVICE_OUT_ANC_FB_HEADSET,
+    SND_DEVICE_OUT_VOICE_ANC_HEADSET,
+    SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET,
+    SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+    SND_DEVICE_OUT_ANC_HANDSET,
+    SND_DEVICE_OUT_SPEAKER_PROTECTED,
+    SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED,
+    SND_DEVICE_OUT_END,
+
+    /*
+     * Note: IN_BEGIN should be same as OUT_END because total number of devices
+     * SND_DEVICES_MAX should not exceed MAX_RX + MAX_TX devices.
+     */
+    /* Capture devices */
+    SND_DEVICE_IN_BEGIN = SND_DEVICE_OUT_END,
+    SND_DEVICE_IN_HANDSET_MIC  = SND_DEVICE_IN_BEGIN,
+    SND_DEVICE_IN_HANDSET_MIC_EXTERNAL,
+    SND_DEVICE_IN_HANDSET_MIC_AEC,
+    SND_DEVICE_IN_HANDSET_MIC_NS,
+    SND_DEVICE_IN_HANDSET_MIC_AEC_NS,
+    SND_DEVICE_IN_HANDSET_DMIC,
+    SND_DEVICE_IN_HANDSET_DMIC_AEC,
+    SND_DEVICE_IN_HANDSET_DMIC_NS,
+    SND_DEVICE_IN_HANDSET_DMIC_AEC_NS,
+    SND_DEVICE_IN_SPEAKER_MIC,
+    SND_DEVICE_IN_SPEAKER_MIC_AEC,
+    SND_DEVICE_IN_SPEAKER_MIC_NS,
+    SND_DEVICE_IN_SPEAKER_MIC_AEC_NS,
+    SND_DEVICE_IN_SPEAKER_DMIC,
+    SND_DEVICE_IN_SPEAKER_DMIC_AEC,
+    SND_DEVICE_IN_SPEAKER_DMIC_NS,
+    SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS,
+    SND_DEVICE_IN_HEADSET_MIC,
+    SND_DEVICE_IN_HEADSET_MIC_FLUENCE,
+    SND_DEVICE_IN_VOICE_SPEAKER_MIC,
+    SND_DEVICE_IN_VOICE_HEADSET_MIC,
+    SND_DEVICE_IN_HDMI_MIC,
+    SND_DEVICE_IN_BT_SCO_MIC,
+    SND_DEVICE_IN_BT_SCO_MIC_NREC,
+    SND_DEVICE_IN_BT_SCO_MIC_WB,
+    SND_DEVICE_IN_BT_SCO_MIC_WB_NREC,
+    SND_DEVICE_IN_CAMCORDER_MIC,
+    SND_DEVICE_IN_VOICE_DMIC,
+    SND_DEVICE_IN_VOICE_SPEAKER_DMIC,
+    SND_DEVICE_IN_VOICE_SPEAKER_QMIC,
+    SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC,
+    SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC,
+    SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC,
+    SND_DEVICE_IN_VOICE_REC_MIC,
+    SND_DEVICE_IN_VOICE_REC_MIC_NS,
+    SND_DEVICE_IN_VOICE_REC_DMIC_STEREO,
+    SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
+    SND_DEVICE_IN_VOICE_RX,
+    SND_DEVICE_IN_USB_HEADSET_MIC,
+    SND_DEVICE_IN_CAPTURE_FM,
+    SND_DEVICE_IN_AANC_HANDSET_MIC,
+    SND_DEVICE_IN_QUAD_MIC,
+    SND_DEVICE_IN_HANDSET_STEREO_DMIC,
+    SND_DEVICE_IN_SPEAKER_STEREO_DMIC,
+    SND_DEVICE_IN_CAPTURE_VI_FEEDBACK,
+    SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE,
+    SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE,
+    SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE,
+    SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE,
+    SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE,
+    SND_DEVICE_IN_END,
+
+    SND_DEVICE_MAX = SND_DEVICE_IN_END,
+
+};
+
+#define DEFAULT_OUTPUT_SAMPLING_RATE 48000
+
+#define ALL_SESSION_VSID                0xFFFFFFFF
+#define DEFAULT_MUTE_RAMP_DURATION_MS   20
+#define DEFAULT_VOLUME_RAMP_DURATION_MS 20
+#define MIXER_PATH_MAX_LENGTH 100
+
+#define MAX_VOL_INDEX 5
+#define MIN_VOL_INDEX 0
+#define percent_to_index(val, min, max) \
+            ((val) * ((max) - (min)) * 0.01 + (min) + .5)
+
+/*
+ * tinyAlsa library interprets period size as number of frames
+ * one frame = channel_count * sizeof (pcm sample)
+ * so if format = 16-bit PCM and channels = Stereo, frame size = 2 ch * 2 = 4 bytes
+ * DEEP_BUFFER_OUTPUT_PERIOD_SIZE = 1024 means 1024 * 4 = 4096 bytes
+ * We should take care of returning proper size when AudioFlinger queries for
+ * the buffer size of an input/output stream
+ */
+#define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 960
+#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 4
+#define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240
+#define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2
+
+#define HDMI_MULTI_PERIOD_SIZE  336
+#define HDMI_MULTI_PERIOD_COUNT 8
+#define HDMI_MULTI_DEFAULT_CHANNEL_COUNT 6
+#define HDMI_MULTI_PERIOD_BYTES (HDMI_MULTI_PERIOD_SIZE * HDMI_MULTI_DEFAULT_CHANNEL_COUNT * 2)
+
+#define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
+#define AUDIO_CAPTURE_PERIOD_COUNT 2
+
+#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
+#define LOW_LATENCY_CAPTURE_PERIOD_SIZE 240
+#define LOW_LATENCY_CAPTURE_USE_CASE 1
+
+#define DEVICE_NAME_MAX_SIZE 128
+#define HW_INFO_ARRAY_MAX_SIZE 32
+
+#define DEEP_BUFFER_PCM_DEVICE 0
+#define AUDIO_RECORD_PCM_DEVICE 0
+#define MULTIMEDIA2_PCM_DEVICE 1
+#define FM_PLAYBACK_PCM_DEVICE 5
+#define FM_CAPTURE_PCM_DEVICE  6
+#define HFP_PCM_RX 5
+
+#define INCALL_MUSIC_UPLINK_PCM_DEVICE 1
+
+#ifdef PLATFORM_MSM8610
+#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 14
+#elif PLATFORM_MSM8x26
+#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16
+#elif PLATFORM_APQ8084
+#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 34
+#else
+#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 35
+#endif
+
+#define SPKR_PROT_CALIB_RX_PCM_DEVICE 5
+#ifdef PLATFORM_APQ8084
+#define SPKR_PROT_CALIB_TX_PCM_DEVICE 35
+#else
+#define SPKR_PROT_CALIB_TX_PCM_DEVICE 25
+#endif
+#define PLAYBACK_OFFLOAD_DEVICE 9
+
+#ifdef MULTIPLE_OFFLOAD_ENABLED
+#ifdef PLATFORM_APQ8084
+#define PLAYBACK_OFFLOAD_DEVICE2 17
+#define PLAYBACK_OFFLOAD_DEVICE3 18
+#define PLAYBACK_OFFLOAD_DEVICE4 34
+#define PLAYBACK_OFFLOAD_DEVICE5 35
+#define PLAYBACK_OFFLOAD_DEVICE6 36
+#define PLAYBACK_OFFLOAD_DEVICE7 37
+#define PLAYBACK_OFFLOAD_DEVICE8 38
+#define PLAYBACK_OFFLOAD_DEVICE9 39
+#endif
+#ifdef PLATFORM_MSM8994
+#define PLAYBACK_OFFLOAD_DEVICE2 17
+#define PLAYBACK_OFFLOAD_DEVICE3 18
+#define PLAYBACK_OFFLOAD_DEVICE4 37
+#define PLAYBACK_OFFLOAD_DEVICE5 38
+#define PLAYBACK_OFFLOAD_DEVICE6 39
+#define PLAYBACK_OFFLOAD_DEVICE7 40
+#define PLAYBACK_OFFLOAD_DEVICE8 41
+#define PLAYBACK_OFFLOAD_DEVICE9 42
+#endif
+#endif
+
+#define COMPRESS_VOIP_CALL_PCM_DEVICE 3
+
+#ifdef PLATFORM_MSM8610
+#define LOWLATENCY_PCM_DEVICE 12
+#define EC_REF_RX "SEC_I2S_RX"
+#else
+#define LOWLATENCY_PCM_DEVICE 15
+#define EC_REF_RX "SLIM_RX"
+#endif
+#ifdef PLATFORM_MSM8x26
+#define COMPRESS_CAPTURE_DEVICE 20
+#else
+#define COMPRESS_CAPTURE_DEVICE 19
+#endif
+
+#ifdef PLATFORM_MSM8x26
+#define VOICE_CALL_PCM_DEVICE 2
+#define VOICE2_CALL_PCM_DEVICE 14
+#define VOLTE_CALL_PCM_DEVICE 17
+#define QCHAT_CALL_PCM_DEVICE 18
+#define VOWLAN_CALL_PCM_DEVICE 30
+#elif PLATFORM_APQ8084
+#define VOICE_CALL_PCM_DEVICE 20
+#define VOICE2_CALL_PCM_DEVICE 25
+#define VOLTE_CALL_PCM_DEVICE 21
+#define QCHAT_CALL_PCM_DEVICE 33
+#define VOWLAN_CALL_PCM_DEVICE -1
+#elif PLATFORM_MSM8610
+#define VOICE_CALL_PCM_DEVICE 2
+#define VOICE2_CALL_PCM_DEVICE 13
+#define VOLTE_CALL_PCM_DEVICE 15
+#define QCHAT_CALL_PCM_DEVICE 14
+#define VOWLAN_CALL_PCM_DEVICE -1
+#elif PLATFORM_MSM8994
+#define VOICE_CALL_PCM_DEVICE 2
+#define VOICE2_CALL_PCM_DEVICE 22
+#define VOLTE_CALL_PCM_DEVICE 14
+#define QCHAT_CALL_PCM_DEVICE 20
+#define VOWLAN_CALL_PCM_DEVICE 36
+#else
+#define VOICE_CALL_PCM_DEVICE 2
+#define VOICE2_CALL_PCM_DEVICE 22
+#define VOLTE_CALL_PCM_DEVICE 14
+#define QCHAT_CALL_PCM_DEVICE 20
+#define VOWLAN_CALL_PCM_DEVICE 36
+#endif
+
+#define AFE_PROXY_PLAYBACK_PCM_DEVICE 7
+#define AFE_PROXY_RECORD_PCM_DEVICE 8
+
+#ifdef PLATFORM_MSM8x26
+#define HFP_SCO_RX 28
+#define HFP_ASM_RX_TX 29
+#else
+#define HFP_SCO_RX 23
+#define HFP_ASM_RX_TX 24
+#endif
+
+#ifdef PLATFORM_APQ8084
+#define FM_RX_VOLUME "Quat MI2S FM RX Volume"
+#elif PLATFORM_MSM8994
+#define FM_RX_VOLUME "PRI MI2S LOOPBACK Volume"
+#else
+#define FM_RX_VOLUME "Internal FM RX Volume"
+#endif
+
+#define LIB_CSD_CLIENT "libcsd-client.so"
+/* CSD-CLIENT related functions */
+typedef int (*init_t)(bool);
+typedef int (*deinit_t)();
+typedef int (*disable_device_t)();
+typedef int (*enable_device_config_t)(int, int);
+typedef int (*enable_device_t)(int, int, uint32_t);
+typedef int (*volume_t)(uint32_t, int, uint16_t);
+typedef int (*mic_mute_t)(uint32_t, int, uint16_t);
+typedef int (*slow_talk_t)(uint32_t, uint8_t);
+typedef int (*start_voice_t)(uint32_t);
+typedef int (*stop_voice_t)(uint32_t);
+typedef int (*start_playback_t)(uint32_t);
+typedef int (*stop_playback_t)(uint32_t);
+typedef int (*set_lch_t)(uint32_t, enum voice_lch_mode);
+typedef int (*start_record_t)(uint32_t, int);
+typedef int (*stop_record_t)(uint32_t);
+typedef int (*get_sample_rate_t)(uint32_t *);
+/* CSD Client structure */
+struct csd_data {
+    void *csd_client;
+    init_t init;
+    deinit_t deinit;
+    disable_device_t disable_device;
+    enable_device_config_t enable_device_config;
+    enable_device_t enable_device;
+    volume_t volume;
+    mic_mute_t mic_mute;
+    slow_talk_t slow_talk;
+    start_voice_t start_voice;
+    stop_voice_t stop_voice;
+    start_playback_t start_playback;
+    stop_playback_t stop_playback;
+    set_lch_t set_lch;
+    start_record_t start_record;
+    stop_record_t stop_record;
+    get_sample_rate_t get_sample_rate;
+};
+
+#endif // QCOM_AUDIO_PLATFORM_H
diff --git a/msm8909/hal/platform_api.h b/msm8909/hal/platform_api.h
new file mode 100644
index 0000000..2222b6e
--- /dev/null
+++ b/msm8909/hal/platform_api.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AUDIO_PLATFORM_API_H
+#define AUDIO_PLATFORM_API_H
+#include <sound/voice_params.h>
+
+#define CODEC_BACKEND_DEFAULT_BIT_WIDTH 16
+#define CODEC_BACKEND_DEFAULT_SAMPLE_RATE 48000
+
+void *platform_init(struct audio_device *adev);
+void platform_deinit(void *platform);
+int platform_is_acdb_initialized(void *platform);
+int platform_acdb_init(void *platform);
+const char *platform_get_snd_device_name(snd_device_t snd_device);
+int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device,
+                                      char *device_name);
+void platform_add_backend_name(char *mixer_path, snd_device_t snd_device);
+int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type);
+int platform_get_snd_device_index(char *snd_device_index_name);
+int platform_set_fluence_type(void *platform, char *value);
+int platform_get_fluence_type(void *platform, char *value, uint32_t len);
+int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id);
+int platform_get_snd_device_acdb_id(snd_device_t snd_device);
+int platform_send_audio_calibration(void *platform, struct audio_usecase *usecase,
+                                    int app_type, int sample_rate);
+int platform_get_default_app_type(void *platform);
+int platform_switch_voice_call_device_pre(void *platform);
+int platform_switch_voice_call_enable_device_config(void *platform,
+                                                    snd_device_t out_snd_device,
+                                                    snd_device_t in_snd_device);
+int platform_switch_voice_call_device_post(void *platform,
+                                           snd_device_t out_snd_device,
+                                           snd_device_t in_snd_device);
+int platform_switch_voice_call_usecase_route_post(void *platform,
+                                                  snd_device_t out_snd_device,
+                                                  snd_device_t in_snd_device);
+int platform_start_voice_call(void *platform, uint32_t vsid);
+int platform_stop_voice_call(void *platform, uint32_t vsid);
+int platform_set_voice_volume(void *platform, int volume);
+int platform_set_mic_mute(void *platform, bool state);
+int platform_get_sample_rate(void *platform, uint32_t *rate);
+int platform_set_device_mute(void *platform, bool state, char *dir);
+snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices);
+snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device);
+int platform_set_hdmi_channels(void *platform, int channel_count);
+int platform_edid_get_max_channels(void *platform);
+void platform_get_parameters(void *platform, struct str_parms *query,
+                             struct str_parms *reply);
+int platform_set_parameters(void *platform, struct str_parms *parms);
+int platform_set_incall_recording_session_id(void *platform, uint32_t session_id,
+                                             int rec_mode);
+int platform_stop_incall_recording_usecase(void *platform);
+int platform_start_incall_music_usecase(void *platform);
+int platform_stop_incall_music_usecase(void *platform);
+int platform_update_lch(void *platform, struct voice_session *session,
+                        enum voice_lch_mode lch_mode);
+/* returns the latency for a usecase in Us */
+int64_t platform_render_latency(audio_usecase_t usecase);
+int platform_update_usecase_from_source(int source, audio_usecase_t usecase);
+
+bool platform_listen_device_needs_event(snd_device_t snd_device);
+bool platform_listen_usecase_needs_event(audio_usecase_t uc_id);
+
+bool platform_sound_trigger_device_needs_event(snd_device_t snd_device);
+bool platform_sound_trigger_usecase_needs_event(audio_usecase_t uc_id);
+
+int platform_set_snd_device_backend(snd_device_t snd_device, const char * backend);
+
+/* From platform_info_parser.c */
+int platform_info_init(const char *filename);
+
+struct audio_offload_info_t;
+uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info);
+uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info);
+
+bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase);
+int platform_get_usecase_index(const char * usecase);
+int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id);
+void platform_set_echo_reference(void *platform, bool enable);
+void platform_get_device_to_be_id_map(int **be_id_map, int *length);
+
+#endif // AUDIO_PLATFORM_API_H
diff --git a/msm8909/hal/platform_info.c b/msm8909/hal/platform_info.c
new file mode 100644
index 0000000..615b9f3
--- /dev/null
+++ b/msm8909/hal/platform_info.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2014, 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 "platform_info"
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <stdio.h>
+#include <expat.h>
+#include <cutils/log.h>
+#include <audio_hw.h>
+#include "platform_api.h"
+#include <platform.h>
+
+#define BUF_SIZE                    1024
+
+typedef enum {
+    ROOT,
+    ACDB,
+    PCM_ID,
+    BACKEND_NAME,
+} section_t;
+
+typedef void (* section_process_fn)(const XML_Char **attr);
+
+static void process_acdb_id(const XML_Char **attr);
+static void process_pcm_id(const XML_Char **attr);
+static void process_backend_name(const XML_Char **attr);
+static void process_root(const XML_Char **attr);
+
+static section_process_fn section_table[] = {
+    [ROOT] = process_root,
+    [ACDB] = process_acdb_id,
+    [PCM_ID] = process_pcm_id,
+    [BACKEND_NAME] = process_backend_name,
+};
+
+static section_t section;
+
+/*
+ * <audio_platform_info>
+ * <acdb_ids>
+ * <device name="???" acdb_id="???"/>
+ * ...
+ * ...
+ * </acdb_ids>
+ * <backend_names>
+ * <device name="???" backend="???"/>
+ * ...
+ * ...
+ * </backend_names>
+ * <pcm_ids>
+ * <usecase name="???" type="in/out" id="???"/>
+ * ...
+ * ...
+ * </pcm_ids>
+ * </audio_platform_info>
+ */
+
+static void process_root(const XML_Char **attr __unused)
+{
+}
+
+/* mapping from usecase to pcm dev id */
+static void process_pcm_id(const XML_Char **attr)
+{
+    int index;
+
+    if (strcmp(attr[0], "name") != 0) {
+        ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
+        goto done;
+    }
+
+    index = platform_get_usecase_index((char *)attr[1]);
+    if (index < 0) {
+        ALOGE("%s: usecase %s not found!",
+              __func__, attr[1]);
+        goto done;
+    }
+
+    if (strcmp(attr[2], "type") != 0) {
+        ALOGE("%s: usecase type not mentioned", __func__);
+        goto done;
+    }
+
+    int type = -1;
+
+    if (!strcasecmp((char *)attr[3], "in")) {
+        type = 1;
+    } else if (!strcasecmp((char *)attr[3], "out")) {
+        type = 0;
+    } else {
+        ALOGE("%s: type must be IN or OUT", __func__);
+        goto done;
+    }
+
+    if (strcmp(attr[4], "id") != 0) {
+        ALOGE("%s: usecase id not mentioned", __func__);
+        goto done;
+    }
+
+    int id = atoi((char *)attr[5]);
+
+    if (platform_set_usecase_pcm_id(index, type, id) < 0) {
+        ALOGE("%s: usecase %s type %d id %d was not set!",
+              __func__, attr[1], type, id);
+        goto done;
+    }
+
+done:
+    return;
+}
+
+/* backend to be used for a device */
+static void process_backend_name(const XML_Char **attr)
+{
+    int index;
+
+    if (strcmp(attr[0], "name") != 0) {
+        ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
+        goto done;
+    }
+
+    index = platform_get_snd_device_index((char *)attr[1]);
+    if (index < 0) {
+        ALOGE("%s: Device %s not found, no ACDB ID set!",
+              __func__, attr[1]);
+        goto done;
+    }
+
+    if (strcmp(attr[2], "backend") != 0) {
+        ALOGE("%s: Device %s has no backend set!",
+              __func__, attr[1]);
+        goto done;
+    }
+
+    if (platform_set_snd_device_backend(index, attr[3]) < 0) {
+        ALOGE("%s: Device %s backend %s was not set!",
+              __func__, attr[1], attr[3]);
+        goto done;
+    }
+
+done:
+    return;
+}
+
+static void process_acdb_id(const XML_Char **attr)
+{
+    int index;
+
+    if (strcmp(attr[0], "name") != 0) {
+        ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
+        goto done;
+    }
+
+    index = platform_get_snd_device_index((char *)attr[1]);
+    if (index < 0) {
+        ALOGE("%s: Device %s in platform info xml not found, no ACDB ID set!",
+              __func__, attr[1]);
+        goto done;
+    }
+
+    if (strcmp(attr[2], "acdb_id") != 0) {
+        ALOGE("%s: Device %s in platform info xml has no acdb_id, no ACDB ID set!",
+              __func__, attr[1]);
+        goto done;
+    }
+
+    if (platform_set_snd_device_acdb_id(index, atoi((char *)attr[3])) < 0) {
+        ALOGE("%s: Device %s, ACDB ID %d was not set!",
+              __func__, attr[1], atoi((char *)attr[3]));
+        goto done;
+    }
+
+done:
+    return;
+}
+
+static void start_tag(void *userdata __unused, const XML_Char *tag_name,
+                      const XML_Char **attr)
+{
+    const XML_Char              *attr_name = NULL;
+    const XML_Char              *attr_value = NULL;
+    unsigned int                i;
+
+    if (strcmp(tag_name, "acdb_ids") == 0) {
+        section = ACDB;
+    } else if (strcmp(tag_name, "pcm_ids") == 0) {
+        section = PCM_ID;
+    } else if (strcmp(tag_name, "backend_names") == 0) {
+        section = BACKEND_NAME;
+    } else if (strcmp(tag_name, "device") == 0) {
+        if ((section != ACDB) && (section != BACKEND_NAME)) {
+            ALOGE("device tag only supported for acdb/backend names");
+            return;
+        }
+
+        /* call into process function for the current section */
+        section_process_fn fn = section_table[section];
+        fn(attr);
+    } else if (strcmp(tag_name, "usecase") == 0) {
+        if (section != PCM_ID) {
+            ALOGE("usecase tag only supported with PCM_ID section");
+            return;
+        }
+
+        section_process_fn fn = section_table[PCM_ID];
+        fn(attr);
+    }
+
+    return;
+}
+
+static void end_tag(void *userdata __unused, const XML_Char *tag_name)
+{
+    if (strcmp(tag_name, "acdb_ids") == 0) {
+        section = ROOT;
+    } else if (strcmp(tag_name, "pcm_ids") == 0) {
+        section = ROOT;
+    } else if (strcmp(tag_name, "backend_names") == 0) {
+        section = ROOT;
+    }
+}
+
+int platform_info_init(const char *filename)
+{
+    XML_Parser      parser;
+    FILE            *file;
+    int             ret = 0;
+    int             bytes_read;
+    void            *buf;
+
+    file = fopen(filename, "r");
+    section = ROOT;
+
+    if (!file) {
+        ALOGD("%s: Failed to open %s, using defaults.",
+            __func__, filename);
+        ret = -ENODEV;
+        goto done;
+    }
+
+    parser = XML_ParserCreate(NULL);
+    if (!parser) {
+        ALOGE("%s: Failed to create XML parser!", __func__);
+        ret = -ENODEV;
+        goto err_close_file;
+    }
+
+    XML_SetElementHandler(parser, start_tag, end_tag);
+
+    while (1) {
+        buf = XML_GetBuffer(parser, BUF_SIZE);
+        if (buf == NULL) {
+            ALOGE("%s: XML_GetBuffer failed", __func__);
+            ret = -ENOMEM;
+            goto err_free_parser;
+        }
+
+        bytes_read = fread(buf, 1, BUF_SIZE, file);
+        if (bytes_read < 0) {
+            ALOGE("%s: fread failed, bytes read = %d", __func__, bytes_read);
+             ret = bytes_read;
+            goto err_free_parser;
+        }
+
+        if (XML_ParseBuffer(parser, bytes_read,
+                            bytes_read == 0) == XML_STATUS_ERROR) {
+            ALOGE("%s: XML_ParseBuffer failed, for %s",
+                __func__, filename);
+            ret = -EINVAL;
+            goto err_free_parser;
+        }
+
+        if (bytes_read == 0)
+            break;
+    }
+
+err_free_parser:
+    XML_ParserFree(parser);
+err_close_file:
+    fclose(file);
+done:
+    return ret;
+}
diff --git a/msm8909/hal/voice.c b/msm8909/hal/voice.c
new file mode 100644
index 0000000..41a0699
--- /dev/null
+++ b/msm8909/hal/voice.c
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "voice"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <stdlib.h>
+#include <math.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+
+#include "audio_hw.h"
+#include "voice.h"
+#include "voice_extn/voice_extn.h"
+#include "platform.h"
+#include "platform_api.h"
+#include "audio_extn.h"
+
+struct pcm_config pcm_config_voice_call = {
+    .channels = 1,
+    .rate = 8000,
+    .period_size = 160,
+    .period_count = 2,
+    .format = PCM_FORMAT_S16_LE,
+};
+
+static struct voice_session *voice_get_session_from_use_case(struct audio_device *adev,
+                              audio_usecase_t usecase_id)
+{
+    struct voice_session *session = NULL;
+    int ret = 0;
+
+    ret = voice_extn_get_session_from_use_case(adev, usecase_id, &session);
+    if (ret == -ENOSYS) {
+        session = &adev->voice.session[VOICE_SESS_IDX];
+    }
+
+    return session;
+}
+
+int voice_stop_usecase(struct audio_device *adev, audio_usecase_t usecase_id)
+{
+    int i, ret = 0;
+    struct audio_usecase *uc_info;
+    struct voice_session *session = NULL;
+
+    ALOGD("%s: enter usecase:%s", __func__, use_case_table[usecase_id]);
+
+    session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id);
+    if (!session) {
+        ALOGE("stop_call: couldn't find voice session");
+        return -EINVAL;
+    }
+
+    session->state.current = CALL_INACTIVE;
+    if (adev->mode == AUDIO_MODE_NORMAL)
+        adev->voice.is_in_call = false;
+
+    ret = platform_stop_voice_call(adev->platform, session->vsid);
+
+    /* 1. Close the PCM devices */
+    if (session->pcm_rx) {
+        pcm_close(session->pcm_rx);
+        session->pcm_rx = NULL;
+    }
+    if (session->pcm_tx) {
+        pcm_close(session->pcm_tx);
+        session->pcm_tx = NULL;
+    }
+
+    uc_info = get_usecase_from_list(adev, usecase_id);
+    if (uc_info == NULL) {
+        ALOGE("%s: Could not find the usecase (%d) in the list",
+              __func__, usecase_id);
+        return -EINVAL;
+    }
+
+    /* 2. Get and set stream specific mixer controls */
+    disable_audio_route(adev, uc_info);
+
+    /* 3. Disable the rx and tx devices */
+    disable_snd_device(adev, uc_info->out_snd_device);
+    disable_snd_device(adev, uc_info->in_snd_device);
+
+    list_remove(&uc_info->list);
+    free(uc_info);
+
+    ALOGD("%s: exit: status(%d)", __func__, ret);
+    return ret;
+}
+
+int voice_start_usecase(struct audio_device *adev, audio_usecase_t usecase_id)
+{
+    int i, ret = 0;
+    struct audio_usecase *uc_info;
+    int pcm_dev_rx_id, pcm_dev_tx_id;
+    uint32_t sample_rate = 8000;
+    struct voice_session *session = NULL;
+    struct pcm_config voice_config = pcm_config_voice_call;
+
+    ALOGD("%s: enter usecase:%s", __func__, use_case_table[usecase_id]);
+
+    session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id);
+    if (!session) {
+        ALOGE("start_call: couldn't find voice session");
+        return -EINVAL;
+    }
+
+    uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+    if (!uc_info) {
+        ALOGE("start_call: couldn't allocate mem for audio_usecase");
+        return -ENOMEM;
+    }
+
+    uc_info->id = usecase_id;
+    uc_info->type = VOICE_CALL;
+    uc_info->stream.out = adev->current_call_output ;
+    uc_info->devices = adev->current_call_output ->devices;
+    uc_info->in_snd_device = SND_DEVICE_NONE;
+    uc_info->out_snd_device = SND_DEVICE_NONE;
+
+    list_add_tail(&adev->usecase_list, &uc_info->list);
+
+    select_devices(adev, usecase_id);
+
+    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);
+
+    if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0) {
+        ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(%d)",
+              __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
+        ret = -EIO;
+        goto error_start_voice;
+    }
+    ret = platform_get_sample_rate(adev->platform, &sample_rate);
+    if (ret < 0) {
+        ALOGE("platform_get_sample_rate error %d\n", ret);
+    } else {
+        voice_config.rate = sample_rate;
+    }
+    ALOGD("voice_config.rate %d\n", voice_config.rate);
+
+    ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
+          __func__, adev->snd_card, pcm_dev_rx_id);
+    session->pcm_rx = pcm_open(adev->snd_card,
+                               pcm_dev_rx_id,
+                               PCM_OUT, &voice_config);
+    if (session->pcm_rx && !pcm_is_ready(session->pcm_rx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_rx));
+        ret = -EIO;
+        goto error_start_voice;
+    }
+
+    ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+          __func__, adev->snd_card, pcm_dev_tx_id);
+    session->pcm_tx = pcm_open(adev->snd_card,
+                               pcm_dev_tx_id,
+                               PCM_IN, &voice_config);
+    if (session->pcm_tx && !pcm_is_ready(session->pcm_tx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_tx));
+        ret = -EIO;
+        goto error_start_voice;
+    }
+    pcm_start(session->pcm_rx);
+    pcm_start(session->pcm_tx);
+
+    voice_set_volume(adev, adev->voice.volume);
+
+    ret = platform_start_voice_call(adev->platform, session->vsid);
+    if (ret < 0) {
+        ALOGE("%s: platform_start_voice_call error %d\n", __func__, ret);
+        goto error_start_voice;
+    }
+
+    session->state.current = CALL_ACTIVE;
+    goto done;
+
+error_start_voice:
+    voice_stop_usecase(adev, usecase_id);
+
+done:
+    ALOGD("%s: exit: status(%d)", __func__, ret);
+    return ret;
+}
+
+bool voice_is_call_state_active(struct audio_device *adev)
+{
+    bool call_state = false;
+    int ret = 0;
+
+    ret = voice_extn_is_call_state_active(adev, &call_state);
+    if (ret == -ENOSYS) {
+        call_state = (adev->voice.session[VOICE_SESS_IDX].state.current == CALL_ACTIVE) ? true : false;
+    }
+
+    return call_state;
+}
+
+bool voice_is_in_call(struct audio_device *adev)
+{
+    return adev->voice.in_call;
+}
+
+bool voice_is_in_call_rec_stream(struct stream_in *in)
+{
+    bool in_call_rec = false;
+    int ret = 0;
+
+    ret = voice_extn_is_in_call_rec_stream(in, &in_call_rec);
+    if (ret == -ENOSYS) {
+        in_call_rec = false;
+    }
+
+    return in_call_rec;
+}
+
+uint32_t voice_get_active_session_id(struct audio_device *adev)
+{
+    int ret = 0;
+    uint32_t session_id;
+
+    ret = voice_extn_get_active_session_id(adev, &session_id);
+    if (ret == -ENOSYS) {
+        session_id = VOICE_VSID;
+    }
+    return session_id;
+}
+
+int voice_check_and_set_incall_rec_usecase(struct audio_device *adev,
+                                           struct stream_in *in)
+{
+    int ret = 0;
+    uint32_t session_id;
+    int usecase_id;
+    int rec_mode = INCALL_REC_NONE;
+
+    if (voice_is_call_state_active(adev)) {
+        switch (in->source) {
+        case AUDIO_SOURCE_VOICE_UPLINK:
+            if (audio_extn_compr_cap_enabled() &&
+                audio_extn_compr_cap_format_supported(in->config.format)) {
+                in->usecase = USECASE_INCALL_REC_UPLINK_COMPRESS;
+            } else
+                in->usecase = USECASE_INCALL_REC_UPLINK;
+            rec_mode = INCALL_REC_UPLINK;
+            break;
+        case AUDIO_SOURCE_VOICE_DOWNLINK:
+            if (audio_extn_compr_cap_enabled() &&
+                audio_extn_compr_cap_format_supported(in->config.format)) {
+                in->usecase = USECASE_INCALL_REC_DOWNLINK_COMPRESS;
+            } else
+                in->usecase = USECASE_INCALL_REC_DOWNLINK;
+            rec_mode = INCALL_REC_DOWNLINK;
+            break;
+        case AUDIO_SOURCE_VOICE_CALL:
+            if (audio_extn_compr_cap_enabled() &&
+                audio_extn_compr_cap_format_supported(in->config.format)) {
+                in->usecase = USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS;
+            } else
+                in->usecase = USECASE_INCALL_REC_UPLINK_AND_DOWNLINK;
+            rec_mode = INCALL_REC_UPLINK_AND_DOWNLINK;
+            break;
+        default:
+            ALOGV("%s: Source type %d doesnt match incall recording criteria",
+                  __func__, in->source);
+            return ret;
+        }
+
+        session_id = voice_get_active_session_id(adev);
+        ret = platform_set_incall_recording_session_id(adev->platform,
+                                                       session_id, rec_mode);
+        ALOGV("%s: Update usecase to %d",__func__, in->usecase);
+    } else {
+        ALOGV("%s: voice call not active", __func__);
+    }
+
+    return ret;
+}
+
+int voice_check_and_stop_incall_rec_usecase(struct audio_device *adev,
+                                            struct stream_in *in)
+{
+    int ret = 0;
+
+    if (in->source == AUDIO_SOURCE_VOICE_UPLINK ||
+        in->source == AUDIO_SOURCE_VOICE_DOWNLINK ||
+        in->source == AUDIO_SOURCE_VOICE_CALL) {
+        ret = platform_stop_incall_recording_usecase(adev->platform);
+        ALOGV("%s: Stop In-call recording", __func__);
+    }
+
+    return ret;
+}
+
+int voice_check_and_set_incall_music_usecase(struct audio_device *adev,
+                                             struct stream_out *out)
+{
+    int ret = 0;
+
+    ret = voice_extn_check_and_set_incall_music_usecase(adev, out);
+    if (ret == -ENOSYS) {
+        /* Incall music delivery is used only for LCH call state */
+        ret = -EINVAL;
+    }
+
+    return ret;
+}
+
+int voice_set_mic_mute(struct audio_device *adev, bool state)
+{
+    int err = 0;
+
+    adev->voice.mic_mute = state;
+    if (adev->mode == AUDIO_MODE_IN_CALL)
+        err = platform_set_mic_mute(adev->platform, state);
+    if (adev->mode == AUDIO_MODE_IN_COMMUNICATION)
+        err = voice_extn_compress_voip_set_mic_mute(adev, state);
+
+    return err;
+}
+
+bool voice_get_mic_mute(struct audio_device *adev)
+{
+    return adev->voice.mic_mute;
+}
+
+int voice_set_volume(struct audio_device *adev, float volume)
+{
+    int vol, err = 0;
+
+    adev->voice.volume = volume;
+    if (adev->mode == AUDIO_MODE_IN_CALL) {
+        if (volume < 0.0) {
+            volume = 0.0;
+        } else if (volume > 1.0) {
+            volume = 1.0;
+        }
+
+        vol = lrint(volume * 100.0);
+
+        // Voice volume levels from android are mapped to driver volume levels as follows.
+        // 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0
+        // So adjust the volume to get the correct volume index in driver
+        vol = 100 - vol;
+
+        err = platform_set_voice_volume(adev->platform, vol);
+    }
+    if (adev->mode == AUDIO_MODE_IN_COMMUNICATION)
+        err = voice_extn_compress_voip_set_volume(adev, volume);
+
+
+    return err;
+}
+
+int voice_start_call(struct audio_device *adev)
+{
+    int ret = 0;
+
+    ret = voice_extn_start_call(adev);
+    if (ret == -ENOSYS) {
+        ret = voice_start_usecase(adev, USECASE_VOICE_CALL);
+    }
+    adev->voice.in_call = true;
+
+    return ret;
+}
+
+int voice_stop_call(struct audio_device *adev)
+{
+    int ret = 0;
+
+    adev->voice.in_call = false;
+    ret = voice_extn_stop_call(adev);
+    if (ret == -ENOSYS) {
+        ret = voice_stop_usecase(adev, USECASE_VOICE_CALL);
+    }
+
+    return ret;
+}
+
+void voice_get_parameters(struct audio_device *adev,
+                          struct str_parms *query,
+                          struct str_parms *reply)
+{
+    voice_extn_get_parameters(adev, query, reply);
+}
+
+int voice_set_parameters(struct audio_device *adev, struct str_parms *parms)
+{
+    char *str;
+    char value[32];
+    int val;
+    int ret = 0, err;
+    char *kv_pairs = str_parms_to_str(parms);
+
+    ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
+
+    ret = voice_extn_set_parameters(adev, parms);
+    if (ret != 0) {
+        if (ret == -ENOSYS)
+            ret = 0;
+        else
+            goto done;
+    }
+
+    ret = voice_extn_compress_voip_set_parameters(adev, parms);
+    if (ret != 0) {
+        if (ret == -ENOSYS)
+            ret = 0;
+        else
+            goto done;
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value));
+    if (err >= 0) {
+        int tty_mode;
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_TTY_MODE);
+        if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_OFF) == 0)
+            tty_mode = TTY_MODE_OFF;
+        else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_VCO) == 0)
+            tty_mode = TTY_MODE_VCO;
+        else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_HCO) == 0)
+            tty_mode = TTY_MODE_HCO;
+        else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_FULL) == 0)
+            tty_mode = TTY_MODE_FULL;
+        else {
+            ret = -EINVAL;
+            goto done;
+        }
+
+        if (tty_mode != adev->voice.tty_mode) {
+            adev->voice.tty_mode = tty_mode;
+            adev->acdb_settings = (adev->acdb_settings & TTY_MODE_CLEAR) | tty_mode;
+            if (voice_is_call_state_active(adev))
+               voice_update_devices_for_all_voice_usecases(adev);
+        }
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_INCALLMUSIC,
+                            value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_INCALLMUSIC);
+        if (strcmp(value, AUDIO_PARAMETER_VALUE_TRUE) == 0)
+            platform_start_incall_music_usecase(adev->platform);
+        else
+            platform_stop_incall_music_usecase(adev->platform);
+    }
+
+done:
+    ALOGV("%s: exit with code(%d)", __func__, ret);
+    free(kv_pairs);
+    return ret;
+}
+
+void voice_init(struct audio_device *adev)
+{
+    int i = 0;
+
+    memset(&adev->voice, 0, sizeof(adev->voice));
+    adev->voice.tty_mode = TTY_MODE_OFF;
+    adev->voice.volume = 1.0f;
+    adev->voice.mic_mute = false;
+    adev->voice.in_call = false;
+    for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+        adev->voice.session[i].pcm_rx = NULL;
+        adev->voice.session[i].pcm_tx = NULL;
+        adev->voice.session[i].state.current = CALL_INACTIVE;
+        adev->voice.session[i].state.new = CALL_INACTIVE;
+        adev->voice.session[i].vsid = VOICE_VSID;
+    }
+
+    voice_extn_init(adev);
+}
+
+void voice_update_devices_for_all_voice_usecases(struct audio_device *adev)
+{
+    struct listnode *node;
+    struct audio_usecase *usecase;
+
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if (usecase->type == VOICE_CALL) {
+            ALOGV("%s: updating device for usecase:%s", __func__,
+                  use_case_table[usecase->id]);
+            usecase->stream.out = adev->current_call_output;
+            select_devices(adev, usecase->id);
+        }
+    }
+}
+
+
diff --git a/msm8909/hal/voice.h b/msm8909/hal/voice.h
new file mode 100644
index 0000000..9be8443
--- /dev/null
+++ b/msm8909/hal/voice.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VOICE_H
+#define VOICE_H
+
+#define BASE_SESS_IDX       0
+#define VOICE_SESS_IDX     (BASE_SESS_IDX)
+
+#ifdef MULTI_VOICE_SESSION_ENABLED
+#define MAX_VOICE_SESSIONS 5
+#else
+#define MAX_VOICE_SESSIONS 1
+#endif
+
+#define BASE_CALL_STATE     1
+#define CALL_INACTIVE       (BASE_CALL_STATE)
+#define CALL_ACTIVE         (BASE_CALL_STATE + 1)
+
+#define VOICE_VSID  0x10C01000
+
+#define AUDIO_PARAMETER_KEY_INCALLMUSIC "incall_music_enabled"
+#define AUDIO_PARAMETER_VALUE_TRUE "true"
+
+struct audio_device;
+struct str_parms;
+struct stream_in;
+struct stream_out;
+typedef int audio_usecase_t;
+
+struct call_state {
+    int current;
+    int new;
+};
+
+struct voice_session {
+    struct pcm *pcm_rx;
+    struct pcm *pcm_tx;
+    struct call_state state;
+    uint32_t vsid;
+};
+
+struct voice {
+    struct voice_session session[MAX_VOICE_SESSIONS];
+    int tty_mode;
+    bool mic_mute;
+    float volume;
+    bool is_in_call;
+    bool in_call;
+};
+
+enum {
+    INCALL_REC_NONE = -1,
+    INCALL_REC_UPLINK,
+    INCALL_REC_DOWNLINK,
+    INCALL_REC_UPLINK_AND_DOWNLINK,
+};
+
+int voice_start_usecase(struct audio_device *adev, audio_usecase_t usecase_id);
+int voice_stop_usecase(struct audio_device *adev, audio_usecase_t usecase_id);
+
+int voice_start_call(struct audio_device *adev);
+int voice_stop_call(struct audio_device *adev);
+int voice_set_parameters(struct audio_device *adev, struct str_parms *parms);
+void voice_get_parameters(struct audio_device *adev, struct str_parms *query,
+                          struct str_parms *reply);
+void voice_init(struct audio_device *adev);
+bool voice_is_in_call(struct audio_device *adev);
+bool voice_is_in_call_rec_stream(struct stream_in *in);
+int voice_set_mic_mute(struct audio_device *dev, bool state);
+bool voice_get_mic_mute(struct audio_device *dev);
+int voice_set_volume(struct audio_device *adev, float volume);
+int voice_check_and_set_incall_rec_usecase(struct audio_device *adev,
+                                           struct stream_in *in);
+int voice_check_and_set_incall_music_usecase(struct audio_device *adev,
+                                             struct stream_out *out);
+int voice_check_and_stop_incall_rec_usecase(struct audio_device *adev,
+                                            struct stream_in *in);
+void voice_update_devices_for_all_voice_usecases(struct audio_device *adev);
+#endif //VOICE_H
diff --git a/msm8909/hal/voice_extn/compress_voip.c b/msm8909/hal/voice_extn/compress_voip.c
new file mode 100644
index 0000000..26636db
--- /dev/null
+++ b/msm8909/hal/voice_extn/compress_voip.c
@@ -0,0 +1,811 @@
+/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "compress_voip"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <math.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <cutils/properties.h>
+
+#include "audio_hw.h"
+#include "platform_api.h"
+#include "platform.h"
+#include "voice_extn.h"
+
+#define COMPRESS_VOIP_IO_BUF_SIZE_NB 320
+#define COMPRESS_VOIP_IO_BUF_SIZE_WB 640
+
+struct pcm_config pcm_config_voip_nb = {
+    .channels = 1,
+    .rate = 8000, /* changed when the stream is opened */
+    .period_size = COMPRESS_VOIP_IO_BUF_SIZE_NB/2,
+    .period_count = 10,
+    .format = PCM_FORMAT_S16_LE,
+};
+
+struct pcm_config pcm_config_voip_wb = {
+    .channels = 1,
+    .rate = 16000, /* changed when the stream is opened */
+    .period_size = COMPRESS_VOIP_IO_BUF_SIZE_WB/2,
+    .period_count = 10,
+    .format = PCM_FORMAT_S16_LE,
+};
+
+struct voip_data {
+    struct pcm *pcm_rx;
+    struct pcm *pcm_tx;
+    struct stream_out *out_stream;
+    uint32_t out_stream_count;
+    uint32_t in_stream_count;
+    uint32_t sample_rate;
+};
+
+#define MODE_IS127              0x2
+#define MODE_4GV_NB             0x3
+#define MODE_4GV_WB             0x4
+#define MODE_AMR                0x5
+#define MODE_AMR_WB             0xD
+#define MODE_PCM                0xC
+#define MODE_4GV_NW             0xE
+
+#define AUDIO_PARAMETER_KEY_VOIP_RATE               "voip_rate"
+#define AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN      "evrc_rate_min"
+#define AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX      "evrc_rate_max"
+#define AUDIO_PARAMETER_KEY_VOIP_DTX_MODE           "dtx_on"
+#define AUDIO_PARAMETER_VALUE_VOIP_TRUE             "true"
+#define AUDIO_PARAMETER_KEY_VOIP_CHECK              "voip_flag"
+#define AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT   "voip_out_stream_count"
+#define AUDIO_PARAMETER_KEY_VOIP_SAMPLE_RATE        "voip_sample_rate"
+
+static struct voip_data voip_data = {
+  .pcm_rx = NULL,
+  .pcm_tx = NULL,
+  .out_stream = NULL,
+  .out_stream_count = 0,
+  .in_stream_count = 0,
+  .sample_rate = 0
+};
+
+static int voip_set_volume(struct audio_device *adev, int volume);
+static int voip_set_mic_mute(struct audio_device *adev, bool state);
+static int voip_set_mode(struct audio_device *adev, int format);
+static int voip_set_rate(struct audio_device *adev, int rate);
+static int voip_set_evrc_min_max_rate(struct audio_device *adev, int min_rate,
+                               int max_rate);
+static int voip_set_dtx(struct audio_device *adev, bool enable);
+static int voip_stop_call(struct audio_device *adev);
+static int voip_start_call(struct audio_device *adev,
+                           struct pcm_config *voip_config);
+
+static int audio_format_to_voip_mode(int format)
+{
+    int mode;
+
+    switch(format) {
+        case AUDIO_FORMAT_PCM_16_BIT:
+            mode = MODE_PCM;
+            break;
+        case AUDIO_FORMAT_AMR_NB:
+            mode = MODE_AMR;
+            break;
+        case AUDIO_FORMAT_AMR_WB:
+            mode = MODE_AMR_WB;
+            break;
+        case AUDIO_FORMAT_EVRC:
+            mode = MODE_IS127;
+            break;
+        case AUDIO_FORMAT_EVRCB:
+            mode = MODE_4GV_NB;
+            break;
+        case AUDIO_FORMAT_EVRCWB:
+            mode = MODE_4GV_WB;
+            break;
+        case AUDIO_FORMAT_EVRCNW:
+            mode = MODE_4GV_NW;
+            break;
+        default:
+            mode = MODE_PCM;
+    }
+    return mode;
+}
+
+static int voip_set_volume(struct audio_device *adev, int volume)
+{
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Voip Rx Gain";
+    int vol_index = 0;
+    uint32_t set_values[ ] = {0,
+                              DEFAULT_VOLUME_RAMP_DURATION_MS};
+
+    ALOGV("%s: enter", __func__);
+
+    /* Voice volume levels are mapped to adsp volume levels as follows.
+     * 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1  0 -> 0
+     * But this values don't changed in kernel. So, below change is need.
+     */
+    vol_index = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX);
+    set_values[0] = vol_index;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    ALOGV("%s: Setting voip volume index: %d", __func__, set_values[0]);
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+    ALOGV("%s: exit", __func__);
+    return 0;
+}
+
+static int voip_set_mic_mute(struct audio_device *adev, bool state)
+{
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Voip Tx Mute";
+    uint32_t set_values[ ] = {0,
+                              DEFAULT_VOLUME_RAMP_DURATION_MS};
+
+    ALOGV("%s: enter, state=%d", __func__, state);
+
+    if (adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
+        set_values[0] = state;
+        ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+        if (!ctl) {
+            ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                  __func__, mixer_ctl_name);
+            return -EINVAL;
+        }
+        mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+    }
+
+    ALOGV("%s: exit", __func__);
+    return 0;
+}
+
+static int voip_set_mode(struct audio_device *adev, int format)
+{
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Voip Mode Config";
+    uint32_t set_values[ ] = {0};
+    int mode;
+
+    ALOGD("%s: enter, format=%d", __func__, format);
+
+    mode = audio_format_to_voip_mode(format);
+    ALOGD("%s: Derived mode = %d", __func__, mode);
+
+    set_values[0] = mode;
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+               __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+    ALOGV("%s: exit", __func__);
+    return 0;
+}
+
+static int voip_set_rate(struct audio_device *adev, int rate)
+{
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Voip Rate Config";
+    uint32_t set_values[ ] = {0};
+
+    ALOGD("%s: enter, rate=%d", __func__, rate);
+
+    set_values[0] = rate;
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+               __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+    ALOGV("%s: exit", __func__);
+    return 0;
+}
+
+static int voip_set_evrc_min_max_rate(struct audio_device *adev, int min_rate,
+                               int max_rate)
+{
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Voip Evrc Min Max Rate Config";
+    uint32_t set_values[ ] = {0, 0};
+
+    ALOGD("%s: enter, min_rate=%d, max_rate=%d",
+          __func__, min_rate, max_rate);
+
+    set_values[0] = min_rate;
+    set_values[1] = max_rate;
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+               __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+    ALOGV("%s: exit", __func__);
+    return 0;
+}
+
+static int voip_set_dtx(struct audio_device *adev, bool enable)
+{
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Voip Dtx Mode";
+    uint32_t set_values[ ] = {0};
+
+    ALOGD("%s: enter, enable=%d", __func__, enable);
+
+    set_values[0] = enable;
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+               __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+    ALOGV("%s: exit", __func__);
+    return 0;
+}
+
+static int voip_stop_call(struct audio_device *adev)
+{
+    int i, ret = 0;
+    struct audio_usecase *uc_info;
+
+    ALOGD("%s: enter, out_stream_count=%d, in_stream_count=%d",
+           __func__, voip_data.out_stream_count, voip_data.in_stream_count);
+
+    if (!voip_data.out_stream_count && !voip_data.in_stream_count) {
+        voip_data.sample_rate = 0;
+        uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
+        if (uc_info == NULL) {
+            ALOGE("%s: Could not find the usecase (%d) in the list",
+                  __func__, USECASE_COMPRESS_VOIP_CALL);
+            return -EINVAL;
+        }
+
+        /* 1. Close the PCM devices */
+        if (voip_data.pcm_rx) {
+            pcm_close(voip_data.pcm_rx);
+            voip_data.pcm_rx = NULL;
+        }
+        if (voip_data.pcm_tx) {
+            pcm_close(voip_data.pcm_tx);
+            voip_data.pcm_tx = NULL;
+        }
+
+        /* 2. Get and set stream specific mixer controls */
+        disable_audio_route(adev, uc_info);
+
+        /* 3. Disable the rx and tx devices */
+        disable_snd_device(adev, uc_info->out_snd_device);
+        disable_snd_device(adev, uc_info->in_snd_device);
+
+        list_remove(&uc_info->list);
+        free(uc_info);
+    } else
+        ALOGV("%s: NO-OP because out_stream_count=%d, in_stream_count=%d",
+               __func__, voip_data.out_stream_count, voip_data.in_stream_count);
+
+    ALOGV("%s: exit: status(%d)", __func__, ret);
+    return ret;
+}
+
+static int voip_start_call(struct audio_device *adev,
+                           struct pcm_config *voip_config)
+{
+    int i, ret = 0;
+    struct audio_usecase *uc_info;
+    int pcm_dev_rx_id, pcm_dev_tx_id;
+
+    ALOGD("%s: enter", __func__);
+
+    uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
+    if (uc_info == NULL) {
+        ALOGV("%s: voip usecase is added to the list", __func__);
+        uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+
+        if (!uc_info) {
+            ALOGE("failed to allocate voip usecase mem");
+            return -ENOMEM;
+        }
+
+        uc_info->id = USECASE_COMPRESS_VOIP_CALL;
+        uc_info->type = VOIP_CALL;
+        if (voip_data.out_stream)
+            uc_info->stream.out = voip_data.out_stream;
+        else
+            uc_info->stream.out = adev->primary_output;
+        uc_info->in_snd_device = SND_DEVICE_NONE;
+        uc_info->out_snd_device = SND_DEVICE_NONE;
+
+        list_add_tail(&adev->usecase_list, &uc_info->list);
+
+        select_devices(adev, USECASE_COMPRESS_VOIP_CALL);
+
+        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);
+
+        if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0) {
+            ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(%d)",
+                  __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
+            ret = -EIO;
+            goto error_start_voip;
+        }
+
+        ALOGD("%s: Opening PCM playback device card_id(%d) device_id(%d)",
+              __func__, adev->snd_card, pcm_dev_rx_id);
+        voip_data.pcm_rx = pcm_open(adev->snd_card,
+                                    pcm_dev_rx_id,
+                                    PCM_OUT, voip_config);
+        if (voip_data.pcm_rx && !pcm_is_ready(voip_data.pcm_rx)) {
+            ALOGE("%s: %s", __func__, pcm_get_error(voip_data.pcm_rx));
+            pcm_close(voip_data.pcm_rx);
+            voip_data.pcm_rx = NULL;
+            ret = -EIO;
+            goto error_start_voip;
+        }
+
+        ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+              __func__, adev->snd_card, pcm_dev_tx_id);
+        voip_data.pcm_tx = pcm_open(adev->snd_card,
+                                    pcm_dev_tx_id,
+                                    PCM_IN, voip_config);
+        if (voip_data.pcm_tx && !pcm_is_ready(voip_data.pcm_tx)) {
+            ALOGE("%s: %s", __func__, pcm_get_error(voip_data.pcm_tx));
+            pcm_close(voip_data.pcm_rx);
+            voip_data.pcm_tx = NULL;
+            if (voip_data.pcm_rx) {
+                pcm_close(voip_data.pcm_rx);
+                voip_data.pcm_rx = NULL;
+            }
+            ret = -EIO;
+            goto error_start_voip;
+        }
+        pcm_start(voip_data.pcm_rx);
+        pcm_start(voip_data.pcm_tx);
+
+        voice_extn_compress_voip_set_volume(adev, adev->voice.volume);
+
+        if (ret < 0) {
+            ALOGE("%s: error %d\n", __func__, ret);
+            goto error_start_voip;
+        }
+    } else {
+        ALOGV("%s: voip usecase is already enabled", __func__);
+        if (voip_data.out_stream)
+            uc_info->stream.out = voip_data.out_stream;
+        else
+            uc_info->stream.out = adev->primary_output;
+        select_devices(adev, USECASE_COMPRESS_VOIP_CALL);
+    }
+
+    return 0;
+
+error_start_voip:
+    voip_stop_call(adev);
+
+    ALOGV("%s: exit: status(%d)", __func__, ret);
+    return ret;
+}
+
+int voice_extn_compress_voip_set_parameters(struct audio_device *adev,
+                                             struct str_parms *parms)
+{
+    char *str;
+    char value[32]={0};
+    int ret = 0, err, rate;
+    int min_rate, max_rate;
+    bool flag;
+    char *kv_pairs = str_parms_to_str(parms);
+
+    ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_RATE,
+                            value, sizeof(value));
+    if (err >= 0) {
+        rate = atoi(value);
+        voip_set_rate(adev, rate);
+        voip_set_evrc_min_max_rate(adev, rate, rate);
+    }
+
+    memset(value, 0, sizeof(value));
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN,
+                            value, sizeof(value));
+    if (err >= 0) {
+        min_rate = atoi(value);
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN);
+        memset(value, 0, sizeof(value));
+        err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX,
+                                value, sizeof(value));
+        if (err >= 0) {
+            max_rate = atoi(value);
+            voip_set_evrc_min_max_rate(adev, min_rate, max_rate);
+        } else {
+            ALOGE("%s: AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX not found", __func__);
+            ret = -EINVAL;
+            goto done;
+        }
+    }
+
+    memset(value, 0, sizeof(value));
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_DTX_MODE,
+                            value, sizeof(value));
+    if (err >= 0) {
+        flag = false;
+        if (strcmp(value, AUDIO_PARAMETER_VALUE_VOIP_TRUE) == 0)
+            flag = true;
+        voip_set_dtx(adev, flag);
+    }
+
+done:
+    ALOGV("%s: exit", __func__);
+    free(kv_pairs);
+    return ret;
+}
+
+void voice_extn_compress_voip_get_parameters(struct str_parms *query,
+                                             struct str_parms *reply)
+{
+    int ret;
+    char value[32]={0};
+    char *str = NULL;
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT,
+                          voip_data.out_stream_count);
+    }
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_SAMPLE_RATE,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_SAMPLE_RATE,
+                          voip_data.sample_rate);
+    }
+}
+
+void voice_extn_compress_voip_out_get_parameters(struct stream_out *out,
+                                                 struct str_parms *query,
+                                                 struct str_parms *reply)
+{
+    int ret, val;
+    char value[32]={0};
+
+    ALOGD("%s: enter", __func__);
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_CHECK, value, sizeof(value));
+
+    if (ret >= 0) {
+        if (out->usecase == USECASE_COMPRESS_VOIP_CALL)
+            str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, true);
+        else
+            str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, false);
+    }
+
+    ALOGV("%s: exit", __func__);
+}
+
+void voice_extn_compress_voip_in_get_parameters(struct stream_in *in,
+                                                struct str_parms *query,
+                                                struct str_parms *reply)
+{
+    int ret, val;
+    char value[32]={0};
+    char *kv_pairs = NULL;
+
+    ALOGV("%s: enter", __func__);
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_CHECK, value, sizeof(value));
+
+    if (ret >= 0) {
+        if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
+            str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, true);
+        else
+            str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, false);
+    }
+
+    kv_pairs = str_parms_to_str(reply);
+    ALOGD_IF(kv_pairs != NULL, "%s: exit: return - %s", __func__, kv_pairs);
+    free(kv_pairs);
+}
+
+int voice_extn_compress_voip_out_get_buffer_size(struct stream_out *out)
+{
+    if (out->config.rate == 16000)
+        return COMPRESS_VOIP_IO_BUF_SIZE_WB;
+    else
+        return COMPRESS_VOIP_IO_BUF_SIZE_NB;
+}
+
+int voice_extn_compress_voip_in_get_buffer_size(struct stream_in *in)
+{
+    if (in->config.rate == 16000)
+        return COMPRESS_VOIP_IO_BUF_SIZE_WB;
+    else
+        return COMPRESS_VOIP_IO_BUF_SIZE_NB;
+}
+
+int voice_extn_compress_voip_start_output_stream(struct stream_out *out)
+{
+    int ret = 0;
+    struct audio_device *adev = out->dev;
+    struct audio_usecase *uc_info;
+    int snd_card_status = get_snd_card_state(adev);
+
+    ALOGD("%s: enter", __func__);
+
+    if (SND_CARD_STATE_OFFLINE == snd_card_status) {
+        ret = -ENETRESET;
+        ALOGE("%s: sound card is not active/SSR returning error %d ", __func__, ret);
+        goto error;
+    }
+
+    if (!voip_data.out_stream_count)
+        ret = voice_extn_compress_voip_open_output_stream(out);
+
+    ret = voip_start_call(adev, &out->config);
+    out->pcm = voip_data.pcm_rx;
+    uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
+    if (uc_info) {
+        uc_info->stream.out = out;
+        uc_info->devices = out->devices;
+    } else {
+        ret = -EINVAL;
+        ALOGE("%s: exit(%d): failed to get use case info", __func__, ret);
+        goto error;
+    }
+
+error:
+    ALOGV("%s: exit: status(%d)", __func__, ret);
+    return ret;
+}
+
+int voice_extn_compress_voip_start_input_stream(struct stream_in *in)
+{
+    int ret = 0;
+    struct audio_usecase *uc_info;
+    struct audio_device *adev = in->dev;
+    int snd_card_status = get_snd_card_state(adev);
+
+    ALOGD("%s: enter", __func__);
+
+    if (SND_CARD_STATE_OFFLINE == snd_card_status) {
+        ret = -ENETRESET;
+        ALOGE("%s: sound card is not active/SSR returning error %d ", __func__, ret);
+        goto error;
+    }
+
+    if (!voip_data.in_stream_count)
+        ret = voice_extn_compress_voip_open_input_stream(in);
+
+    adev->active_input = in;
+    ret = voip_start_call(adev, &in->config);
+    in->pcm = voip_data.pcm_tx;
+
+error:
+    ALOGV("%s: exit: status(%d)", __func__, ret);
+    return ret;
+}
+
+int voice_extn_compress_voip_close_output_stream(struct audio_stream *stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    struct audio_device *adev = out->dev;
+    int ret = 0;
+
+    ALOGD("%s: enter", __func__);
+    if (voip_data.out_stream_count > 0) {
+        voip_data.out_stream_count--;
+        ret = voip_stop_call(adev);
+        voip_data.out_stream = NULL;
+        out->pcm = NULL;
+    }
+
+    ALOGV("%s: exit: status(%d)", __func__, ret);
+    return ret;
+}
+
+int voice_extn_compress_voip_open_output_stream(struct stream_out *out)
+{
+    int mode, ret;
+
+    ALOGD("%s: enter", __func__);
+
+    out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_MONO;
+    out->channel_mask = AUDIO_CHANNEL_OUT_MONO;
+    out->usecase = USECASE_COMPRESS_VOIP_CALL;
+    if (out->sample_rate == 16000)
+        out->config = pcm_config_voip_wb;
+    else
+        out->config = pcm_config_voip_nb;
+
+    voip_data.out_stream = out;
+    voip_data.out_stream_count++;
+    voip_data.sample_rate = out->sample_rate;
+    ret = voip_set_mode(out->dev, out->format);
+
+    ALOGV("%s: exit", __func__);
+    return ret;
+}
+
+int voice_extn_compress_voip_close_input_stream(struct audio_stream *stream)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    struct audio_device *adev = in->dev;
+    int status = 0;
+
+    ALOGD("%s: enter", __func__);
+
+    if(voip_data.in_stream_count > 0) {
+       adev->active_input = NULL;
+       voip_data.in_stream_count--;
+       status = voip_stop_call(adev);
+       in->pcm = NULL;
+    }
+
+    ALOGV("%s: exit: status(%d)", __func__, status);
+    return status;
+}
+
+int voice_extn_compress_voip_open_input_stream(struct stream_in *in)
+{
+    int sample_rate;
+    int buffer_size,frame_size;
+    int mode, ret;
+
+    ALOGD("%s: enter", __func__);
+
+    if ((voip_data.sample_rate != 0) &&
+        (voip_data.sample_rate != in->config.rate)) {
+        ret = -ENOTSUP;
+        goto done;
+    } else {
+        voip_data.sample_rate = in->config.rate;
+    }
+
+    in->usecase = USECASE_COMPRESS_VOIP_CALL;
+    if (in->config.rate == 16000)
+        in->config = pcm_config_voip_wb;
+    else
+        in->config = pcm_config_voip_nb;
+
+    voip_data.in_stream_count++;
+    ret = voip_set_mode(in->dev, in->format);
+
+done:
+    ALOGV("%s: exit, ret=%d", __func__, ret);
+    return ret;
+}
+
+int voice_extn_compress_voip_set_volume(struct audio_device *adev, float volume)
+{
+    int vol, err = 0;
+
+    ALOGV("%s: enter", __func__);
+
+    if (volume < 0.0) {
+        volume = 0.0;
+    } else if (volume > 1.0) {
+        volume = 1.0;
+    }
+
+    vol = lrint(volume * 100.0);
+
+    /* Voice volume levels from android are mapped to driver volume levels as follows.
+     * 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0
+     * So adjust the volume to get the correct volume index in driver
+     */
+    vol = 100 - vol;
+
+    err = voip_set_volume(adev, vol);
+
+    ALOGV("%s: exit: status(%d)", __func__, err);
+
+    return err;
+}
+
+int voice_extn_compress_voip_set_mic_mute(struct audio_device *adev, bool state)
+{
+    int err = 0;
+
+    ALOGV("%s: enter", __func__);
+
+    err = voip_set_mic_mute(adev, state);
+
+    ALOGV("%s: exit: status(%d)", __func__, err);
+    return err;
+}
+
+bool voice_extn_compress_voip_pcm_prop_check()
+{
+    char prop_value[PROPERTY_VALUE_MAX] = {0};
+
+    property_get("use.voice.path.for.pcm.voip", prop_value, "0");
+    if (!strncmp("true", prop_value, sizeof("true")))
+    {
+        ALOGD("%s: VoIP PCM property is enabled", __func__);
+        return true;
+    }
+    else
+        return false;
+}
+
+bool voice_extn_compress_voip_is_active(struct audio_device *adev)
+{
+    struct audio_usecase *voip_usecase = NULL;
+    voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
+
+    if (voip_usecase != NULL)
+        return true;
+    else
+        return false;
+}
+
+bool voice_extn_compress_voip_is_format_supported(audio_format_t format)
+{
+    switch (format) {
+    case AUDIO_FORMAT_PCM_16_BIT:
+        if (voice_extn_compress_voip_pcm_prop_check())
+            return true;
+        else
+            return false;
+    case AUDIO_FORMAT_AMR_NB:
+    case AUDIO_FORMAT_AMR_WB:
+    case AUDIO_FORMAT_EVRC:
+    case AUDIO_FORMAT_EVRCB:
+    case AUDIO_FORMAT_EVRCWB:
+    case AUDIO_FORMAT_EVRCNW:
+        return true;
+    default:
+        return false;
+    }
+}
+
+bool voice_extn_compress_voip_is_config_supported(struct audio_config *config)
+{
+    bool ret = false;
+
+    ret = voice_extn_compress_voip_is_format_supported(config->format);
+    if (ret) {
+        if ((popcount(config->channel_mask) == 1) &&
+            (config->sample_rate == 8000 || config->sample_rate == 16000))
+            ret = ((voip_data.sample_rate == 0) ? true:
+                    (voip_data.sample_rate == config->sample_rate));
+        else
+            ret = false;
+    }
+    return ret;
+}
diff --git a/msm8909/hal/voice_extn/voice_extn.c b/msm8909/hal/voice_extn/voice_extn.c
new file mode 100644
index 0000000..13a98b3
--- /dev/null
+++ b/msm8909/hal/voice_extn/voice_extn.c
@@ -0,0 +1,611 @@
+/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "voice_extn"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <math.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <sys/ioctl.h>
+#include <sound/voice_params.h>
+#include <stdlib.h>
+
+#include "audio_hw.h"
+#include "voice.h"
+#include "platform.h"
+#include "platform_api.h"
+#include "voice_extn.h"
+
+#define AUDIO_PARAMETER_KEY_VSID                "vsid"
+#define AUDIO_PARAMETER_KEY_CALL_STATE          "call_state"
+#define AUDIO_PARAMETER_KEY_AUDIO_MODE          "audio_mode"
+#define AUDIO_PARAMETER_KEY_ALL_CALL_STATES     "all_call_states"
+#define AUDIO_PARAMETER_KEY_DEVICE_MUTE         "device_mute"
+#define AUDIO_PARAMETER_KEY_DIRECTION           "direction"
+#define AUDIO_PARAMETER_KEY_IN_CALL             "in_call"
+
+#define VOICE_EXTN_PARAMETER_VALUE_MAX_LEN 256
+
+#define VOICE2_VSID 0x10DC1000
+#define VOLTE_VSID  0x10C02000
+#define QCHAT_VSID  0x10803000
+#define VOWLAN_VSID 0x10002000
+#define ALL_VSID    0xFFFFFFFF
+
+/* Voice Session Indices */
+#define VOICE2_SESS_IDX    (VOICE_SESS_IDX + 1)
+#define VOLTE_SESS_IDX     (VOICE_SESS_IDX + 2)
+#define QCHAT_SESS_IDX     (VOICE_SESS_IDX + 3)
+#define VOWLAN_SESS_IDX    (VOICE_SESS_IDX + 4)
+
+/* Call States */
+#define CALL_HOLD           (BASE_CALL_STATE + 2)
+#define CALL_LOCAL_HOLD     (BASE_CALL_STATE + 3)
+
+struct pcm_config pcm_config_incall_music = {
+    .channels = 1,
+    .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
+    .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
+    .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
+    .format = PCM_FORMAT_S16_LE,
+    .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
+    .stop_threshold = INT_MAX,
+    .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
+};
+
+int voice_extn_is_call_state_active(struct audio_device *adev, bool *is_call_active);
+
+static bool is_valid_call_state(int call_state)
+{
+    if (call_state < CALL_INACTIVE || call_state > CALL_LOCAL_HOLD)
+        return false;
+    else
+        return true;
+}
+
+static bool is_valid_vsid(uint32_t vsid)
+{
+    if (vsid == VOICE_VSID ||
+        vsid == VOICE2_VSID ||
+        vsid == VOLTE_VSID ||
+        vsid == QCHAT_VSID ||
+        vsid == VOWLAN_VSID)
+        return true;
+    else
+        return false;
+}
+
+static audio_usecase_t voice_extn_get_usecase_for_session_idx(const int index)
+{
+    audio_usecase_t usecase_id = -1;
+
+    switch(index) {
+    case VOICE_SESS_IDX:
+        usecase_id = USECASE_VOICE_CALL;
+        break;
+
+    case VOICE2_SESS_IDX:
+        usecase_id = USECASE_VOICE2_CALL;
+        break;
+
+    case VOLTE_SESS_IDX:
+        usecase_id = USECASE_VOLTE_CALL;
+        break;
+
+    case QCHAT_SESS_IDX:
+        usecase_id = USECASE_QCHAT_CALL;
+        break;
+
+    case VOWLAN_SESS_IDX:
+        usecase_id = USECASE_VOWLAN_CALL;
+        break;
+
+    default:
+        ALOGE("%s: Invalid voice session index\n", __func__);
+    }
+
+    return usecase_id;
+}
+
+static uint32_t get_session_id_with_state(struct audio_device *adev,
+                                          int call_state)
+{
+    struct voice_session *session = NULL;
+    int i = 0;
+    uint32_t session_id = 0;
+
+    for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+        session = &adev->voice.session[i];
+        if(session->state.current == call_state){
+            session_id = session->vsid;
+            break;
+        }
+    }
+
+    return session_id;
+}
+
+static int update_calls(struct audio_device *adev)
+{
+    int i = 0;
+    audio_usecase_t usecase_id = 0;
+    enum voice_lch_mode lch_mode;
+    struct voice_session *session = NULL;
+    int fd = 0;
+    int ret = 0;
+
+    ALOGD("%s: enter:", __func__);
+
+    for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+        usecase_id = voice_extn_get_usecase_for_session_idx(i);
+        session = &adev->voice.session[i];
+        ALOGD("%s: cur_state=%d new_state=%d vsid=%x",
+              __func__, session->state.current, session->state.new, session->vsid);
+
+        switch(session->state.new)
+        {
+        case CALL_ACTIVE:
+            switch(session->state.current)
+            {
+            case CALL_INACTIVE:
+                ALOGD("%s: INACTIVE -> ACTIVE vsid:%x", __func__, session->vsid);
+                ret = voice_start_usecase(adev, usecase_id);
+                if(ret < 0) {
+                    ALOGE("%s: voice_start_usecase() failed for usecase: %d\n",
+                          __func__, usecase_id);
+                } else {
+                    session->state.current = session->state.new;
+                }
+                break;
+
+            case CALL_HOLD:
+                ALOGD("%s: HOLD -> ACTIVE vsid:%x", __func__, session->vsid);
+                session->state.current = session->state.new;
+                break;
+
+            case CALL_LOCAL_HOLD:
+                ALOGD("%s: LOCAL_HOLD -> ACTIVE vsid:%x", __func__, session->vsid);
+                lch_mode = VOICE_LCH_STOP;
+                ret = platform_update_lch(adev->platform, session, lch_mode);
+                if (ret < 0)
+                    ALOGE("%s: lch mode update failed, ret = %d", __func__, ret);
+                else
+                    session->state.current = session->state.new;
+                break;
+
+            default:
+                ALOGV("%s: CALL_ACTIVE cannot be handled in state=%d vsid:%x",
+                      __func__, session->state.current, session->vsid);
+                break;
+            }
+            break;
+
+        case CALL_INACTIVE:
+            switch(session->state.current)
+            {
+            case CALL_ACTIVE:
+            case CALL_HOLD:
+            case CALL_LOCAL_HOLD:
+                ALOGD("%s: ACTIVE/HOLD/LOCAL_HOLD -> INACTIVE vsid:%x", __func__, session->vsid);
+                ret = voice_stop_usecase(adev, usecase_id);
+                if(ret < 0) {
+                    ALOGE("%s: voice_stop_usecase() failed for usecase: %d\n",
+                          __func__, usecase_id);
+                } else {
+                    session->state.current = session->state.new;
+                }
+                break;
+
+            default:
+                ALOGV("%s: CALL_INACTIVE cannot be handled in state=%d vsid:%x",
+                      __func__, session->state.current, session->vsid);
+                break;
+            }
+            break;
+
+        case CALL_HOLD:
+            switch(session->state.current)
+            {
+            case CALL_ACTIVE:
+                ALOGD("%s: CALL_ACTIVE -> HOLD vsid:%x", __func__, session->vsid);
+                session->state.current = session->state.new;
+                break;
+
+            case CALL_LOCAL_HOLD:
+                ALOGD("%s: CALL_LOCAL_HOLD -> HOLD vsid:%x", __func__, session->vsid);
+                lch_mode = VOICE_LCH_STOP;
+                ret = platform_update_lch(adev->platform, session, lch_mode);
+                if (ret < 0)
+                    ALOGE("%s: lch mode update failed, ret = %d", __func__, ret);
+                else
+                    session->state.current = session->state.new;
+                break;
+
+            default:
+                ALOGV("%s: CALL_HOLD cannot be handled in state=%d vsid:%x",
+                      __func__, session->state.current, session->vsid);
+                break;
+            }
+            break;
+
+        case CALL_LOCAL_HOLD:
+            switch(session->state.current)
+            {
+            case CALL_ACTIVE:
+            case CALL_HOLD:
+                ALOGD("%s: ACTIVE/CALL_HOLD -> LOCAL_HOLD vsid:%x", __func__,
+                      session->vsid);
+                lch_mode = VOICE_LCH_START;
+                ret = platform_update_lch(adev->platform, session, lch_mode);
+                if (ret < 0)
+                    ALOGE("%s: lch mode update failed, ret = %d", __func__, ret);
+                else
+                    session->state.current = session->state.new;
+                break;
+
+            default:
+                ALOGV("%s: CALL_LOCAL_HOLD cannot be handled in state=%d vsid:%x",
+                      __func__, session->state.current, session->vsid);
+                break;
+            }
+            break;
+
+        default:
+            break;
+        } //end out switch loop
+    } //end for loop
+
+    return ret;
+}
+
+static int update_call_states(struct audio_device *adev,
+                                    const uint32_t vsid, const int call_state)
+{
+    struct voice_session *session = NULL;
+    int i = 0;
+    bool is_call_active;
+
+    for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+        if (vsid == adev->voice.session[i].vsid) {
+            session = &adev->voice.session[i];
+            break;
+        }
+    }
+
+    if (session) {
+        session->state.new = call_state;
+        voice_extn_is_call_state_active(adev, &is_call_active);
+        ALOGD("%s is_call_active:%d in_call:%d, mode:%d\n",
+              __func__, is_call_active, adev->voice.in_call, adev->mode);
+        /* Dont start voice call before device routing for voice usescases has
+         * occured, otherwise voice calls will be started unintendedly on
+         * speaker.
+         */
+        if (is_call_active ||
+                (adev->voice.in_call && adev->mode == AUDIO_MODE_IN_CALL)) {
+            /* Device routing is not triggered for voice calls on the subsequent
+             * subs, Hence update the call states if voice call is already
+             * active on other sub.
+             */
+            update_calls(adev);
+        }
+    } else {
+        return -EINVAL;
+    }
+
+    return 0;
+
+}
+
+int voice_extn_get_active_session_id(struct audio_device *adev,
+                                     uint32_t *session_id)
+{
+    *session_id = get_session_id_with_state(adev, CALL_ACTIVE);
+    return 0;
+}
+
+int voice_extn_is_call_state_active(struct audio_device *adev, bool *is_call_active)
+{
+    struct voice_session *session = NULL;
+    int i = 0;
+    *is_call_active = false;
+
+    for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+        session = &adev->voice.session[i];
+        if(session->state.current != CALL_INACTIVE){
+            *is_call_active = true;
+            break;
+        }
+    }
+
+    return 0;
+}
+
+int voice_extn_is_in_call_rec_stream(struct stream_in *in, bool *in_call_rec)
+{
+    *in_call_rec = false;
+
+    if(in->source == AUDIO_SOURCE_VOICE_DOWNLINK ||
+       in->source == AUDIO_SOURCE_VOICE_UPLINK ||
+       in->source == AUDIO_SOURCE_VOICE_CALL) {
+       *in_call_rec = true;
+    }
+
+    return 0;
+}
+
+void voice_extn_init(struct audio_device *adev)
+{
+    adev->voice.session[VOICE_SESS_IDX].vsid =  VOICE_VSID;
+    adev->voice.session[VOICE2_SESS_IDX].vsid = VOICE2_VSID;
+    adev->voice.session[VOLTE_SESS_IDX].vsid =  VOLTE_VSID;
+    adev->voice.session[QCHAT_SESS_IDX].vsid =  QCHAT_VSID;
+    adev->voice.session[VOWLAN_SESS_IDX].vsid = VOWLAN_VSID;
+}
+
+int voice_extn_get_session_from_use_case(struct audio_device *adev,
+                                         const audio_usecase_t usecase_id,
+                                         struct voice_session **session)
+{
+
+    switch(usecase_id)
+    {
+    case USECASE_VOICE_CALL:
+        *session = &adev->voice.session[VOICE_SESS_IDX];
+        break;
+
+    case USECASE_VOICE2_CALL:
+        *session = &adev->voice.session[VOICE2_SESS_IDX];
+        break;
+
+    case USECASE_VOLTE_CALL:
+        *session = &adev->voice.session[VOLTE_SESS_IDX];
+        break;
+
+    case USECASE_QCHAT_CALL:
+        *session = &adev->voice.session[QCHAT_SESS_IDX];
+        break;
+
+    case USECASE_VOWLAN_CALL:
+        *session = &adev->voice.session[VOWLAN_SESS_IDX];
+        break;
+
+    default:
+        ALOGE("%s: Invalid usecase_id:%d\n", __func__, usecase_id);
+        *session = NULL;
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+int voice_extn_start_call(struct audio_device *adev)
+{
+    /* Start voice calls on sessions whose call state has been
+     * udpated.
+     */
+    ALOGV("%s: enter:", __func__);
+    return update_calls(adev);
+}
+
+int voice_extn_stop_call(struct audio_device *adev)
+{
+    int i;
+    int ret = 0;
+
+    ALOGV("%s: enter:", __func__);
+
+    /* If BT device is enabled and voice calls are ended, telephony will call
+     * set_mode(AUDIO_MODE_NORMAL) which will trigger audio policy manager to
+     * set routing with device BT A2DP profile. Hence end all voice calls when
+     * set_mode(AUDIO_MODE_NORMAL) before BT A2DP profile is selected.
+     */
+    if (adev->mode == AUDIO_MODE_NORMAL) {
+        ALOGD("%s: end all calls", __func__);
+        for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+            adev->voice.session[i].state.new = CALL_INACTIVE;
+        }
+
+        ret = update_calls(adev);
+    }
+
+    return ret;
+}
+
+int voice_extn_set_parameters(struct audio_device *adev,
+                              struct str_parms *parms)
+{
+    char *str;
+    int value;
+    int ret = 0, err;
+    char *kv_pairs = str_parms_to_str(parms);
+    char str_value[256] = {0};
+
+    ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
+
+    err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_VSID, &value);
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_VSID);
+        uint32_t vsid = value;
+        int call_state = -1;
+        err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_CALL_STATE, &value);
+        if (err >= 0) {
+            call_state = value;
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_CALL_STATE);
+        } else {
+            ALOGE("%s: call_state key not found", __func__);
+            ret = -EINVAL;
+            goto done;
+        }
+
+        if (is_valid_vsid(vsid) && is_valid_call_state(call_state)) {
+            ret = update_call_states(adev, vsid, call_state);
+        } else {
+            ALOGE("%s: invalid vsid:%x or call_state:%d",
+                  __func__, vsid, call_state);
+            ret = -EINVAL;
+            goto done;
+        }
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_DEVICE_MUTE, str_value,
+                            sizeof(str_value));
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_DEVICE_MUTE);
+        bool mute = false;
+
+        if (!strncmp("true", str_value, sizeof("true"))) {
+            mute = true;
+        }
+
+        err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_DIRECTION, str_value,
+                                sizeof(str_value));
+        if (err >= 0) {
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_DIRECTION);
+        } else {
+            ALOGE("%s: direction key not found", __func__);
+            ret = -EINVAL;
+            goto done;
+        }
+
+        ret = platform_set_device_mute(adev->platform, mute, str_value);
+        if (ret != 0) {
+            ALOGE("%s: Failed to set mute err:%d", __func__, ret);
+            ret = -EINVAL;
+            goto done;
+        }
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_IN_CALL, str_value,
+                            sizeof(str_value));
+    if (err >= 0) {
+          str_parms_del(parms, AUDIO_PARAMETER_KEY_IN_CALL);
+           if (!strncmp("true", str_value, sizeof("true"))) {
+           adev->voice.is_in_call = true;
+        }
+    }
+
+done:
+    ALOGV("%s: exit with code(%d)", __func__, ret);
+    free(kv_pairs);
+    return ret;
+}
+
+static int get_all_call_states_str(const struct audio_device *adev,
+                            char *value)
+{
+    int ret = 0;
+    char *cur_ptr = value;
+    int i, len=0;
+
+    for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+        snprintf(cur_ptr, VOICE_EXTN_PARAMETER_VALUE_MAX_LEN - len,
+                 "%d:%d,",adev->voice.session[i].vsid,
+                 adev->voice.session[i].state.current);
+        len = strlen(cur_ptr);
+        cur_ptr = cur_ptr + len;
+    }
+    ALOGV("%s:value=%s", __func__, value);
+    return ret;
+}
+
+void voice_extn_get_parameters(const struct audio_device *adev,
+                               struct str_parms *query,
+                               struct str_parms *reply)
+{
+    int ret;
+    char value[VOICE_EXTN_PARAMETER_VALUE_MAX_LEN] = {0};
+    char *str = str_parms_to_str(query);
+    int val = 0;
+
+    ALOGV_IF(str != NULL, "%s: enter %s", __func__, str);
+    free(str);
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_IN_CALL, value,
+                            sizeof(value));
+    if (ret >=0) {
+        if (adev->voice.is_in_call)
+            val = 1;
+        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_IN_CALL, val);
+    }
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_AUDIO_MODE, value,
+                            sizeof(value));
+    if (ret >= 0) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_AUDIO_MODE, adev->mode);
+    }
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ALL_CALL_STATES,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        ret = get_all_call_states_str(adev, value);
+        if (ret) {
+            ALOGE("%s: Error fetching call states, err:%d", __func__, ret);
+            return;
+        }
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_ALL_CALL_STATES, value);
+    }
+    voice_extn_compress_voip_get_parameters(query, reply);
+
+    str = str_parms_to_str(reply);
+    ALOGV_IF(str != NULL, "%s: exit: returns \"%s\"", __func__, str);
+    free(str);
+}
+
+void voice_extn_out_get_parameters(struct stream_out *out,
+                                   struct str_parms *query,
+                                   struct str_parms *reply)
+{
+    voice_extn_compress_voip_out_get_parameters(out, query, reply);
+}
+
+void voice_extn_in_get_parameters(struct stream_in *in,
+                                  struct str_parms *query,
+                                  struct str_parms *reply)
+{
+    voice_extn_compress_voip_in_get_parameters(in, query, reply);
+}
+
+#ifdef INCALL_MUSIC_ENABLED
+int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev,
+                                                  struct stream_out *out)
+{
+    uint32_t session_id = 0;
+
+    session_id = get_session_id_with_state(adev, CALL_LOCAL_HOLD);
+    if (session_id == VOICE_VSID) {
+        out->usecase = USECASE_INCALL_MUSIC_UPLINK;
+    } else if (session_id == VOICE2_VSID) {
+        out->usecase = USECASE_INCALL_MUSIC_UPLINK2;
+    } else {
+        ALOGE("%s: Invalid session id %x", __func__, session_id);
+        return -EINVAL;
+    }
+
+    out->config = pcm_config_incall_music;
+    out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_MONO;
+    out->channel_mask = AUDIO_CHANNEL_OUT_MONO;
+
+    return 0;
+}
+#endif
+
diff --git a/msm8909/hal/voice_extn/voice_extn.h b/msm8909/hal/voice_extn/voice_extn.h
new file mode 100644
index 0000000..15e5248
--- /dev/null
+++ b/msm8909/hal/voice_extn/voice_extn.h
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VOICE_EXTN_H
+#define VOICE_EXTN_H
+
+#ifdef MULTI_VOICE_SESSION_ENABLED
+int voice_extn_start_call(struct audio_device *adev);
+int voice_extn_stop_call(struct audio_device *adev);
+int voice_extn_get_session_from_use_case(struct audio_device *adev,
+                                         const audio_usecase_t usecase_id,
+                                         struct voice_session **session);
+void voice_extn_init(struct audio_device *adev);
+int voice_extn_set_parameters(struct audio_device *adev,
+                              struct str_parms *parms);
+void voice_extn_get_parameters(const struct audio_device *adev,
+                               struct str_parms *query,
+                               struct str_parms *reply);
+int voice_extn_is_in_call_rec_stream(struct stream_in *in, bool *in_call_rec);
+int voice_extn_is_call_state_active(struct audio_device *adev,
+                                    bool *is_call_active);
+int voice_extn_get_active_session_id(struct audio_device *adev,
+                                     uint32_t *session_id);
+void voice_extn_in_get_parameters(struct stream_in *in,
+                                  struct str_parms *query,
+                                  struct str_parms *reply);
+void voice_extn_out_get_parameters(struct stream_out *out,
+                                   struct str_parms *query,
+                                   struct str_parms *reply);
+#else
+static int voice_extn_start_call(struct audio_device *adev __unused)
+{
+    return -ENOSYS;
+}
+
+static int voice_extn_stop_call(struct audio_device *adev __unused)
+{
+    return -ENOSYS;
+}
+
+static int voice_extn_get_session_from_use_case(struct audio_device *adev __unused,
+                                                const audio_usecase_t usecase_id __unused,
+                                                struct voice_session **session __unused)
+{
+    return -ENOSYS;
+}
+
+static void voice_extn_init(struct audio_device *adev __unused)
+{
+}
+
+static int voice_extn_set_parameters(struct audio_device *adev __unused,
+                                     struct str_parms *parms __unused)
+{
+    return -ENOSYS;
+}
+
+static void voice_extn_get_parameters(const struct audio_device *adev __unused,
+                                      struct str_parms *query __unused,
+                                      struct str_parms *reply __unused)
+{
+}
+
+static int voice_extn_is_call_state_active(struct audio_device *adev __unused,
+                                           bool *is_call_active __unused)
+{
+    return -ENOSYS;
+}
+
+static int voice_extn_is_in_call_rec_stream(struct stream_in *in __unused, bool *in_call_rec __unused)
+{
+    return -ENOSYS;
+}
+
+static int voice_extn_get_active_session_id(struct audio_device *adev __unused,
+                                            uint32_t *session_id __unused)
+{
+    return -ENOSYS;
+}
+
+static void voice_extn_in_get_parameters(struct stream_in *in __unused,
+                                         struct str_parms *query __unused,
+                                         struct str_parms *reply __unused)
+{
+}
+
+static void voice_extn_out_get_parameters(struct stream_out *out __unused,
+                                          struct str_parms *query __unused,
+                                          struct str_parms *reply __unused)
+{
+}
+#endif
+
+#ifdef INCALL_MUSIC_ENABLED
+int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev,
+                                                  struct stream_out *out);
+#else
+static int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev __unused,
+                                                         struct stream_out *out __unused)
+{
+    return -ENOSYS;
+}
+#endif
+
+#ifdef COMPRESS_VOIP_ENABLED
+int voice_extn_compress_voip_close_output_stream(struct audio_stream *stream);
+int voice_extn_compress_voip_open_output_stream(struct stream_out *out);
+
+int voice_extn_compress_voip_close_input_stream(struct audio_stream *stream);
+int voice_extn_compress_voip_open_input_stream(struct stream_in *in);
+
+int voice_extn_compress_voip_out_get_buffer_size(struct stream_out *out);
+int voice_extn_compress_voip_in_get_buffer_size(struct stream_in *in);
+
+int voice_extn_compress_voip_start_input_stream(struct stream_in *in);
+int voice_extn_compress_voip_start_output_stream(struct stream_out *out);
+
+int voice_extn_compress_voip_set_mic_mute(struct audio_device *dev, bool state);
+int voice_extn_compress_voip_set_volume(struct audio_device *adev, float volume);
+int voice_extn_compress_voip_select_devices(struct audio_device *adev,
+                                            snd_device_t *out_snd_device,
+                                            snd_device_t *in_snd_device);
+int voice_extn_compress_voip_set_parameters(struct audio_device *adev,
+                                             struct str_parms *parms);
+void voice_extn_compress_voip_get_parameters(struct str_parms *query,
+                                             struct str_parms *reply);
+
+void voice_extn_compress_voip_out_get_parameters(struct stream_out *out,
+                                                 struct str_parms *query,
+                                                 struct str_parms *reply);
+void voice_extn_compress_voip_in_get_parameters(struct stream_in *in,
+                                                struct str_parms *query,
+                                                struct str_parms *reply);
+bool voice_extn_compress_voip_pcm_prop_check();
+bool voice_extn_compress_voip_is_active(struct audio_device *adev);
+bool voice_extn_compress_voip_is_format_supported(audio_format_t format);
+bool voice_extn_compress_voip_is_config_supported(struct audio_config *config);
+#else
+static int voice_extn_compress_voip_close_output_stream(struct audio_stream *stream __unused)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+    return -ENOSYS;
+}
+
+static int voice_extn_compress_voip_open_output_stream(struct stream_out *out __unused)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+    return -ENOSYS;
+}
+
+static int voice_extn_compress_voip_close_input_stream(struct audio_stream *stream __unused)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+    return -ENOSYS;
+}
+
+static int voice_extn_compress_voip_open_input_stream(struct stream_in *in __unused)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+    return -ENOSYS;
+}
+
+static int voice_extn_compress_voip_out_get_buffer_size(struct stream_out *stream __unused)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+    return -ENOSYS;
+}
+
+static int voice_extn_compress_voip_in_get_buffer_size(struct stream_in *in __unused)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+    return -ENOSYS;
+}
+
+static int voice_extn_compress_voip_start_input_stream(struct stream_in *in __unused)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+    return -ENOSYS;
+}
+
+static int voice_extn_compress_voip_start_output_stream(struct stream_out *out __unused)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+    return -ENOSYS;
+}
+
+static int voice_extn_compress_voip_set_mic_mute(struct audio_device *adev, bool state __unused)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+    return 0;
+}
+
+static int voice_extn_compress_voip_set_volume(struct audio_device *adev __unused, float volume __unused)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+    return 0;
+}
+
+static int voice_extn_compress_voip_select_devices(struct audio_device *adev __unused,
+                                                   snd_device_t *out_snd_device __unused,
+                                                   snd_device_t *in_snd_device __unused)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+    return -ENOSYS;
+}
+
+static int voice_extn_compress_voip_set_parameters(struct audio_device *adev __unused,
+                                                    struct str_parms *parms __unused)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+    return -ENOSYS;
+}
+
+static void voice_extn_compress_voip_get_parameters(struct str_parms *query __unused,
+                                                    struct str_parms *reply __unused)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+}
+
+static void voice_extn_compress_voip_out_get_parameters(struct stream_out *out __unused,
+                                                        struct str_parms *query __unused,
+                                                        struct str_parms *reply __unused)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+}
+
+static void voice_extn_compress_voip_in_get_parameters(struct stream_in *in __unused,
+                                                       struct str_parms *query __unused,
+                                                       struct str_parms *reply __unused)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+}
+
+static bool voice_extn_compress_voip_pcm_prop_check()
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+    return false;
+}
+
+static bool voice_extn_compress_voip_is_active(struct audio_device *adev __unused)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+    return false;
+}
+
+static bool voice_extn_compress_voip_is_format_supported(audio_format_t format __unused)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+    return true;
+}
+
+static bool voice_extn_compress_voip_is_config_supported(struct audio_config *config __unused)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+    return true;
+}
+#endif
+
+#endif //VOICE_EXTN_H