msm8660: Import audio HAL

Change-Id: I81ca52d392e5bba337f4a3a1288f716ba265ffe1
diff --git a/Android.mk b/Android.mk
index 7a0a25a..021396d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,4 +1,4 @@
-ifneq ($(filter msm8960 msm7x30,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8960 msm8660 msm7x30,$(TARGET_BOARD_PLATFORM)),)
 ifeq ($(TARGET_QCOM_AUDIO_VARIANT),caf)
 
 AUDIO_HW_ROOT := $(call my-dir)
@@ -13,6 +13,9 @@
 ifeq ($(TARGET_BOARD_PLATFORM),msm7x30)
     include $(AUDIO_HW_ROOT)/msm7x30/Android.mk
 endif
-
+ifeq ($(TARGET_BOARD_PLATFORM),msm8660)
+    include $(AUDIO_HW_ROOT)/msm8660/Android.mk
+    include $(AUDIO_HW_ROOT)/mm-audio/Android.mk
+endif
 endif
 endif
diff --git a/msm8660/Android.mk b/msm8660/Android.mk
new file mode 100644
index 0000000..1d1ec09
--- /dev/null
+++ b/msm8660/Android.mk
@@ -0,0 +1,127 @@
+#AUDIO_POLICY_TEST := true
+#ENABLE_AUDIO_DUMP := true
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_ARM_MODE := arm
+LOCAL_CFLAGS := -D_POSIX_SOURCE
+
+LOCAL_SRC_FILES := \
+    AudioHardware.cpp \
+    audio_hw_hal.cpp
+
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+  LOCAL_CFLAGS += -DWITH_A2DP
+endif
+
+ifeq ($(BOARD_HAVE_QCOM_FM),true)
+  LOCAL_CFLAGS += -DQCOM_FM_ENABLED
+endif
+
+ifeq ($(BOARD_USE_QCOM_LPA),true)
+  LOCAL_CFLAGS += -DQCOM_TUNNEL_LPA_ENABLED
+endif
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils       \
+    libutils        \
+    libmedia        \
+    libaudioalsa    \
+    libacdbloader   \
+    libacdbmapper
+
+# hack for prebuilt
+$(shell mkdir -p $(OUT)/obj/SHARED_LIBRARIES/libaudioalsa_intermediates/)
+$(shell touch $(OUT)/obj/SHARED_LIBRARIES/libaudioalsa_intermediates/export_includes)
+$(shell mkdir -p $(OUT)/obj/SHARED_LIBRARIES/libacdbloader_intermediates/)
+$(shell touch $(OUT)/obj/SHARED_LIBRARIES/libacdbloader_intermediates/export_includes)
+$(shell mkdir -p $(OUT)/obj/SHARED_LIBRARIES/libacdbmapper_intermediates/)
+$(shell touch $(OUT)/obj/SHARED_LIBRARIES/libacdbmapper_intermediates/export_includes)
+
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_STATIC_LIBRARIES := \
+    libmedia_helper \
+    libaudiohw_legacy \
+    libaudiopolicy_legacy \
+
+LOCAL_MODULE := audio.primary.msm8660
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS += -fno-short-enums
+
+LOCAL_C_INCLUDES := $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audcal
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audio-acdb-util
+LOCAL_C_INCLUDES += hardware/libhardware/include
+LOCAL_C_INCLUDES += hardware/libhardware_legacy/include
+LOCAL_C_INCLUDES += frameworks/base/include
+LOCAL_C_INCLUDES += system/core/include
+
+ifeq ($(BOARD_USES_QCOM_HARDWARE),true)
+LOCAL_CFLAGS += -DQCOM_ACDB_ENABLED
+endif
+
+ifeq ($(BOARD_HAVE_SAMSUNG_AUDIO),true)
+LOCAL_CFLAGS += -DSAMSUNG_AUDIO
+endif
+
+ifeq ($(BOARD_HAVE_SONY_AUDIO),true)
+LOCAL_CFLAGS += -DSONY_AUDIO
+endif
+
+ifeq ($(BOARD_HAVE_BACK_MIC_CAMCORDER),true)
+LOCAL_CFLAGS += -DBACK_MIC_CAMCORDER
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+# The audio policy is implemented on top of legacy policy code
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    AudioPolicyManager.cpp \
+    audio_policy_hal.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    libutils \
+    libmedia
+
+LOCAL_STATIC_LIBRARIES := \
+    libaudiohw_legacy \
+    libmedia_helper \
+    libaudiopolicy_legacy
+
+LOCAL_MODULE := audio_policy.msm8660
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_TAGS := optional
+
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+  LOCAL_CFLAGS += -DWITH_A2DP
+endif
+
+LOCAL_C_INCLUDES += hardware/libhardware_legacy/audio
+
+ifeq ($(BOARD_HAVE_SAMSUNG_AUDIO),true)
+LOCAL_CFLAGS += -DSAMSUNG_AUDIO
+endif
+
+ifeq ($(BOARD_HAVE_BACK_MIC_CAMCORDER),true)
+LOCAL_CFLAGS += -DBACK_MIC_CAMCORDER
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Load audio_policy.conf to system/etc/
+include $(CLEAR_VARS)
+LOCAL_MODULE       := audio_policy.conf
+LOCAL_MODULE_TAGS  := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH  := $(TARGET_OUT_ETC)/
+LOCAL_SRC_FILES    := audio_policy.conf
+include $(BUILD_PREBUILT)
diff --git a/msm8660/AudioHardware.cpp b/msm8660/AudioHardware.cpp
new file mode 100644
index 0000000..4eb6d71
--- /dev/null
+++ b/msm8660/AudioHardware.cpp
@@ -0,0 +1,5311 @@
+/*
+** Copyright 2008, The Android Open-Source Project
+** Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <math.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AudioHardwareMSM8660"
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include "AudioHardware.h"
+#include <media/AudioSystem.h>
+#include <cutils/properties.h>
+
+#include <linux/android_pmem.h>
+#ifdef QCOM_ACDB_ENABLED
+#include <linux/msm_audio_acdb.h>
+#endif
+#include <linux/msm_audio_mvs.h>
+#include <sys/mman.h>
+#include "control.h"
+#include "acdb.h"
+
+#ifdef HTC_ACOUSTIC_AUDIO
+    extern "C" {
+    #include <linux/spi_aic3254.h>
+    #include <linux/tpa2051d3.h>
+    }
+    #define DSP_EFFECT_KEY "dolby_srs_eq"
+#endif
+
+#define VOICE_SESSION_NAME "Voice session"
+#define VOIP_SESSION_NAME "VoIP session"
+
+// hardware specific functions
+
+#define LOG_SND_RPC 0  // Set to 1 to log sound RPC's
+
+#define DUALMIC_KEY "dualmic_enabled"
+#define BTHEADSET_VGS "bt_headset_vgs"
+#define ANC_KEY "anc_enabled"
+#define TTY_MODE_KEY "tty_mode"
+#define ECHO_SUPRESSION "ec_supported"
+
+
+#define MVS_DEVICE "/dev/msm_mvs"
+
+#ifdef QCOM_FM_ENABLED
+#define FM_DEVICE  "/dev/msm_fm"
+#define FM_A2DP_REC 1
+#define FM_FILE_REC 2
+#endif
+
+#ifdef QCOM_ACDB_ENABLED
+#define INVALID_ACDB_ID -1
+#endif
+
+namespace android_audio_legacy {
+
+Mutex   mDeviceSwitchLock;
+#ifdef HTC_ACOUSTIC_AUDIO
+Mutex   mAIC3254ConfigLock;
+#endif
+static int audpre_index, tx_iir_index;
+static void * acoustic;
+const uint32_t AudioHardware::inputSamplingRates[] = {
+        8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+static const uint32_t INVALID_DEVICE                        = 65535;
+static const uint32_t SND_DEVICE_CURRENT                    = -1;
+static const uint32_t SND_DEVICE_HANDSET                    = 0;
+static const uint32_t SND_DEVICE_SPEAKER                    = 1;
+static const uint32_t SND_DEVICE_HEADSET                    = 2;
+static const uint32_t SND_DEVICE_FM_HANDSET                 = 3;
+static const uint32_t SND_DEVICE_FM_SPEAKER                 = 4;
+static const uint32_t SND_DEVICE_FM_HEADSET                 = 5;
+static const uint32_t SND_DEVICE_BT                         = 6;
+static const uint32_t SND_DEVICE_HEADSET_AND_SPEAKER        = 7;
+static const uint32_t SND_DEVICE_NO_MIC_HEADSET             = 8;
+static const uint32_t SND_DEVICE_IN_S_SADC_OUT_HANDSET      = 9;
+static const uint32_t SND_DEVICE_IN_S_SADC_OUT_SPEAKER_PHONE= 10;
+static const uint32_t SND_DEVICE_TTY_HEADSET                = 11;
+static const uint32_t SND_DEVICE_TTY_HCO                    = 12;
+static const uint32_t SND_DEVICE_TTY_VCO                    = 13;
+static const uint32_t SND_DEVICE_TTY_FULL                   = 14;
+static const uint32_t SND_DEVICE_HDMI                       = 15;
+static const uint32_t SND_DEVICE_CARKIT                     = -1;
+static const uint32_t SND_DEVICE_ANC_HEADSET                = 16;
+static const uint32_t SND_DEVICE_NO_MIC_ANC_HEADSET         = 17;
+static const uint32_t SND_DEVICE_HEADPHONE_AND_SPEAKER      = 18;
+static const uint32_t SND_DEVICE_FM_TX                      = 19;
+static const uint32_t SND_DEVICE_FM_TX_AND_SPEAKER          = 20;
+static const uint32_t SND_DEVICE_SPEAKER_TX                 = 21;
+static const uint32_t SND_DEVICE_BACK_MIC_CAMCORDER         = 33;
+#ifdef HTC_ACOUSTIC_AUDIO
+static const uint32_t SND_DEVICE_SPEAKER_BACK_MIC           = 26;
+static const uint32_t SND_DEVICE_HANDSET_BACK_MIC           = 27;
+static const uint32_t SND_DEVICE_NO_MIC_HEADSET_BACK_MIC    = 28;
+static const uint32_t SND_DEVICE_HEADSET_AND_SPEAKER_BACK_MIC = 30;
+static const uint32_t SND_DEVICE_I2S_SPEAKER                = 32;
+static const uint32_t SND_DEVICE_BT_EC_OFF                  = 45;
+static const uint32_t SND_DEVICE_HAC                        = 252;
+static const uint32_t SND_DEVICE_USB_HEADSET                = 253;
+#else
+static const uint32_t SND_DEVICE_BT_EC_OFF                  = -1;
+#endif
+#ifdef SAMSUNG_AUDIO
+static uint32_t SND_DEVICE_VOIP_HANDSET               = 50;
+static uint32_t SND_DEVICE_VOIP_SPEAKER               = 51;
+static uint32_t SND_DEVICE_VOIP_HEADSET               = 52;
+static uint32_t SND_DEVICE_CALL_HANDSET               = 60;
+static uint32_t SND_DEVICE_CALL_SPEAKER               = 61;
+static uint32_t SND_DEVICE_CALL_HEADSET               = 62;
+static uint32_t SND_DEVICE_VR_SPEAKER                 = 70;
+static uint32_t SND_DEVICE_VR_HEADSET                 = 71;
+static uint32_t SND_DEVICE_HAC                        = 252;
+static uint32_t SND_DEVICE_USB_HEADSET                = 253;
+#endif
+static const uint32_t DEVICE_HANDSET_RX            = 0; // handset_rx
+static const uint32_t DEVICE_HANDSET_TX            = 1;//handset_tx
+static const uint32_t DEVICE_SPEAKER_RX            = 2; //speaker_stereo_rx
+static const uint32_t DEVICE_SPEAKER_TX            = 3;//speaker_mono_tx
+static const uint32_t DEVICE_HEADSET_RX            = 4; //headset_stereo_rx
+static const uint32_t DEVICE_HEADSET_TX            = 5; //headset_mono_tx
+static const uint32_t DEVICE_FMRADIO_HANDSET_RX    = 6; //fmradio_handset_rx
+static const uint32_t DEVICE_FMRADIO_HEADSET_RX    = 7; //fmradio_headset_rx
+static const uint32_t DEVICE_FMRADIO_SPEAKER_RX    = 8; //fmradio_speaker_rx
+static const uint32_t DEVICE_DUALMIC_HANDSET_TX    = 9; //handset_dual_mic_endfire_tx
+static const uint32_t DEVICE_DUALMIC_SPEAKER_TX    = 10; //speaker_dual_mic_endfire_tx
+static const uint32_t DEVICE_TTY_HEADSET_MONO_RX   = 11; //tty_headset_mono_rx
+static const uint32_t DEVICE_TTY_HEADSET_MONO_TX   = 12; //tty_headset_mono_tx
+static const uint32_t DEVICE_SPEAKER_HEADSET_RX    = 13; //headset_stereo_speaker_stereo_rx
+static const uint32_t DEVICE_FMRADIO_STEREO_TX     = 14;
+static const uint32_t DEVICE_HDMI_STERO_RX         = 15; //hdmi_stereo_rx
+static const uint32_t DEVICE_ANC_HEADSET_STEREO_RX = 16; //ANC RX
+static const uint32_t DEVICE_BT_SCO_RX             = 17; //bt_sco_rx
+static const uint32_t DEVICE_BT_SCO_TX             = 18; //bt_sco_tx
+static const uint32_t DEVICE_FMRADIO_STEREO_RX     = 19;
+#ifdef SAMSUNG_AUDIO
+// Samsung devices
+static uint32_t DEVICE_HANDSET_VOIP_RX       = 40; // handset_voip_rx
+static uint32_t DEVICE_HANDSET_VOIP_TX       = 41; // handset_voip_tx
+static uint32_t DEVICE_SPEAKER_VOIP_RX       = 42; // speaker_voip_rx
+static uint32_t DEVICE_SPEAKER_VOIP_TX       = 43; // speaker_voip_tx
+static uint32_t DEVICE_HEADSET_VOIP_RX       = 44; // headset_voip_rx
+static uint32_t DEVICE_HEADSET_VOIP_TX       = 45; // headset_voip_tx
+static uint32_t DEVICE_HANDSET_CALL_RX       = 60; // handset_call_rx
+static uint32_t DEVICE_HANDSET_CALL_TX       = 61; // handset_call_tx
+static uint32_t DEVICE_SPEAKER_CALL_RX       = 62; // speaker_call_rx
+static uint32_t DEVICE_SPEAKER_CALL_TX       = 63; // speaker_call_tx
+static uint32_t DEVICE_HEADSET_CALL_RX       = 64; // headset_call_rx
+static uint32_t DEVICE_HEADSET_CALL_TX       = 65; // headset_call_tx
+static uint32_t DEVICE_SPEAKER_VR_TX         = 82; // speaker_vr_tx
+static uint32_t DEVICE_HEADSET_VR_TX         = 83; // headset_vr_tx
+#endif
+static uint32_t DEVICE_CAMCORDER_TX          = 105; // camcoder_tx (misspelled by Samsung)
+                                                    // secondary_mic_tx (sony)
+
+static uint32_t FLUENCE_MODE_ENDFIRE   = 0;
+static uint32_t FLUENCE_MODE_BROADSIDE = 1;
+static int vr_enable = 0;
+
+int dev_cnt = 0;
+const char ** name = NULL;
+int mixer_cnt = 0;
+static uint32_t cur_tx = INVALID_DEVICE;
+static uint32_t cur_rx = INVALID_DEVICE;
+#ifdef QCOM_VOIP_ENABLED
+int voip_session_id = 0;
+int voip_session_mute = 0;
+#endif
+int voice_session_id = 0;
+int voice_session_mute = 0;
+static bool dualmic_enabled = false;
+static bool anc_running = false;
+static bool anc_setting = false;
+// This flag is used for avoiding multiple init/deinit of ANC driver.
+static bool anc_enabled = false;
+bool vMicMute = false;
+
+#ifdef QCOM_ACDB_ENABLED
+static bool bInitACDB = false;
+#endif
+#ifdef HTC_ACOUSTIC_AUDIO
+int rx_htc_acdb = 0;
+int tx_htc_acdb = 0;
+static bool support_aic3254 = true;
+static bool aic3254_enabled = true;
+int (*set_sound_effect)(const char* effect);
+static bool support_tpa2051 = true;
+static bool support_htc_backmic = true;
+static bool fm_enabled = false;
+static int alt_enable = 0;
+static int hac_enable = 0;
+static uint32_t cur_aic_tx = UPLINK_OFF;
+static uint32_t cur_aic_rx = DOWNLINK_OFF;
+static int cur_tpa_mode = 0;
+#endif
+
+typedef struct routing_table
+{
+    unsigned short dec_id;
+    int dev_id;
+    int dev_id_tx;
+    int stream_type;
+    bool active;
+    struct routing_table *next;
+} Routing_table;
+Routing_table* head;
+Mutex       mRoutingTableLock;
+
+typedef struct device_table
+{
+    int dev_id;
+    int acdb_id;
+    int class_id;
+    int capability;
+}Device_table;
+Device_table* device_list;
+
+enum STREAM_TYPES {
+    PCM_PLAY=1,
+    PCM_REC,
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+    LPA_DECODE,
+#endif
+    VOICE_CALL,
+#ifdef QCOM_VOIP_ENABLED
+    VOIP_CALL,
+#endif
+#ifdef QCOM_FM_ENABLED
+    FM_RADIO,
+    FM_REC,
+    FM_A2DP,
+#endif
+    INVALID_STREAM
+};
+
+typedef struct ComboDeviceType
+{
+    uint32_t DeviceId;
+    STREAM_TYPES StreamType;
+}CurrentComboDeviceStruct;
+CurrentComboDeviceStruct CurrentComboDeviceData;
+Mutex   mComboDeviceLock;
+
+#ifdef QCOM_FM_ENABLED
+enum FM_STATE {
+    FM_INVALID=1,
+    FM_OFF,
+    FM_ON
+};
+
+FM_STATE fmState = FM_INVALID;
+#endif
+
+static uint32_t fmDevice = INVALID_DEVICE;
+
+#define MAX_DEVICE_COUNT 200
+#define DEV_ID(X) device_list[X].dev_id
+#ifdef QCOM_ACDB_ENABLED
+#define ACDB_ID(X) device_list[X].acdb_id
+#endif
+#define CAPABILITY(X) device_list[X].capability
+
+void addToTable(int decoder_id,int device_id,int device_id_tx,int stream_type,bool active) {
+    Routing_table* temp_ptr;
+    ALOGD("addToTable stream %d",stream_type);
+    Mutex::Autolock lock(mRoutingTableLock);
+    temp_ptr = (Routing_table* ) malloc(sizeof(Routing_table));
+    temp_ptr->next = NULL;
+    temp_ptr->dec_id = decoder_id;
+    temp_ptr->dev_id = device_id;
+    temp_ptr->dev_id_tx = device_id_tx;
+    temp_ptr->stream_type = stream_type;
+    temp_ptr->active = active;
+    //make sure Voice node is always on top.
+    //For voice call device Switching, there a limitation
+    //Routing must happen before disabling/Enabling device.
+    if(head->next != NULL){
+       if(head->next->stream_type == VOICE_CALL){
+          temp_ptr->next = head->next->next;
+          head->next->next = temp_ptr;
+          return;
+       }
+    }
+    //add new Node to head.
+    temp_ptr->next =head->next;
+    head->next = temp_ptr;
+}
+
+bool isStreamOn(int Stream_type) {
+    Routing_table* temp_ptr;
+    Mutex::Autolock lock(mRoutingTableLock);
+    temp_ptr = head->next;
+    while(temp_ptr!=NULL) {
+        if(temp_ptr->stream_type == Stream_type)
+                return true;
+        temp_ptr=temp_ptr->next;
+    }
+    return false;
+}
+
+bool isStreamOnAndActive(int Stream_type) {
+    Routing_table* temp_ptr;
+    Mutex::Autolock lock(mRoutingTableLock);
+    temp_ptr = head->next;
+    while(temp_ptr!=NULL) {
+        if(temp_ptr->stream_type == Stream_type) {
+            if(temp_ptr->active == true) {
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+        temp_ptr=temp_ptr->next;
+    }
+    return false;
+}
+
+bool isStreamOnAndInactive(int Stream_type) {
+    Routing_table* temp_ptr;
+    Mutex::Autolock lock(mRoutingTableLock);
+    temp_ptr = head->next;
+    while(temp_ptr!=NULL) {
+        if(temp_ptr->stream_type == Stream_type) {
+            if(temp_ptr->active == false) {
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+        temp_ptr=temp_ptr->next;
+    }
+    return false;
+}
+
+Routing_table*  getNodeByStreamType(int Stream_type) {
+    Routing_table* temp_ptr;
+    Mutex::Autolock lock(mRoutingTableLock);
+    temp_ptr = head->next;
+    while(temp_ptr!=NULL) {
+        if(temp_ptr->stream_type == Stream_type) {
+            return temp_ptr;
+        }
+        temp_ptr=temp_ptr->next;
+    }
+    return NULL;
+}
+
+void modifyActiveStateOfStream(int Stream_type, bool Active) {
+    Routing_table* temp_ptr;
+    Mutex::Autolock lock(mRoutingTableLock);
+    temp_ptr = head->next;
+    while(temp_ptr!=NULL) {
+        if(temp_ptr->stream_type == Stream_type) {
+            temp_ptr->active = Active;
+        }
+        temp_ptr=temp_ptr->next;
+    }
+}
+
+void modifyActiveDeviceOfStream(int Stream_type,int Device_id,int Device_id_tx) {
+    Routing_table* temp_ptr;
+    temp_ptr = head->next;
+    while(temp_ptr!=NULL) {
+        if(temp_ptr->stream_type == Stream_type) {
+            temp_ptr->dev_id = Device_id;
+            temp_ptr->dev_id_tx = Device_id_tx;
+        }
+        temp_ptr=temp_ptr->next;
+    }
+}
+
+void printTable()
+{
+    Routing_table * temp_ptr;
+    Mutex::Autolock lock(mRoutingTableLock);
+    temp_ptr = head->next;
+    while(temp_ptr!=NULL) {
+        printf("%d %d %d %d %d\n",temp_ptr->dec_id,temp_ptr->dev_id,temp_ptr->dev_id_tx,temp_ptr->stream_type,temp_ptr->active);
+        temp_ptr = temp_ptr->next;
+    }
+}
+
+void deleteFromTable(int Stream_type) {
+    Routing_table *temp_ptr,*temp1;
+    ALOGD("deleteFromTable stream %d",Stream_type);
+    Mutex::Autolock lock(mRoutingTableLock);
+    temp_ptr = head;
+    while(temp_ptr->next!=NULL) {
+        if(temp_ptr->next->stream_type == Stream_type) {
+            temp1 = temp_ptr->next;
+            temp_ptr->next = temp_ptr->next->next;
+            free(temp1);
+            return;
+        }
+        temp_ptr=temp_ptr->next;
+    }
+
+}
+
+bool isDeviceListEmpty() {
+    if(head->next == NULL)
+        return true;
+    else
+        return false;
+}
+
+#ifdef QCOM_ANC_HEADSET_ENABLED
+//NEEDS to be called with device already enabled
+#define ANC_ACDB_STEREO_FF_ID 26
+int enableANC(int enable, uint32_t device)
+{
+    int rc;
+    device = 16;
+    ALOGD("%s: enable=%d, device=%d", __func__, enable, device);
+
+    // If anc is already enabled/disabled, then don't initalize the driver again.
+    if (enable == anc_enabled)
+    {
+        ALOGV("ANC driver is already in state %d. Not calling anc driver", enable);
+        return -EPERM;
+    }
+
+    if (enable) {
+#ifdef QCOM_ACDB_ENABLED
+        rc = acdb_loader_send_anc_cal(ANC_ACDB_STEREO_FF_ID);
+        if (rc) {
+            ALOGE("Error processing ANC ACDB data\n");
+            return rc;
+        }
+#endif
+    }
+    rc = msm_enable_anc(DEV_ID(device),enable);
+
+    if ( rc == 0 )
+    {
+        ALOGV("msm_enable_anc was successful");
+        anc_enabled = enable;
+    } else
+    {
+        ALOGV("msm_enable_anc failed");
+    }
+
+    return rc;
+}
+#endif
+
+#ifdef QCOM_ACDB_ENABLED
+static void initACDB() {
+    while(bInitACDB == false) {
+        ALOGD("Calling acdb_loader_init_ACDB()");
+        if(acdb_loader_init_ACDB() == 0){
+            ALOGD("acdb_loader_init_ACDB() successful");
+            bInitACDB = true;
+        }
+    }
+}
+#endif
+
+int enableDevice(int device,short enable) {
+
+    // prevent disabling of a device if it doesn't exist
+    //Temporaray hack till speaker_tx device is mainlined
+    if(DEV_ID(device) == INVALID_DEVICE) {
+        return 0;
+    }
+#ifdef QCOM_ACDB_ENABLED
+    if(bInitACDB == false) {
+        initACDB();
+    }
+#endif
+    ALOGE("value of device and enable is %d %d ALSA dev id:%d",device,enable,DEV_ID(device));
+    if( msm_en_device(DEV_ID(device), enable)) {
+        ALOGE("msm_en_device(%d,%d) failed errno = %d",DEV_ID(device),enable, errno);
+        return -1;
+    }
+    return 0;
+}
+
+static status_t updateDeviceInfo(int rx_device,int tx_device) {
+    bool isRxDeviceEnabled = false,isTxDeviceEnabled = false;
+    Routing_table *temp_ptr,*temp_head;
+    int tx_dev_prev = INVALID_DEVICE;
+    temp_head = head;
+
+    ALOGD("updateDeviceInfo: E");
+    Mutex::Autolock lock(mDeviceSwitchLock);
+
+    if(temp_head->next == NULL) {
+        ALOGD("simple device switch");
+        if(cur_rx!=INVALID_DEVICE)
+            enableDevice(cur_rx,0);
+        if(cur_tx != INVALID_DEVICE)
+            enableDevice(cur_tx,0);
+        cur_rx = rx_device;
+        cur_tx = tx_device;
+        if(cur_rx == DEVICE_ANC_HEADSET_STEREO_RX) {
+            enableDevice(cur_rx,1);
+            enableDevice(cur_tx,1);
+        }
+        return NO_ERROR;
+    }
+
+    Mutex::Autolock lock_1(mRoutingTableLock);
+
+    while(temp_head->next != NULL) {
+        temp_ptr = temp_head->next;
+        switch(temp_ptr->stream_type) {
+            case PCM_PLAY:
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+            case LPA_DECODE:
+#endif
+#ifdef QCOM_FM_ENABLED
+            case FM_RADIO:
+            case FM_A2DP:
+#endif
+                if(rx_device == INVALID_DEVICE)
+                    return -1;
+                ALOGD("The node type is %d", temp_ptr->stream_type);
+                ALOGV("rx_device = %d,temp_ptr->dev_id = %d",rx_device,temp_ptr->dev_id);
+                if(rx_device != temp_ptr->dev_id) {
+                    enableDevice(temp_ptr->dev_id,0);
+                }
+                if(msm_route_stream(PCM_PLAY,temp_ptr->dec_id,DEV_ID(temp_ptr->dev_id),0)) {
+                     ALOGV("msm_route_stream(PCM_PLAY,%d,%d,0) failed",temp_ptr->dec_id,DEV_ID(temp_ptr->dev_id));
+                }
+                if(isRxDeviceEnabled == false) {
+                    enableDevice(rx_device,1);
+#ifdef QCOM_ACDB_ENABLED
+                    acdb_loader_send_audio_cal(ACDB_ID(rx_device), CAPABILITY(rx_device));
+#endif
+                    isRxDeviceEnabled = true;
+                }
+                if(msm_route_stream(PCM_PLAY,temp_ptr->dec_id,DEV_ID(rx_device),1)) {
+                    ALOGV("msm_route_stream(PCM_PLAY,%d,%d,1) failed",temp_ptr->dec_id,DEV_ID(rx_device));
+                }
+                modifyActiveDeviceOfStream(temp_ptr->stream_type,rx_device,INVALID_DEVICE);
+                cur_tx = tx_device ;
+                cur_rx = rx_device ;
+                break;
+
+            case PCM_REC:
+
+                if(tx_device == INVALID_DEVICE)
+                    return -1;
+
+                // If dual  mic is enabled in QualComm settings then that takes preference.
+                if ( dualmic_enabled && (DEV_ID(DEVICE_DUALMIC_SPEAKER_TX) != INVALID_DEVICE))
+                {
+                   tx_device = DEVICE_DUALMIC_SPEAKER_TX;
+                }
+
+                ALOGD("case PCM_REC");
+                if(isTxDeviceEnabled == false) {
+                    enableDevice(temp_ptr->dev_id,0);
+                    enableDevice(tx_device,1);
+#ifdef QCOM_ACDB_ENABLED
+                    acdb_loader_send_audio_cal(ACDB_ID(tx_device), CAPABILITY(tx_device));
+#endif
+                    isTxDeviceEnabled = true;
+                }
+                if(msm_route_stream(PCM_REC,temp_ptr->dec_id,DEV_ID(temp_ptr->dev_id),0)) {
+                    ALOGV("msm_route_stream(PCM_PLAY,%d,%d,0) failed",temp_ptr->dec_id,DEV_ID(temp_ptr->dev_id));
+                }
+                if(msm_route_stream(PCM_REC,temp_ptr->dec_id,DEV_ID(tx_device),1)) {
+                    ALOGV("msm_route_stream(PCM_REC,%d,%d,1) failed",temp_ptr->dec_id,DEV_ID(tx_device));
+                }
+                modifyActiveDeviceOfStream(PCM_REC,tx_device,INVALID_DEVICE);
+                tx_dev_prev = cur_tx;
+                cur_tx = tx_device ;
+                cur_rx = rx_device ;
+                if((vMicMute == true) && (tx_dev_prev != cur_tx)) {
+                    ALOGD("REC:device switch with mute enabled :tx_dev_prev %d cur_tx: %d",tx_dev_prev, cur_tx);
+                    msm_device_mute(DEV_ID(cur_tx), true);
+                }
+                break;
+            case VOICE_CALL:
+#ifdef QCOM_VOIP_ENABLED
+            case VOIP_CALL:
+#endif
+                if(rx_device == INVALID_DEVICE || tx_device == INVALID_DEVICE)
+                    return -1;
+                ALOGD("case VOICE_CALL/VOIP CALL %d",temp_ptr->stream_type);
+#ifdef QCOM_ACDB_ENABLED
+    #ifdef HTC_ACOUSTIC_AUDIO
+                if (rx_htc_acdb == 0)
+                    rx_htc_acdb = ACDB_ID(rx_device);
+                if (tx_htc_acdb == 0)
+                    tx_htc_acdb = ACDB_ID(tx_device);
+                ALOGD("acdb_loader_send_voice_cal acdb_rx = %d, acdb_tx = %d", rx_htc_acdb, tx_htc_acdb);
+                acdb_loader_send_voice_cal(rx_htc_acdb, tx_htc_acdb);
+    #else
+                acdb_loader_send_voice_cal(ACDB_ID(rx_device),ACDB_ID(tx_device));
+    #endif
+#endif
+                msm_route_voice(DEV_ID(rx_device),DEV_ID(tx_device),1);
+
+                // Temporary work around for Speaker mode. The driver is not
+                // supporting Speaker Rx and Handset Tx combo
+                if(isRxDeviceEnabled == false) {
+                    if (rx_device != temp_ptr->dev_id)
+                    {
+                        enableDevice(temp_ptr->dev_id,0);
+                    }
+                    isRxDeviceEnabled = true;
+                }
+                if(isTxDeviceEnabled == false) {
+                    if (tx_device != temp_ptr->dev_id_tx)
+                    {
+                        enableDevice(temp_ptr->dev_id_tx,0);
+                    }
+                    isTxDeviceEnabled = true;
+                }
+
+                if (rx_device != temp_ptr->dev_id)
+                {
+                    enableDevice(rx_device,1);
+                }
+
+                if (tx_device != temp_ptr->dev_id_tx)
+                {
+                    enableDevice(tx_device,1);
+                }
+
+                cur_rx = rx_device;
+                cur_tx = tx_device;
+                modifyActiveDeviceOfStream(temp_ptr->stream_type,cur_rx,cur_tx);
+                break;
+            default:
+                break;
+        }
+        temp_head = temp_head->next;
+    }
+    ALOGD("updateDeviceInfo: X");
+    return NO_ERROR;
+}
+
+void freeMemory() {
+    Routing_table *temp;
+    while(head != NULL) {
+        temp = head->next;
+        free(head);
+        head = temp;
+    }
+free(device_list);
+}
+
+//
+// ----------------------------------------------------------------------------
+
+AudioHardware::AudioHardware() :
+    mInit(false), mMicMute(true), mBluetoothNrec(true), mBluetoothId(0),
+#ifdef HTC_ACOUSTIC_AUDIO
+    mHACSetting(false), mBluetoothIdTx(0), mBluetoothIdRx(0),
+#endif
+    mOutput(0),mBluetoothVGS(false),
+    mCurSndDevice(-1),
+    mTtyMode(TTY_OFF), mFmFd(-1), mNumPcmRec(0)
+#ifdef QCOM_VOIP_ENABLED
+    , mVoipFd(-1), mNumVoipStreams(0), mDirectOutput(0)
+#endif
+#ifdef HTC_ACOUSTIC_AUDIO
+    , mRecordState(false), mEffectEnabled(false)
+#endif
+{
+
+    int control;
+    int i = 0,index = 0;
+#ifdef QCOM_ACDB_ENABLED
+    int acdb_id = INVALID_ACDB_ID;
+#endif
+    int fluence_mode = FLUENCE_MODE_ENDFIRE;
+    char value[128];
+#ifdef HTC_ACOUSTIC_AUDIO
+    int (*snd_get_num)();
+    int (*snd_get_bt_endpoint)(msm_bt_endpoint *);
+    int (*set_acoustic_parameters)();
+    int (*set_tpa2051_parameters)();
+    int (*set_aic3254_parameters)();
+    int (*support_back_mic)();
+
+    struct msm_bt_endpoint *ept;
+#endif
+        head = (Routing_table* ) malloc(sizeof(Routing_table));
+        head->next = NULL;
+
+#ifdef HTC_ACOUSTIC_AUDIO
+        acoustic =:: dlopen("/system/lib/libhtc_acoustic.so", RTLD_NOW);
+        if (acoustic == NULL ) {
+            ALOGD("Could not open libhtc_acoustic.so");
+            /* this is not really an error on non-htc devices... */
+            mNumBTEndpoints = 0;
+            support_aic3254 = false;
+            support_tpa2051 = false;
+            support_htc_backmic = false;
+        }
+#endif
+
+        ALOGD("msm_mixer_open: Opening the device");
+        control = msm_mixer_open("/dev/snd/controlC0", 0);
+        if(control< 0)
+                ALOGE("ERROR opening the device");
+
+
+        mixer_cnt = msm_mixer_count();
+        ALOGD("msm_mixer_count:mixer_cnt =%d",mixer_cnt);
+
+        dev_cnt = msm_get_device_count();
+        ALOGV("got device_count %d",dev_cnt);
+        if (dev_cnt <= 0) {
+           ALOGE("NO devices registered\n");
+           return;
+        }
+
+        //End any voice call if it exists. This is to ensure the next request
+        //to voice call after a mediaserver crash or sub system restart
+        //is not ignored by the voice driver.
+        if (msm_end_voice() < 0)
+            ALOGE("msm_end_voice() failed");
+
+        if(msm_reset_all_device() < 0)
+            ALOGE("msm_reset_all_device() failed");
+
+        name = msm_get_device_list();
+        device_list = (Device_table* )malloc(sizeof(Device_table)*MAX_DEVICE_COUNT);
+        if(device_list == NULL) {
+            ALOGE("malloc failed for device list");
+            return;
+        }
+        property_get("persist.audio.fluence.mode",value,"0");
+        if (!strcmp("broadside", value)) {
+              fluence_mode = FLUENCE_MODE_BROADSIDE;
+        }
+
+    property_get("persist.audio.vr.enable",value,"Unknown");
+    if (!strcmp("true", value))
+        vr_enable = 1;
+
+        for(i = 0;i<MAX_DEVICE_COUNT;i++)
+            device_list[i].dev_id = INVALID_DEVICE;
+
+        for(i = 0; i < dev_cnt;i++) {
+            if(strcmp((char* )name[i],"handset_rx") == 0) {
+                index = DEVICE_HANDSET_RX;
+            }
+            else if(strcmp((char* )name[i],"handset_tx") == 0) {
+                index = DEVICE_HANDSET_TX;
+            }
+            else if((strcmp((char* )name[i],"speaker_stereo_rx") == 0) || 
+                    (strcmp((char* )name[i],"speaker_stereo_rx_playback") == 0) ||
+                    (strcmp((char* )name[i],"speaker_rx") == 0)) {
+                index = DEVICE_SPEAKER_RX;
+            }
+            else if((strcmp((char* )name[i],"speaker_mono_tx") == 0) || (strcmp((char* )name[i],"speaker_tx") == 0)) {
+                index = DEVICE_SPEAKER_TX;
+            }
+            else if((strcmp((char* )name[i],"headset_stereo_rx") == 0) || (strcmp((char* )name[i],"headset_rx") == 0)) {
+                index = DEVICE_HEADSET_RX;
+            }
+            else if((strcmp((char* )name[i],"headset_mono_tx") == 0) || (strcmp((char* )name[i],"headset_tx") == 0)) {
+                index = DEVICE_HEADSET_TX;
+            }
+            else if(strcmp((char* )name[i],"fmradio_handset_rx") == 0) {
+                index = DEVICE_FMRADIO_HANDSET_RX;
+            }
+            else if((strcmp((char* )name[i],"fmradio_headset_rx") == 0) || (strcmp((char* )name[i],"fm_radio_headset_rx") == 0)) {
+                index = DEVICE_FMRADIO_HEADSET_RX;
+            }
+            else if((strcmp((char* )name[i],"fmradio_speaker_rx") == 0) || (strcmp((char* )name[i],"fm_radio_speaker_rx") == 0)) {
+                index = DEVICE_FMRADIO_SPEAKER_RX;
+            }
+            else if((strcmp((char* )name[i],"handset_dual_mic_endfire_tx") == 0) || (strcmp((char* )name[i],"dualmic_handset_ef_tx") == 0)) {
+                if (fluence_mode == FLUENCE_MODE_ENDFIRE) {
+                     index = DEVICE_DUALMIC_HANDSET_TX;
+                } else {
+                     ALOGV("Endfire handset found but user request for %d\n", fluence_mode);
+                     continue;
+                }
+            }
+            else if((strcmp((char* )name[i],"speaker_dual_mic_endfire_tx") == 0)|| (strcmp((char* )name[i],"dualmic_speaker_ef_tx") == 0)) {
+                if (fluence_mode == FLUENCE_MODE_ENDFIRE) {
+                     index = DEVICE_DUALMIC_SPEAKER_TX;
+                } else {
+                     ALOGV("Endfire speaker found but user request for %d\n", fluence_mode);
+                     continue;
+                }
+            }
+            else if(strcmp((char* )name[i],"handset_dual_mic_broadside_tx") == 0) {
+                if (fluence_mode == FLUENCE_MODE_BROADSIDE) {
+                     index = DEVICE_DUALMIC_HANDSET_TX;
+                } else {
+                     ALOGV("Broadside handset found but user request for %d\n", fluence_mode);
+                     continue;
+                }
+            }
+            else if(strcmp((char* )name[i],"speaker_dual_mic_broadside_tx") == 0) {
+                if (fluence_mode == FLUENCE_MODE_BROADSIDE) {
+                     index = DEVICE_DUALMIC_SPEAKER_TX;
+                } else {
+                     ALOGV("Broadside speaker found but user request for %d\n", fluence_mode);
+                     continue;
+                }
+            }
+            else if((strcmp((char* )name[i],"tty_headset_mono_rx") == 0) || (strcmp((char* )name[i],"tty_headset_rx") == 0)) {
+                index = DEVICE_TTY_HEADSET_MONO_RX;
+            }
+            else if((strcmp((char* )name[i],"tty_headset_mono_tx") == 0) || (strcmp((char* )name[i],"tty_headset_tx") == 0)) {
+                index = DEVICE_TTY_HEADSET_MONO_TX;
+            }
+            else if((strcmp((char* )name[i],"bt_sco_rx") == 0) || (strcmp((char* )name[i],"bt_sco_mono_rx") == 0)) {
+                index = DEVICE_BT_SCO_RX;
+            }
+            else if((strcmp((char* )name[i],"bt_sco_tx") == 0) || (strcmp((char* )name[i],"bt_sco_mono_tx") == 0)) {
+                index = DEVICE_BT_SCO_TX;
+            }
+            else if((strcmp((char*)name[i],"headset_stereo_speaker_stereo_rx") == 0) ||
+                    (strcmp((char*)name[i],"headset_stereo_rx_playback") == 0) ||
+                    (strcmp((char*)name[i],"headset_speaker_stereo_rx") == 0) || (strcmp((char*)name[i],"speaker_headset_rx") == 0)) {
+                index = DEVICE_SPEAKER_HEADSET_RX;
+            }
+            else if((strcmp((char*)name[i],"fmradio_stereo_tx") == 0) || (strcmp((char*)name[i],"fm_radio_tx") == 0)) {
+                index = DEVICE_FMRADIO_STEREO_TX;
+            }
+            else if((strcmp((char*)name[i],"hdmi_stereo_rx") == 0) || (strcmp((char*)name[i],"hdmi_rx") == 0)) {
+                index = DEVICE_HDMI_STERO_RX;
+            }
+            //to check for correct name and ACDB number for ANC
+            else if(strcmp((char*)name[i],"anc_headset_stereo_rx") == 0) {
+                index = DEVICE_ANC_HEADSET_STEREO_RX;
+            }
+            else if(strcmp((char*)name[i],"fmradio_stereo_rx") == 0)
+                index = DEVICE_FMRADIO_STEREO_RX;
+#ifdef SAMSUNG_AUDIO
+            else if(strcmp((char* )name[i], "handset_voip_rx") == 0)
+                index = DEVICE_HANDSET_VOIP_RX;
+            else if(strcmp((char* )name[i], "handset_voip_tx") == 0)
+                index = DEVICE_HANDSET_VOIP_TX;
+            else if(strcmp((char* )name[i], "speaker_voip_rx") == 0)
+                index = DEVICE_SPEAKER_VOIP_RX;
+            else if(strcmp((char* )name[i], "speaker_voip_tx") == 0)
+                index = DEVICE_SPEAKER_VOIP_TX;
+            else if(strcmp((char* )name[i], "headset_voip_rx") == 0)
+                index = DEVICE_HEADSET_VOIP_RX;
+            else if(strcmp((char* )name[i], "headset_voip_tx") == 0)
+                index = DEVICE_HEADSET_VOIP_TX;
+            else if(strcmp((char* )name[i], "handset_call_rx") == 0)
+                index = DEVICE_HANDSET_CALL_RX;
+            else if(strcmp((char* )name[i], "handset_call_tx") == 0)
+                index = DEVICE_HANDSET_CALL_TX;
+            else if(strcmp((char* )name[i], "speaker_call_rx") == 0)
+                index = DEVICE_SPEAKER_CALL_RX;
+            else if(strcmp((char* )name[i], "speaker_call_tx") == 0)
+                index = DEVICE_SPEAKER_CALL_TX;
+            else if(strcmp((char* )name[i], "headset_call_rx") == 0)
+                index = DEVICE_HEADSET_CALL_RX;
+            else if(strcmp((char* )name[i], "headset_call_tx") == 0)
+                index = DEVICE_HEADSET_CALL_TX;
+            else if(strcmp((char* )name[i], "speaker_vr_tx") == 0)
+                index = DEVICE_SPEAKER_VR_TX;
+            else if(strcmp((char* )name[i], "headset_vr_tx") == 0)
+                index = DEVICE_HEADSET_VR_TX;
+#endif
+            else if((strcmp((char* )name[i], "camcoder_tx") == 0) ||
+#ifdef SONY_AUDIO
+                    (strcmp((char* )name[i], "secondary_mic_tx") == 0))
+#else
+                    (strcmp((char* )name[i], "camcorder_tx") == 0) ||
+                    (strcmp((char* )name[i], "handset_lgcam_tx") == 0))
+#endif
+                index = DEVICE_CAMCORDER_TX;
+            else {
+                ALOGI("Not used device: %s", ( char* )name[i]);
+                continue;
+            }
+            ALOGI("index = %d",index);
+
+            device_list[index].dev_id = msm_get_device((char* )name[i]);
+            if(device_list[index].dev_id >= 0) {
+                    ALOGI("Found device: %s:index = %d,dev_id: %d",( char* )name[i], index,device_list[index].dev_id);
+            }
+#ifdef QCOM_ACDB_ENABLED
+            acdb_mapper_get_acdb_id_from_dev_name((char* )name[i], &device_list[index].acdb_id);
+            device_list[index].class_id = msm_get_device_class(device_list[index].dev_id);
+            device_list[index].capability = msm_get_device_capability(device_list[index].dev_id);
+            ALOGI("acdb ID = %d,class ID = %d,capablity = %d for device %d",device_list[index].acdb_id,
+            device_list[index].class_id,device_list[index].capability,device_list[index].dev_id);
+#endif
+        }
+
+        CurrentComboDeviceData.DeviceId = INVALID_DEVICE;
+        CurrentComboDeviceData.StreamType = INVALID_STREAM;
+#ifdef HTC_ACOUSTIC_AUDIO
+    set_acoustic_parameters = (int (*)(void))::dlsym(acoustic, "set_acoustic_parameters");
+    if ((*set_acoustic_parameters) == 0 ) {
+        ALOGE("Could not open set_acoustic_parameters()");
+        return;
+    }
+
+    int rc = set_acoustic_parameters();
+    if (rc < 0) {
+        ALOGD("Could not set acoustic parameters to share memory: %d", rc);
+    }
+
+    /* Check the system property for enable or not the ALT function */
+    property_get("htc.audio.alt.enable", value, "0");
+    alt_enable = atoi(value);
+    ALOGV("Enable ALT function: %d", alt_enable);
+
+    /* Check the system property for enable or not the HAC function */
+    property_get("htc.audio.hac.enable", value, "0");
+    hac_enable = atoi(value);
+    ALOGV("Enable HAC function: %d", hac_enable);
+
+    set_tpa2051_parameters = (int (*)(void))::dlsym(acoustic, "set_tpa2051_parameters");
+    if ((*set_tpa2051_parameters) == 0) {
+        ALOGI("set_tpa2051_parameters() not present");
+        support_tpa2051 = false;
+    }
+
+    if (support_tpa2051) {
+        if (set_tpa2051_parameters() < 0) {
+            ALOGI("Speaker amplifies tpa2051 is not supported");
+            support_tpa2051 = false;
+        }
+    }
+
+    set_aic3254_parameters = (int (*)(void))::dlsym(acoustic, "set_aic3254_parameters");
+    if ((*set_aic3254_parameters) == 0 ) {
+        ALOGI("set_aic3254_parameters() not present");
+        support_aic3254 = false;
+    }
+
+    if (support_aic3254) {
+        if (set_aic3254_parameters() < 0) {
+            ALOGI("AIC3254 DSP is not supported");
+            support_aic3254 = false;
+        }
+    }
+
+    if (support_aic3254) {
+        set_sound_effect = (int (*)(const char*))::dlsym(acoustic, "set_sound_effect");
+        if ((*set_sound_effect) == 0 ) {
+            ALOGI("set_sound_effect() not present");
+            ALOGI("AIC3254 DSP is not supported");
+            support_aic3254 = false;
+        } else
+            strcpy(mEffect, "\0");
+    }
+
+    support_back_mic = (int (*)(void))::dlsym(acoustic, "support_back_mic");
+    if ((*support_back_mic) == 0 ) {
+        ALOGI("support_back_mic() not present");
+        support_htc_backmic = false;
+    }
+
+    if (support_htc_backmic) {
+        if (support_back_mic() != 1) {
+            ALOGI("HTC DualMic is not supported");
+            support_htc_backmic = false;
+        }
+    }
+
+    snd_get_num = (int (*)(void))::dlsym(acoustic, "snd_get_num");
+    if ((*snd_get_num) == 0 ) {
+        ALOGD("Could not open snd_get_num()");
+    }
+
+    mNumBTEndpoints = snd_get_num();
+    ALOGV("mNumBTEndpoints = %d", mNumBTEndpoints);
+    mBTEndpoints = new msm_bt_endpoint[mNumBTEndpoints];
+    ALOGV("constructed %d SND endpoints)", mNumBTEndpoints);
+    ept = mBTEndpoints;
+    snd_get_bt_endpoint = (int (*)(msm_bt_endpoint *))::dlsym(acoustic, "snd_get_bt_endpoint");
+    if ((*snd_get_bt_endpoint) == 0 ) {
+        mInit = true;
+        ALOGE("Could not open snd_get_bt_endpoint()");
+        return;
+    }
+    snd_get_bt_endpoint(mBTEndpoints);
+
+    for (int i = 0; i < mNumBTEndpoints; i++) {
+        ALOGV("BT name %s (tx,rx)=(%d,%d)", mBTEndpoints[i].name, mBTEndpoints[i].tx, mBTEndpoints[i].rx);
+    }
+#endif
+    mInit = true;
+}
+
+AudioHardware::~AudioHardware()
+{
+    for (size_t index = 0; index < mInputs.size(); index++) {
+        closeInputStream((AudioStreamIn*)mInputs[index]);
+    }
+    mInputs.clear();
+#ifdef QCOM_VOIP_ENABLED
+    mVoipInputs.clear();
+#endif
+    closeOutputStream((AudioStreamOut*)mOutput);
+    if (acoustic) {
+        ::dlclose(acoustic);
+        acoustic = 0;
+    }
+    msm_mixer_close();
+#ifdef QCOM_ACDB_ENABLED
+    acdb_loader_deallocate_ACDB();
+#endif
+    freeMemory();
+
+    mInit = false;
+}
+
+status_t AudioHardware::initCheck()
+{
+    return mInit ? NO_ERROR : NO_INIT;
+}
+
+AudioStreamOut* AudioHardware::openOutputStream(
+        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
+{
+    { // scope for the lock
+        status_t lStatus;
+        audio_output_flags_t flags = static_cast<audio_output_flags_t> (*status);
+        Mutex::Autolock lock(mLock);
+#ifdef QCOM_VOIP_ENABLED
+        // only one output stream allowed
+        if (mOutput && !((flags & AUDIO_OUTPUT_FLAG_DIRECT) && (flags & AUDIO_OUTPUT_FLAG_VOIP_RX))
+                    && !(flags & AUDIO_OUTPUT_FLAG_LPA)) {
+            if (status) {
+                *status = INVALID_OPERATION;
+            }
+            ALOGE(" AudioHardware::openOutputStream Only one output stream allowed \n");
+            return 0;
+        }
+
+        if ((flags & AUDIO_OUTPUT_FLAG_DIRECT) && (flags & AUDIO_OUTPUT_FLAG_VOIP_RX)) {
+            // open direct output stream
+            if(mDirectOutput == 0) {
+               ALOGV(" AudioHardware::openOutputStream Direct output stream \n");
+               AudioStreamOutDirect* out = new AudioStreamOutDirect();
+               lStatus = out->set(this, devices, format, channels, sampleRate);
+               if (status) {
+                   *status = lStatus;
+               }
+               if (lStatus == NO_ERROR) {
+                   mDirectOutput = out;
+                   ALOGV(" \n set sucessful for AudioStreamOutDirect");
+               } else {
+                   ALOGE(" \n set Failed for AudioStreamOutDirect");
+                   delete out;
+               }
+            }
+            else {
+                   ALOGE(" \n AudioHardware::AudioStreamOutDirect is already open");
+            }
+            return mDirectOutput;
+        } else
+#endif
+	    if (flags & AUDIO_OUTPUT_FLAG_LPA) {
+			status_t err = BAD_VALUE;
+#if 0
+            if (mOutput) {
+                if (status) {
+                  *status = INVALID_OPERATION;
+                }
+                ALOGE(" AudioHardware::openOutputStream Only one output stream allowed \n");
+                return 0;
+            }
+#endif
+            // create new output LPA stream
+            AudioSessionOutLPA* out = NULL;
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+            out = new AudioSessionOutLPA(this, devices, *format, *channels,*sampleRate,0,&err);
+            if(err != NO_ERROR) {
+                delete out;
+                out = NULL;
+            }
+#endif
+            if (status) *status = err;
+            mOutputLPA = out;
+            return mOutputLPA;
+
+        } else {
+#if 0
+            ALOGV(" AudioHardware::openOutputStream AudioStreamOutMSM8x60 output stream \n");
+            // only one output stream allowed
+            if (mOutput) {
+                if (status) {
+                  *status = INVALID_OPERATION;
+                }
+                ALOGE(" AudioHardware::openOutputStream Only one output stream allowed \n");
+                return 0;
+            }
+#endif
+            // create new output stream
+            AudioStreamOutMSM8x60* out = new AudioStreamOutMSM8x60();
+            lStatus = out->set(this, devices, format, channels, sampleRate);
+            if (status) {
+                *status = lStatus;
+            }
+            if (lStatus == NO_ERROR) {
+                mOutput = out;
+            } else {
+                delete out;
+            }
+            return mOutput;
+        }
+    }
+    return NULL;
+}
+
+
+void AudioHardware::closeOutputStream(AudioStreamOut* out) {
+    Mutex::Autolock lock(mLock);
+    if ((mOutput == 0
+#ifdef QCOM_VOIP_ENABLED
+        && mDirectOutput == 0
+#endif
+        && mOutputLPA == 0) || ((mOutput != out)
+#ifdef QCOM_VOIP_ENABLED
+         && (mDirectOutput != out)
+#endif
+       && (mOutputLPA != out))) {
+        ALOGW("Attempt to close invalid output stream");
+    }
+    else if (mOutput == out) {
+        delete mOutput;
+        mOutput = 0;
+    }
+#ifdef QCOM_VOIP_ENABLED
+    else if (mDirectOutput == out) {
+        ALOGV(" deleting  mDirectOutput \n");
+        delete mDirectOutput;
+        mDirectOutput = 0;
+    }
+#endif
+    else if (mOutputLPA == out) {
+	    ALOGV(" deleting  mOutputLPA \n");
+        delete mOutputLPA;
+        mOutputLPA = 0;
+	}
+}
+
+AudioStreamIn* AudioHardware::openInputStream(
+        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status,
+        AudioSystem::audio_in_acoustics acoustic_flags)
+{
+    // check for valid input source
+    if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) {
+        return 0;
+    }
+
+    mLock.lock();
+#ifdef QCOM_VOIP_ENABLED
+    if(devices == AudioSystem::DEVICE_IN_COMMUNICATION) {
+        ALOGE("Create Audio stream Voip \n");
+        AudioStreamInVoip* inVoip = new AudioStreamInVoip();
+        status_t lStatus = NO_ERROR;
+        lStatus =  inVoip->set(this, devices, format, channels, sampleRate, acoustic_flags);
+        if (status) {
+            *status = lStatus;
+        }
+        if (lStatus != NO_ERROR) {
+            ALOGE(" Error creating voip input \n");
+            mLock.unlock();
+            delete inVoip;
+            return 0;
+        }
+        mVoipInputs.add(inVoip);
+        mLock.unlock();
+        return inVoip;
+    } else
+#endif
+    {
+        AudioStreamInMSM8x60* in8x60 = new AudioStreamInMSM8x60();
+        status_t lStatus = in8x60->set(this, devices, format, channels, sampleRate, acoustic_flags);
+        if (status) {
+            *status = lStatus;
+        }
+        if (lStatus != NO_ERROR) {
+            ALOGE("Error creating Audio stream AudioStreamInMSM8x60 \n");
+            mLock.unlock();
+            delete in8x60;
+            return 0;
+        }
+        mInputs.add(in8x60);
+        mLock.unlock();
+        return in8x60;
+    }
+}
+
+void AudioHardware::closeInputStream(AudioStreamIn* in) {
+    Mutex::Autolock lock(mLock);
+
+    ssize_t index = -1;
+    if((index = mInputs.indexOf((AudioStreamInMSM8x60 *)in)) >= 0) {
+        ALOGV("closeInputStream AudioStreamInMSM8x60");
+        mLock.unlock();
+        delete mInputs[index];
+        mLock.lock();
+        mInputs.removeAt(index);
+    }
+#ifdef QCOM_VOIP_ENABLED
+    else if ((index = mVoipInputs.indexOf((AudioStreamInVoip *)in)) >= 0) {
+        ALOGV("closeInputStream mVoipInputs");
+        mLock.unlock();
+        delete mVoipInputs[index];
+        mLock.lock();
+        mInputs.removeAt(index);
+    }
+#endif
+    else {
+        ALOGE("Attempt to close invalid input stream");
+    }
+}
+
+status_t AudioHardware::setMode(int mode)
+{
+    status_t status = AudioHardwareBase::setMode(mode);
+    if (status == NO_ERROR) {
+        // make sure that doAudioRouteOrMute() is called by doRouting()
+        // even if the new device selected is the same as current one.
+        clearCurDevice();
+    }
+    return status;
+}
+
+bool AudioHardware::checkOutputStandby()
+{
+    if (mOutput)
+        if (!mOutput->checkStandby())
+            return false;
+
+    return true;
+}
+
+status_t AudioHardware::setMicMute(bool state)
+{
+    Mutex::Autolock lock(mLock);
+    return setMicMute_nosync(state);
+}
+
+// always call with mutex held
+status_t AudioHardware::setMicMute_nosync(bool state)
+{
+    int session_id = 0;
+    if (mMicMute != state) {
+        mMicMute = state;
+        ALOGD("setMicMute_nosync calling voice mute with the mMicMute %d", mMicMute);
+        if(isStreamOnAndActive(VOICE_CALL)) {
+             session_id = voice_session_id;
+             voice_session_mute = mMicMute;
+#ifdef QCOM_VOIP_ENABLED
+        } else if (isStreamOnAndActive(VOIP_CALL)) {
+            session_id = voip_session_id;
+            voip_session_mute = mMicMute;
+#endif
+        } else {
+            ALOGE(" unknown voice stream");
+            return -1;
+        }
+#ifdef LEGACY_QCOM_VOICE
+        msm_set_voice_tx_mute(mMicMute);
+#else
+        msm_set_voice_tx_mute_ext(mMicMute,session_id);
+#endif
+    }
+    return NO_ERROR;
+}
+
+status_t AudioHardware::getMicMute(bool* state)
+{
+    int session_id = 0;
+    if(isStreamOnAndActive(VOICE_CALL)) {
+          session_id = voice_session_id;
+          *state = mMicMute = voice_session_mute;
+#ifdef QCOM_VOIP_ENABLED
+    } else if (isStreamOnAndActive(VOIP_CALL)) {
+           session_id = voip_session_id;
+           *state = mMicMute = voip_session_mute;
+#endif
+    } else
+         *state = mMicMute;
+    return NO_ERROR;
+}
+
+status_t AudioHardware::setParameters(const String8& keyValuePairs)
+{
+    AudioParameter param = AudioParameter(keyValuePairs);
+    int rc = 0;
+    String8 value;
+    String8 key;
+    const char BT_NREC_KEY[] = "bt_headset_nrec";
+    const char BT_NAME_KEY[] = "bt_headset_name";
+    const char BT_NREC_VALUE_ON[] = "on";
+#ifdef QCOM_FM_ENABLED
+    const char FM_NAME_KEY[] = "FMRadioOn";
+    const char FM_VALUE_HANDSET[] = "handset";
+    const char FM_VALUE_SPEAKER[] = "speaker";
+    const char FM_VALUE_HEADSET[] = "headset";
+    const char FM_VALUE_FALSE[] = "false";
+#endif
+#ifdef HTC_ACOUSTIC_AUDIO
+    const char ACTIVE_AP[] = "active_ap";
+    const char EFFECT_ENABLED[] = "sound_effect_enable";
+#endif
+
+    ALOGV("setParameters() %s", keyValuePairs.string());
+
+    if (keyValuePairs.length() == 0) return BAD_VALUE;
+
+    key = String8(BT_NREC_KEY);
+    if (param.get(key, value) == NO_ERROR) {
+        if (value == BT_NREC_VALUE_ON) {
+            mBluetoothNrec = true;
+        } else {
+            mBluetoothNrec = false;
+            ALOGI("Turning noise reduction and echo cancellation off for BT "
+                 "headset");
+        }
+    }
+    key = String8(BTHEADSET_VGS);
+    if (param.get(key, value) == NO_ERROR) {
+        if (value == BT_NREC_VALUE_ON) {
+            mBluetoothVGS = true;
+        } else {
+            mBluetoothVGS = false;
+        }
+    }
+    key = String8(BT_NAME_KEY);
+    if (param.get(key, value) == NO_ERROR) {
+#ifdef HTC_ACOUSTIC_AUDIO
+        mBluetoothIdTx = 0;
+        mBluetoothIdRx = 0;
+        for (int i = 0; i < mNumBTEndpoints; i++) {
+            if (!strcasecmp(value.string(), mBTEndpoints[i].name)) {
+                mBluetoothIdTx = mBTEndpoints[i].tx;
+                mBluetoothIdRx = mBTEndpoints[i].rx;
+                ALOGD("Using custom acoustic parameters for %s", value.string());
+                break;
+            }
+        }
+        if (mBluetoothIdTx == 0) {
+            ALOGD("Using default acoustic parameters "
+                 "(%s not in acoustic database)", value.string());
+        }
+#endif
+        doRouting(NULL);
+    }
+
+    key = String8(DUALMIC_KEY);
+    if (param.get(key, value) == NO_ERROR) {
+        if (value == "true") {
+            dualmic_enabled = true;
+            ALOGI("DualMic feature Enabled");
+        } else {
+            dualmic_enabled = false;
+            ALOGI("DualMic feature Disabled");
+        }
+        doRouting(NULL);
+    }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+    key = String8(ANC_KEY);
+    if (param.get(key, value) == NO_ERROR) {
+        if (value == "true") {
+          ALOGE("Enabling ANC setting in the setparameter\n");
+          anc_setting= true;
+        } else {
+           ALOGE("Disabling ANC setting in the setparameter\n");
+           anc_setting= false;
+           //disabling ANC feature.
+           enableANC(0,cur_rx);
+           anc_running = false;
+        }
+     doRouting(NULL);
+    }
+#endif
+
+    key = String8(TTY_MODE_KEY);
+    if (param.get(key, value) == NO_ERROR) {
+        if (value == "full") {
+            mTtyMode = TTY_FULL;
+        } else if (value == "hco") {
+            mTtyMode = TTY_HCO;
+        } else if (value == "vco") {
+            mTtyMode = TTY_VCO;
+        } else {
+            mTtyMode = TTY_OFF;
+        }
+        if(mMode != AudioSystem::MODE_IN_CALL){
+           return NO_ERROR;
+        }
+        ALOGI("Changed TTY Mode=%s", value.string());
+        if((mMode == AudioSystem::MODE_IN_CALL) &&
+           (cur_rx == DEVICE_HEADSET_RX) &&
+           (cur_tx == DEVICE_HEADSET_TX))
+           doRouting(NULL);
+    }
+#ifdef HTC_ACOUSTIC_AUDIO
+    key = String8(ACTIVE_AP);
+    if (param.get(key, value) == NO_ERROR) {
+        const char* active_ap = value.string();
+        ALOGD("Active AP = %s", active_ap);
+        strcpy(mActiveAP, active_ap);
+
+        const char* dsp_effect = "\0";
+        key = String8(DSP_EFFECT_KEY);
+        if (param.get(key, value) == NO_ERROR) {
+            ALOGD("DSP Effect = %s", value.string());
+            dsp_effect = value.string();
+            strcpy(mEffect, dsp_effect);
+        }
+
+        key = String8(EFFECT_ENABLED);
+        if (param.get(key, value) == NO_ERROR) {
+            const char* sound_effect_enable = value.string();
+            ALOGD("Sound Effect Enabled = %s", sound_effect_enable);
+            if (value == "on") {
+                mEffectEnabled = true;
+                if (support_aic3254)
+                    aic3254_config(get_snd_dev());
+            } else {
+                strcpy(mEffect, "\0");
+                mEffectEnabled = false;
+            }
+        }
+    }
+#endif
+
+    return NO_ERROR;
+}
+
+String8 AudioHardware::getParameters(const String8& keys)
+{
+    AudioParameter param = AudioParameter(keys);
+    String8 value;
+
+    String8 key = String8(DUALMIC_KEY);
+    if (param.get(key, value) == NO_ERROR) {
+        value = String8(dualmic_enabled ? "true" : "false");
+        param.add(key, value);
+    }
+#ifdef QCOM_FM_ENABLED
+    key = String8("Fm-radio");
+    if ( param.get(key,value) == NO_ERROR ) {
+        if ( getNodeByStreamType(FM_RADIO) ) {
+            param.addInt(String8("isFMON"), true );
+        }
+    }
+#endif
+    key = String8(BTHEADSET_VGS);
+    if (param.get(key, value) == NO_ERROR) {
+        if(mBluetoothVGS)
+           param.addInt(String8("isVGS"), true);
+    }
+    key = String8(ECHO_SUPRESSION);
+    if (param.get(key, value) == NO_ERROR) {
+        value = String8("yes");
+        param.add(key, value);
+    }
+
+#ifdef HTC_ACOUSTIC_AUDIO
+    key = String8(DSP_EFFECT_KEY);
+    if (param.get(key, value) == NO_ERROR) {
+        value = String8(mCurDspProfile);
+        param.add(key, value);
+    }
+#endif
+    ALOGV("AudioHardware::getParameters() %s", param.toString().string());
+    return param.toString();
+}
+
+
+static unsigned calculate_audpre_table_index(unsigned index)
+{
+    switch (index) {
+        case 48000:    return SAMP_RATE_INDX_48000;
+        case 44100:    return SAMP_RATE_INDX_44100;
+        case 32000:    return SAMP_RATE_INDX_32000;
+        case 24000:    return SAMP_RATE_INDX_24000;
+        case 22050:    return SAMP_RATE_INDX_22050;
+        case 16000:    return SAMP_RATE_INDX_16000;
+        case 12000:    return SAMP_RATE_INDX_12000;
+        case 11025:    return SAMP_RATE_INDX_11025;
+        case 8000:    return SAMP_RATE_INDX_8000;
+        default:     return -1;
+    }
+}
+size_t AudioHardware::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+    if (format != AudioSystem::PCM_16_BIT){
+        ALOGW("getInputBufferSize bad format: %d", format);
+        return 0;
+    }
+    if (channelCount < 1 || channelCount > 2) {
+        ALOGW("getInputBufferSize bad channel count: %d", channelCount);
+        return 0;
+    }
+
+    if (sampleRate == 8000) {
+       return 320*channelCount;
+    } else if (sampleRate == 16000){
+       return 640*channelCount;
+    } else {
+        /*
+            Return pcm record buffer size based on the sampling rate:
+            If sampling rate >= 44.1 Khz, use 512 samples/channel pcm recording and
+            If sampling rate < 44.1 Khz, use 256 samples/channel pcm recording
+        */
+       if(sampleRate >= 44100){
+           return 1024*channelCount;
+       } else {
+           return 512*channelCount;
+       }
+    }
+}
+
+static status_t set_volume_rpc(uint32_t device,
+                               uint32_t method,
+                               uint32_t volume)
+{
+    ALOGV("set_volume_rpc(%d, %d, %d)\n", device, method, volume);
+
+    if (device == -1UL) return NO_ERROR;
+     return NO_ERROR;
+}
+
+status_t AudioHardware::setVoiceVolume(float v)
+{
+    int session_id = 0;
+    if (v < 0.0) {
+        ALOGW("setVoiceVolume(%f) under 0.0, assuming 0.0\n", v);
+        v = 0.0;
+    } else if (v > 1.0) {
+        ALOGW("setVoiceVolume(%f) over 1.0, assuming 1.0\n", v);
+        v = 1.0;
+    }
+
+#ifdef HTC_ACOUSTIC_AUDIO
+    mVoiceVolume = v;
+#endif
+
+    if(isStreamOnAndActive(VOICE_CALL)) {
+        session_id = voice_session_id;
+    }
+#ifdef QCOM_VOIP_ENABLED
+    else if (isStreamOnAndActive(VOIP_CALL)) {
+        session_id = voip_session_id;
+    }
+#endif
+    else {
+        ALOGE(" unknown stream ");
+        return -1;
+    }
+    int vol = lrint(v * 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
+    vol = 5 - (vol/20);
+    ALOGD("setVoiceVolume(%f)\n", v);
+    ALOGI("Setting in-call volume to %d (available range is 5(MIN VOLUME)  to 0(MAX VOLUME)\n", vol);
+
+#ifdef LEGACY_QCOM_VOICE
+    if (msm_set_voice_rx_vol(vol)) {
+        ALOGE("msm_set_voice_rx_vol(%d) failed errno = %d", vol, errno);
+        return -1;
+    }
+#else
+    if(msm_set_voice_rx_vol_ext(vol,session_id)) {
+        ALOGE("msm_set_voice_rx_vol(%d) failed errno = %d",vol,errno);
+        return -1;
+    }
+#endif
+    ALOGV("msm_set_voice_rx_vol(%d) succeeded session_id %d",vol,session_id);
+    return NO_ERROR;
+}
+
+#ifdef QCOM_FM_ENABLED
+status_t AudioHardware::setFmVolume(float v)
+{
+    int vol = android::AudioSystem::logToLinear( (v?(v + 0.005):v) );
+    if ( vol > 100 ) {
+        vol = 100;
+    }
+    else if ( vol < 0 ) {
+        vol = 0;
+    }
+    ALOGV("setFmVolume(%f)\n", v);
+    ALOGV("Setting FM volume to %d (available range is 0 to 100)\n", vol);
+    Routing_table* temp = NULL;
+    temp = getNodeByStreamType(FM_RADIO);
+    if(temp == NULL){
+        ALOGV("No Active FM stream is running");
+        return NO_ERROR;
+    }
+    if(msm_set_volume(temp->dec_id, vol)) {
+        ALOGE("msm_set_volume(%d) failed for FM errno = %d",vol,errno);
+        return -1;
+    }
+    ALOGV("msm_set_volume(%d) for FM succeeded",vol);
+    return NO_ERROR;
+}
+#endif
+
+status_t AudioHardware::setMasterVolume(float v)
+{
+    Mutex::Autolock lock(mLock);
+    int vol = ceil(v * 7.0);
+    ALOGI("Set master volume to %d.\n", vol);
+
+    set_volume_rpc(SND_DEVICE_HANDSET, SND_METHOD_VOICE, vol);
+    set_volume_rpc(SND_DEVICE_SPEAKER, SND_METHOD_VOICE, vol);
+    set_volume_rpc(SND_DEVICE_BT,      SND_METHOD_VOICE, vol);
+    set_volume_rpc(SND_DEVICE_HEADSET, SND_METHOD_VOICE, vol);
+    //TBD - does HDMI require this handling
+
+    // We return an error code here to let the audioflinger do in-software
+    // volume on top of the maximum volume that we set through the SND API.
+    // return error - software mixer will handle it
+    return -1;
+}
+
+#ifdef HTC_ACOUSTIC_AUDIO
+status_t get_batt_temp(int *batt_temp) {
+    ALOGD("Enable ALT for speaker");
+
+    int i, fd, len;
+    char get_batt_temp[6] = { 0 };
+    const char *fn = "/sys/class/power_supply/battery/batt_temp";
+
+    if ((fd = open(fn, O_RDONLY)) < 0) {
+        ALOGE("Couldn't open sysfs file batt_temp");
+        return UNKNOWN_ERROR;
+    }
+
+    if ((len = read(fd, get_batt_temp, sizeof(get_batt_temp))) <= 1) {
+        ALOGE("read battery temp fail: %s", strerror(errno));
+        close(fd);
+        return BAD_VALUE;
+    }
+
+    *batt_temp = strtol(get_batt_temp, NULL, 10);
+    ALOGD("ALT batt_temp = %d", *batt_temp);
+
+    close(fd);
+    return NO_ERROR;
+}
+
+status_t do_tpa2051_control(int mode)
+{
+    int fd, rc;
+    int tpa_mode = 0;
+
+    if (mode) {
+        if (cur_rx == DEVICE_HEADSET_RX)
+            tpa_mode = TPA2051_MODE_VOICECALL_HEADSET;
+        else if (cur_rx == DEVICE_SPEAKER_RX)
+            tpa_mode = TPA2051_MODE_VOICECALL_SPKR;
+    } else {
+        switch (cur_rx) {
+            case DEVICE_FMRADIO_HEADSET_RX:
+                tpa_mode = TPA2051_MODE_FM_HEADSET;
+                break;
+            case DEVICE_FMRADIO_SPEAKER_RX:
+                tpa_mode = TPA2051_MODE_FM_SPKR;
+                break;
+            case DEVICE_SPEAKER_HEADSET_RX:
+                tpa_mode = TPA2051_MODE_RING;
+                break;
+            case DEVICE_HEADSET_RX:
+                tpa_mode = TPA2051_MODE_PLAYBACK_HEADSET;
+                break;
+            case DEVICE_SPEAKER_RX:
+                tpa_mode = TPA2051_MODE_PLAYBACK_SPKR;
+                break;
+            default:
+                break;
+        }
+    }
+
+    fd = open("/dev/tpa2051d3", O_RDWR);
+    if (fd < 0) {
+        ALOGE("can't open /dev/tpa2051d3 %d", fd);
+        return -1;
+    }
+
+    if (tpa_mode != cur_tpa_mode) {
+        cur_tpa_mode = tpa_mode;
+        rc = ioctl(fd, TPA2051_SET_MODE, &tpa_mode);
+        if (rc < 0)
+            ALOGE("ioctl TPA2051_SET_MODE failed: %s", strerror(errno));
+        else
+            ALOGD("update TPA2051_SET_MODE to mode %d success", tpa_mode);
+    }
+
+    close(fd);
+    return 0;
+}
+#endif
+
+static status_t do_route_audio_rpc(uint32_t device,
+                                   int mode, bool mic_mute)
+{
+    if(device == -1)
+        return 0;
+
+    int new_rx_device = INVALID_DEVICE,new_tx_device = INVALID_DEVICE,fm_device = INVALID_DEVICE;
+    Routing_table* temp = NULL;
+    ALOGV("do_route_audio_rpc(%d, %d, %d)", device, mode, mic_mute);
+
+    if(device == SND_DEVICE_HANDSET) {
+        new_rx_device = DEVICE_HANDSET_RX;
+        new_tx_device = DEVICE_HANDSET_TX;
+        ALOGV("In HANDSET");
+    }
+    else if(device == SND_DEVICE_SPEAKER) {
+        new_rx_device = DEVICE_SPEAKER_RX;
+        new_tx_device = DEVICE_SPEAKER_TX;
+        ALOGV("In SPEAKER");
+    }
+    else if(device == SND_DEVICE_HEADSET) {
+        new_rx_device = DEVICE_HEADSET_RX;
+        new_tx_device = DEVICE_HEADSET_TX;
+        ALOGV("In HEADSET");
+    }
+    else if(device == SND_DEVICE_NO_MIC_HEADSET) {
+        new_rx_device = DEVICE_HEADSET_RX;
+        new_tx_device = DEVICE_HANDSET_TX;
+        ALOGV("In NO MIC HEADSET");
+    }
+#ifdef QCOM_FM_ENABLED
+    else if (device == SND_DEVICE_FM_HANDSET) {
+        fm_device = DEVICE_FMRADIO_HANDSET_RX;
+        ALOGV("In FM HANDSET");
+    }
+    else if(device == SND_DEVICE_FM_SPEAKER) {
+        fm_device = DEVICE_FMRADIO_SPEAKER_RX;
+        ALOGV("In FM SPEAKER");
+    }
+    else if(device == SND_DEVICE_FM_HEADSET) {
+        fm_device = DEVICE_FMRADIO_HEADSET_RX;
+        ALOGV("In FM HEADSET");
+    }
+#endif
+#ifdef SAMSUNG_AUDIO
+    else if(device == SND_DEVICE_IN_S_SADC_OUT_HANDSET) {
+        new_rx_device = DEVICE_HANDSET_CALL_RX;
+        new_tx_device = DEVICE_DUALMIC_HANDSET_TX;
+        ALOGV("In DUALMIC_CALL_HANDSET");
+        if(DEV_ID(new_tx_device) == INVALID_DEVICE) {
+            new_tx_device = DEVICE_HANDSET_CALL_TX;
+            ALOGV("Falling back to HANDSET_CALL_RX AND HANDSET_CALL_TX as no DUALMIC_HANDSET_TX support found");
+        }
+    }
+#else
+    else if(device == SND_DEVICE_IN_S_SADC_OUT_HANDSET) {
+        new_rx_device = DEVICE_HANDSET_RX;
+        new_tx_device = DEVICE_DUALMIC_HANDSET_TX;
+        ALOGV("In DUALMIC_HANDSET");
+        if(DEV_ID(new_tx_device) == INVALID_DEVICE) {
+            new_tx_device = DEVICE_HANDSET_TX;
+            ALOGV("Falling back to HANDSET_RX AND HANDSET_TX as no DUALMIC_HANDSET_TX support found");
+        }
+    }
+#endif
+    else if(device == SND_DEVICE_IN_S_SADC_OUT_SPEAKER_PHONE) {
+        new_rx_device = DEVICE_SPEAKER_RX;
+        new_tx_device = DEVICE_DUALMIC_SPEAKER_TX;
+        ALOGV("In DUALMIC_SPEAKER");
+        if(DEV_ID(new_tx_device) == INVALID_DEVICE) {
+            new_tx_device = DEVICE_SPEAKER_TX;
+            ALOGV("Falling back to SPEAKER_RX AND SPEAKER_TX as no DUALMIC_SPEAKER_TX support found");
+        }
+    }
+    else if(device == SND_DEVICE_TTY_FULL) {
+        new_rx_device = DEVICE_TTY_HEADSET_MONO_RX;
+        new_tx_device = DEVICE_TTY_HEADSET_MONO_TX;
+        ALOGV("In TTY_FULL");
+    }
+    else if(device == SND_DEVICE_TTY_VCO) {
+        new_rx_device = DEVICE_TTY_HEADSET_MONO_RX;
+        new_tx_device = DEVICE_HANDSET_TX;
+        ALOGV("In TTY_VCO");
+    }
+    else if(device == SND_DEVICE_TTY_HCO) {
+        new_rx_device = DEVICE_HANDSET_RX;
+        new_tx_device = DEVICE_TTY_HEADSET_MONO_TX;
+        ALOGV("In TTY_HCO");
+    }
+#ifdef HTC_ACOUSTIC_AUDIO
+    else if((device == SND_DEVICE_BT) ||
+            (device == SND_DEVICE_BT_EC_OFF)) {
+#else
+    else if(device == SND_DEVICE_BT) {
+#endif
+        new_rx_device = DEVICE_BT_SCO_RX;
+        new_tx_device = DEVICE_BT_SCO_TX;
+        ALOGV("In BT_HCO");
+    }
+    else if(device == SND_DEVICE_HEADSET_AND_SPEAKER) {
+        new_rx_device = DEVICE_SPEAKER_HEADSET_RX;
+        new_tx_device = DEVICE_HEADSET_TX;
+        ALOGV("In DEVICE_SPEAKER_HEADSET_RX and DEVICE_HEADSET_TX");
+        if(DEV_ID(new_rx_device) == INVALID_DEVICE) {
+             new_rx_device = DEVICE_HEADSET_RX;
+             ALOGV("Falling back to HEADSET_RX AND HEADSET_TX as no combo device support found");
+        }
+    }
+    else if(device == SND_DEVICE_HEADPHONE_AND_SPEAKER) {
+        new_rx_device = DEVICE_SPEAKER_HEADSET_RX;
+        new_tx_device = DEVICE_HANDSET_TX;
+        ALOGV("In DEVICE_SPEAKER_HEADSET_RX and DEVICE_HANDSET_TX");
+        if(DEV_ID(new_rx_device) == INVALID_DEVICE) {
+             new_rx_device = DEVICE_HEADSET_RX;
+             ALOGV("Falling back to HEADSET_RX AND HANDSET_TX as no combo device support found");
+        }
+    }
+    else if (device == SND_DEVICE_HDMI) {
+        new_rx_device = DEVICE_HDMI_STERO_RX;
+        new_tx_device = cur_tx;
+        ALOGI("In DEVICE_HDMI_STERO_RX and cur_tx");
+    }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+    else if(device == SND_DEVICE_ANC_HEADSET) {
+        new_rx_device = DEVICE_ANC_HEADSET_STEREO_RX;
+        new_tx_device = DEVICE_HEADSET_TX;
+        ALOGI("In ANC HEADSET");
+    }
+    else if(device == SND_DEVICE_NO_MIC_ANC_HEADSET) {
+        new_rx_device = DEVICE_ANC_HEADSET_STEREO_RX;
+        new_tx_device = DEVICE_HANDSET_TX;
+        ALOGI("In ANC HEADPhone");
+    }
+#endif
+#ifdef QCOM_FM_ENABLED
+    else if(device == SND_DEVICE_FM_TX){
+        new_rx_device = DEVICE_FMRADIO_STEREO_RX;
+        ALOGI("In DEVICE_FMRADIO_STEREO_RX and cur_tx");
+    }
+#endif
+    else if(device == SND_DEVICE_SPEAKER_TX) {
+        new_rx_device = cur_rx;
+        new_tx_device = DEVICE_SPEAKER_TX;
+        ALOGI("In SPEAKER_TX cur_rx = %d\n", cur_rx);
+    }
+#ifdef SAMSUNG_AUDIO
+#if 0
+    else if (device == SND_DEVICE_VOIP_HANDSET) {
+        new_rx_device = DEVICE_HANDSET_VOIP_RX;
+        new_tx_device = DEVICE_HANDSET_VOIP_TX;
+        ALOGD("In VOIP HANDSET");
+    }
+    else if (device == SND_DEVICE_VOIP_SPEAKER) {
+        new_rx_device = DEVICE_SPEAKER_VOIP_RX;
+        new_tx_device = DEVICE_SPEAKER_VOIP_TX;
+        ALOGD("In VOIP SPEAKER");
+    }
+    else if (device == SND_DEVICE_VOIP_HEADSET) {
+        new_rx_device = DEVICE_HEADSET_VOIP_RX;
+        new_tx_device = DEVICE_HEADSET_VOIP_TX;
+        ALOGD("In VOIP HEADSET");
+    }
+#endif
+    else if (device == SND_DEVICE_CALL_HANDSET) {
+        new_rx_device = DEVICE_HANDSET_CALL_RX;
+        new_tx_device = DEVICE_HANDSET_CALL_TX;
+        ALOGD("In CALL HANDSET");
+    }
+    else if (device == SND_DEVICE_CALL_SPEAKER) {
+        new_rx_device = DEVICE_SPEAKER_CALL_RX;
+        new_tx_device = DEVICE_SPEAKER_CALL_TX;
+        ALOGD("In CALL SPEAKER");
+    }
+    else if (device == SND_DEVICE_CALL_HEADSET) {
+        new_rx_device = DEVICE_HEADSET_CALL_RX;
+        new_tx_device = DEVICE_HEADSET_CALL_TX;
+        ALOGD("In CALL HEADSET");
+    }
+    else if(device == SND_DEVICE_VR_SPEAKER) {
+        new_rx_device = DEVICE_SPEAKER_RX;
+        new_tx_device = DEVICE_SPEAKER_VR_TX;
+        ALOGV("In VR SPEAKER");
+    }
+    else if(device == SND_DEVICE_VR_HEADSET) {
+        new_rx_device = DEVICE_HEADSET_RX;
+        new_tx_device = DEVICE_HEADSET_VR_TX;
+        ALOGV("In VR HEADSET");
+    }
+#endif
+#ifdef BACK_MIC_CAMCORDER
+    else if (device == SND_DEVICE_BACK_MIC_CAMCORDER) {
+        new_rx_device = cur_rx;
+        new_tx_device = DEVICE_CAMCORDER_TX;
+        ALOGV("In BACK_MIC_CAMCORDER");
+    }
+#endif
+    if(new_rx_device != INVALID_DEVICE)
+        ALOGD("new_rx = %d", DEV_ID(new_rx_device));
+    if(new_tx_device != INVALID_DEVICE)
+        ALOGD("new_tx = %d", DEV_ID(new_tx_device));
+
+    if ((mode == AudioSystem::MODE_IN_CALL) && !isStreamOn(VOICE_CALL)) {
+#ifdef LEGACY_QCOM_VOICE
+        msm_start_voice();
+#endif
+        ALOGV("Going to enable RX/TX device for voice stream");
+            // Routing Voice
+            if ( (new_rx_device != INVALID_DEVICE) && (new_tx_device != INVALID_DEVICE))
+            {
+#ifdef QCOM_ACDB_ENABLED
+                initACDB();
+                acdb_loader_send_voice_cal(ACDB_ID(new_rx_device),ACDB_ID(new_tx_device));
+#endif
+                ALOGD("Starting voice on Rx %d and Tx %d device", DEV_ID(new_rx_device), DEV_ID(new_tx_device));
+                msm_route_voice(DEV_ID(new_rx_device),DEV_ID(new_tx_device), 1);
+            }
+            else
+            {
+                return -1;
+            }
+
+            if(cur_rx != INVALID_DEVICE && (enableDevice(cur_rx,0) == -1))
+                    return -1;
+
+            if(cur_tx != INVALID_DEVICE&&(enableDevice(cur_tx,0) == -1))
+                    return -1;
+
+           //Enable RX device
+           if(new_rx_device !=INVALID_DEVICE && (enableDevice(new_rx_device,1) == -1))
+               return -1;
+            //Enable TX device
+           if(new_tx_device !=INVALID_DEVICE && (enableDevice(new_tx_device,1) == -1))
+               return -1;
+#ifdef LEGACY_QCOM_VOICE
+           msm_set_voice_tx_mute(0);
+#else
+           voice_session_id = msm_get_voc_session(VOICE_SESSION_NAME);
+           if(voice_session_id <=0) {
+                ALOGE("voice session invalid");
+                return 0;
+           }
+           msm_start_voice_ext(voice_session_id);
+           msm_set_voice_tx_mute_ext(voice_session_mute,voice_session_id);
+#endif
+
+           if(!isDeviceListEmpty())
+               updateDeviceInfo(new_rx_device,new_tx_device);
+            cur_rx = new_rx_device;
+            cur_tx = new_tx_device;
+            addToTable(0,cur_rx,cur_tx,VOICE_CALL,true);
+    }
+    else if ((mode == AudioSystem::MODE_NORMAL) && isStreamOnAndActive(VOICE_CALL)) {
+        ALOGV("Going to disable RX/TX device during end of voice call");
+        temp = getNodeByStreamType(VOICE_CALL);
+        if(temp == NULL)
+            return 0;
+
+        // Ending voice call
+        ALOGD("Ending Voice call");
+#ifdef LEGACY_QCOM_VOICE
+        msm_end_voice();
+#else
+        msm_end_voice_ext(voice_session_id);
+        voice_session_id = 0;
+        voice_session_mute = 0;
+#endif
+
+        if((temp->dev_id != INVALID_DEVICE && temp->dev_id_tx != INVALID_DEVICE)
+#ifdef QCOM_VOIP_ENABLED
+        && (!isStreamOn(VOIP_CALL))
+#endif
+        ) {
+           enableDevice(temp->dev_id,0);
+           enableDevice(temp->dev_id_tx,0);
+        }
+        deleteFromTable(VOICE_CALL);
+        updateDeviceInfo(new_rx_device,new_tx_device);
+        if(new_rx_device != INVALID_DEVICE && new_tx_device != INVALID_DEVICE) {
+            cur_rx = new_rx_device;
+            cur_tx = new_tx_device;
+        }
+    }
+    else {
+        ALOGD("updateDeviceInfo() called for default case");
+        updateDeviceInfo(new_rx_device,new_tx_device);
+    }
+#ifdef HTC_ACOUSTIC_AUDIO
+    if (support_tpa2051)
+        do_tpa2051_control(mode ^1);
+#endif
+    return NO_ERROR;
+}
+
+// always call with mutex held
+status_t AudioHardware::doAudioRouteOrMute(uint32_t device)
+{
+// BT acoustics is not supported. This might be used by OEMs. Hence commenting
+// the code and not removing it.
+#if 0
+    if (device == (uint32_t)SND_DEVICE_BT || device == (uint32_t)SND_DEVICE_CARKIT) {
+        if (mBluetoothId) {
+            device = mBluetoothId;
+        } else if (!mBluetoothNrec) {
+            device = SND_DEVICE_BT_EC_OFF;
+        }
+    }
+#endif
+
+#ifdef HTC_ACOUSTIC_AUDIO
+    if (device == SND_DEVICE_BT) {
+        if (!mBluetoothNrec)
+            device = SND_DEVICE_BT_EC_OFF;
+    }
+
+    if (support_aic3254) {
+        aic3254_config(device);
+        do_aic3254_control(device);
+    }
+
+    getACDB(device);
+#endif
+
+    if (isStreamOnAndActive(VOICE_CALL) && mMicMute == false)
+        msm_set_voice_tx_mute(0);
+
+#ifdef HTC_ACOUSTIC_AUDIO
+    if (isInCall())
+        setVoiceVolume(mVoiceVolume);
+#endif
+    ALOGV("doAudioRouteOrMute() device %x, mMode %d, mMicMute %d", device, mMode, mMicMute);
+    return do_route_audio_rpc(device, mMode, mMicMute);
+}
+
+#ifdef HTC_ACOUSTIC_AUDIO
+status_t AudioHardware::set_mRecordState(bool onoff) {
+    mRecordState = onoff;
+    return 0;
+}
+
+status_t AudioHardware::get_mRecordState(void) {
+    return mRecordState;
+}
+
+status_t AudioHardware::get_snd_dev(void) {
+    return mCurSndDevice;
+}
+
+void AudioHardware::getACDB(uint32_t device) {
+    rx_htc_acdb = 0;
+    tx_htc_acdb = 0;
+
+    if (device == SND_DEVICE_BT) {
+        if (mBluetoothIdTx != 0) {
+            rx_htc_acdb = mBluetoothIdRx;
+            tx_htc_acdb = mBluetoothIdTx;
+        } else {
+            /* use default BT entry defined in AudioBTID.csv */
+            rx_htc_acdb = mBTEndpoints[0].rx;
+            tx_htc_acdb = mBTEndpoints[0].tx;
+        }
+    } else if (device == SND_DEVICE_CARKIT ||
+               device == SND_DEVICE_BT_EC_OFF) {
+        if (mBluetoothIdTx != 0) {
+            rx_htc_acdb = mBluetoothIdRx;
+            tx_htc_acdb = mBluetoothIdTx;
+        } else {
+            /* use default carkit entry defined in AudioBTID.csv */
+            rx_htc_acdb = mBTEndpoints[1].rx;
+            tx_htc_acdb = mBTEndpoints[1].tx;
+        }
+    }
+
+    ALOGV("getACDB: device = %d, HTC RX ACDB ID = %d, HTC TX ACDB ID = %d",
+         device, rx_htc_acdb, tx_htc_acdb);
+}
+
+status_t AudioHardware::do_aic3254_control(uint32_t device) {
+    ALOGD("do_aic3254_control device: %d mode: %d record: %d", device, mMode, mRecordState);
+
+    uint32_t new_aic_txmode = UPLINK_OFF;
+    uint32_t new_aic_rxmode = DOWNLINK_OFF;
+
+    Mutex::Autolock lock(mAIC3254ConfigLock);
+
+    if (isInCall()) {
+        switch (device) {
+            case SND_DEVICE_HEADSET:
+                new_aic_rxmode = CALL_DOWNLINK_EMIC_HEADSET;
+                new_aic_txmode = CALL_UPLINK_EMIC_HEADSET;
+                break;
+            case SND_DEVICE_SPEAKER:
+            case SND_DEVICE_SPEAKER_BACK_MIC:
+                new_aic_rxmode = CALL_DOWNLINK_IMIC_SPEAKER;
+                new_aic_txmode = CALL_UPLINK_IMIC_SPEAKER;
+                break;
+            case SND_DEVICE_HEADSET_AND_SPEAKER:
+            case SND_DEVICE_HEADSET_AND_SPEAKER_BACK_MIC:
+                new_aic_rxmode = RING_HEADSET_SPEAKER;
+                break;
+            case SND_DEVICE_NO_MIC_HEADSET:
+            case SND_DEVICE_NO_MIC_HEADSET_BACK_MIC:
+                new_aic_rxmode = CALL_DOWNLINK_IMIC_HEADSET;
+                new_aic_txmode = CALL_UPLINK_IMIC_HEADSET;
+                break;
+            case SND_DEVICE_HANDSET:
+            case SND_DEVICE_HANDSET_BACK_MIC:
+                new_aic_rxmode = CALL_DOWNLINK_IMIC_RECEIVER;
+                new_aic_txmode = CALL_UPLINK_IMIC_RECEIVER;
+                break;
+            default:
+                break;
+        }
+    } else {
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+        if (checkOutputStandby() && !isStreamOnAndActive(LPA_DECODE)) {
+#else
+        if (checkOutputStandby()) {
+#endif
+            if (device == SND_DEVICE_FM_HEADSET) {
+                new_aic_rxmode = FM_OUT_HEADSET;
+                new_aic_txmode = FM_IN_HEADSET;
+            } else if (device == SND_DEVICE_FM_SPEAKER) {
+                new_aic_rxmode = FM_OUT_SPEAKER;
+                new_aic_txmode = FM_IN_SPEAKER;
+            }
+        } else {
+            switch (device) {
+                case SND_DEVICE_HEADSET_AND_SPEAKER:
+                case SND_DEVICE_HEADSET_AND_SPEAKER_BACK_MIC:
+                case SND_DEVICE_HEADPHONE_AND_SPEAKER:
+                    new_aic_rxmode = RING_HEADSET_SPEAKER;
+                    break;
+                case SND_DEVICE_SPEAKER:
+                case SND_DEVICE_SPEAKER_BACK_MIC:
+                    new_aic_rxmode = PLAYBACK_SPEAKER;
+                    break;
+                case SND_DEVICE_HANDSET:
+                case SND_DEVICE_HANDSET_BACK_MIC:
+                    new_aic_rxmode = PLAYBACK_RECEIVER;
+                    break;
+                case SND_DEVICE_HEADSET:
+                case SND_DEVICE_NO_MIC_HEADSET:
+                case SND_DEVICE_NO_MIC_HEADSET_BACK_MIC:
+                    new_aic_rxmode = PLAYBACK_HEADSET;
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        if (mRecordState) {
+            switch (device) {
+                case SND_DEVICE_HEADSET:
+                    new_aic_txmode = VOICERECORD_EMIC;
+                    break;
+                case SND_DEVICE_HANDSET_BACK_MIC:
+                case SND_DEVICE_SPEAKER_BACK_MIC:
+                case SND_DEVICE_NO_MIC_HEADSET_BACK_MIC:
+                case SND_DEVICE_HEADSET_AND_SPEAKER_BACK_MIC:
+                    new_aic_txmode = VIDEORECORD_IMIC;
+                    break;
+                case SND_DEVICE_HANDSET:
+                case SND_DEVICE_SPEAKER:
+                case SND_DEVICE_NO_MIC_HEADSET:
+                case SND_DEVICE_HEADSET_AND_SPEAKER:
+                    new_aic_txmode = VOICERECORD_IMIC;
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    if (new_aic_rxmode != cur_aic_rx)
+        ALOGD("do_aic3254_control: set aic3254 rx to %d", new_aic_rxmode);
+    if (aic3254_ioctl(AIC3254_CONFIG_RX, new_aic_rxmode) >= 0)
+        cur_aic_rx = new_aic_rxmode;
+
+    if (new_aic_txmode != cur_aic_tx)
+        ALOGD("do_aic3254_control: set aic3254 tx to %d", new_aic_txmode);
+    if (aic3254_ioctl(AIC3254_CONFIG_TX, new_aic_txmode) >= 0)
+        cur_aic_tx = new_aic_txmode;
+
+    if (cur_aic_tx == UPLINK_OFF && cur_aic_rx == DOWNLINK_OFF && aic3254_enabled) {
+        strcpy(mCurDspProfile, "\0");
+        aic3254_enabled = false;
+        aic3254_powerdown();
+    } else if (cur_aic_tx != UPLINK_OFF || cur_aic_rx != DOWNLINK_OFF)
+        aic3254_enabled = true;
+
+    return NO_ERROR;
+}
+
+bool AudioHardware::isAic3254Device(uint32_t device) {
+    switch(device) {
+        case SND_DEVICE_HANDSET:
+        case SND_DEVICE_SPEAKER:
+        case SND_DEVICE_HEADSET:
+        case SND_DEVICE_NO_MIC_HEADSET:
+        case SND_DEVICE_FM_HEADSET:
+        case SND_DEVICE_HEADSET_AND_SPEAKER:
+        case SND_DEVICE_FM_SPEAKER:
+        case SND_DEVICE_HEADPHONE_AND_SPEAKER:
+        case SND_DEVICE_HANDSET_BACK_MIC:
+        case SND_DEVICE_SPEAKER_BACK_MIC:
+        case SND_DEVICE_NO_MIC_HEADSET_BACK_MIC:
+        case SND_DEVICE_HEADSET_AND_SPEAKER_BACK_MIC:
+            return true;
+            break;
+        default:
+            return false;
+            break;
+    }
+}
+
+status_t AudioHardware::aic3254_config(uint32_t device) {
+    ALOGD("aic3254_config: device %d enabled %d", device, aic3254_enabled);
+    char name[22] = "\0";
+    char aap[9] = "\0";
+
+    if ((!isAic3254Device(device) ||
+         !aic3254_enabled) &&
+        strlen(mCurDspProfile) != 0)
+        return NO_ERROR;
+
+    Mutex::Autolock lock(mAIC3254ConfigLock);
+
+    if (mMode == AudioSystem::MODE_IN_CALL) {
+        strcpy(name, "Phone_Default");
+        switch (device) {
+            case SND_DEVICE_HANDSET:
+            case SND_DEVICE_HANDSET_BACK_MIC:
+                strcpy(name, "Phone_Handset_Dualmic");
+                break;
+            case SND_DEVICE_HEADSET:
+            case SND_DEVICE_HEADSET_AND_SPEAKER:
+            case SND_DEVICE_HEADSET_AND_SPEAKER_BACK_MIC:
+            case SND_DEVICE_NO_MIC_HEADSET:
+                strcpy(name, "Phone_Headset");
+                break;
+            case SND_DEVICE_SPEAKER:
+                strcpy(name, "Phone_Speaker_Dualmic");
+                break;
+            default:
+                break;
+        }
+    } else {
+        if ((strcasecmp(mActiveAP, "Camcorder") == 0)) {
+            if (strlen(mEffect) != 0) {
+                strcpy(name, "Recording_");
+                strcat(name, mEffect);
+            } else
+                strcpy(name, "Playback_Default");
+        } else if (mRecordState) {
+            strcpy(name, "Record_Default");
+        } else if (strlen(mEffect) == 0 && !mEffectEnabled)
+            strcpy(name, "Playback_Default");
+        else {
+            if (mEffectEnabled)
+                strcpy(name, mEffect);
+
+            if ((strcasecmp(name, "Srs") == 0) ||
+                (strcasecmp(name, "Dolby") == 0)) {
+                strcpy(mEffect, name);
+                if (strcasecmp(mActiveAP, "Music") == 0)
+                    strcat(name, "_a");
+                else if (strcasecmp(mActiveAP, "Video") == 0)
+                    strcat(name, "_v");
+                if (device == SND_DEVICE_SPEAKER)
+                    strcat(name, "_spk");
+                else
+                    strcat(name, "_hp");
+            }
+        }
+    }
+
+    if (strcasecmp(mCurDspProfile, name)) {
+        ALOGD("aic3254_config: loading effect %s", name);
+        strcpy(mCurDspProfile, name);
+    } else {
+        ALOGD("aic3254_config: effect %s already loaded", name);
+        return NO_ERROR;
+    }
+
+    int rc = set_sound_effect(name);
+    if (rc < 0) {
+        ALOGE("Could not set sound effect %s: %d", name, rc);
+        return rc;
+    }
+
+    return NO_ERROR;
+}
+
+int AudioHardware::aic3254_ioctl(int cmd, const int argc) {
+    int rc = -1;
+    int (*set_aic3254_ioctl)(int, const int*);
+
+    set_aic3254_ioctl = (int (*)(int, const int*))::dlsym(acoustic, "set_aic3254_ioctl");
+    if ((*set_aic3254_ioctl) == 0) {
+        ALOGE("Could not open set_aic3254_ioctl()");
+        return rc;
+    }
+
+    rc = set_aic3254_ioctl(cmd, &argc);
+    if (rc < 0)
+        ALOGE("aic3254_ioctl failed");
+
+    return rc;
+}
+
+void AudioHardware::aic3254_powerdown() {
+    int rc = aic3254_ioctl(AIC3254_POWERDOWN, 0);
+    if (rc < 0)
+        ALOGE("aic3254_powerdown failed");
+    else
+        ALOGI("aic3254 powered off");
+}
+#endif
+
+status_t AudioHardware::doRouting(AudioStreamInMSM8x60 *input)
+{
+    Mutex::Autolock lock(mLock);
+    uint32_t outputDevices = mOutput->devices();
+    status_t ret = NO_ERROR;
+    int audProcess = (ADRC_DISABLE | EQ_DISABLE | RX_IIR_DISABLE);
+    int sndDevice = -1;
+
+
+
+    if (input != NULL) {
+        uint32_t inputDevice = input->devices();
+        ALOGI("do input routing device %x\n", inputDevice);
+        // ignore routing device information when we start a recording in voice
+        // call
+        // Recording will happen through currently active tx device
+        if((inputDevice == AudioSystem::DEVICE_IN_VOICE_CALL)
+#ifdef QCOM_FM_ENABLED
+           || (inputDevice == AudioSystem::DEVICE_IN_FM_RX)
+           || (inputDevice == AudioSystem::DEVICE_IN_FM_RX_A2DP)
+#endif
+        )
+            return NO_ERROR;
+        if (inputDevice != 0) {
+            if (inputDevice & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+                ALOGI("Routing audio to Bluetooth PCM\n");
+                sndDevice = SND_DEVICE_BT;
+#ifdef BACK_MIC_CAMCORDER
+            } else if (inputDevice & AudioSystem::DEVICE_IN_BACK_MIC) {
+                ALOGI("Routing audio to back mic (camcorder)");
+                sndDevice = SND_DEVICE_BACK_MIC_CAMCORDER;
+#endif
+            } else if (inputDevice & AudioSystem::DEVICE_IN_WIRED_HEADSET) {
+                if ((outputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) &&
+                    (outputDevices & AudioSystem::DEVICE_OUT_SPEAKER)) {
+                    ALOGI("Routing audio to Wired Headset and Speaker\n");
+                    sndDevice = SND_DEVICE_HEADSET_AND_SPEAKER;
+                    audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+                } else {
+                    ALOGI("Routing audio to Wired Headset\n");
+                    sndDevice = SND_DEVICE_HEADSET;
+                }
+            }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+            else if (inputDevice & AudioSystem::DEVICE_IN_ANC_HEADSET) {
+                    ALOGI("Routing audio to ANC Headset\n");
+                    sndDevice = SND_DEVICE_ANC_HEADSET;
+                }
+#endif
+            else if (isStreamOnAndActive(PCM_PLAY)
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+                     || isStreamOnAndActive(LPA_DECODE)
+#endif
+              ) {
+                if (outputDevices & AudioSystem::DEVICE_OUT_EARPIECE) {
+                    ALOGI("Routing audio to Handset\n");
+                    sndDevice = SND_DEVICE_HANDSET;
+                } else if (outputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) {
+                    ALOGI("Routing audio to Speakerphone\n");
+                    sndDevice = SND_DEVICE_NO_MIC_HEADSET;
+                }
+#ifdef QCOM_FM_ENABLED
+                 else if (outputDevices & AudioSystem::DEVICE_OUT_FM_TX) {
+                    ALOGE("Routing audio_rx to Speaker\n");
+                    sndDevice = SND_DEVICE_SPEAKER_TX;
+                }
+#endif
+                else {
+                    ALOGI("Routing audio to Speaker\n");
+                    sndDevice = SND_DEVICE_SPEAKER;
+                }
+            } else {
+                ALOGI("Routing audio to Speaker (default)\n");
+                sndDevice = SND_DEVICE_SPEAKER;
+            }
+#ifdef SAMSUNG_AUDIO
+            if (input->isForVR()) {
+                if (sndDevice == SND_DEVICE_SPEAKER)
+                    sndDevice = SND_DEVICE_VR_SPEAKER;
+                else if (sndDevice == SND_DEVICE_HEADSET)
+                    sndDevice = SND_DEVICE_VR_HEADSET;
+            }
+#endif
+        }
+        // if inputDevice == 0, restore output routing
+    }
+
+    if (sndDevice == -1) {
+        if (outputDevices & (outputDevices - 1)) {
+            if ((outputDevices & AudioSystem::DEVICE_OUT_SPEAKER) == 0) {
+                ALOGW("Hardware does not support requested route combination (%#X),"
+                     " picking closest possible route...", outputDevices);
+            }
+        }
+        if ((mTtyMode != TTY_OFF) && (mMode == AudioSystem::MODE_IN_CALL) &&
+                ((outputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET)
+#ifdef QCOM_ANC_HEADSET_ENABLED
+                 ||(outputDevices & AudioSystem::DEVICE_OUT_ANC_HEADSET)
+#endif
+            )) {
+            if (mTtyMode == TTY_FULL) {
+                ALOGI("Routing audio to TTY FULL Mode\n");
+                sndDevice = SND_DEVICE_TTY_FULL;
+            } else if (mTtyMode == TTY_VCO) {
+                ALOGI("Routing audio to TTY VCO Mode\n");
+                sndDevice = SND_DEVICE_TTY_VCO;
+            } else if (mTtyMode == TTY_HCO) {
+                ALOGI("Routing audio to TTY HCO Mode\n");
+                sndDevice = SND_DEVICE_TTY_HCO;
+            }
+        } else if (outputDevices &
+                   (AudioSystem::DEVICE_OUT_BLUETOOTH_SCO | AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET)) {
+            ALOGI("Routing audio to Bluetooth PCM\n");
+            sndDevice = SND_DEVICE_BT;
+        } else if (outputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
+            ALOGI("Routing audio to Bluetooth PCM\n");
+            sndDevice = SND_DEVICE_CARKIT;
+        } else if (outputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
+            ALOGI("Routing audio to HDMI\n");
+            sndDevice = SND_DEVICE_HDMI;
+        } else if ((outputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) &&
+                   (outputDevices & AudioSystem::DEVICE_OUT_SPEAKER)) {
+            ALOGI("Routing audio to Wired Headset and Speaker\n");
+            sndDevice = SND_DEVICE_HEADSET_AND_SPEAKER;
+            audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+        } else 
+#ifdef QCOM_FM_ENABLED
+          if ((outputDevices & AudioSystem::DEVICE_OUT_FM_TX) &&
+                   (outputDevices & AudioSystem::DEVICE_OUT_SPEAKER)) {
+            ALOGI("Routing audio to FM Tx and Speaker\n");
+            sndDevice = SND_DEVICE_FM_TX_AND_SPEAKER;
+            enableComboDevice(sndDevice,1);
+            audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+        }  else
+#endif
+          if (outputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) {
+            if (outputDevices & AudioSystem::DEVICE_OUT_SPEAKER) {
+                ALOGI("Routing audio to No microphone Wired Headset and Speaker (%d,%x)\n", mMode, outputDevices);
+                sndDevice = SND_DEVICE_HEADPHONE_AND_SPEAKER;
+                audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+            } else {
+                ALOGI("Routing audio to No microphone Wired Headset (%d,%x)\n", mMode, outputDevices);
+                sndDevice = SND_DEVICE_NO_MIC_HEADSET;
+                audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+            }
+        }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+             else if (outputDevices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE) {
+                ALOGI("Routing audio to No microphone ANC Headset (%d,%x)\n", mMode, outputDevices);
+                sndDevice = SND_DEVICE_NO_MIC_ANC_HEADSET;
+                audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+        }
+#endif
+         else if (outputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) {
+             ALOGI("Routing audio to Wired Headset\n");
+             sndDevice = SND_DEVICE_HEADSET;
+             audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+        }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+          else if (outputDevices & AudioSystem::DEVICE_OUT_ANC_HEADSET) {
+            ALOGI("Routing audio to ANC Headset\n");
+            sndDevice = SND_DEVICE_ANC_HEADSET;
+            audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+        }
+#endif
+          else if (outputDevices & AudioSystem::DEVICE_OUT_SPEAKER) {
+            ALOGI("Routing audio to Speakerphone\n");
+            sndDevice = SND_DEVICE_SPEAKER;
+            audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+        } else
+#ifdef QCOM_FM_ENABLED
+         if (outputDevices & AudioSystem::DEVICE_OUT_FM_TX){
+            ALOGI("Routing audio to FM Tx Device\n");
+            sndDevice = SND_DEVICE_FM_TX;
+            audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+        } else
+#endif
+          if(outputDevices & AudioSystem::DEVICE_OUT_EARPIECE){
+            ALOGI("Routing audio to Handset\n");
+            sndDevice = SND_DEVICE_HANDSET;
+            audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+        }
+    }
+
+    if (dualmic_enabled) {
+#ifdef SAMSUNG_AUDIO
+        if (sndDevice == SND_DEVICE_HANDSET) {
+            ALOGI("Routing audio to Handset with DualMike enabled\n");
+            sndDevice = SND_DEVICE_IN_S_SADC_OUT_HANDSET;
+        }
+#else
+        if (sndDevice == SND_DEVICE_HANDSET) {
+            ALOGI("Routing audio to Handset with DualMike enabled\n");
+            sndDevice = SND_DEVICE_IN_S_SADC_OUT_HANDSET;
+        } else if (sndDevice == SND_DEVICE_SPEAKER) {
+            ALOGI("Routing audio to Speakerphone with DualMike enabled\n");
+            sndDevice = SND_DEVICE_IN_S_SADC_OUT_SPEAKER_PHONE;
+        }
+#endif
+    }
+
+#ifdef SAMSUNG_AUDIO
+    if (mMode == AudioSystem::MODE_IN_CALL) {
+        if ((!dualmic_enabled) && (sndDevice == SND_DEVICE_HANDSET)) {
+            ALOGD("Routing audio to Call Handset\n");
+            sndDevice = SND_DEVICE_CALL_HANDSET;
+        } else if (sndDevice == SND_DEVICE_SPEAKER) {
+            ALOGD("Routing audio to Call Speaker\n");
+            sndDevice = SND_DEVICE_CALL_SPEAKER;
+        } else if (sndDevice == SND_DEVICE_HEADSET) {
+            ALOGD("Routing audio to Call Headset\n");
+            sndDevice = SND_DEVICE_CALL_HEADSET;
+        }
+#if 0
+    } else if (mMode == AudioSystem::MODE_IN_COMMUNICATION) {
+        if (sndDevice == SND_DEVICE_HANDSET) {
+            ALOGD("Routing audio to VOIP handset\n");
+            sndDevice = SND_DEVICE_VOIP_HANDSET;
+        } else if (sndDevice == SND_DEVICE_SPEAKER) {
+            ALOGD("Routing audio to VOIP speaker\n");
+            sndDevice = SND_DEVICE_VOIP_SPEAKER;
+        } else if (sndDevice == SND_DEVICE_HEADSET) {
+            ALOGD("Routing audio to VOIP headset\n");
+            sndDevice = SND_DEVICE_VOIP_HEADSET;
+        }
+#endif
+    }
+#endif
+
+#ifdef QCOM_FM_ENABLED
+    if ((outputDevices & AudioSystem::DEVICE_OUT_FM) && (mFmFd == -1)){
+        enableFM(sndDevice);
+    }
+    if ((mFmFd != -1) && !(outputDevices & AudioSystem::DEVICE_OUT_FM)){
+        disableFM();
+    }
+
+    if ((CurrentComboDeviceData.DeviceId == INVALID_DEVICE) &&
+        (sndDevice == SND_DEVICE_FM_TX_AND_SPEAKER )){
+        /* speaker rx is already enabled change snd device to the fm tx
+         * device and let the flow take the regular route to
+         * updatedeviceinfo().
+         */
+        Mutex::Autolock lock_1(mComboDeviceLock);
+
+        CurrentComboDeviceData.DeviceId = SND_DEVICE_FM_TX_AND_SPEAKER;
+        sndDevice = DEVICE_FMRADIO_STEREO_RX;
+    }
+    else
+#endif
+    if(CurrentComboDeviceData.DeviceId != INVALID_DEVICE){
+        /* time to disable the combo device */
+        enableComboDevice(CurrentComboDeviceData.DeviceId,0);
+        Mutex::Autolock lock_2(mComboDeviceLock);
+        CurrentComboDeviceData.DeviceId = INVALID_DEVICE;
+        CurrentComboDeviceData.StreamType = INVALID_STREAM;
+    }
+
+    if (sndDevice != -1 && sndDevice != mCurSndDevice) {
+        ret = doAudioRouteOrMute(sndDevice);
+        mCurSndDevice = sndDevice;
+    }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+    //check if ANC setting is ON
+    if (anc_setting == true
+                && (sndDevice == SND_DEVICE_ANC_HEADSET
+                || sndDevice ==SND_DEVICE_NO_MIC_ANC_HEADSET)) {
+        enableANC(1,sndDevice);
+        anc_running = true;
+    } else {
+        //disconnection case
+        anc_running = false;
+    }
+#endif
+    return ret;
+}
+
+status_t AudioHardware::enableComboDevice(uint32_t sndDevice, bool enableOrDisable)
+{
+    ALOGD("enableComboDevice %u",enableOrDisable);
+    status_t status = NO_ERROR;
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+    Routing_table *LpaNode = getNodeByStreamType(LPA_DECODE);
+#endif
+    Routing_table *PcmNode = getNodeByStreamType(PCM_PLAY);
+
+    if(enableDevice(DEVICE_SPEAKER_RX, enableOrDisable)) {
+         ALOGE("enableDevice failed for device %d", DEVICE_SPEAKER_RX);
+         return -1;
+    }
+#ifdef QCOM_FM_ENABLED
+    if(SND_DEVICE_FM_TX_AND_SPEAKER == sndDevice){
+
+        if(getNodeByStreamType(VOICE_CALL) || getNodeByStreamType(FM_RADIO) ||
+           getNodeByStreamType(FM_A2DP)){
+            ALOGE("voicecall/FM radio active bailing out");
+            return NO_ERROR;
+        }
+
+        if(
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+         !LpaNode &&
+#endif
+         !PcmNode) {
+            ALOGE("No active playback session active bailing out ");
+            cur_rx = DEVICE_FMRADIO_STEREO_RX;
+            return NO_ERROR;
+        }
+
+        Mutex::Autolock lock_1(mComboDeviceLock);
+
+        Routing_table* temp = NULL;
+
+        if (enableOrDisable == 1) {
+            if(CurrentComboDeviceData.StreamType == INVALID_STREAM){
+                if (PcmNode){
+                    temp = PcmNode;
+                    CurrentComboDeviceData.StreamType = PCM_PLAY;
+                    ALOGD("PCM_PLAY session Active ");
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+                }else if(LpaNode){
+                    temp = LpaNode;
+                    CurrentComboDeviceData.StreamType = LPA_DECODE;
+                    ALOGD("LPA_DECODE session Active ");
+#endif
+                } else {
+                    ALOGE("no PLAYback session Active ");
+                    return -1;
+                }
+            }else
+                temp = getNodeByStreamType(CurrentComboDeviceData.StreamType);
+
+            if(temp == NULL){
+                ALOGE("speaker de-route not possible");
+                return -1;
+            }
+
+            ALOGD("combo:msm_route_stream(%d,%d,1)",temp->dec_id,
+                DEV_ID(DEVICE_SPEAKER_RX));
+            if(msm_route_stream(PCM_PLAY, temp->dec_id, DEV_ID(DEVICE_SPEAKER_RX),
+                1)) {
+                ALOGE("msm_route_stream failed");
+                return -1;
+            }
+
+        }else if(enableOrDisable == 0) {
+            temp = getNodeByStreamType(CurrentComboDeviceData.StreamType);
+
+
+            if(temp == NULL){
+                ALOGE("speaker de-route not possible");
+                return -1;
+            }
+
+            ALOGD("combo:de-route msm_route_stream(%d,%d,0)",temp->dec_id,
+                DEV_ID(DEVICE_SPEAKER_RX));
+            if(msm_route_stream(PCM_PLAY, temp->dec_id,
+                DEV_ID(DEVICE_SPEAKER_RX), 0)) {
+                ALOGE("msm_route_stream failed");
+                return -1;
+            }
+        }
+
+    }
+#endif
+
+    return status;
+}
+#ifdef QCOM_FM_ENABLED
+status_t AudioHardware::enableFM(int sndDevice)
+{
+    ALOGD("enableFM");
+    status_t status = NO_INIT;
+    unsigned short session_id = INVALID_DEVICE;
+    status = ::open(FM_DEVICE, O_RDWR);
+    if (status < 0) {
+           ALOGE("Cannot open FM_DEVICE errno: %d", errno);
+           goto Error;
+    }
+    mFmFd = status;
+    if(ioctl(mFmFd, AUDIO_GET_SESSION_ID, &session_id)) {
+           ALOGE("AUDIO_GET_SESSION_ID failed*********");
+           goto Error;
+    }
+
+    if(enableDevice(DEVICE_FMRADIO_STEREO_TX, 1)) {
+           ALOGE("enableDevice failed for device %d", DEVICE_FMRADIO_STEREO_TX);
+           goto Error;
+    }
+#ifdef QCOM_ACDB_ENABLED
+    acdb_loader_send_audio_cal(ACDB_ID(DEVICE_FMRADIO_STEREO_TX),
+    CAPABILITY(DEVICE_FMRADIO_STEREO_TX));
+#endif
+    if(msm_route_stream(PCM_PLAY, session_id, DEV_ID(DEVICE_FMRADIO_STEREO_TX), 1)) {
+           ALOGE("msm_route_stream failed");
+           goto Error;
+    }
+    addToTable(session_id,cur_rx,INVALID_DEVICE,FM_RADIO,true);
+    if(sndDevice == mCurSndDevice || mCurSndDevice == -1) {
+        enableDevice(cur_rx, 1);
+#ifdef QCOM_ACDB_ENABLED
+        acdb_loader_send_audio_cal(ACDB_ID(cur_rx), CAPABILITY(cur_rx));
+#endif
+        msm_route_stream(PCM_PLAY,session_id,DEV_ID(cur_rx),1);
+    }
+    status = ioctl(mFmFd, AUDIO_START, 0);
+    if (status < 0) {
+            ALOGE("Cannot do AUDIO_START");
+            goto Error;
+    }
+    return NO_ERROR;
+    Error:
+    if (mFmFd >= 0) {
+        ::close(mFmFd);
+        mFmFd = -1;
+    }
+    return NO_ERROR;
+}
+
+status_t AudioHardware::disableFM()
+{
+    ALOGD("disableFM");
+    Routing_table* temp = NULL;
+    temp = getNodeByStreamType(FM_RADIO);
+    if(temp == NULL)
+        return 0;
+    if (mFmFd >= 0) {
+            ::close(mFmFd);
+            mFmFd = -1;
+    }
+    if(msm_route_stream(PCM_PLAY, temp->dec_id, DEV_ID(DEVICE_FMRADIO_STEREO_TX), 0)) {
+           ALOGE("msm_route_stream failed");
+           return 0;
+    }
+    if(!getNodeByStreamType(FM_A2DP)) {
+       if(enableDevice(DEVICE_FMRADIO_STEREO_TX, 0)) {
+          ALOGE("Device disable failed for device %d", DEVICE_FMRADIO_STEREO_TX);
+       }
+    }
+    deleteFromTable(FM_RADIO);
+    if(!getNodeByStreamType(VOICE_CALL)
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+      && !getNodeByStreamType(LPA_DECODE)
+#endif
+        && !getNodeByStreamType(PCM_PLAY)
+#ifdef QCOM_VOIP_ENABLED
+        && !getNodeByStreamType(VOIP_CALL)
+#endif
+        ) {
+        if(enableDevice(cur_rx, 0)) {
+            ALOGV("Disable device[%d] failed errno = %d",DEV_ID(cur_rx),errno);
+            return 0;
+        }
+    }
+    return NO_ERROR;
+}
+#endif
+
+status_t AudioHardware::dumpInternals(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    result.append("AudioHardware::dumpInternals\n");
+    snprintf(buffer, SIZE, "\tmInit: %s\n", mInit? "true": "false");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmMicMute: %s\n", mMicMute? "true": "false");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmBluetoothNrec: %s\n", mBluetoothNrec? "true": "false");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmBluetoothId: %d\n", mBluetoothId);
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioHardware::dump(int fd, const Vector<String16>& args)
+{
+    dumpInternals(fd, args);
+    for (size_t index = 0; index < mInputs.size(); index++) {
+        mInputs[index]->dump(fd, args);
+    }
+
+    if (mOutput) {
+        mOutput->dump(fd, args);
+    }
+    return NO_ERROR;
+}
+
+uint32_t AudioHardware::getInputSampleRate(uint32_t sampleRate)
+{
+    uint32_t i;
+    uint32_t prevDelta;
+    uint32_t delta;
+
+    for (i = 0, prevDelta = 0xFFFFFFFF; i < sizeof(inputSamplingRates)/sizeof(uint32_t); i++, prevDelta = delta) {
+        delta = abs(sampleRate - inputSamplingRates[i]);
+        if (delta > prevDelta) break;
+    }
+    // i is always > 0 here
+    return inputSamplingRates[i-1];
+}
+
+
+
+// ----------------------------------------------------------------------------
+
+AudioHardware::AudioStreamOutMSM8x60::AudioStreamOutMSM8x60() :
+    mHardware(0), mFd(-1), mStartCount(0), mRetryCount(0), mStandby(true), mDevices(0)
+{
+}
+
+status_t AudioHardware::AudioStreamOutMSM8x60::set(
+        AudioHardware* hw, uint32_t devices, int *pFormat, uint32_t *pChannels, uint32_t *pRate)
+{
+    int lFormat = pFormat ? *pFormat : 0;
+    uint32_t lChannels = pChannels ? *pChannels : 0;
+    uint32_t lRate = pRate ? *pRate : 0;
+
+    mHardware = hw;
+
+    // fix up defaults
+    if (lFormat == 0) lFormat = format();
+    if (lChannels == 0) lChannels = channels();
+    if (lRate == 0) lRate = sampleRate();
+
+    // check values
+    if ((lFormat != format()) ||
+        (lChannels != channels()) ||
+        (lRate != sampleRate())) {
+        if (pFormat) *pFormat = format();
+        if (pChannels) *pChannels = channels();
+        if (pRate) *pRate = sampleRate();
+        return BAD_VALUE;
+    }
+
+    if (pFormat) *pFormat = lFormat;
+    if (pChannels) *pChannels = lChannels;
+    if (pRate) *pRate = lRate;
+
+    mDevices = devices;
+
+    return NO_ERROR;
+}
+
+AudioHardware::AudioStreamOutMSM8x60::~AudioStreamOutMSM8x60()
+{
+    if (mFd >= 0) close(mFd);
+}
+
+ssize_t AudioHardware::AudioStreamOutMSM8x60::write(const void* buffer, size_t bytes)
+{
+    //ALOGE("AudioStreamOutMSM8x60::write(%p, %u)", buffer, bytes);
+    status_t status = NO_INIT;
+    size_t count = bytes;
+    const uint8_t* p = static_cast<const uint8_t*>(buffer);
+    unsigned short dec_id = INVALID_DEVICE;
+
+    if (mStandby) {
+
+        // open driver
+        ALOGV("open driver");
+        status = ::open("/dev/msm_pcm_out", O_WRONLY/*O_RDWR*/);
+        if (status < 0) {
+            ALOGE("Cannot open /dev/msm_pcm_out errno: %d", errno);
+            goto Error;
+        }
+        mFd = status;
+
+        // configuration
+        ALOGV("get config");
+        struct msm_audio_config config;
+        status = ioctl(mFd, AUDIO_GET_CONFIG, &config);
+        if (status < 0) {
+            ALOGE("Cannot read config");
+            goto Error;
+        }
+
+        ALOGV("set config");
+        config.channel_count = AudioSystem::popCount(channels());
+        config.sample_rate = sampleRate();
+        config.buffer_size = bufferSize();
+        config.buffer_count = AUDIO_HW_NUM_OUT_BUF;
+        config.type = CODEC_TYPE_PCM;
+        status = ioctl(mFd, AUDIO_SET_CONFIG, &config);
+        if (status < 0) {
+            ALOGE("Cannot set config");
+            goto Error;
+        }
+
+        ALOGV("buffer_size: %u", config.buffer_size);
+        ALOGV("buffer_count: %u", config.buffer_count);
+        ALOGV("channel_count: %u", config.channel_count);
+        ALOGV("sample_rate: %u", config.sample_rate);
+
+        // fill 2 buffers before AUDIO_START
+        mStartCount = AUDIO_HW_NUM_OUT_BUF;
+        mStandby = false;
+#ifdef HTC_ACOUSTIC_AUDIO
+        if (support_tpa2051)
+            do_tpa2051_control(0);
+#endif
+    }
+
+    while (count) {
+        ssize_t written = ::write(mFd, p, count);
+        if (written > 0) {
+            count -= written;
+            p += written;
+        } else {
+            if (errno != EAGAIN) return written;
+            mRetryCount++;
+            ALOGW("EAGAIN - retry");
+        }
+    }
+
+    // start audio after we fill 2 buffers
+    if (mStartCount) {
+        if (--mStartCount == 0) {
+            if(ioctl(mFd, AUDIO_GET_SESSION_ID, &dec_id)) {
+                ALOGE("AUDIO_GET_SESSION_ID failed*********");
+                return 0;
+            }
+            ALOGE("write(): dec_id = %d cur_rx = %d\n",dec_id,cur_rx);
+            if(cur_rx == INVALID_DEVICE) {
+                //return 0; //temporary fix until team upmerges code to froyo tip
+                cur_rx = 0;
+                cur_tx = 1;
+            }
+
+            Mutex::Autolock lock(mDeviceSwitchLock);
+
+#ifdef HTC_ACOUSTIC_AUDIO
+            int snd_dev = mHardware->get_snd_dev();
+            if (support_aic3254)
+                mHardware->do_aic3254_control(snd_dev);
+#endif
+            ALOGE("cur_rx for pcm playback = %d",cur_rx);
+            if(enableDevice(cur_rx, 1)) {
+                ALOGE("enableDevice failed for device cur_rx %d", cur_rx);
+                return 0;
+            }
+#ifdef QCOM_ACDB_ENABLED
+            acdb_loader_send_audio_cal(ACDB_ID(cur_rx), CAPABILITY(cur_rx));
+#endif
+            if(msm_route_stream(PCM_PLAY, dec_id, DEV_ID(cur_rx), 1)) {
+                ALOGE("msm_route_stream failed");
+                return 0;
+            }
+            Mutex::Autolock lock_1(mComboDeviceLock);
+#ifdef QCOM_FM_ENABLED
+            if(CurrentComboDeviceData.DeviceId == SND_DEVICE_FM_TX_AND_SPEAKER){
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+                Routing_table *LpaNode = getNodeByStreamType(LPA_DECODE);
+                /* This de-routes the LPA being routed on to speaker, which is done in
+                  * enablecombo()
+                  */
+                if(LpaNode != NULL) {
+                    ALOGD("combo:de-route:msm_route_stream(%d,%d,0)",LpaNode ->dec_id,
+                        DEV_ID(DEVICE_SPEAKER_RX));
+                    if(msm_route_stream(PCM_PLAY, LpaNode ->dec_id,
+                        DEV_ID(DEVICE_SPEAKER_RX), 0)) {
+                            ALOGE("msm_route_stream failed");
+                            return -1;
+                    }
+                }
+#endif
+                ALOGD("Routing PCM stream to speaker for combo device");
+                ALOGD("combo:msm_route_stream(PCM_PLAY,session id:%d,dev id:%d,1)",dec_id,
+                    DEV_ID(DEVICE_SPEAKER_RX));
+                if(msm_route_stream(PCM_PLAY, dec_id, DEV_ID(DEVICE_SPEAKER_RX),
+                    1)) {
+                    ALOGE("msm_route_stream failed");
+                    return -1;
+                }
+                CurrentComboDeviceData.StreamType = PCM_PLAY;
+            }
+#endif
+            addToTable(dec_id,cur_rx,INVALID_DEVICE,PCM_PLAY,true);
+            ioctl(mFd, AUDIO_START, 0);
+        }
+    }
+    return bytes;
+
+Error:
+    if (mFd >= 0) {
+        ::close(mFd);
+        mFd = -1;
+    }
+    // Simulate audio output timing in case of error
+    usleep(bytes * 1000000 / frameSize() / sampleRate());
+    return status;
+}
+
+status_t AudioHardware::AudioStreamOutMSM8x60::standby()
+{
+    Routing_table* temp = NULL;
+    ALOGD("AudioStreamOutMSM8x60::standby()");
+    status_t status = NO_ERROR;
+
+    temp = getNodeByStreamType(PCM_PLAY);
+
+    if(temp == NULL)
+        return NO_ERROR;
+
+    ALOGD("Deroute pcm stream");
+    if(msm_route_stream(PCM_PLAY, temp->dec_id,DEV_ID(temp->dev_id), 0)) {
+        ALOGE("could not set stream routing\n");
+        deleteFromTable(PCM_PLAY);
+        return -1;
+    }
+    deleteFromTable(PCM_PLAY);
+    if(!getNodeByStreamType(VOICE_CALL)
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+       && !getNodeByStreamType(LPA_DECODE)
+#endif
+#ifdef QCOM_FM_ENABLED
+       && !getNodeByStreamType(FM_RADIO)
+#endif
+#ifdef QCOM_VOIP_ENABLED
+       && !getNodeByStreamType(VOIP_CALL)
+#endif
+     ) {
+#ifdef QCOM_ANC_HEADSET_ENABLED
+    //in case if ANC don't disable cur device.
+      if (anc_running == false){
+#endif
+        if(enableDevice(cur_rx, 0)) {
+            ALOGE("Disabling device failed for cur_rx %d", cur_rx);
+            return 0;
+        }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+      }
+#endif
+    }
+
+    if (!mStandby && mFd >= 0) {
+        ::close(mFd);
+        mFd = -1;
+    }
+
+    mStandby = true;
+#ifdef HTC_ACOUSTIC_AUDIO
+    if (support_aic3254)
+        mHardware->do_aic3254_control(mHardware->get_snd_dev());
+#endif
+    return status;
+}
+
+status_t AudioHardware::AudioStreamOutMSM8x60::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    result.append("AudioStreamOutMSM8x60::dump\n");
+    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tformat: %d\n", format());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmHardware: %p\n", mHardware);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmStartCount: %d\n", mStartCount);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmRetryCount: %d\n", mRetryCount);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmStandby: %s\n", mStandby? "true": "false");
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+bool AudioHardware::AudioStreamOutMSM8x60::checkStandby()
+{
+    return mStandby;
+}
+
+
+status_t AudioHardware::AudioStreamOutMSM8x60::setParameters(const String8& keyValuePairs)
+{
+    AudioParameter param = AudioParameter(keyValuePairs);
+    String8 key = String8(AudioParameter::keyRouting);
+    status_t status = NO_ERROR;
+    int device;
+    ALOGV("AudioStreamOutMSM8x60::setParameters() %s", keyValuePairs.string());
+
+    if (param.getInt(key, device) == NO_ERROR) {
+        mDevices = device;
+        ALOGV("set output routing %x", mDevices);
+        status = mHardware->doRouting(NULL);
+        param.remove(key);
+    }
+
+    if (param.size()) {
+        status = BAD_VALUE;
+    }
+    return status;
+}
+
+String8 AudioHardware::AudioStreamOutMSM8x60::getParameters(const String8& keys)
+{
+    AudioParameter param = AudioParameter(keys);
+    String8 value;
+    String8 key = String8(AudioParameter::keyRouting);
+
+    if (param.get(key, value) == NO_ERROR) {
+        ALOGV("get routing %x", mDevices);
+        param.addInt(key, (int)mDevices);
+    }
+
+    ALOGV("AudioStreamOutMSM8x60::getParameters() %s", param.toString().string());
+    return param.toString();
+}
+
+status_t AudioHardware::AudioStreamOutMSM8x60::getRenderPosition(uint32_t *dspFrames)
+{
+    //TODO: enable when supported by driver
+    return INVALID_OPERATION;
+}
+
+#ifdef QCOM_VOIP_ENABLED
+// ----------------------------------------------------------------------------
+// Audio Stream from DirectOutput thread
+// ----------------------------------------------------------------------------
+
+AudioHardware::AudioStreamOutDirect::AudioStreamOutDirect() :
+    mHardware(0), mFd(-1), mStartCount(0), mRetryCount(0), mStandby(true), mDevices(0),mChannels(AudioSystem::CHANNEL_OUT_MONO),
+    mSampleRate(AUDIO_HW_VOIP_SAMPLERATE_8K), mBufferSize(AUDIO_HW_VOIP_BUFFERSIZE_8K)
+{
+}
+
+status_t AudioHardware::AudioStreamOutDirect::set(
+        AudioHardware* hw, uint32_t devices, int *pFormat, uint32_t *pChannels, uint32_t *pRate)
+{
+    int lFormat = pFormat ? *pFormat : 0;
+    uint32_t lChannels = pChannels ? *pChannels : 0;
+    uint32_t lRate = pRate ? *pRate : 0;
+
+    ALOGV("set1  lFormat = %d lChannels= %u lRate = %u\n", lFormat, lChannels, lRate );
+    mHardware = hw;
+
+    // fix up defaults
+    if (lFormat == 0) lFormat = format();
+    if (lChannels == 0) lChannels = channels();
+    if (lRate == 0) lRate = sampleRate();
+
+    // check values
+    mFormat =  lFormat;
+    mChannels = lChannels;
+    mSampleRate = lRate;
+    if(mSampleRate == AUDIO_HW_VOIP_SAMPLERATE_8K) {
+        mBufferSize = AUDIO_HW_VOIP_BUFFERSIZE_8K;
+    } else if(mSampleRate == AUDIO_HW_VOIP_SAMPLERATE_16K) {
+        mBufferSize = AUDIO_HW_VOIP_BUFFERSIZE_16K;
+    } else {
+        ALOGE("  AudioStreamOutDirect::set return bad values\n");
+        return BAD_VALUE;
+    }
+
+    mDevices = devices;
+
+#ifndef LEGACY_QCOM_VOICE
+    if((voip_session_id <= 0)) {
+        voip_session_id = msm_get_voc_session(VOIP_SESSION_NAME);
+    }
+#endif
+    mHardware->mNumVoipStreams++;
+    return NO_ERROR;
+}
+
+AudioHardware::AudioStreamOutDirect::~AudioStreamOutDirect()
+{
+    ALOGV("AudioStreamOutDirect destructor");
+    standby();
+    if (mHardware->mNumVoipStreams)
+        mHardware->mNumVoipStreams--;
+}
+
+ssize_t AudioHardware::AudioStreamOutDirect::write(const void* buffer, size_t bytes)
+{
+    status_t status = NO_INIT;
+    size_t count = bytes;
+    const uint8_t* p = static_cast<const uint8_t*>(buffer);
+    unsigned short dec_id = INVALID_DEVICE;
+
+    if (mStandby) {
+        if(mHardware->mVoipFd >= 0) {
+                mFd = mHardware->mVoipFd;
+        }
+        else {
+            // open driver
+            ALOGV("open mvs driver");
+            status = ::open(MVS_DEVICE, /*O_WRONLY*/ O_RDWR);
+            if (status < 0) {
+                ALOGE("Cannot open %s errno: %d",MVS_DEVICE, errno);
+                goto Error;
+            }
+            mFd = status;
+            mHardware->mVoipFd = mFd;
+            // configuration
+            ALOGV("get mvs config");
+            struct msm_audio_mvs_config mvs_config;
+            status = ioctl(mFd, AUDIO_GET_MVS_CONFIG, &mvs_config);
+            if (status < 0) {
+               ALOGE("Cannot read mvs config");
+               goto Error;
+            }
+
+            ALOGV("set mvs config");
+            int samplerate = sampleRate();
+            if(samplerate == AUDIO_HW_VOIP_SAMPLERATE_8K) {
+                 mvs_config.mvs_mode = MVS_MODE_PCM;
+            } else if(samplerate == AUDIO_HW_VOIP_SAMPLERATE_16K) {
+                 mvs_config.mvs_mode = MVS_MODE_PCM_WB;
+            } else {
+                 ALOGE("unsupported samplerate for voip");
+                 goto Error;
+            }
+            status = ioctl(mFd, AUDIO_SET_MVS_CONFIG, &mvs_config);
+            if (status < 0) {
+                ALOGE("Cannot set mvs config");
+                goto Error;
+            }
+
+            ALOGV("start mvs config");
+            status = ioctl(mFd, AUDIO_START, 0);
+            if (status < 0) {
+                ALOGE("Cannot start mvs driver");
+                goto Error;
+            }
+
+            // fill 2 buffers before AUDIO_START
+            mStartCount = AUDIO_HW_NUM_OUT_BUF;
+            mStandby = false;
+
+            Mutex::Autolock lock(mDeviceSwitchLock);
+            //Routing Voip
+            if ((cur_rx != INVALID_DEVICE) && (cur_tx != INVALID_DEVICE))
+            {
+                ALOGV("Starting voip call on Rx %d and Tx %d device", DEV_ID(cur_rx), DEV_ID(cur_tx));
+                msm_route_voice(DEV_ID(cur_rx),DEV_ID(cur_tx), 1);
+            }
+            else {
+               return -1;
+            }
+
+            //Enable RX device
+            if(cur_rx != INVALID_DEVICE && (enableDevice(cur_rx,1) == -1))
+            {
+               return -1;
+            }
+
+            //Enable TX device
+            if(cur_tx != INVALID_DEVICE&&(enableDevice(cur_tx,1) == -1))
+            {
+               return -1;
+            }
+#ifdef QCOM_ACDB_ENABLED
+            // voip calibration
+            acdb_loader_send_voice_cal(ACDB_ID(cur_rx),ACDB_ID(cur_tx));
+#endif
+            // start Voip call
+            ALOGD("Starting voip call and UnMuting the call");
+#ifdef LEGACY_QCOM_VOICE
+            msm_start_voice();
+            msm_set_voice_tx_mute(0);
+#else
+            msm_start_voice_ext(voip_session_id);
+            msm_set_voice_tx_mute_ext(voip_session_mute,voip_session_id);
+#endif
+            addToTable(0,cur_rx,cur_tx,VOIP_CALL,true);
+        }
+    }
+    struct msm_audio_mvs_frame audio_mvs_frame;
+    audio_mvs_frame.frame_type = 0;
+    while (count) {
+        audio_mvs_frame.len = count;
+        memcpy(&audio_mvs_frame.voc_pkt, p, count);
+        size_t written = ::write(mFd, &audio_mvs_frame, sizeof(audio_mvs_frame));
+        ALOGV(" mvs bytes count = %d written : %d \n", count, written);
+        if (written == 0) {
+            count -= audio_mvs_frame.len;
+            p += audio_mvs_frame.len;
+        } else {
+            if (errno != EAGAIN) return written;
+            mRetryCount++;
+            ALOGW("EAGAIN - retry");
+        }
+    }
+
+    // start audio after we fill 2 buffers
+    if (mStartCount) {
+        if (--mStartCount == 0) {
+            if(ioctl(mFd, AUDIO_GET_SESSION_ID, &dec_id)) {
+                ALOGE("AUDIO_GET_SESSION_ID failed*********");
+                return 0;
+            }
+            ALOGD("write(): dec_id = %d cur_rx = %d\n",dec_id,cur_rx);
+            if(cur_rx == INVALID_DEVICE) {
+                //return 0; //temporary fix until team upmerges code to froyo tip
+                cur_rx = 0;
+                cur_tx = 1;
+            }
+        }
+    }
+    bytes = audio_mvs_frame.len;
+    return bytes;
+
+Error:
+ALOGE("  write Error \n");
+    if (mFd >= 0) {
+        ::close(mFd);
+        mFd = -1;
+        mHardware->mVoipFd = -1;
+    }
+    // Simulate audio output timing in case of error
+    usleep(bytes * 1000000 / frameSize() / sampleRate());
+
+    return status;
+}
+
+status_t AudioHardware::AudioStreamOutDirect::standby()
+{
+    Routing_table* temp = NULL;
+    ALOGD("AudioStreamOutDirect::standby()");
+    status_t status = NO_ERROR;
+    int ret = 0;
+
+    ALOGV(" AudioStreamOutDirect::standby mHardware->mNumVoipStreams = %d mFd = %d\n", mHardware->mNumVoipStreams, mFd);
+    if (mFd >= 0 && (mHardware->mNumVoipStreams == 1)) {
+#ifdef LEGACY_QCOM_VOICE
+        msm_end_voice();
+#else
+        ret = msm_end_voice_ext(voip_session_id);
+        if (ret < 0)
+                ALOGE("Error %d ending voip\n", ret);
+#endif
+        temp = getNodeByStreamType(VOIP_CALL);
+        if(temp == NULL)
+        {
+            ALOGE("VOIP: Going to disable RX/TX return 0");
+            return 0;
+        }
+
+        if((temp->dev_id != INVALID_DEVICE && temp->dev_id_tx != INVALID_DEVICE)&& (!isStreamOn(VOICE_CALL))) {
+            ALOGE(" Streamout: disable VOIP rx tx ");
+           enableDevice(temp->dev_id,0);
+           enableDevice(temp->dev_id_tx,0);
+        }
+        deleteFromTable(VOIP_CALL);
+       if (mFd >= 0) {
+           ret = ioctl(mFd, AUDIO_STOP, NULL);
+           ALOGE("MVS stop returned %d \n", ret);
+           ::close(mFd);
+           mFd = mHardware->mVoipFd = -1;
+           ALOGV("driver closed");
+           voip_session_id = 0;
+           voip_session_mute = 0;
+       }
+   }
+    mStandby = true;
+    return status;
+}
+
+status_t AudioHardware::AudioStreamOutDirect::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    result.append("AudioStreamOutDirect::dump\n");
+    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tformat: %d\n", format());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmHardware: %p\n", mHardware);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmStartCount: %d\n", mStartCount);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmRetryCount: %d\n", mRetryCount);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmStandby: %s\n", mStandby? "true": "false");
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+bool AudioHardware::AudioStreamOutDirect::checkStandby()
+{
+    return mStandby;
+}
+
+
+status_t AudioHardware::AudioStreamOutDirect::setParameters(const String8& keyValuePairs)
+{
+    AudioParameter param = AudioParameter(keyValuePairs);
+    String8 key = String8(AudioParameter::keyRouting);
+    status_t status = NO_ERROR;
+    int device;
+    ALOGV("AudioStreamOutDirect::setParameters() %s", keyValuePairs.string());
+
+    if (param.getInt(key, device) == NO_ERROR) {
+        mDevices = device;
+        ALOGV("set output routing %x", mDevices);
+        status = mHardware->doRouting(NULL);
+        param.remove(key);
+    }
+
+    if (param.size()) {
+        status = BAD_VALUE;
+    }
+    return status;
+}
+
+String8 AudioHardware::AudioStreamOutDirect::getParameters(const String8& keys)
+{
+    AudioParameter param = AudioParameter(keys);
+    String8 value;
+    String8 key = String8(AudioParameter::keyRouting);
+
+    if (param.get(key, value) == NO_ERROR) {
+        ALOGV("get routing %x", mDevices);
+        param.addInt(key, (int)mDevices);
+    }
+
+    ALOGV("AudioStreamOutDirect::getParameters() %s", param.toString().string());
+    return param.toString();
+}
+
+status_t AudioHardware::AudioStreamOutDirect::getRenderPosition(uint32_t *dspFrames)
+{
+    //TODO: enable when supported by driver
+    return INVALID_OPERATION;
+}
+
+// End AudioStreamOutDirect
+//.----------------------------------------------------------------------------
+#endif
+
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+// ----------------------------------------------------------------------------
+// Audio Stream from LPA output
+// Start AudioSessionOutLPA
+// ----------------------------------------------------------------------------
+
+AudioHardware::AudioSessionOutLPA::AudioSessionOutLPA( AudioHardware *hw,
+                                         uint32_t   devices,
+                                         int        format,
+                                         uint32_t   channels,
+                                         uint32_t   samplingRate,
+                                         int        type,
+                                         status_t   *status)
+{
+    Mutex::Autolock autoLock(mLock);
+    // Default initilization
+	mHardware = hw;
+    ALOGE("AudioSessionOutLPA constructor");
+    mFormat             = format;
+    mSampleRate         = samplingRate;
+    mChannels           = popcount(channels);
+    mBufferSize         = LPA_BUFFER_SIZE; //TODO to check what value is correct
+    *status             = BAD_VALUE;
+
+    mPaused             = false;
+    mIsDriverStarted    = false;
+    mSeeking            = false;
+    mReachedEOS         = false;
+    mSkipWrite          = false;
+    timeStarted = 0;
+    timePlayed = 0;
+
+    mInputBufferSize    = LPA_BUFFER_SIZE;
+    mInputBufferCount   = BUFFER_COUNT;
+    efd = -1;
+    mEosEventReceived   =false;
+
+    mEventThread        = NULL;
+    mEventThreadAlive   = false;
+    mKillEventThread    = false;
+    mObserver           = NULL;
+    if((format == AUDIO_FORMAT_PCM_16_BIT) && (mChannels == 0 || mChannels > 2)) {
+        ALOGE("Invalid number of channels %d", channels);
+        return;
+    }
+
+    *status = openAudioSessionDevice();
+
+    //Creates the event thread to poll events from LPA Driver
+    if (*status == NO_ERROR)
+    createEventThread();
+}
+
+AudioHardware::AudioSessionOutLPA::~AudioSessionOutLPA()
+{
+    ALOGV("AudioSessionOutLPA destructor");
+	mSkipWrite = true;
+    mWriteCv.signal();
+
+    //TODO: This might need to be Locked using Parent lock
+    reset();
+    //standby();//TODO Do we really need standby?
+
+}
+
+ssize_t AudioHardware::AudioSessionOutLPA::write(const void* buffer, size_t bytes)
+{
+    Mutex::Autolock autoLock(mLock);
+    int err;
+    ALOGV("write Empty Queue size() = %d, Filled Queue size() = %d ",
+         mEmptyQueue.size(),mFilledQueue.size());
+
+    if (mSkipWrite) {
+        mSkipWrite = false;
+        if (bytes < LPA_BUFFER_SIZE)
+            bytes = 0;
+        else
+            return 0;
+    }
+
+    if (mSkipWrite)
+        mSkipWrite = false;
+
+    //2.) Dequeue the buffer from empty buffer queue. Copy the data to be
+    //    written into the buffer. Then Enqueue the buffer to the filled
+    //    buffer queue
+    List<BuffersAllocated>::iterator it = mEmptyQueue.begin();
+    BuffersAllocated buf = *it;
+    mEmptyQueue.erase(it);
+    mEmptyQueueMutex.unlock();
+
+    memset(buf.memBuf, 0, bytes);
+    memcpy(buf.memBuf, buffer, bytes);
+    buf.bytesToWrite = bytes;
+
+    struct msm_audio_aio_buf aio_buf_local;
+    if ( buf.bytesToWrite > 0) {
+        memset(&aio_buf_local, 0, sizeof(msm_audio_aio_buf));
+        aio_buf_local.buf_addr = buf.memBuf;
+        aio_buf_local.buf_len = buf.bytesToWrite;
+        aio_buf_local.data_len = buf.bytesToWrite;
+        aio_buf_local.private_data = (void*) buf.memFd;
+
+        if ( (buf.bytesToWrite % 2) != 0 ) {
+            ALOGV("Increment for even bytes");
+            aio_buf_local.data_len += 1;
+        }
+        if (timeStarted == 0)
+            timeStarted = nanoseconds_to_microseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+    } else {
+            /* Put the buffer back into requestQ */
+            ALOGV("mEmptyQueueMutex locking: %d", __LINE__);
+            mEmptyQueueMutex.lock();
+            ALOGV("mEmptyQueueMutex locked: %d", __LINE__);
+            mEmptyQueue.push_back(buf);
+            ALOGV("mEmptyQueueMutex unlocking: %d", __LINE__);
+            mEmptyQueueMutex.unlock();
+            ALOGV("mEmptyQueueMutex unlocked: %d", __LINE__);
+            //Post EOS in case the filled queue is empty and EOS is reached.
+        mReachedEOS = true;
+        mFilledQueueMutex.lock();
+        if (mFilledQueue.empty() && !mEosEventReceived) {
+            ALOGV("mEosEventReceived made true");
+            mEosEventReceived = true;
+            if (mObserver != NULL) {
+                ALOGV("mObserver: posting EOS");
+                mObserver->postEOS(0);
+            }
+        }
+        mFilledQueueMutex.unlock();
+        return NO_ERROR;
+    }
+    mFilledQueueMutex.lock();
+    mFilledQueue.push_back(buf);
+    mFilledQueueMutex.unlock();
+
+    ALOGV("PCM write start");
+    //3.) Write the buffer to the Driver
+    if(mIsDriverStarted) {
+    if ( ioctl(afd, AUDIO_ASYNC_WRITE, &aio_buf_local ) < 0 ) {
+        ALOGE("error on async write\n");
+       }
+    }
+    ALOGV("PCM write complete");
+
+    if (bytes < LPA_BUFFER_SIZE) {
+        ALOGV("Last buffer case");
+        if (fsync(afd) != 0) {
+            ALOGE("fsync failed.");
+        }
+        mReachedEOS = true;
+    }
+
+    return NO_ERROR; //TODO Do we need to send error
+}
+
+
+status_t AudioHardware::AudioSessionOutLPA::standby()
+{
+    ALOGD("AudioSessionOutLPA::standby()");
+    status_t status = NO_ERROR;
+    //TODO  Do we really need standby()
+    return status;
+}
+
+
+status_t AudioHardware::AudioSessionOutLPA::dump(int fd, const Vector<String16>& args)
+{
+    return NO_ERROR;
+}
+
+status_t AudioHardware::AudioSessionOutLPA::setParameters(const String8& keyValuePairs)
+{
+    AudioParameter param = AudioParameter(keyValuePairs);
+    String8 key = String8(AudioParameter::keyRouting);
+    status_t status = NO_ERROR;
+    int device;
+    ALOGE("AudioSessionOutLPA::setParameters() %s", keyValuePairs.string());
+
+    if (param.getInt(key, device) == NO_ERROR) {
+        mDevices = device;
+        ALOGE("set output routing %x", mDevices);
+        status = mHardware->doRouting(NULL);
+        param.remove(key);
+    }
+
+    if (param.size()) {
+        status = BAD_VALUE;
+    }
+    return status;
+}
+
+String8 AudioHardware::AudioSessionOutLPA::getParameters(const String8& keys)
+{
+    AudioParameter param = AudioParameter(keys);
+    String8 value;
+    String8 key = String8(AudioParameter::keyRouting);
+
+    if (param.get(key, value) == NO_ERROR) {
+        ALOGV("get routing %x", mDevices);
+        param.addInt(key, (int)mDevices);
+    }
+
+    ALOGV("AudioSessionOutLPA::getParameters() %s", param.toString().string());
+    return param.toString();
+}
+
+status_t AudioHardware::AudioSessionOutLPA::setVolume(float left, float right)
+{
+    float v = (left + right) / 2;
+    int sessionId = 0;
+    unsigned short decId;
+    if (v < 0.0) {
+        ALOGW("AudioSessionOutLPA::setVolume(%f) under 0.0, assuming 0.0\n", v);
+        v = 0.0;
+    } else if (v > 1.0) {
+        ALOGW("AudioSessionOutLPA::setVolume(%f) over 1.0, assuming 1.0\n", v);
+        v = 1.0;
+    }
+    if ( ioctl(afd, AUDIO_GET_SESSION_ID, &decId) == -1 ) {
+        ALOGE("AUDIO_GET_SESSION_ID FAILED\n");
+        return BAD_VALUE;
+    } else {
+        sessionId = (int)decId;
+        ALOGE("AUDIO_GET_SESSION_ID success : decId = %d", decId);
+    }
+    // Ensure to convert the log volume back to linear for LPA
+    float vol = v * 100;
+    ALOGV("AudioSessionOutLPA::setVolume(%f)\n", v);
+    ALOGV("Setting session volume to %f (available range is 0 to 100)\n", vol);
+
+    if(msm_set_volume(sessionId, vol)) {
+        ALOGE("msm_set_volume(%d %f) failed errno = %d",sessionId, vol,errno);
+        return -1;
+    }
+    ALOGV("LPA volume set (%f) succeeded",vol);
+    return NO_ERROR;
+}
+
+status_t AudioHardware::AudioSessionOutLPA::openAudioSessionDevice( )
+{
+    status_t status = NO_ERROR;
+
+    //It opens LPA driver
+    ALOGE("Opening LPA pcm_dec driver");
+    afd = open("/dev/msm_pcm_lp_dec", O_WRONLY | O_NONBLOCK);
+    if ( afd < 0 ) {
+        ALOGE("pcm_lp_dec: cannot open pcm_dec device and the error is %d", errno);
+        //initCheck = false;
+        return UNKNOWN_ERROR;
+    } else {
+        //initCheck = true;
+        ALOGV("pcm_lp_dec: pcm_lp_dec Driver opened");
+    }
+
+    start();
+    ALOGE("Calling bufferAlloc ");
+        bufferAlloc();
+
+    return status;
+}
+
+void AudioHardware::AudioSessionOutLPA::bufferAlloc( )
+{
+    // Allocate ION buffers
+    void *ion_buf; int32_t ion_fd;
+    struct msm_audio_ion_info ion_info;
+    ALOGE("Allocate ION buffers");
+    //1. Open the ion_audio
+    ionfd = open("/dev/ion", O_RDONLY | O_SYNC);
+    if (ionfd < 0) {
+        ALOGE("/dev/ion open failed \n");
+        return;
+    }
+    for (int i = 0; i < mInputBufferCount; i++) {
+        ion_buf = memBufferAlloc(mInputBufferSize, &ion_fd);
+        memset(&ion_info, 0, sizeof(msm_audio_ion_info));
+        ALOGE("Registering ION with fd %d and address as %p", ion_fd, ion_buf);
+        ion_info.fd = ion_fd;
+        ion_info.vaddr = ion_buf;
+        if ( ioctl(afd, AUDIO_REGISTER_ION, &ion_info) < 0 ) {
+            ALOGE("Registration of ION with the Driver failed with fd %d and memory %x",
+                 ion_info.fd, (unsigned int)ion_info.vaddr);
+        }
+    }
+    ALOGE("Allocating ION buffers complete");
+}
+
+
+void* AudioHardware::AudioSessionOutLPA::memBufferAlloc(int nSize, int32_t *ion_fd)
+{
+    void  *ion_buf = NULL;
+    void  *local_buf = NULL;
+    struct ion_fd_data fd_data;
+    struct ion_allocation_data alloc_data;
+
+    alloc_data.len =   nSize;
+    alloc_data.align = 0x1000;
+    alloc_data.flags = ION_HEAP(ION_AUDIO_HEAP_ID);
+    int rc = ioctl(ionfd, ION_IOC_ALLOC, &alloc_data);
+    if (rc) {
+        ALOGE("ION_IOC_ALLOC ioctl failed\n");
+        return ion_buf;
+    }
+    fd_data.handle = alloc_data.handle;
+
+    rc = ioctl(ionfd, ION_IOC_SHARE, &fd_data);
+    if (rc) {
+        ALOGE("ION_IOC_SHARE ioctl failed\n");
+        rc = ioctl(ionfd, ION_IOC_FREE, &(alloc_data.handle));
+        if (rc) {
+            ALOGE("ION_IOC_FREE ioctl failed\n");
+        }
+        return ion_buf;
+    }
+
+    // 2. MMAP to get the virtual address
+    ion_buf = mmap(NULL, nSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd_data.fd, 0);
+    if(MAP_FAILED == ion_buf) {
+        ALOGE("mmap() failed \n");
+        close(fd_data.fd);
+        rc = ioctl(ionfd, ION_IOC_FREE, &(alloc_data.handle));
+        if (rc) {
+            ALOGE("ION_IOC_FREE ioctl failed\n");
+        }
+        return ion_buf;
+    }
+
+    local_buf = malloc(nSize);
+    if (NULL == local_buf) {
+        // unmap the corresponding ION buffer and close the fd
+        munmap(ion_buf, mInputBufferSize);
+        close(fd_data.fd);
+        rc = ioctl(ionfd, ION_IOC_FREE, &(alloc_data.handle));
+        if (rc) {
+            ALOGE("ION_IOC_FREE ioctl failed\n");
+        }
+        return NULL;
+    }
+
+    // 3. Store this information for internal mapping / maintanence
+    BuffersAllocated buf(local_buf, ion_buf, nSize, fd_data.fd, alloc_data.handle);
+    mEmptyQueue.push_back(buf);
+
+    // 4. Send the mem fd information
+    *ion_fd = fd_data.fd;
+    ALOGV("IONBufferAlloc calling with required size %d", nSize);
+    ALOGV("ION allocated is %d, fd_data.fd %d and buffer is %x", *ion_fd, fd_data.fd, (unsigned int)ion_buf);
+
+    // 5. Return the virtual address
+    return ion_buf;
+}
+
+void AudioHardware::AudioSessionOutLPA::bufferDeAlloc()
+{
+    // De-Allocate ION buffers
+    int rc = 0;
+    //Remove all the buffers from empty queue
+    mEmptyQueueMutex.lock();
+    while (!mEmptyQueue.empty())  {
+        List<BuffersAllocated>::iterator it = mEmptyQueue.begin();
+        BuffersAllocated &ionBuffer = *it;
+        struct msm_audio_ion_info ion_info;
+        ion_info.vaddr = (*it).memBuf;
+        ion_info.fd = (*it).memFd;
+        if (ioctl(afd, AUDIO_DEREGISTER_ION, &ion_info) < 0) {
+            ALOGE("ION deregister failed");
+        }
+        ALOGV("Ion Unmapping the address %p, size %d, fd %d from empty",ionBuffer.memBuf,ionBuffer.bytesToWrite,ionBuffer.memFd);
+        munmap(ionBuffer.memBuf, mInputBufferSize);
+        ALOGV("closing the ion shared fd");
+        close(ionBuffer.memFd);
+        rc = ioctl(ionfd, ION_IOC_FREE, &ionBuffer.ion_handle);
+        if (rc) {
+            ALOGE("ION_IOC_FREE ioctl failed\n");
+        }
+        // free the local buffer corresponding to ion buffer
+        free(ionBuffer.localBuf);
+        ALOGE("Removing from empty Q");
+        mEmptyQueue.erase(it);
+    }
+    mEmptyQueueMutex.unlock();
+
+    //Remove all the buffers from Filled queue
+    mFilledQueueMutex.lock();
+    while(!mFilledQueue.empty()){
+        List<BuffersAllocated>::iterator it = mFilledQueue.begin();
+        BuffersAllocated &ionBuffer = *it;
+        struct msm_audio_ion_info ion_info;
+        ion_info.vaddr = (*it).memBuf;
+        ion_info.fd = (*it).memFd;
+        if (ioctl(afd, AUDIO_DEREGISTER_ION, &ion_info) < 0) {
+            ALOGE("ION deregister failed");
+        }
+        ALOGV("Ion Unmapping the address %p, size %d, fd %d from Request",ionBuffer.memBuf,ionBuffer.bytesToWrite,ionBuffer.memFd);
+        munmap(ionBuffer.memBuf, mInputBufferSize);
+        ALOGV("closing the ion shared fd");
+        close(ionBuffer.memFd);
+        rc = ioctl(ionfd, ION_IOC_FREE, &ionBuffer.ion_handle);
+        if (rc) {
+            ALOGE("ION_IOC_FREE ioctl failed\n");
+        }
+        // free the local buffer corresponding to ion buffer
+        free(ionBuffer.localBuf);
+        ALOGV("Removing from Filled Q");
+        mFilledQueue.erase(it);
+    }
+    mFilledQueueMutex.unlock();
+    if (ionfd >= 0) {
+        close(ionfd);
+        ionfd = -1;
+    }
+}
+
+uint32_t AudioHardware::AudioSessionOutLPA::latency() const
+{
+    // Android wants latency in milliseconds.
+    return 1000;//TODO to correct the value
+}
+
+void AudioHardware::AudioSessionOutLPA::requestAndWaitForEventThreadExit()
+{
+    if (!mEventThreadAlive)
+        return;
+    mKillEventThread = true;
+    if (ioctl(afd, AUDIO_ABORT_GET_EVENT, 0) < 0) {
+        ALOGE("Audio Abort event failed");
+    }
+    pthread_join(mEventThread,NULL);
+}
+
+void * AudioHardware::AudioSessionOutLPA::eventThreadWrapper(void *me)
+{
+    static_cast<AudioSessionOutLPA *>(me)->eventThreadEntry();
+    return NULL;
+}
+
+void  AudioHardware::AudioSessionOutLPA::eventThreadEntry()
+{
+    struct msm_audio_event cur_pcmdec_event;
+    mEventThreadAlive = true;
+    int rc = 0;
+    //2.) Set the priority for the event thread
+    pid_t tid  = gettid();
+    androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO);
+    prctl(PR_SET_NAME, (unsigned long)"HAL Audio EventThread", 0, 0, 0);
+    ALOGV("event thread created ");
+    if (mKillEventThread) {
+        mEventThreadAlive = false;
+        ALOGV("Event Thread is dying.");
+        return;
+    }
+    while (1) {
+        //Wait for an event to occur
+        rc = ioctl(afd, AUDIO_GET_EVENT, &cur_pcmdec_event);
+        ALOGE("pcm dec Event Thread rc = %d and errno is %d",rc, errno);
+
+        if ( (rc < 0) && ((errno == ENODEV) || (errno == EBADF)) ) {
+            ALOGV("AUDIO__GET_EVENT called. Exit the thread");
+            break;
+        }
+
+        switch ( cur_pcmdec_event.event_type ) {
+        case AUDIO_EVENT_WRITE_DONE:
+            {
+                ALOGE("WRITE_DONE: addr %p len %d and fd is %d\n",
+                     cur_pcmdec_event.event_payload.aio_buf.buf_addr,
+                     cur_pcmdec_event.event_payload.aio_buf.data_len,
+                     (int32_t) cur_pcmdec_event.event_payload.aio_buf.private_data);
+                Mutex::Autolock autoLock(mLock);
+                mFilledQueueMutex.lock();
+                BuffersAllocated buf = *(mFilledQueue.begin());
+                for (List<BuffersAllocated>::iterator it = mFilledQueue.begin();
+                    it != mFilledQueue.end(); ++it) {
+                    if (it->memBuf == cur_pcmdec_event.event_payload.aio_buf.buf_addr) {
+                        buf = *it;
+                        mFilledQueue.erase(it);
+                        // Post buffer to Empty Q
+                        ALOGV("mEmptyQueueMutex locking: %d", __LINE__);
+                        mEmptyQueueMutex.lock();
+                        ALOGV("mEmptyQueueMutex locked: %d", __LINE__);
+                        mEmptyQueue.push_back(buf);
+                        ALOGV("mEmptyQueueMutex unlocking: %d", __LINE__);
+                        mEmptyQueueMutex.unlock();
+                        ALOGV("mEmptyQueueMutex unlocked: %d", __LINE__);
+                        if (mFilledQueue.empty() && mReachedEOS) {
+                            ALOGV("Posting the EOS to the observer player %p", mObserver);
+                            mEosEventReceived = true;
+                            if (mObserver != NULL) {
+                                ALOGV("mObserver: posting EOS");
+                                mObserver->postEOS(0);
+                            }
+                        }
+                        break;
+                    }
+                }
+                mFilledQueueMutex.unlock();
+                 mWriteCv.signal();
+            }
+            break;
+        case AUDIO_EVENT_SUSPEND:
+            {
+                struct msm_audio_stats stats;
+                int nBytesConsumed = 0;
+
+                ALOGV("AUDIO_EVENT_SUSPEND received\n");
+                if (!mPaused) {
+                    ALOGV("Not in paused, no need to honor SUSPEND event");
+                    break;
+                }
+                // 1. Get the Byte count that is consumed
+                if ( ioctl(afd, AUDIO_GET_STATS, &stats)  < 0 ) {
+                    ALOGE("AUDIO_GET_STATUS failed");
+                } else {
+                    ALOGV("Number of bytes consumed by DSP is %u", stats.byte_count);
+                    nBytesConsumed = stats.byte_count;
+                    }
+                    // Reset eosflag to resume playback where we actually paused
+                    mReachedEOS = false;
+                    // 3. Call AUDIO_STOP on the Driver.
+                    ALOGV("Received AUDIO_EVENT_SUSPEND and calling AUDIO_STOP");
+                    if ( ioctl(afd, AUDIO_STOP, 0) < 0 ) {
+                         ALOGE("AUDIO_STOP failed");
+                    }
+                    mIsDriverStarted = false;
+                    break;
+            }
+            break;
+        case AUDIO_EVENT_RESUME:
+            {
+                ALOGV("AUDIO_EVENT_RESUME received\n");
+            }
+            break;
+        default:
+            ALOGE("Received Invalid Event from driver\n");
+            break;
+        }
+    }
+    mEventThreadAlive = false;
+    ALOGV("Event Thread is dying.");
+}
+
+
+void AudioHardware::AudioSessionOutLPA::createEventThread()
+{
+    ALOGV("Creating Event Thread");
+    mKillEventThread = false;
+    mEventThreadAlive = true;
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+    pthread_create(&mEventThread, &attr, eventThreadWrapper, this);
+    ALOGV("Event Thread created");
+}
+
+status_t AudioHardware::AudioSessionOutLPA::start( )
+{
+
+    ALOGE("LPA playback start");
+    if (mPaused && mIsDriverStarted) {
+        mPaused = false;
+        if (ioctl(afd, AUDIO_PAUSE, 0) < 0) {
+            ALOGE("Resume:: LPA driver resume failed");
+            return UNKNOWN_ERROR;
+        }
+
+    } else {
+	 //get config, set config and AUDIO_START LPA driver
+	 int sessionId = 0;
+        mPaused = false;
+        if ( afd >= 0 ) {
+           struct msm_audio_config config;
+           if ( ioctl(afd, AUDIO_GET_CONFIG, &config) < 0 ) {
+               ALOGE("could not get config");
+               close(afd);
+               afd = -1;
+               return BAD_VALUE;
+        }
+
+        config.sample_rate = mSampleRate;
+        config.channel_count = mChannels;
+        ALOGE("sample_rate=%d and channel count=%d \n", mSampleRate, mChannels);
+        if ( ioctl(afd, AUDIO_SET_CONFIG, &config) < 0 ) {
+            ALOGE("could not set config");
+            close(afd);
+            afd = -1;
+            return BAD_VALUE;
+        }
+    }
+    unsigned short decId;
+    // Get the session id from the LPA Driver
+    // Register the session id with HAL for routing
+    if ( ioctl(afd, AUDIO_GET_SESSION_ID, &decId) == -1 ) {
+        ALOGE("AUDIO_GET_SESSION_ID FAILED\n");
+        return BAD_VALUE;
+    } else {
+        sessionId = (int)decId;
+        ALOGV("AUDIO_GET_SESSION_ID success : decId = %d", decId);
+    }
+
+    Mutex::Autolock lock(mDeviceSwitchLock);
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+    if(getNodeByStreamType(LPA_DECODE) != NULL) {
+        ALOGE("Not allowed, There is alread an LPA Node existing");
+        return -1;
+    }
+    ALOGE("AudioSessionOutMSM8x60::set() Adding LPA_DECODE Node to Table");
+    addToTable(sessionId,cur_rx,INVALID_DEVICE,LPA_DECODE,true);
+#endif
+    ALOGE("enableDevice(cur_rx = %d, dev_id = %d)",cur_rx,DEV_ID(cur_rx));
+    if (enableDevice(cur_rx, 1)) {
+        ALOGE("enableDevice failed for device cur_rx %d", cur_rx);
+        return -1;
+    }
+
+    ALOGE("msm_route_stream(PCM_PLAY,%d,%d,0)",sessionId,DEV_ID(cur_rx));
+#ifdef QCOM_ACDB_ENABLED
+    acdb_loader_send_audio_cal(ACDB_ID(cur_rx), CAPABILITY(cur_rx));
+#endif
+    if(msm_route_stream(PCM_PLAY,sessionId,DEV_ID(cur_rx),1)) {
+        ALOGE("msm_route_stream(PCM_PLAY,%d,%d,1) failed",sessionId,DEV_ID(cur_rx));
+        return -1;
+    }
+
+    Mutex::Autolock lock_1(mComboDeviceLock);
+#ifdef QCOM_FM_ENABLED
+    if(CurrentComboDeviceData.DeviceId == SND_DEVICE_FM_TX_AND_SPEAKER){
+        ALOGD("Routing LPA steam to speaker for combo device");
+        ALOGD("combo:msm_route_stream(LPA_DECODE,session id:%d,dev id:%d,1)",sessionId,
+            DEV_ID(DEVICE_SPEAKER_RX));
+            /* music session is already routed to speaker in
+             * enableComboDevice(), but at this point it can
+             * be said that it was done with incorrect session id,
+             * so re-routing with correct session id here.
+             */
+        if(msm_route_stream(PCM_PLAY, sessionId, DEV_ID(DEVICE_SPEAKER_RX),
+           1)) {
+            ALOGE("msm_route_stream failed");
+            return -1;
+        }
+        CurrentComboDeviceData.StreamType = LPA_DECODE;
+    }
+#endif
+	//Start the Driver
+    if (ioctl(afd, AUDIO_START,0) < 0) {
+        ALOGE("Driver start failed!");
+        return BAD_VALUE;
+    }
+    mIsDriverStarted = true;
+    ALOGE("LPA Playback started");
+    if (timeStarted == 0)
+        timeStarted = nanoseconds_to_microseconds(systemTime(SYSTEM_TIME_MONOTONIC));// Needed
+	}
+	return NO_ERROR;
+}
+
+status_t AudioHardware::AudioSessionOutLPA::pause()
+{
+    ALOGV("LPA playback pause");
+    if (ioctl(afd, AUDIO_PAUSE, 1) < 0) {
+    ALOGE("Audio Pause failed");
+    }
+    mPaused = true;
+	timePlayed += (nanoseconds_to_microseconds(systemTime(SYSTEM_TIME_MONOTONIC)) - timeStarted);//needed
+    return NO_ERROR;
+}
+
+status_t AudioHardware::AudioSessionOutLPA::drain()
+{
+    ALOGV("LPA playback EOS");
+    return NO_ERROR;
+}
+
+status_t AudioHardware::AudioSessionOutLPA::flush()
+{
+    ALOGV("LPA playback flush ");
+    int err;
+
+    // 2.) Add all the available buffers to Empty Queue (Maintain order)
+    mFilledQueueMutex.lock();
+    mEmptyQueueMutex.lock();
+    while (!mFilledQueue.empty()) {
+        List<BuffersAllocated>::iterator it = mFilledQueue.begin();
+        BuffersAllocated buf = *it;
+        buf.bytesToWrite = 0;
+        mEmptyQueue.push_back(buf);
+        mFilledQueue.erase(it);
+    }
+    mEmptyQueueMutex.unlock();
+    mFilledQueueMutex.unlock();
+    ALOGV("Transferred all the buffers from Filled queue to "
+          "Empty queue to handle seek");
+    mReachedEOS = false;
+    if (!mPaused) {
+        if (!mEosEventReceived) {
+            if (ioctl(afd, AUDIO_PAUSE, 1) < 0) {
+                ALOGE("Audio Pause failed");
+                return UNKNOWN_ERROR;
+            }
+            if (ioctl(afd, AUDIO_FLUSH, 0) < 0) {
+                ALOGE("Audio Flush failed");
+                return UNKNOWN_ERROR;
+            }
+        }
+    } else {
+        timeStarted = 0;
+        if (ioctl(afd, AUDIO_FLUSH, 0) < 0) {
+            ALOGE("Audio Flush failed");
+            return UNKNOWN_ERROR;
+        }
+        if (ioctl(afd, AUDIO_PAUSE, 1) < 0) {
+            ALOGE("Audio Pause failed");
+            return UNKNOWN_ERROR;
+        }
+    }
+    mEosEventReceived = false;
+    //4.) Skip the current write from the decoder and signal to the Write get
+    //   the next set of data from the decoder
+    mSkipWrite = true;
+    mWriteCv.signal();
+    return NO_ERROR;
+}
+status_t AudioHardware::AudioSessionOutLPA::stop()
+{
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("AudioSessionOutLPA- stop");
+    // close all the existing PCM devices
+    mSkipWrite = true;
+    mWriteCv.signal();
+    return NO_ERROR;
+}
+
+status_t AudioHardware::AudioSessionOutLPA::setObserver(void *observer)
+{
+    ALOGV("Registering the callback \n");
+    mObserver = reinterpret_cast<AudioEventObserver *>(observer);
+    return NO_ERROR;
+}
+
+status_t  AudioHardware::AudioSessionOutLPA::getNextWriteTimestamp(int64_t *timestamp)
+{
+
+    *timestamp = nanoseconds_to_microseconds(systemTime(SYSTEM_TIME_MONOTONIC)) - timeStarted + timePlayed;//needed
+    ALOGV("Timestamp returned = %lld\n", *timestamp);
+    return NO_ERROR;
+}
+
+void AudioHardware::AudioSessionOutLPA::reset()
+{
+	Routing_table* temp = NULL;
+    ALOGD("AudioSessionOutLPA::reset()");
+    ioctl(afd,AUDIO_STOP,0);
+    mIsDriverStarted = false;
+	requestAndWaitForEventThreadExit();
+    status_t status = NO_ERROR;
+    bufferDeAlloc();
+    ::close(afd);
+    temp = getNodeByStreamType(LPA_DECODE);
+
+    if (temp == NULL) {
+        ALOGE("LPA node does not exist");
+        return ;
+    }
+    ALOGD("Deroute lpa playback stream");
+    if(msm_route_stream(PCM_PLAY, temp->dec_id,DEV_ID(temp->dev_id), 0)) {
+        ALOGE("could not set stream routing\n");
+        deleteFromTable(LPA_DECODE);
+    }
+    deleteFromTable(LPA_DECODE);
+    if (!getNodeByStreamType(VOICE_CALL) && !getNodeByStreamType(PCM_PLAY)
+#ifdef QCOM_FM_ENABLED
+        && !getNodeByStreamType(FM_RADIO)
+#endif
+#ifdef QCOM_VOIP_ENABLED
+        && !getNodeByStreamType(VOIP_CALL)
+#endif
+       ) {
+#ifdef QCOM_ANC_HEADSET_ENABLED
+        if (anc_running == false) {
+#endif
+            if (enableDevice(cur_rx, 0)) {
+                ALOGE("Disabling device failed for cur_rx %d", cur_rx);
+            }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+        }
+#endif
+    }
+    ALOGE("AudioSessionOutLPA::reset() complete");
+}
+
+status_t AudioHardware::AudioSessionOutLPA::getRenderPosition(uint32_t *dspFrames)
+{
+    //TODO: enable when supported by driver
+    return INVALID_OPERATION;
+}
+
+
+status_t AudioHardware::AudioSessionOutLPA::getBufferInfo(buf_info **buf) {
+
+    buf_info *tempbuf = (buf_info *)malloc(sizeof(buf_info) + mInputBufferCount*sizeof(int *));
+    ALOGV("Get buffer info");
+    tempbuf->bufsize = LPA_BUFFER_SIZE;
+    tempbuf->nBufs = mInputBufferCount;
+    tempbuf->buffers = (int **)((char*)tempbuf + sizeof(buf_info));
+    List<BuffersAllocated>::iterator it = mEmptyQueue.begin();
+    for (int i = 0; i < mInputBufferCount; i++) {
+        tempbuf->buffers[i] = (int *)it->memBuf;
+        it++;
+    }
+    *buf = tempbuf;
+    return NO_ERROR;
+}
+
+status_t AudioHardware::AudioSessionOutLPA::isBufferAvailable(int *isAvail) {
+
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("isBufferAvailable Empty Queue size() = %d, Filled Queue size() = %d ",
+          mEmptyQueue.size(),mFilledQueue.size());
+    *isAvail = false;
+    // 1.) Wait till a empty buffer is available in the Empty buffer queue
+    mEmptyQueueMutex.lock();
+    if (mEmptyQueue.empty()) {
+        ALOGV("Write: waiting on mWriteCv");
+        mLock.unlock();
+        mWriteCv.wait(mEmptyQueueMutex);
+        mLock.lock();
+        if (mSkipWrite) {
+            ALOGV("Write: Flushing the previous write buffer");
+            mSkipWrite = false;
+            mEmptyQueueMutex.unlock();
+            return NO_ERROR;
+        }
+        ALOGV("Write: received a signal to wake up");
+    }
+    mEmptyQueueMutex.unlock();
+
+    *isAvail = true;
+    return NO_ERROR;
+}
+
+// End AudioSessionOutLPA
+//.----------------------------------------------------------------------------
+#endif
+
+int mFdin = -1;
+AudioHardware::AudioStreamInMSM8x60::AudioStreamInMSM8x60() :
+    mHardware(0), mState(AUDIO_INPUT_CLOSED), mRetryCount(0),
+    mFormat(AUDIO_HW_IN_FORMAT), mChannels(AUDIO_HW_IN_CHANNELS),
+    mSampleRate(AUDIO_HW_IN_SAMPLERATE), mBufferSize(AUDIO_HW_IN_BUFFERSIZE),
+    mAcoustics((AudioSystem::audio_in_acoustics)0), mDevices(0), mForVR(0)
+{
+}
+
+status_t AudioHardware::AudioStreamInMSM8x60::set(
+        AudioHardware* hw, uint32_t devices, int *pFormat, uint32_t *pChannels, uint32_t *pRate,
+        AudioSystem::audio_in_acoustics acoustic_flags)
+{
+    if ((pFormat == 0) || (*pFormat != AUDIO_HW_IN_FORMAT))
+    {
+        *pFormat = AUDIO_HW_IN_FORMAT;
+        return BAD_VALUE;
+    }
+
+    if (pRate == 0) {
+        return BAD_VALUE;
+    }
+    uint32_t rate = hw->getInputSampleRate(*pRate);
+    if (rate != *pRate) {
+        *pRate = rate;
+        ALOGE(" sample rate does not match\n");
+        return BAD_VALUE;
+    }
+
+    if (pChannels == 0 || (*pChannels & (AudioSystem::CHANNEL_IN_MONO | AudioSystem::CHANNEL_IN_STEREO)) == 0) {
+        *pChannels = AUDIO_HW_IN_CHANNELS;
+        ALOGE(" Channel count does not match\n");
+        return BAD_VALUE;
+    }
+
+    mHardware = hw;
+
+    ALOGV("AudioStreamInMSM8x60::set(%d, %d, %u)", *pFormat, *pChannels, *pRate);
+    if (mFdin >= 0) {
+        ALOGE("Audio record already open");
+        return -EPERM;
+    }
+    status_t status =0;
+    struct msm_voicerec_mode voc_rec_cfg;
+#ifdef QCOM_FM_ENABLED
+    if(devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
+        status = ::open("/dev/msm_pcm_in", O_RDONLY);
+        if (status < 0) {
+            ALOGE("Cannot open /dev/msm_pcm_in errno: %d", errno);
+            goto Error;
+        }
+        mFdin = status;
+        // configuration
+        ALOGV("get config");
+        struct msm_audio_config config;
+        status = ioctl(mFdin, AUDIO_GET_CONFIG, &config);
+        if (status < 0) {
+            ALOGE("Cannot read config");
+            goto Error;
+        }
+
+        ALOGV("set config");
+        config.channel_count = AudioSystem::popCount(*pChannels);
+        config.sample_rate = *pRate;
+        config.buffer_size = bufferSize();
+        config.buffer_count = 2;
+        config.type = CODEC_TYPE_PCM;
+        status = ioctl(mFdin, AUDIO_SET_CONFIG, &config);
+        if (status < 0) {
+            ALOGE("Cannot set config");
+            if (ioctl(mFdin, AUDIO_GET_CONFIG, &config) == 0) {
+                if (config.channel_count == 1) {
+                    *pChannels = AudioSystem::CHANNEL_IN_MONO;
+                } else {
+                    *pChannels = AudioSystem::CHANNEL_IN_STEREO;
+                }
+                *pRate = config.sample_rate;
+            }
+            goto Error;
+        }
+
+        ALOGV("confirm config");
+        status = ioctl(mFdin, AUDIO_GET_CONFIG, &config);
+        if (status < 0) {
+            ALOGE("Cannot read config");
+            goto Error;
+        }
+        ALOGV("buffer_size: %u", config.buffer_size);
+        ALOGV("buffer_count: %u", config.buffer_count);
+        ALOGV("channel_count: %u", config.channel_count);
+        ALOGV("sample_rate: %u", config.sample_rate);
+
+        mDevices = devices;
+        mFormat = AUDIO_HW_IN_FORMAT;
+        mChannels = *pChannels;
+        mSampleRate = config.sample_rate;
+        mBufferSize = config.buffer_size;
+    } else
+#endif
+      if (*pFormat == AUDIO_HW_IN_FORMAT) {
+        if (mHardware->mNumPcmRec > 0) {
+            /* Only one PCM recording is allowed at a time */
+            ALOGE("Multiple PCM recordings is not allowed");
+            status = -1;
+            goto Error;
+        }
+        // open audio input device
+        status = ::open("/dev/msm_pcm_in", O_RDWR);
+        if (status < 0) {
+            ALOGE("Cannot open /dev/msm_pcm_in errno: %d", errno);
+            goto Error;
+        }
+        mHardware->mNumPcmRec ++;
+        mFdin = status;
+
+        // configuration
+        ALOGV("get config");
+        struct msm_audio_config config;
+        status = ioctl(mFdin, AUDIO_GET_CONFIG, &config);
+        if (status < 0) {
+            ALOGE("Cannot read config");
+            goto Error;
+        }
+
+        ALOGV("set config");
+        config.channel_count = AudioSystem::popCount((*pChannels) &
+                              (AudioSystem::CHANNEL_IN_STEREO|
+                               AudioSystem::CHANNEL_IN_MONO));
+
+        config.sample_rate = *pRate;
+
+        mBufferSize = mHardware->getInputBufferSize(config.sample_rate,
+                                                    AUDIO_HW_IN_FORMAT,
+                                                    config.channel_count);
+        config.buffer_size = bufferSize();
+        // Make buffers to be allocated in driver equal to the number of buffers
+        // that AudioFlinger allocates (Shared memory)
+        config.buffer_count = 4;
+        config.type = CODEC_TYPE_PCM;
+        status = ioctl(mFdin, AUDIO_SET_CONFIG, &config);
+        if (status < 0) {
+            ALOGE("Cannot set config");
+            if (ioctl(mFdin, AUDIO_GET_CONFIG, &config) == 0) {
+                if (config.channel_count == 1) {
+                    *pChannels = AudioSystem::CHANNEL_IN_MONO;
+                } else {
+                    *pChannels = AudioSystem::CHANNEL_IN_STEREO;
+                }
+                *pRate = config.sample_rate;
+            }
+            goto Error;
+        }
+
+        ALOGV("confirm config");
+        status = ioctl(mFdin, AUDIO_GET_CONFIG, &config);
+        if (status < 0) {
+            ALOGE("Cannot read config");
+            goto Error;
+        }
+        ALOGV("buffer_size: %u", config.buffer_size);
+        ALOGV("buffer_count: %u", config.buffer_count);
+        ALOGV("channel_count: %u", config.channel_count);
+        ALOGV("sample_rate: %u", config.sample_rate);
+
+        mDevices = devices;
+        mFormat = AUDIO_HW_IN_FORMAT;
+        mChannels = *pChannels;
+        mSampleRate = config.sample_rate;
+        mBufferSize = config.buffer_size;
+
+        if (mDevices == AudioSystem::DEVICE_IN_VOICE_CALL) {
+            if ((mChannels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) &&
+                (mChannels & AudioSystem::CHANNEL_IN_VOICE_UPLINK)) {
+                ALOGV("Recording Source: Voice Call Both Uplink and Downlink");
+                voc_rec_cfg.rec_mode = VOC_REC_BOTH;
+            } else if (mChannels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
+                ALOGV("Recording Source: Voice Call DownLink");
+                voc_rec_cfg.rec_mode = VOC_REC_DOWNLINK;
+            } else if (mChannels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) {
+                ALOGV("Recording Source: Voice Call UpLink");
+                voc_rec_cfg.rec_mode = VOC_REC_UPLINK;
+            }
+            if (ioctl(mFdin, AUDIO_SET_INCALL, &voc_rec_cfg)) {
+                ALOGE("Error: AUDIO_SET_INCALL failed\n");
+                goto  Error;
+            }
+        }
+#ifdef QCOM_ACDB_ENABLED
+    if(vr_enable && dualmic_enabled) {
+        int audpre_mask = 0;
+        audpre_mask = FLUENCE_ENABLE;
+
+            ALOGV("enable fluence");
+            if (ioctl(mFdin, AUDIO_ENABLE_AUDPRE, &audpre_mask)) {
+                ALOGV("cannot write audio config");
+                goto Error;
+            }
+        }
+#endif
+    }
+    //mHardware->setMicMute_nosync(false);
+    mState = AUDIO_INPUT_OPENED;
+#ifdef HTC_ACOUSTIC_AUDIO
+    mHardware->set_mRecordState(true);
+#endif
+
+    if (!acoustic)
+    {
+        return NO_ERROR;
+    }
+#ifdef QCOM_ACDB_ENABLED
+    int (*msm8x60_set_audpre_params)(int, int);
+    msm8x60_set_audpre_params = (int (*)(int, int))::dlsym(acoustic, "msm8x60_set_audpre_params");
+    if ((*msm8x60_set_audpre_params) == 0) {
+        ALOGI("msm8x60_set_audpre_params not present");
+        return NO_ERROR;
+    }
+
+    int (*msm8x60_enable_audpre)(int, int, int);
+    msm8x60_enable_audpre = (int (*)(int, int, int))::dlsym(acoustic, "msm8x60_enable_audpre");
+    if ((*msm8x60_enable_audpre) == 0) {
+        ALOGI("msm8x60_enable_audpre not present");
+        return NO_ERROR;
+    }
+
+    audpre_index = calculate_audpre_table_index(mSampleRate);
+    tx_iir_index = (audpre_index * 2) + (hw->checkOutputStandby() ? 0 : 1);
+    ALOGD("audpre_index = %d, tx_iir_index = %d\n", audpre_index, tx_iir_index);
+
+    /**
+     * If audio-preprocessing failed, we should not block record.
+     */
+    status = msm8x60_set_audpre_params(audpre_index, tx_iir_index);
+    if (status < 0)
+        ALOGE("Cannot set audpre parameters");
+
+    mAcoustics = acoustic_flags;
+    status = msm8x60_enable_audpre((int)acoustic_flags, audpre_index, tx_iir_index);
+    if (status < 0)
+        ALOGE("Cannot enable audpre");
+#endif
+    return NO_ERROR;
+
+Error:
+    if (mFdin >= 0) {
+        ::close(mFdin);
+        mFdin = -1;
+    }
+    return status;
+}
+
+AudioHardware::AudioStreamInMSM8x60::~AudioStreamInMSM8x60()
+{
+    ALOGV("AudioStreamInMSM8x60 destructor");
+    standby();
+}
+
+ssize_t AudioHardware::AudioStreamInMSM8x60::read( void* buffer, ssize_t bytes)
+{
+    unsigned short dec_id = INVALID_DEVICE;
+    ALOGV("AudioStreamInMSM8x60::read(%p, %ld)", buffer, bytes);
+    if (!mHardware) return -1;
+
+    size_t count = bytes;
+    size_t  aac_framesize= bytes;
+    uint8_t* p = static_cast<uint8_t*>(buffer);
+    uint32_t* recogPtr = (uint32_t *)p;
+    uint16_t* frameCountPtr;
+    uint16_t* frameSizePtr;
+
+    if (mState < AUDIO_INPUT_OPENED) {
+        AudioHardware *hw = mHardware;
+        hw->mLock.lock();
+        status_t status = set(hw, mDevices, &mFormat, &mChannels, &mSampleRate, mAcoustics);
+        if (status != NO_ERROR) {
+            hw->mLock.unlock();
+            return -1;
+        }
+#ifdef QCOM_FM_ENABLED
+        if((mDevices == AudioSystem::DEVICE_IN_FM_RX) || (mDevices == AudioSystem::DEVICE_IN_FM_RX_A2DP) ){
+            if(ioctl(mFdin, AUDIO_GET_SESSION_ID, &dec_id)) {
+                ALOGE("AUDIO_GET_SESSION_ID failed*********");
+                hw->mLock.unlock();
+                return -1;
+            }
+
+            if(enableDevice(DEVICE_FMRADIO_STEREO_TX, 1)) {
+                ALOGE("enableDevice DEVICE_FMRADIO_STEREO_TX failed");
+                hw->mLock.unlock();
+                return -1;
+             }
+
+            acdb_loader_send_audio_cal(ACDB_ID(DEVICE_FMRADIO_STEREO_TX),
+            CAPABILITY(DEVICE_FMRADIO_STEREO_TX));
+
+            ALOGV("route FM");
+            if(msm_route_stream(PCM_REC, dec_id, DEV_ID(DEVICE_FMRADIO_STEREO_TX), 1)) {
+                ALOGE("msm_route_stream failed");
+                hw->mLock.unlock();
+                return -1;
+            }
+
+            //addToTable(dec_id,cur_tx,INVALID_DEVICE,PCM_REC,true);
+            mFirstread = false;
+            if (mDevices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
+                addToTable(dec_id,cur_tx,INVALID_DEVICE,FM_A2DP,true);
+                mFmRec = FM_A2DP_REC;
+            } else {
+                addToTable(dec_id,cur_tx,INVALID_DEVICE,FM_REC,true);
+                mFmRec = FM_FILE_REC;
+            }
+            hw->mLock.unlock();
+        } else
+#endif
+        {
+            hw->mLock.unlock();
+            if(ioctl(mFdin, AUDIO_GET_SESSION_ID, &dec_id)) {
+                ALOGE("AUDIO_GET_SESSION_ID failed*********");
+                return -1;
+            }
+            Mutex::Autolock lock(mDeviceSwitchLock);
+            if (!(mChannels & AudioSystem::CHANNEL_IN_VOICE_DNLINK ||
+                  mChannels & AudioSystem::CHANNEL_IN_VOICE_UPLINK)) {
+                 ALOGV("dec_id = %d,cur_tx= %d",dec_id,cur_tx);
+                 if(cur_tx == INVALID_DEVICE)
+                     cur_tx = DEVICE_HANDSET_TX;
+                 if(enableDevice(cur_tx, 1)) {
+                     ALOGE("enableDevice failed for device cur_rx %d",cur_rx);
+                     return -1;
+                 }
+#ifdef QCOM_ACDB_ENABLED
+                 acdb_loader_send_audio_cal(ACDB_ID(cur_tx), CAPABILITY(cur_tx));
+#endif
+                 if(msm_route_stream(PCM_REC, dec_id, DEV_ID(cur_tx), 1)) {
+                    ALOGE("msm_route_stream failed");
+                    return -1;
+                 }
+                 addToTable(dec_id,cur_tx,INVALID_DEVICE,PCM_REC,true);
+            }
+            mFirstread = false;
+        }
+    }
+
+
+    if (mState < AUDIO_INPUT_STARTED) {
+        if (!(mChannels & AudioSystem::CHANNEL_IN_VOICE_DNLINK ||
+            mChannels & AudioSystem::CHANNEL_IN_VOICE_UPLINK)) {
+#ifdef QCOM_FM_ENABLED
+            // force routing to input device
+            // for FM recording, no need to reconfigure afe loopback path
+            if (mFmRec != FM_FILE_REC) {
+#endif
+                mHardware->clearCurDevice();
+                mHardware->doRouting(this);
+#ifdef HTC_ACOUSTIC_AUDIO
+                if (support_aic3254) {
+                    int snd_dev = mHardware->get_snd_dev();
+                    mHardware->aic3254_config(snd_dev);
+                    mHardware->do_aic3254_control(snd_dev);
+                }
+#endif
+#ifdef QCOM_FM_ENABLED
+            }
+#endif
+        }
+        if (ioctl(mFdin, AUDIO_START, 0)) {
+            ALOGE("Error starting record");
+            standby();
+            return -1;
+        }
+        mState = AUDIO_INPUT_STARTED;
+    }
+
+    bytes = 0;
+    if(mFormat == AUDIO_HW_IN_FORMAT)
+    {
+        if(count < mBufferSize) {
+            ALOGE("read:: read size requested is less than min input buffer size");
+            return 0;
+        }
+        while (count >= mBufferSize) {
+            ssize_t bytesRead = ::read(mFdin, buffer, count);
+            usleep(1);
+            if (bytesRead >= 0) {
+                count -= bytesRead;
+                p += bytesRead;
+                bytes += bytesRead;
+                if(!mFirstread)
+                {
+                   mFirstread = true;
+                   ALOGE(" FirstRead Done bytesRead = %d count = %d",bytesRead,count);
+                   break;
+                }
+            } else {
+                if (errno != EAGAIN) return bytesRead;
+                mRetryCount++;
+                ALOGW("EAGAIN - retrying");
+            }
+        }
+    }
+
+    return bytes;
+}
+
+status_t AudioHardware::AudioStreamInMSM8x60::standby()
+{
+    bool isDriverClosed = false;
+    ALOGD("AudioStreamInMSM8x60::standby()");
+    Routing_table* temp = NULL;
+    if (!mHardware) return -1;
+#ifdef HTC_ACOUSTIC_AUDIO
+    mHardware->set_mRecordState(false);
+    if (support_aic3254) {
+        int snd_dev = mHardware->get_snd_dev();
+        mHardware->aic3254_config(snd_dev);
+        mHardware->do_aic3254_control(snd_dev);
+    }
+#endif
+    if (mState > AUDIO_INPUT_CLOSED) {
+        if (mFdin >= 0) {
+            ::close(mFdin);
+            mFdin = -1;
+            ALOGV("driver closed");
+            isDriverClosed = true;
+            if(mHardware->mNumPcmRec && mFormat == AUDIO_HW_IN_FORMAT) {
+                mHardware->mNumPcmRec --;
+            }
+        }
+        mState = AUDIO_INPUT_CLOSED;
+    }
+#ifdef QCOM_FM_ENABLED
+       if (mFmRec == FM_A2DP_REC) {
+        //A2DP Recording
+        temp = getNodeByStreamType(FM_A2DP);
+        if(temp == NULL)
+            return NO_ERROR;
+        if(msm_route_stream(PCM_PLAY, temp->dec_id, DEV_ID(DEVICE_FMRADIO_STEREO_TX), 0)) {
+           ALOGE("msm_route_stream failed");
+           return 0;
+        }
+        deleteFromTable(FM_A2DP);
+        if(enableDevice(DEVICE_FMRADIO_STEREO_TX, 0)) {
+            ALOGE("enableDevice failed for device cur_rx %d", cur_rx);
+        }
+    }
+    if (mFmRec == FM_FILE_REC) {
+        //FM Recording
+        temp = getNodeByStreamType(FM_REC);
+        if(temp == NULL)
+            return NO_ERROR;
+        if(msm_route_stream(PCM_PLAY, temp->dec_id, DEV_ID(DEVICE_FMRADIO_STEREO_TX), 0)) {
+           ALOGE("msm_route_stream failed");
+           return 0;
+        }
+        deleteFromTable(FM_REC);
+    }
+#endif
+    temp = getNodeByStreamType(PCM_REC);
+    if(temp == NULL)
+        return NO_ERROR;
+
+    if(isDriverClosed){
+        ALOGV("Deroute pcm stream");
+        if (!(mChannels & AudioSystem::CHANNEL_IN_VOICE_DNLINK ||
+            mChannels & AudioSystem::CHANNEL_IN_VOICE_UPLINK)) {
+            if(msm_route_stream(PCM_REC, temp->dec_id,DEV_ID(temp->dev_id), 0)) {
+               ALOGE("could not set stream routing\n");
+               deleteFromTable(PCM_REC);
+               return -1;
+            }
+        }
+        ALOGV("Disable device");
+        deleteFromTable(PCM_REC);
+        if(!getNodeByStreamType(VOICE_CALL)
+#ifdef QCOM_VOIP_ENABLED
+         && !getNodeByStreamType(VOIP_CALL)
+#endif
+         ) {
+            if(enableDevice(cur_tx, 0)) {
+                ALOGE("Disabling device failed for cur_tx %d", cur_tx);
+                return 0;
+            }
+        }
+    } //isDriverClosed condition
+    // restore output routing if necessary
+    mHardware->clearCurDevice();
+    mHardware->doRouting(this);
+    return NO_ERROR;
+}
+
+status_t AudioHardware::AudioStreamInMSM8x60::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    result.append("AudioStreamInMSM8x60::dump\n");
+    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tformat: %d\n", format());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmHardware: %p\n", mHardware);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmFd count: %d\n", mFdin);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmState: %d\n", mState);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmRetryCount: %d\n", mRetryCount);
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioHardware::AudioStreamInMSM8x60::setParameters(const String8& keyValuePairs)
+{
+    AudioParameter param = AudioParameter(keyValuePairs);
+    String8 key = String8(AudioParameter::keyRouting);
+    status_t status = NO_ERROR;
+    int device;
+    ALOGV("AudioStreamInMSM8x60::setParameters() %s", keyValuePairs.string());
+
+    if (param.getInt(String8("vr_mode"), mForVR) == NO_ERROR)
+        ALOGV("voice_recognition=%d", mForVR);
+
+    if (param.getInt(key, device) == NO_ERROR) {
+        ALOGV("set input routing %x", device);
+        if (device & (device - 1)) {
+            status = BAD_VALUE;
+        } else if (device) {
+            mDevices = device;
+            status = mHardware->doRouting(this);
+        }
+        param.remove(key);
+    }
+
+    if (param.size()) {
+        status = BAD_VALUE;
+    }
+    return status;
+}
+
+String8 AudioHardware::AudioStreamInMSM8x60::getParameters(const String8& keys)
+{
+    AudioParameter param = AudioParameter(keys);
+    String8 value;
+    String8 key = String8(AudioParameter::keyRouting);
+
+    if (param.get(key, value) == NO_ERROR) {
+        ALOGV("get routing %x", mDevices);
+        param.addInt(key, (int)mDevices);
+    }
+
+    ALOGV("AudioStreamInMSM8x60::getParameters() %s", param.toString().string());
+    return param.toString();
+}
+
+// getActiveInput_l() must be called with mLock held
+AudioHardware::AudioStreamInMSM8x60 *AudioHardware::getActiveInput_l()
+{
+    for (size_t i = 0; i < mInputs.size(); i++) {
+        // return first input found not being in standby mode
+        // as only one input can be in this state
+        if (mInputs[i]->state() > AudioStreamInMSM8x60::AUDIO_INPUT_CLOSED) {
+            return mInputs[i];
+        }
+    }
+
+    return NULL;
+}
+
+#ifdef QCOM_VOIP_ENABLED
+// ----------------------------------------------------------------------------
+//  VOIP stream class
+//.----------------------------------------------------------------------------
+AudioHardware::AudioStreamInVoip::AudioStreamInVoip() :
+    mHardware(0), mFd(-1), mState(AUDIO_INPUT_CLOSED), mRetryCount(0),
+    mFormat(AUDIO_HW_IN_FORMAT), mChannels(AUDIO_HW_IN_CHANNELS),
+    mSampleRate(AUDIO_HW_VOIP_SAMPLERATE_8K), mBufferSize(AUDIO_HW_VOIP_BUFFERSIZE_8K),
+    mAcoustics((AudioSystem::audio_in_acoustics)0), mDevices(0)
+{
+}
+
+status_t AudioHardware::AudioStreamInVoip::set(
+        AudioHardware* hw, uint32_t devices, int *pFormat, uint32_t *pChannels, uint32_t *pRate,
+        AudioSystem::audio_in_acoustics acoustic_flags)
+{
+    ALOGV(" AudioHardware::AudioStreamInVoip::set devices = %u format = %d pChannels = %u Rate = %u \n",
+         devices, *pFormat, *pChannels, *pRate);
+    ALOGV("AudioStreamInVoip cur_rx %d, cur_tx %d" ,cur_rx,cur_tx);
+    if ((pFormat == 0) || (*pFormat != AUDIO_HW_IN_FORMAT))
+    {
+        *pFormat = AUDIO_HW_IN_FORMAT;
+        return BAD_VALUE;
+    }
+
+    if (pRate == 0) {
+        return BAD_VALUE;
+    }
+    uint32_t rate = hw->getInputSampleRate(*pRate);
+    if (rate != *pRate) {
+        *pRate = rate;
+        ALOGE(" sample rate does not match\n");
+        return BAD_VALUE;
+    }
+
+    if (pChannels == 0 || (*pChannels & (AudioSystem::CHANNEL_IN_MONO)) == 0) {
+        *pChannels = AUDIO_HW_IN_CHANNELS;
+        ALOGE(" Channle count does not match\n");
+        return BAD_VALUE;
+    }
+
+    mHardware = hw;
+
+    ALOGV("AudioStreamInVoip::set(%d, %d, %u)", *pFormat, *pChannels, *pRate);
+    if (mFd >= 0) {
+        ALOGE("Audio record already open");
+        return -EPERM;
+    }
+
+        status_t status = NO_INIT;
+        // open driver
+        ALOGV("Check if driver is open");
+        if(mHardware->mVoipFd >= 0) {
+            mFd = mHardware->mVoipFd;
+            // Increment voip stream count
+            mHardware->mNumVoipStreams++;
+            ALOGV("MVS driver is already opened, mHardware->mNumVoipStreams = %d \n", mHardware->mNumVoipStreams);
+        }
+        else {
+            ALOGE("open mvs driver");
+            status = ::open(MVS_DEVICE, /*O_WRONLY*/ O_RDWR);
+            if (status < 0) {
+                ALOGE("Cannot open %s errno: %d",MVS_DEVICE, errno);
+                goto Error;
+            }
+            mFd = status;
+            ALOGE("VOPIstreamin : Save the fd \n");
+            mHardware->mVoipFd = mFd;
+            // Increment voip stream count
+            mHardware->mNumVoipStreams++;
+            ALOGV(" input stream set mHardware->mNumVoipStreams = %d \n", mHardware->mNumVoipStreams);
+
+            // configuration
+            ALOGV("get mvs config");
+            struct msm_audio_mvs_config mvs_config;
+            status = ioctl(mFd, AUDIO_GET_MVS_CONFIG, &mvs_config);
+            if (status < 0) {
+               ALOGE("Cannot read mvs config");
+               goto Error;
+            }
+
+            ALOGV("set mvs config");
+            int samplerate = *pRate;
+            if(samplerate == AUDIO_HW_VOIP_SAMPLERATE_8K) {
+                 mvs_config.mvs_mode = MVS_MODE_PCM;
+            } else if(samplerate == AUDIO_HW_VOIP_SAMPLERATE_16K) {
+                 mvs_config.mvs_mode = MVS_MODE_PCM_WB;
+            } else {
+                 ALOGE("unsupported samplerate for voip");
+                 goto Error;
+            }
+            status = ioctl(mFd, AUDIO_SET_MVS_CONFIG, &mvs_config);
+            if (status < 0) {
+                ALOGE("Cannot set mvs config");
+                goto Error;
+            }
+
+            ALOGV("start mvs");
+            status = ioctl(mFd, AUDIO_START, 0);
+            if (status < 0) {
+                ALOGE("Cannot start mvs driver");
+                goto Error;
+            }
+
+            ALOGV("Going to enable RX/TX device for voice stream");
+
+            Mutex::Autolock lock(mDeviceSwitchLock);
+            // Routing Voip
+           if ( (cur_rx != INVALID_DEVICE) && (cur_tx != INVALID_DEVICE))
+           {
+               ALOGV("Starting voip on Rx %d and Tx %d device", DEV_ID(cur_rx), DEV_ID(cur_tx));
+               msm_route_voice(DEV_ID(cur_rx),DEV_ID(cur_tx), 1);
+           }
+           else
+           {
+               return -1;
+           }
+
+           if(cur_rx != INVALID_DEVICE && (enableDevice(cur_rx,1) == -1))
+           {
+               ALOGE(" Enable device for cur_rx failed \n");
+               return -1;
+           }
+
+           if(cur_tx != INVALID_DEVICE&&(enableDevice(cur_tx,1) == -1))
+           {
+               ALOGE(" Enable device for cur_tx failed \n");
+               return -1;
+           }
+#ifdef QCOM_ACDB_ENABLED
+           // voice calibration
+           acdb_loader_send_voice_cal(ACDB_ID(cur_rx),ACDB_ID(cur_tx));
+#endif
+           // start Voice call
+#ifdef LEGACY_QCOM_VOICE
+           msm_start_voice();
+           msm_set_voice_tx_mute(0);
+#else
+           if(voip_session_id <= 0) {
+                voip_session_id = msm_get_voc_session(VOIP_SESSION_NAME);
+           }
+           ALOGD("Starting voip call and UnMuting the call");
+           msm_start_voice_ext(voip_session_id);
+           msm_set_voice_tx_mute_ext(voip_session_mute,voip_session_id);
+#endif
+           addToTable(0,cur_rx,cur_tx,VOIP_CALL,true);
+    }
+    mFormat =  *pFormat;
+    mChannels = *pChannels;
+    mSampleRate = *pRate;
+    if(mSampleRate == 8000)
+       mBufferSize = 320;
+    else if(mSampleRate == 16000)
+       mBufferSize = 640;
+    else
+    {
+       ALOGE(" unsupported sample rate");
+       return -1;
+    }
+
+	 ALOGV(" AudioHardware::AudioStreamInVoip::set after configuring devices = %u format = %d pChannels = %u Rate = %u \n",
+         devices, mFormat, mChannels, mSampleRate);
+
+    ALOGV(" Set state  AUDIO_INPUT_OPENED\n");
+    mState = AUDIO_INPUT_OPENED;
+
+    if (!acoustic)
+        return NO_ERROR;
+
+     return NO_ERROR;
+
+Error:
+    if (mFd >= 0) {
+        ::close(mFd);
+        mFd = -1;
+        mHardware->mVoipFd = -1;
+    }
+    ALOGE("Error : ret status \n");
+    return status;
+}
+
+AudioHardware::AudioStreamInVoip::~AudioStreamInVoip()
+{
+    ALOGV("AudioStreamInVoip destructor");
+    standby();
+    if (mHardware->mNumVoipStreams)
+        mHardware->mNumVoipStreams--;
+}
+
+ssize_t AudioHardware::AudioStreamInVoip::read( void* buffer, ssize_t bytes)
+{
+    unsigned short dec_id = INVALID_DEVICE;
+    ALOGV("AudioStreamInVoip::read(%p, %ld)", buffer, bytes);
+    if (!mHardware) return -1;
+
+    size_t count = bytes;
+    size_t totalBytesRead = 0;
+    size_t  aac_framesize= bytes;
+    uint8_t* p = static_cast<uint8_t*>(buffer);
+    uint32_t* recogPtr = (uint32_t *)p;
+    uint16_t* frameCountPtr;
+    uint16_t* frameSizePtr;
+    if (mState < AUDIO_INPUT_OPENED) {
+       ALOGE(" reopen the device \n");
+        AudioHardware *hw = mHardware;
+        hw->mLock.lock();
+        status_t status = set(hw, mDevices, &mFormat, &mChannels, &mSampleRate, mAcoustics);
+        if (status != NO_ERROR) {
+            hw->mLock.unlock();
+            return -1;
+        }
+        hw->mLock.unlock();
+        mState = AUDIO_INPUT_STARTED;
+        bytes = 0;
+  } else {
+      ALOGE("AudioStreamInVoip::read : device is already open \n");
+  }
+
+
+  if(mFormat == AUDIO_HW_IN_FORMAT)
+  {
+      if(count < mBufferSize) {
+          ALOGE("read:: read size requested is less than min input buffer size");
+          return 0;
+      }
+
+      struct msm_audio_mvs_frame audio_mvs_frame;
+      audio_mvs_frame.frame_type = 0;
+      while (count >= mBufferSize) {
+          audio_mvs_frame.len = count;
+          ALOGV("Calling read count = %u mBufferSize = %u\n",count, mBufferSize );
+          int bytesRead = ::read(mFd, &audio_mvs_frame, sizeof(audio_mvs_frame));
+          ALOGV("read_bytes = %d \n", bytesRead);
+          if (bytesRead > 0) {
+              memcpy(buffer,&audio_mvs_frame.voc_pkt, count);
+              count -= audio_mvs_frame.len;
+              p += audio_mvs_frame.len;
+              totalBytesRead += audio_mvs_frame.len;
+              if(!mFirstread) {
+                  mFirstread = true;
+                  break;
+              }
+              } else {
+                  ALOGE("retry read count = %d buffersize = %d\n", count, mBufferSize);
+                  if (errno != EAGAIN) return bytesRead;
+                  mRetryCount++;
+                  ALOGW("EAGAIN - retrying");
+              }
+      }
+  }
+  return totalBytesRead;
+}
+
+status_t AudioHardware::AudioStreamInVoip::standby()
+{
+    bool isDriverClosed = false;
+    Routing_table* temp = NULL;
+    if (!mHardware) return -1;
+    ALOGV(" AudioStreamInVoip::standby = %d \n", mHardware->mNumVoipStreams);
+    if (mState > AUDIO_INPUT_CLOSED && (mHardware->mNumVoipStreams == 1)) {
+         ALOGE(" closing mvs driver\n");
+         //Mute and disable the device.
+         int ret = 0;
+#ifdef LEGACY_QCOM_VOICE
+        msm_end_voice();
+#else
+         ret = msm_end_voice_ext(voip_session_id);
+         if (ret < 0)
+                 ALOGE("Error %d ending voice\n", ret);
+#endif
+        temp = getNodeByStreamType(VOIP_CALL);
+        if(temp == NULL)
+        {
+            ALOGE("VOIPin: Going to disable RX/TX return 0");
+            return 0;
+        }
+
+        if((temp->dev_id != INVALID_DEVICE && temp->dev_id_tx != INVALID_DEVICE)) {
+           if(!getNodeByStreamType(VOICE_CALL)
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+              && !getNodeByStreamType(LPA_DECODE)
+#endif /*QCOM_TUNNEL_LPA_ENABLED*/
+              && !getNodeByStreamType(PCM_PLAY)
+#ifdef QCOM_FM_ENABLED
+              && !getNodeByStreamType(FM_RADIO)
+#endif /*QCOM_FM_ENABLED*/
+            ) {
+#ifdef QCOM_ANC_HEADSET_ENABLED
+               if (anc_running == false) {
+#endif
+                   enableDevice(temp->dev_id, 0);
+                   ALOGV("Voipin: disable voip rx");
+#ifdef QCOM_ANC_HEADSET_ENABLED
+               }
+#endif
+            }
+            if(!getNodeByStreamType(VOICE_CALL) && !getNodeByStreamType(PCM_REC)) {
+                 enableDevice(temp->dev_id_tx,0);
+                 ALOGD("VOIPin: disable voip tx");
+            }
+        }
+        deleteFromTable(VOIP_CALL);
+         if (mFd >= 0) {
+            ret = ioctl(mFd, AUDIO_STOP, NULL);
+            ALOGE("MVS stop returned %d \n", ret);
+            ::close(mFd);
+            mFd = mHardware->mVoipFd = -1;
+            ALOGV("driver closed");
+            isDriverClosed = true;
+            voip_session_id = 0;
+            voip_session_mute = 0;
+        }
+        mState = AUDIO_INPUT_CLOSED;
+    }
+    return NO_ERROR;
+}
+
+status_t AudioHardware::AudioStreamInVoip::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    result.append("AudioStreamInVoip::dump\n");
+    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tformat: %d\n", format());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmHardware: %p\n", mHardware);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmFd count: %d\n", mFd);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmState: %d\n", mState);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmRetryCount: %d\n", mRetryCount);
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioHardware::AudioStreamInVoip::setParameters(const String8& keyValuePairs)
+{
+    AudioParameter param = AudioParameter(keyValuePairs);
+    String8 key = String8(AudioParameter::keyRouting);
+    status_t status = NO_ERROR;
+    int device;
+    ALOGV("AudioStreamInVoip::setParameters() %s", keyValuePairs.string());
+
+    if (param.getInt(key, device) == NO_ERROR) {
+        ALOGV("set input routing %x", device);
+        if (device & (device - 1)) {
+            status = BAD_VALUE;
+        } else {
+            mDevices = device;
+            status = mHardware->doRouting(this);
+        }
+        param.remove(key);
+    }
+
+    if (param.size()) {
+        status = BAD_VALUE;
+    }
+    return status;
+}
+
+String8 AudioHardware::AudioStreamInVoip::getParameters(const String8& keys)
+{
+    AudioParameter param = AudioParameter(keys);
+    String8 value;
+    String8 key = String8(AudioParameter::keyRouting);
+
+    if (param.get(key, value) == NO_ERROR) {
+        ALOGV("get routing %x", mDevices);
+        param.addInt(key, (int)mDevices);
+    }
+
+    ALOGV("AudioStreamInVoip::getParameters() %s", param.toString().string());
+    return param.toString();
+}
+
+// getActiveInput_l() must be called with mLock held
+AudioHardware::AudioStreamInVoip*AudioHardware::getActiveVoipInput_l()
+{
+    for (size_t i = 0; i < mVoipInputs.size(); i++) {
+        // return first input found not being in standby mode
+        // as only one input can be in this state
+        if (mVoipInputs[i]->state() > AudioStreamInVoip::AUDIO_INPUT_CLOSED) {
+            return mVoipInputs[i];
+        }
+    }
+
+    return NULL;
+}
+// ---------------------------------------------------------------------------
+//  VOIP stream class end
+#endif
+
+extern "C" AudioHardwareInterface* createAudioHardware(void) {
+    return new AudioHardware();
+}
+
+}; // namespace android_audio_legacy
diff --git a/msm8660/AudioHardware.h b/msm8660/AudioHardware.h
new file mode 100644
index 0000000..d66d941
--- /dev/null
+++ b/msm8660/AudioHardware.h
@@ -0,0 +1,581 @@
+/*
+** Copyright 2008, The Android Open-Source Project
+** Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+**
+** 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 ANDROID_AUDIO_HARDWARE_H
+#define ANDROID_AUDIO_HARDWARE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/List.h>
+
+#include <utils/threads.h>
+#include <sys/prctl.h>
+#include <utils/SortedVector.h>
+
+#include <hardware_legacy/AudioHardwareBase.h>
+
+extern "C" {
+#include <linux/msm_audio.h>
+#include <linux/ion.h>
+#include <linux/msm_audio_aac.h>
+}
+namespace android_audio_legacy {
+using android::List;
+using android::SortedVector;
+using android::Mutex;
+using android::Condition;
+
+// ----------------------------------------------------------------------------
+// Kernel driver interface
+//
+
+#define SAMP_RATE_INDX_8000	    0
+#define SAMP_RATE_INDX_11025	1
+#define SAMP_RATE_INDX_12000	2
+#define SAMP_RATE_INDX_16000	3
+#define SAMP_RATE_INDX_22050	4
+#define SAMP_RATE_INDX_24000	5
+#define SAMP_RATE_INDX_32000	6
+#define SAMP_RATE_INDX_44100	7
+#define SAMP_RATE_INDX_48000	8
+
+#define EQ_MAX_BAND_NUM 12
+
+#define ADRC_ENABLE     0x0001
+#define ADRC_DISABLE    0x0000
+#define EQ_ENABLE       0x0002
+#define EQ_DISABLE      0x0000
+#define RX_IIR_ENABLE   0x0004
+#define RX_IIR_DISABLE  0x0000
+#define LPA_BUFFER_SIZE 512*1024
+#define BUFFER_COUNT 2
+#define MONO_CHANNEL_MODE 1
+
+#ifdef HTC_ACOUSTIC_AUDIO
+    #define MOD_PLAY 1
+    #define MOD_REC  2
+    #define MOD_TX   3
+    #define MOD_RX   4
+
+    #define ACDB_ID_HEADSET_PLAYBACK          10
+    #define ACDB_ID_ALT_SPKR_PLAYBACK         601
+
+    #define ACDB_ID_HAC_HANDSET_MIC           107
+    #define ACDB_ID_HAC_HANDSET_SPKR          207
+    #define ACDB_ID_EXT_MIC_REC               307
+    #define ACDB_ID_HEADSET_RINGTONE_PLAYBACK 408
+    #define ACDB_ID_INT_MIC_REC               507
+    #define ACDB_ID_CAMCORDER                 508
+    #define ACDB_ID_INT_MIC_VR                509
+    #define ACDB_ID_SPKR_PLAYBACK             607
+
+    struct msm_bt_endpoint {
+        int tx;
+        int rx;
+        char name[64];
+    };
+#endif
+
+struct eq_filter_type {
+    int16_t  gain;
+    uint16_t freq;
+    uint16_t type;
+    uint16_t qf;
+};
+
+struct eqalizer {
+    uint16_t bands;
+    uint16_t params[132];
+};
+
+struct rx_iir_filter {
+    uint16_t num_bands;
+    uint16_t iir_params[48];
+};
+
+enum tty_modes {
+    TTY_OFF = 0,
+    TTY_VCO = 1,
+    TTY_HCO = 2,
+    TTY_FULL = 3
+};
+
+#define CODEC_TYPE_PCM 0
+#define AUDIO_HW_NUM_OUT_BUF 2  // Number of buffers in audio driver for output
+// TODO: determine actual audio DSP and hardware latency
+#define AUDIO_HW_OUT_LATENCY_MS 0  // Additionnal latency introduced by audio DSP and hardware in ms
+
+#define AUDIO_HW_IN_SAMPLERATE 8000                 // Default audio input sample rate
+#define AUDIO_HW_IN_CHANNELS (AudioSystem::CHANNEL_IN_MONO) // Default audio input channel mask
+#define AUDIO_HW_IN_BUFFERSIZE 480 * 4                 // Default audio input buffer size
+#define AUDIO_HW_IN_FORMAT (AudioSystem::PCM_16_BIT)  // Default audio input sample format
+#ifdef QCOM_VOIP_ENABLED
+#define AUDIO_HW_VOIP_BUFFERSIZE_8K 320
+#define AUDIO_HW_VOIP_BUFFERSIZE_16K 640
+#define AUDIO_HW_VOIP_SAMPLERATE_8K 8000
+#define AUDIO_HW_VOIP_SAMPLERATE_16K 16000
+#endif
+
+class AudioHardware : public  AudioHardwareBase
+{
+    class AudioStreamOutMSM8x60;
+    class AudioSessionOutLPA;
+    class AudioStreamInMSM8x60;
+#ifdef QCOM_VOIP_ENABLED
+    class AudioStreamOutDirect;
+    class AudioStreamInVoip;
+#endif
+
+public:
+                        AudioHardware();
+    virtual             ~AudioHardware();
+    virtual status_t    initCheck();
+
+    virtual status_t    setVoiceVolume(float volume);
+    virtual status_t    setMasterVolume(float volume);
+#ifdef QCOM_FM_ENABLED
+    virtual status_t    setFmVolume(float volume);
+#endif
+    virtual status_t    setMode(int mode);
+
+    // mic mute
+    virtual status_t    setMicMute(bool state);
+    virtual status_t    getMicMute(bool* state);
+
+    virtual status_t    setParameters(const String8& keyValuePairs);
+    virtual String8     getParameters(const String8& keys);
+
+    // create I/O streams
+    virtual AudioStreamOut* openOutputStream(
+                                uint32_t devices,
+                                int *format=0,
+                                uint32_t *channels=0,
+                                uint32_t *sampleRate=0,
+                                status_t *status=0);
+    virtual AudioStreamIn* openInputStream(
+                                uint32_t devices,
+                                int *format,
+                                uint32_t *channels,
+                                uint32_t *sampleRate,
+                                status_t *status,
+                                AudioSystem::audio_in_acoustics acoustics);
+
+    virtual    void        closeOutputStream(AudioStreamOut* out);
+    virtual    void        closeInputStream(AudioStreamIn* in);
+
+    virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+               void        clearCurDevice() { mCurSndDevice = -1; }
+
+protected:
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+
+private:
+
+    status_t    doAudioRouteOrMute(uint32_t device);
+    status_t    setMicMute_nosync(bool state);
+    status_t    checkMicMute();
+    status_t    dumpInternals(int fd, const Vector<String16>& args);
+    uint32_t    getInputSampleRate(uint32_t sampleRate);
+    bool        checkOutputStandby();
+#ifdef HTC_ACOUSTIC_AUDIO
+    status_t    get_mMode();
+    status_t    set_mRecordState(bool onoff);
+    status_t    get_mRecordState();
+    status_t    get_snd_dev();
+#endif
+    status_t    doRouting(AudioStreamInMSM8x60 *input);
+#ifdef HTC_ACOUSTIC_AUDIO
+    void        getACDB(uint32_t device);
+    status_t    do_aic3254_control(uint32_t device);
+    bool        isAic3254Device(uint32_t device);
+    status_t    aic3254_config(uint32_t device);
+    int         aic3254_ioctl(int cmd, const int argc);
+    void        aic3254_powerdown();
+#endif
+#ifdef QCOM_FM_ENABLED
+    status_t    enableFM(int sndDevice);
+#endif
+    status_t    enableComboDevice(uint32_t sndDevice, bool enableOrDisable);
+#ifdef QCOM_FM_ENABLED
+    status_t    disableFM();
+#endif
+    AudioStreamInMSM8x60*   getActiveInput_l();
+#ifdef QCOM_VOIP_ENABLED
+    AudioStreamInVoip* getActiveVoipInput_l();
+#endif
+    class AudioStreamOutMSM8x60 : public AudioStreamOut {
+    public:
+                            AudioStreamOutMSM8x60();
+        virtual             ~AudioStreamOutMSM8x60();
+                status_t    set(AudioHardware* mHardware,
+                                uint32_t devices,
+                                int *pFormat,
+                                uint32_t *pChannels,
+                                uint32_t *pRate);
+        virtual uint32_t    sampleRate() const { return 44100; }
+        // must be 32-bit aligned - driver only seems to like 4800
+        virtual size_t      bufferSize() const { return 4800; }
+        virtual uint32_t    channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
+        virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+        virtual uint32_t    latency() const { return (1000*AUDIO_HW_NUM_OUT_BUF*(bufferSize()/frameSize()))/sampleRate()+AUDIO_HW_OUT_LATENCY_MS; }
+        virtual status_t    setVolume(float left, float right) { return INVALID_OPERATION; }
+        virtual ssize_t     write(const void* buffer, size_t bytes);
+        virtual status_t    standby();
+        virtual status_t    dump(int fd, const Vector<String16>& args);
+                bool        checkStandby();
+        virtual status_t    setParameters(const String8& keyValuePairs);
+        virtual String8     getParameters(const String8& keys);
+                uint32_t    devices() { return mDevices; }
+        virtual status_t    getRenderPosition(uint32_t *dspFrames);
+
+    private:
+                AudioHardware* mHardware;
+                int         mFd;
+                int         mStartCount;
+                int         mRetryCount;
+                bool        mStandby;
+                uint32_t    mDevices;
+    };
+#ifdef QCOM_VOIP_ENABLED
+    class AudioStreamOutDirect : public AudioStreamOut {
+    public:
+                            AudioStreamOutDirect();
+        virtual             ~AudioStreamOutDirect();
+                status_t    set(AudioHardware* mHardware,
+                                uint32_t devices,
+                                int *pFormat,
+                                uint32_t *pChannels,
+                                uint32_t *pRate);
+        virtual uint32_t    sampleRate() const { return mSampleRate; }
+        virtual size_t      bufferSize() const { return mBufferSize; }
+        virtual uint32_t    channels() const { return mChannels; }
+        virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+        virtual uint32_t    latency() const { return (1000*AUDIO_HW_NUM_OUT_BUF*(bufferSize()/frameSize()))/sampleRate()+AUDIO_HW_OUT_LATENCY_MS; }
+        virtual status_t    setVolume(float left, float right) { return INVALID_OPERATION; }
+        virtual ssize_t     write(const void* buffer, size_t bytes);
+        virtual status_t    standby();
+        virtual status_t    dump(int fd, const Vector<String16>& args);
+                bool        checkStandby();
+        virtual status_t    setParameters(const String8& keyValuePairs);
+        virtual String8     getParameters(const String8& keys);
+                uint32_t    devices() { return mDevices; }
+        virtual status_t    getRenderPosition(uint32_t *dspFrames);
+
+    private:
+                AudioHardware* mHardware;
+                int         mFd;
+                int         mStartCount;
+                int         mRetryCount;
+                bool        mStandby;
+                uint32_t    mDevices;
+                uint32_t    mChannels;
+                uint32_t    mSampleRate;
+                size_t      mBufferSize;
+                int         mFormat;
+    };
+#endif
+
+class AudioSessionOutLPA : public AudioStreamOut
+{
+public:
+    AudioSessionOutLPA(AudioHardware* mHardware,
+                        uint32_t   devices,
+                        int        format,
+                        uint32_t   channels,
+                        uint32_t   samplingRate,
+                        int        type,
+                        status_t   *status);
+    virtual            ~AudioSessionOutLPA();
+
+    virtual uint32_t    sampleRate() const
+    {
+        return mSampleRate;
+    }
+
+    virtual size_t      bufferSize() const
+    {
+        return mBufferSize;
+    }
+
+    virtual uint32_t    channels() const
+    {
+        return mChannels;
+    }
+
+    virtual int         format() const
+    {
+        return mFormat;
+    }
+
+    virtual uint32_t    latency() const;
+
+    virtual ssize_t     write(const void *buffer, size_t bytes);
+
+    virtual status_t    start( );
+    virtual status_t    pause();
+    virtual status_t    flush();
+    virtual status_t    stop();
+
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+
+    status_t            setVolume(float left, float right);
+
+    virtual status_t    standby();
+
+    virtual status_t    setParameters(const String8& keyValuePairs);
+
+    virtual String8     getParameters(const String8& keys);
+
+
+    // return the number of audio frames written by the audio dsp to DAC since
+    // the output has exited standby
+    virtual status_t    getRenderPosition(uint32_t *dspFrames);
+
+    virtual status_t    getNextWriteTimestamp(int64_t *timestamp);
+    virtual status_t    setObserver(void *observer);
+    virtual status_t    getBufferInfo(buf_info **buf);
+    virtual status_t    isBufferAvailable(int *isAvail);
+
+    void* memBufferAlloc(int nSize, int32_t *ion_fd);
+
+private:
+    Mutex               mLock;
+    uint32_t            mFrameCount;
+    uint32_t            mSampleRate;
+    uint32_t            mChannels;
+    size_t              mBufferSize;
+    int                 mFormat;
+    uint32_t            mStreamVol;
+
+    bool                mPaused;
+    bool                mIsDriverStarted;
+    bool                mSeeking;
+    bool                mReachedEOS;
+    bool                mSkipWrite;
+    bool                mEosEventReceived;
+    uint32_t    mDevices;
+    AudioHardware* mHardware;
+    AudioEventObserver *mObserver;
+
+    void                createEventThread();
+    void                bufferAlloc();
+    void                bufferDeAlloc();
+    bool                isReadyToPostEOS(int errPoll, void *fd);
+    status_t            drain();
+	status_t            openAudioSessionDevice();
+    // make sure the event thread also exited
+    void                requestAndWaitForEventThreadExit();
+    int32_t             writeToDriver(char *buffer, int bytes);
+    static void *       eventThreadWrapper(void *me);
+    void                eventThreadEntry();
+//??    status_t            pause_l();
+//??    status_t            resume_l();
+    void                reset();
+
+    //Structure to hold ion buffer information
+    class BuffersAllocated {
+    /* overload BuffersAllocated constructor to support both ion and pmem memory allocation */
+    public:
+        BuffersAllocated(void *buf1, void *buf2, int32_t nSize, int32_t fd) :
+        localBuf(buf1), memBuf(buf2), memBufsize(nSize), memFd(fd)
+        {}
+        BuffersAllocated(void *buf1, void *buf2, int32_t nSize, int32_t share_fd, struct ion_handle *handle) :
+        ion_handle(handle), localBuf(buf1), memBuf(buf2), memBufsize(nSize), memFd(share_fd)
+        {}
+        struct ion_handle *ion_handle;
+        void* localBuf;
+        void* memBuf;
+        int32_t memBufsize;
+        int32_t memFd;
+        uint32_t bytesToWrite;
+    };
+    List<BuffersAllocated> mEmptyQueue;
+    List<BuffersAllocated> mFilledQueue;
+    List<BuffersAllocated> mBufPool;
+
+    //Declare all the threads
+    pthread_t mEventThread;
+
+    //Declare the condition Variables and Mutex
+    Mutex mEmptyQueueMutex;
+    Mutex mFilledQueueMutex;
+
+    Condition mWriteCv;
+    Condition mEventCv;
+	pthread_mutex_t event_mutex;
+    bool mKillEventThread;
+    bool mEventThreadAlive;
+    int mInputBufferSize;
+    int mInputBufferCount;
+    int64_t timePlayed;
+    int64_t timeStarted;
+
+    //event fd to signal the EOS and Kill from the userspace
+    int efd;
+	int afd;
+	int ionfd;
+};
+
+
+    class AudioStreamInMSM8x60 : public AudioStreamIn {
+    public:
+        enum input_state {
+            AUDIO_INPUT_CLOSED,
+            AUDIO_INPUT_OPENED,
+            AUDIO_INPUT_STARTED
+        };
+
+                            AudioStreamInMSM8x60();
+        virtual             ~AudioStreamInMSM8x60();
+                status_t    set(AudioHardware* mHardware,
+                                uint32_t devices,
+                                int *pFormat,
+                                uint32_t *pChannels,
+                                uint32_t *pRate,
+                                AudioSystem::audio_in_acoustics acoustics);
+        virtual size_t      bufferSize() const { return mBufferSize; }
+        virtual uint32_t    channels() const { return mChannels; }
+        virtual int         format() const { return mFormat; }
+        virtual uint32_t    sampleRate() const { return mSampleRate; }
+        virtual status_t    setGain(float gain) { return INVALID_OPERATION; }
+        virtual ssize_t     read(void* buffer, ssize_t bytes);
+        virtual status_t    dump(int fd, const Vector<String16>& args);
+        virtual status_t    standby();
+        virtual status_t    setParameters(const String8& keyValuePairs);
+        virtual String8     getParameters(const String8& keys);
+        virtual unsigned int  getInputFramesLost() const { return 0; }
+                uint32_t    devices() { return mDevices; }
+                int         state() const { return mState; }
+        virtual status_t    addAudioEffect(effect_interface_s**) { return 0;}
+        virtual status_t    removeAudioEffect(effect_interface_s**) { return 0;}
+        virtual int         isForVR() const { return mForVR; }
+
+    private:
+                AudioHardware* mHardware;
+                int         mState;
+                int         mRetryCount;
+                int         mFormat;
+                uint32_t    mChannels;
+                uint32_t    mSampleRate;
+                size_t      mBufferSize;
+                AudioSystem::audio_in_acoustics mAcoustics;
+                uint32_t    mDevices;
+                bool        mFirstread;
+                uint32_t    mFmRec;
+                int         mForVR;
+    };
+#ifdef QCOM_VOIP_ENABLED
+        class AudioStreamInVoip : public AudioStreamInMSM8x60 {
+    public:
+        enum input_state {
+            AUDIO_INPUT_CLOSED,
+            AUDIO_INPUT_OPENED,
+            AUDIO_INPUT_STARTED
+        };
+
+                            AudioStreamInVoip();
+        virtual             ~AudioStreamInVoip();
+                status_t    set(AudioHardware* mHardware,
+                                uint32_t devices,
+                                int *pFormat,
+                                uint32_t *pChannels,
+                                uint32_t *pRate,
+                                AudioSystem::audio_in_acoustics acoustics);
+        virtual size_t      bufferSize() const { return mBufferSize; }
+        virtual uint32_t    channels() const { return mChannels; }
+        virtual int         format() const { return AUDIO_HW_IN_FORMAT; }
+        virtual uint32_t    sampleRate() const { return mSampleRate; }
+        virtual status_t    setGain(float gain) { return INVALID_OPERATION; }
+        virtual ssize_t     read(void* buffer, ssize_t bytes);
+        virtual status_t    dump(int fd, const Vector<String16>& args);
+        virtual status_t    standby();
+        virtual status_t    setParameters(const String8& keyValuePairs);
+        virtual String8     getParameters(const String8& keys);
+        virtual unsigned int  getInputFramesLost() const { return 0; }
+                uint32_t    devices() { return mDevices; }
+                int         state() const { return mState; }
+        virtual int         isForVR() const { return 0; }
+
+    private:
+                AudioHardware* mHardware;
+                int         mFd;
+                int         mState;
+                int         mRetryCount;
+                int         mFormat;
+                uint32_t    mChannels;
+                uint32_t    mSampleRate;
+                size_t      mBufferSize;
+                AudioSystem::audio_in_acoustics mAcoustics;
+                uint32_t    mDevices;
+                bool        mFirstread;
+                uint32_t    mFmRec;
+    };
+#endif
+            static const uint32_t inputSamplingRates[];
+            bool        mInit;
+            bool        mMicMute;
+            int         mFmFd;
+            bool        mBluetoothNrec;
+            bool        mBluetoothVGS;
+            uint32_t    mBluetoothId;
+#ifdef HTC_ACOUSTIC_AUDIO
+            bool        mHACSetting;
+            uint32_t    mBluetoothIdTx;
+            uint32_t    mBluetoothIdRx;
+#endif
+            AudioStreamOutMSM8x60*  mOutput;
+#ifdef QCOM_VOIP_ENABLED
+            AudioStreamOutDirect*  mDirectOutput;
+#endif
+            AudioSessionOutLPA* mOutputLPA;
+            SortedVector <AudioStreamInMSM8x60*>   mInputs;
+#ifdef QCOM_VOIP_ENABLED
+            SortedVector <AudioStreamInVoip*>   mVoipInputs;
+#endif
+#ifdef HTC_ACOUSTIC_AUDIO
+            msm_bt_endpoint *mBTEndpoints;
+            int mNumBTEndpoints;
+#endif
+            int mCurSndDevice;
+#ifdef HTC_ACOUSTIC_AUDIO
+            float mVoiceVolume;
+#endif
+            int mTtyMode;
+            int mNumPcmRec;
+            Mutex mLock;
+#ifdef QCOM_VOIP_ENABLED
+            int mVoipFd;
+            int mNumVoipStreams;
+#endif
+#ifdef HTC_ACOUSTIC_AUDIO
+            int mNoiseSuppressionState;
+            bool mDualMicEnabled;
+            bool mRecordState;
+            char mCurDspProfile[22];
+            bool mEffectEnabled;
+            char mActiveAP[10];
+            char mEffect[10];
+#endif
+
+};
+
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_MSM72XX_H
diff --git a/msm8660/AudioPolicyManager.cpp b/msm8660/AudioPolicyManager.cpp
new file mode 100644
index 0000000..429faf0
--- /dev/null
+++ b/msm8660/AudioPolicyManager.cpp
@@ -0,0 +1,939 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2010-2012, Code Aurora Forum. All rights reserved.
+ *
+ * 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 "AudioPolicyManager"
+
+//#define LOG_NDEBUG 0
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+#include <utils/Log.h>
+#include "AudioPolicyManager.h"
+#include <media/mediarecorder.h>
+#include <hardware/audio.h>
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManager for msm8660 platform
+// ----------------------------------------------------------------------------
+audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy, bool fromCache)
+{
+    uint32_t device = 0;
+
+    if (fromCache) {
+        ALOGV("getDeviceForStrategy() from cache strategy %d, device %x",
+              strategy, mDeviceForStrategy[strategy]);
+        return mDeviceForStrategy[strategy];
+    }
+
+    switch (strategy) {
+
+    case STRATEGY_SONIFICATION_RESPECTFUL:
+        if (isInCall()) {
+            device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+        } else if (isStreamActive(AudioSystem::MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+            // while media is playing (or has recently played), use the same device
+            device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+        } else {
+            // when media is not playing anymore, fall back on the sonification behavior
+            device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+        }
+
+        break;
+
+    case STRATEGY_DTMF:
+        if (!isInCall()) {
+            // when off call, DTMF strategy follows the same rules as MEDIA strategy
+            device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+            break;
+        }
+        // when in call, DTMF and PHONE strategies follow the same rules
+        // FALL THROUGH
+
+    case STRATEGY_PHONE:
+        // for phone strategy, we first consider the forced use and then the available devices by order
+        // of priority
+        switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) {
+        case AudioSystem::FORCE_BT_SCO:
+            if (!isInCall() || strategy != STRATEGY_DTMF) {
+                device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+                if (device) break;
+            }
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+            if (device) break;
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO;
+            if (device) break;
+            // if SCO device is requested but no SCO device is available, fall back to default case
+            // FALL THROUGH
+
+        default:    // FORCE_NONE
+            // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
+            if (mHasA2dp && !isInCall() &&
+                    (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+                    (getA2dpOutput() != 0) && !mA2dpSuspended) {
+                device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
+                if (device) break;
+                device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+                if (device) break;
+            }
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
+            if (device) break;
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
+            if (device) break;
+#ifdef QCOM_ANC_HEADSET_ENABLED
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE;
+            if (device) break;
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADSET;
+            if (device) break;
+#endif
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+            if (device) break;
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+            if (device) break;
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET;
+            if (device) break;
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
+            if (device) break;
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_EARPIECE;
+            if (device) break;
+            device = mDefaultOutputDevice;
+            if (device == 0) {
+                ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE");
+            }
+            break;
+
+        case AudioSystem::FORCE_SPEAKER:
+            // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to
+            // A2DP speaker when forcing to speaker output
+            if (mHasA2dp && !isInCall() &&
+                    (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+                    (getA2dpOutput() != 0) && !mA2dpSuspended) {
+                device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+                if (device) break;
+            }
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+            if (device) break;
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+            if (device) break;
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET;
+            if (device) break;
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
+            if (device) break;
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+            if (device) break;
+            device = mDefaultOutputDevice;
+            if (device == 0) {
+                ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER");
+            }
+            break;
+        }
+#ifdef QCOM_FM_ENABLED
+        if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_FM) {
+            device |= AudioSystem::DEVICE_OUT_FM;
+        }
+#endif
+    break;
+
+    case STRATEGY_SONIFICATION:
+
+        // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
+        // handleIncallSonification().
+        if (isInCall()) {
+            device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/);
+            break;
+        }
+        // FALL THROUGH
+
+    case STRATEGY_ENFORCED_AUDIBLE:
+        // strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION
+        // except:
+        //   - when in call where it doesn't default to STRATEGY_PHONE behavior
+        //   - in countries where not enforced in which case it follows STRATEGY_MEDIA
+
+        if (strategy == STRATEGY_SONIFICATION ||
+                !mStreams[AUDIO_STREAM_ENFORCED_AUDIBLE].mCanBeMuted) {
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+            if (device == 0) {
+                ALOGE("getDeviceForStrategy() speaker device not found for STRATEGY_SONIFICATION");
+            }
+        }
+        // The second device used for sonification is the same as the device used by media strategy
+        // FALL THROUGH
+
+    case STRATEGY_MEDIA: {
+        //To route FM stream to speaker when headset is connected, a new switch case is added.
+        //case AudioSystem::FORCE_SPEAKER for STRATEGY_MEDIA will come only when we need to route
+        //FM stream to speaker.
+        switch (mForceUse[AudioSystem::FOR_MEDIA]) {
+        default:{
+        uint32_t device2 = 0;
+        if ((mHasA2dp && (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+                (getA2dpOutput() != 0) && !mA2dpSuspended )) {
+            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
+            if (device2 == 0) {
+                device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+            }
+            if (device2 == 0) {
+                device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+            }
+        }
+        if (device2 == 0) {
+            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
+        }
+        if (device2 == 0) {
+            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
+        }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+        if (device2 == 0) {
+            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE;
+        }
+        if (device2 == 0) {
+            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADSET;
+        }
+#endif
+#ifdef QCOM_FM_ENABLED
+        if (device2 == 0) {
+            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_FM_TX;
+        }
+#endif
+        if (device2 == 0) {
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+        }
+        if (device2 == 0) {
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+        }
+        if (device2 == 0) {
+            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET;
+        }
+        if (device2 == 0) {
+            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL;
+        }
+        if (device2 == 0) {
+            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
+        }
+        if (device2 == 0) {
+            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+        }
+
+        // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
+        // STRATEGY_ENFORCED_AUDIBLE, 0 otherwise
+        device |= device2;
+        if (device) break;
+        device = mDefaultOutputDevice;
+      }
+        break;
+        case AudioSystem::FORCE_SPEAKER:
+           device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+           break;
+       }
+#ifdef QCOM_FM_ENABLED
+        if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_FM) {
+           device |= AudioSystem::DEVICE_OUT_FM;
+       }
+#endif
+#ifdef QCOM_ANC_HEADSET_ENABLED
+       if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADSET) {
+           device |= AudioSystem::DEVICE_OUT_ANC_HEADSET;
+       }
+       if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE) {
+           device |= AudioSystem::DEVICE_OUT_ANC_HEADPHONE;
+       }
+#endif
+       // Do not play media stream if in call and the requested device would change the hardware
+       // output routing
+       if (mPhoneState == AudioSystem::MODE_IN_CALL &&
+          !AudioSystem::isA2dpDevice((AudioSystem::audio_devices)device) &&
+           device != getDeviceForStrategy(STRATEGY_PHONE)) {
+           device = getDeviceForStrategy(STRATEGY_PHONE);
+           ALOGV("getDeviceForStrategy() incompatible media and phone devices");
+       }
+       if (device == 0) {
+           ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA");
+       }
+    } break;
+
+    default:
+        ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
+        break;
+    }
+
+    ALOGV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
+    return (audio_devices_t)device;
+}
+
+
+status_t AudioPolicyManager::setDeviceConnectionState(AudioSystem::audio_devices device,
+                                                      AudioSystem::device_connection_state state,
+                                                      const char *device_address)
+{
+    SortedVector <audio_io_handle_t> outputs;
+
+    ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address);
+
+    // connect/disconnect only 1 device at a time
+    if (AudioSystem::popCount(device) != 1) return BAD_VALUE;
+
+    if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
+        ALOGE("setDeviceConnectionState() invalid address: %s", device_address);
+        return BAD_VALUE;
+    }
+
+    // handle output devices
+    if (AudioSystem::isOutputDevice(device)) {
+
+        if (!mHasA2dp && AudioSystem::isA2dpDevice(device)) {
+            ALOGE("setDeviceConnectionState() invalid device: %x", device);
+            return BAD_VALUE;
+        }
+        if (!mHasUsb && audio_is_usb_device((audio_devices_t)device)) {
+            ALOGE("setDeviceConnectionState() invalid device: %x", device);
+            return BAD_VALUE;
+        }
+
+        switch (state)
+        {
+        // handle output device connection
+        case AudioSystem::DEVICE_STATE_AVAILABLE:
+
+            if (mAvailableOutputDevices & device) {
+                ALOGW("setDeviceConnectionState() device already connected: %x", device);
+                return INVALID_OPERATION;
+            }
+            ALOGV("setDeviceConnectionState() connecting device %x", device);
+
+            if (checkOutputsForDevice((audio_devices_t)device, state, outputs) != NO_ERROR) {
+                return INVALID_OPERATION;
+            }
+            ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %d outputs",
+                  outputs.size());
+            // register new device as available
+            mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices | device);
+            ALOGV("setDeviceConnectionState() connecting device %x", mAvailableOutputDevices);
+
+            if (!outputs.isEmpty()) {
+                String8 paramStr;
+                if (mHasA2dp && AudioSystem::isA2dpDevice(device)) {
+                    // handle A2DP device connection
+                    AudioParameter param;
+                    param.add(String8(AUDIO_PARAMETER_A2DP_SINK_ADDRESS), String8(device_address));
+                    paramStr = param.toString();
+                    mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+                    mA2dpSuspended = false;
+                } else if (AudioSystem::isBluetoothScoDevice(device)) {
+                    // handle SCO device connection
+                    mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+                } else if (mHasUsb && audio_is_usb_device((audio_devices_t)device)) {
+                    // handle USB device connection
+                    mUsbCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+                    paramStr = mUsbCardAndDevice;
+                }
+                if (!paramStr.isEmpty()) {
+                    for (size_t i = 0; i < outputs.size(); i++) {
+                        mpClientInterface->setParameters(outputs[i], paramStr);
+                    }
+                }
+            }
+            break;
+        // handle output device disconnection
+        case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+            if (!(mAvailableOutputDevices & device)) {
+                ALOGW("setDeviceConnectionState() device not connected: %x", device);
+                return INVALID_OPERATION;
+            }
+
+            ALOGV("setDeviceConnectionState() disconnecting device %x", device);
+            // remove device from available output devices
+            mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices & ~device);
+
+            checkOutputsForDevice((audio_devices_t)device, state, outputs);
+            if (mHasA2dp && AudioSystem::isA2dpDevice(device)) {
+                // handle A2DP device disconnection
+                mA2dpDeviceAddress = "";
+                mA2dpSuspended = false;
+            } else if (AudioSystem::isBluetoothScoDevice(device)) {
+                // handle SCO device disconnection
+                mScoDeviceAddress = "";
+            } else if (mHasUsb && audio_is_usb_device((audio_devices_t)device)) {
+                // handle USB device disconnection
+                mUsbCardAndDevice = "";
+            }
+            } break;
+
+        default:
+            ALOGE("setDeviceConnectionState() invalid state: %x", state);
+            return BAD_VALUE;
+        }
+
+        audio_devices_t NewDevice = AudioPolicyManagerBase::getNewDevice(mPrimaryOutput, false /*fromCache*/);
+#ifdef QCOM_FM_ENABLED
+        if (device == AudioSystem::DEVICE_OUT_FM) {
+            if (state == AudioSystem::DEVICE_STATE_AVAILABLE) {
+                mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::FM, 1);
+            }
+            else {
+                mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::FM, -1);
+            }
+        }
+#endif
+#ifdef QCOM_ANC_HEADSET_ENABLED
+        if(device == AudioSystem::DEVICE_OUT_ANC_HEADPHONE ||
+            device == AudioSystem::DEVICE_OUT_ANC_HEADSET) {
+            if(NewDevice == 0){
+                NewDevice = getDeviceForStrategy(STRATEGY_MEDIA, false);
+            }
+        }
+#endif
+ 
+        checkA2dpSuspend();
+        AudioPolicyManagerBase::checkOutputForAllStrategies();
+        // outputs must be closed after checkOutputForAllStrategies() is executed
+        if (!outputs.isEmpty()) {
+            for (size_t i = 0; i < outputs.size(); i++) {
+                // close unused outputs after device disconnection or direct outputs that have been
+                // opened by checkOutputsForDevice() to query dynamic parameters
+                if ((state == AudioSystem::DEVICE_STATE_UNAVAILABLE) ||
+                        (mOutputs.valueFor(outputs[i])->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
+                    closeOutput(outputs[i]);
+                }
+            }
+        }
+
+        //updateDeviceForStrategy();
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            setOutputDevice(mOutputs.keyAt(i), getNewDevice(mOutputs.keyAt(i), true /*fromCache*/));
+        }
+
+        if (device == AudioSystem::DEVICE_OUT_WIRED_HEADSET) {
+            device = AudioSystem::DEVICE_IN_WIRED_HEADSET;
+        } else if (device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO ||
+                   device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET ||
+                   device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
+            device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+#ifdef QCOM_ANC_HEADSET_ENABLED
+        } else if (device == AudioSystem::DEVICE_OUT_ANC_HEADSET) {
+            device =  AudioSystem::DEVICE_IN_ANC_HEADSET; //wait for actual ANC device
+#endif
+        }else {
+            return NO_ERROR;
+        }
+    }
+    // handle input devices
+    if (AudioSystem::isInputDevice(device)) {
+
+        switch (state)
+        {
+        // handle input device connection
+        case AudioSystem::DEVICE_STATE_AVAILABLE: {
+            if (mAvailableInputDevices & device) {
+                ALOGW("setDeviceConnectionState() device already connected: %d", device);
+                return INVALID_OPERATION;
+            }
+            mAvailableInputDevices = (audio_devices_t)(mAvailableInputDevices | device);
+            }
+            break;
+
+        // handle input device disconnection
+        case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+            if (!(mAvailableInputDevices & device)) {
+                ALOGW("setDeviceConnectionState() device not connected: %d", device);
+                return INVALID_OPERATION;
+            }
+            mAvailableInputDevices = (audio_devices_t) (mAvailableInputDevices & ~device);
+            } break;
+
+        default:
+            ALOGE("setDeviceConnectionState() invalid state: %x", state);
+            return BAD_VALUE;
+        }
+
+        audio_io_handle_t activeInput = getActiveInput();
+        if (activeInput != 0) {
+            AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
+            audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+            if ((newDevice != 0) && (newDevice != inputDesc->mDevice)) {
+                ALOGV("setDeviceConnectionState() changing device from %x to %x for input %d",
+                        inputDesc->mDevice, newDevice, activeInput);
+                inputDesc->mDevice = newDevice;
+                AudioParameter param = AudioParameter();
+                param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
+                mpClientInterface->setParameters(activeInput, param.toString());
+            }
+        }
+
+        return NO_ERROR;
+    }
+
+    ALOGW("setDeviceConnectionState() invalid device: %x", device);
+    return BAD_VALUE;
+}
+
+status_t AudioPolicyManager::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session)
+{
+    ALOGV("startOutput() output %d, stream %d, session %d", output, stream, session);
+    ssize_t index = mOutputs.indexOfKey(output);
+    if (index < 0) {
+        ALOGW("startOutput() unknow output %d", output);
+        return BAD_VALUE;
+    }
+
+    AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+    // increment usage count for this stream on the requested output:
+    // NOTE that the usage count is the same for duplicated output and hardware output which is
+    // necessary for a correct control of hardware output routing by startOutput() and stopOutput()
+    outputDesc->changeRefCount(stream, 1);
+
+    if (outputDesc->mRefCount[stream] == 1) {
+        audio_devices_t prevDevice = outputDesc->device();
+        audio_devices_t newDevice = AudioPolicyManagerBase::getNewDevice(output, false /*fromCache*/);
+        routing_strategy strategy = AudioPolicyManagerBase::getStrategy(stream);
+        bool shouldWait = (strategy == STRATEGY_SONIFICATION) ||
+                            (strategy == STRATEGY_SONIFICATION_RESPECTFUL);
+        uint32_t waitMs = 0;
+        bool force = false;
+        uint32_t muteWaitMs;
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+            if (desc != outputDesc) {
+                // force a device change if any other output is managed by the same hw
+                // module and has a current device selection that differs from selected device.
+                // In this case, the audio HAL must receive the new device selection so that it can
+                // change the device currently selected by the other active output.
+                if (outputDesc->sharesHwModuleWith(desc) &&
+                    desc->device() != newDevice) {
+                    force = true;
+                }
+                // wait for audio on other active outputs to be presented when starting
+                // a notification so that audio focus effect can propagate.
+                if (shouldWait && (desc->refCount() != 0) && (waitMs < desc->latency())) {
+                    waitMs = desc->latency();
+                }
+            }
+        }
+
+        setOutputDevice(output, AudioPolicyManagerBase::getNewDevice((output), true));
+
+        // handle special case for sonification while in call
+        if (isInCall()) {
+            AudioPolicyManagerBase::handleIncallSonification(stream, true, false);
+        }
+
+        // apply volume rules for current stream and device if necessary
+        checkAndSetVolume(stream,
+                          mStreams[stream].getVolumeIndex((audio_devices_t)newDevice),
+                          output,
+                          newDevice);
+
+        // update the outputs if starting an output with a stream that can affect notification
+        // routing
+        handleNotificationRoutingForStream(stream);
+        if (waitMs > muteWaitMs) {
+            usleep((waitMs - muteWaitMs) * 2 * 1000);
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session)
+{
+    ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session);
+    ssize_t index = mOutputs.indexOfKey(output);
+    if (index < 0) {
+        ALOGW("stopOutput() unknow output %d", output);
+        return BAD_VALUE;
+    }
+
+    AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+    // handle special case for sonification while in call
+    if (isInCall()) {
+        handleIncallSonification(stream, false, false);
+    }
+
+    if (outputDesc->mRefCount[stream] > 0) {
+        // decrement usage count of this stream on the output
+        outputDesc->changeRefCount(stream, -1);
+        // store time at which the stream was stopped - see isStreamActive()
+        if (outputDesc->mRefCount[stream] == 0) {
+            if (stream == AudioSystem::MUSIC) {
+                outputDesc->mStopTime[stream] = systemTime();
+            }
+            audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+            // delay the device switch by twice the latency because stopOutput() is executed when
+            // the track stop() command is received and at that time the audio track buffer can
+            // still contain data that needs to be drained. The latency only covers the audio HAL
+            // and kernel buffers. Also the latency does not always include additional delay in the
+            // audio path (audio DSP, CODEC ...)
+            setOutputDevice(output, newDevice, false, outputDesc->mLatency*2);
+
+            // force restoring the device selection on other active outputs if it differs from the
+            // one being selected for this output
+            for (size_t i = 0; i < mOutputs.size(); i++) {
+                audio_io_handle_t curOutput = mOutputs.keyAt(i);
+                AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+                if (curOutput != output &&
+                        desc->refCount() != 0 &&
+                        outputDesc->sharesHwModuleWith(desc) &&
+                        newDevice != desc->device()) {
+                    setOutputDevice(curOutput,
+                                    getNewDevice(curOutput, false /*fromCache*/),
+                                    true,
+                                    outputDesc->mLatency*2);
+                }
+            }
+            // update the outputs if stopping one with a stream that can affect notification routing
+            handleNotificationRoutingForStream(stream);
+        }
+        return NO_ERROR;
+    } else {
+        ALOGW("stopOutput() refcount is already 0 for output %d", output);
+        return INVALID_OPERATION;
+    }
+}
+
+status_t AudioPolicyManager::stopInput(audio_io_handle_t input)
+{
+    ALOGV("stopInput() input %d", input);
+    uint32_t newDevice = NULL;
+    ssize_t index = mInputs.indexOfKey(input);
+    if (index < 0) {
+        ALOGW("stopInput() unknow input %d", input);
+        return BAD_VALUE;
+    }
+    AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+    if (inputDesc->mRefCount == 0) {
+        ALOGW("stopInput() input %d already stopped", input);
+        return INVALID_OPERATION;
+    } else {
+        AudioParameter param = AudioParameter();
+        param.addInt(String8(AudioParameter::keyRouting), 0);
+        ALOGV("stopInput string to setParam %s\n",  param.toString().string());
+        mpClientInterface->setParameters(input, param.toString());
+        inputDesc->mRefCount = 0;
+
+        newDevice = AudioPolicyManagerBase::getNewDevice(mPrimaryOutput, false);
+        param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
+        mpClientInterface->setParameters(mPrimaryOutput, param.toString());
+        return NO_ERROR;
+    }
+    return NO_ERROR;
+}
+
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManager
+// ----------------------------------------------------------------------------
+
+// ---  class factory
+
+
+extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+{
+    return new AudioPolicyManager(clientInterface);
+}
+
+extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface)
+{
+    delete interface;
+}
+
+// ---
+
+uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output, audio_devices_t device, bool force, int delayMs)
+{
+    ALOGV("setOutputDevice() output %d device %04x delayMs %d", output, device, delayMs);
+    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    AudioParameter param;
+    uint32_t muteWaitMs = 0;
+
+    if (outputDesc->isDuplicated()) {
+        muteWaitMs = setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);
+        muteWaitMs += setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
+        return muteWaitMs;
+    }
+    // filter devices according to output selected
+    device = (audio_devices_t)(device & outputDesc->mProfile->mSupportedDevices);
+
+    audio_devices_t prevDevice = outputDesc->mDevice;
+
+    ALOGV("setOutputDevice() prevDevice %04x", prevDevice);
+
+    if (device != 0) {
+        outputDesc->mDevice = device;
+    }
+    muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+
+    // Do not change the routing if:
+    //  - the requested device is 0
+    //  - the requested device is the same as current device and force is not specified.
+    // Doing this check here allows the caller to call setOutputDevice() without conditions
+    if ((device == 0 || device == prevDevice) && !force) {
+        ALOGV("setOutputDevice() setting same device %04x or null device for output %d", device, output);
+        return muteWaitMs;
+    }
+
+    ALOGV("setOutputDevice() changing device");
+    // do the routing
+    param.addInt(String8(AudioParameter::keyRouting), (int)device);
+    mpClientInterface->setParameters(output, param.toString(), delayMs);
+
+    // update stream volumes according to new device
+    applyStreamVolumes(output, device, delayMs);
+
+    return muteWaitMs;
+}
+
+status_t AudioPolicyManager::checkAndSetVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device, int delayMs, bool force)
+{
+    // do not change actual stream volume if the stream is muted
+    if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) {
+        ALOGVV("checkAndSetVolume() stream %d muted count %d",
+              stream, mOutputs.valueFor(output)->mMuteCount[stream]);
+        return NO_ERROR;
+    }
+
+    // do not change in call volume if bluetooth is connected and vice versa
+    if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
+        (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) {
+        ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",
+             stream, mForceUse[AudioSystem::FOR_COMMUNICATION]);
+        return INVALID_OPERATION;
+    }
+
+    float volume = computeVolume(stream, index, output, device);
+    // We actually change the volume if:
+    // - the float value returned by computeVolume() changed
+    // - the force flag is set
+    if (volume != mOutputs.valueFor(output)->mCurVolume[stream]
+#ifdef QCOM_FM_ENABLED
+            || (stream == AudioSystem::FM)
+#endif
+            || force) {
+        mOutputs.valueFor(output)->mCurVolume[stream] = volume;
+        ALOGVV("checkAndSetVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs);
+        if (stream == AudioSystem::VOICE_CALL ||
+            stream == AudioSystem::DTMF ||
+            stream == AudioSystem::BLUETOOTH_SCO) {
+            float voiceVolume = -1.0;
+            // offset value to reflect actual hardware volume that never reaches 0
+            // 1% corresponds roughly to first step in VOICE_CALL stream volume setting (see AudioService.java)
+            volume = 0.01 + 0.99 * volume;
+            if (stream == AudioSystem::VOICE_CALL) {
+                voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
+            } else if (stream == AudioSystem::BLUETOOTH_SCO) {
+                voiceVolume = 1.0;
+            }
+            if (voiceVolume >= 0 && output == mPrimaryOutput) {
+                mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
+            }
+#ifdef QCOM_FM_ENABLED
+        } else if (stream == AudioSystem::FM) {
+            float fmVolume = -1.0;
+            fmVolume = computeVolume(stream, index, output, device);
+            if (fmVolume >= 0) {
+                if(output == mPrimaryOutput)
+                    mpClientInterface->setFmVolume(fmVolume, delayMs);
+                else if(mHasA2dp && output == getA2dpOutput())
+                    mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
+            }
+            return NO_ERROR;
+#endif
+        }
+        mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
+    }
+    return NO_ERROR;
+}
+
+void AudioPolicyManager::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+{
+    ALOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState);
+
+    bool forceVolumeReeval = false;
+    switch(usage) {
+    case AudioSystem::FOR_COMMUNICATION:
+        if (config != AudioSystem::FORCE_SPEAKER && config != AudioSystem::FORCE_BT_SCO &&
+            config != AudioSystem::FORCE_NONE) {
+            ALOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config);
+            return;
+        }
+        forceVolumeReeval = true;
+        mForceUse[usage] = config;
+        break;
+    case AudioSystem::FOR_MEDIA:
+        if (config != AudioSystem::FORCE_HEADPHONES && config != AudioSystem::FORCE_BT_A2DP &&
+            config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+            config != AudioSystem::FORCE_ANALOG_DOCK &&
+            config != AudioSystem::FORCE_DIGITAL_DOCK && config != AudioSystem::FORCE_NONE &&
+            config != AudioSystem::FORCE_NO_BT_A2DP &&
+            config != AudioSystem::FORCE_SPEAKER) {
+            ALOGW("setForceUse() invalid config %d for FOR_MEDIA", config);
+            return;
+        }
+        mForceUse[usage] = config;
+        {
+            audio_devices_t device = getDeviceForStrategy(STRATEGY_MEDIA);
+            setOutputDevice(mPrimaryOutput, device);
+        }
+        break;
+    case AudioSystem::FOR_RECORD:
+        if (config != AudioSystem::FORCE_BT_SCO && config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+            config != AudioSystem::FORCE_NONE) {
+            ALOGW("setForceUse() invalid config %d for FOR_RECORD", config);
+            return;
+        }
+        mForceUse[usage] = config;
+        break;
+    case AudioSystem::FOR_DOCK:
+        if (config != AudioSystem::FORCE_NONE && config != AudioSystem::FORCE_BT_CAR_DOCK &&
+            config != AudioSystem::FORCE_BT_DESK_DOCK &&
+            config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+            config != AudioSystem::FORCE_ANALOG_DOCK &&
+            config != AudioSystem::FORCE_DIGITAL_DOCK) {
+            ALOGW("setForceUse() invalid config %d for FOR_DOCK", config);
+        }
+        forceVolumeReeval = true;
+        mForceUse[usage] = config;
+        break;
+    default:
+        ALOGW("setForceUse() invalid usage %d", usage);
+        break;
+    }
+
+    // check for device and output changes triggered by new force usage
+    checkA2dpSuspend();
+    checkOutputForAllStrategies();
+    //updateDeviceForStrategy();
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        audio_io_handle_t output = mOutputs.keyAt(i);
+        audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/);
+        setOutputDevice(output, newDevice, (newDevice != 0));
+        if (forceVolumeReeval && (newDevice != 0)) {
+            applyStreamVolumes(output, newDevice, 0, true);
+        }
+    }
+
+    audio_io_handle_t activeInput = getActiveInput();
+    if (activeInput != 0) {
+        AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
+        audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+        if ((newDevice != 0) && (newDevice != inputDesc->mDevice)) {
+            ALOGV("setForceUse() changing device from %x to %x for input %d",
+                    inputDesc->mDevice, newDevice, activeInput);
+            inputDesc->mDevice = newDevice;
+            AudioParameter param = AudioParameter();
+            param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
+            mpClientInterface->setParameters(activeInput, param.toString());
+        }
+    }
+}
+
+audio_devices_t AudioPolicyManager::getDeviceForInputSource(int inputSource)
+{
+    uint32_t device = 0;
+
+    switch(inputSource) {
+    case AUDIO_SOURCE_DEFAULT:
+    case AUDIO_SOURCE_MIC:
+    case AUDIO_SOURCE_VOICE_RECOGNITION:
+        if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO &&
+            mAvailableInputDevices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+            device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+        } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_WIRED_HEADSET) {
+            device = AudioSystem::DEVICE_IN_WIRED_HEADSET;
+#ifdef QCOM_ANC_HEADSET_ENABLED
+        } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_ANC_HEADSET) {
+            device = AudioSystem::DEVICE_IN_ANC_HEADSET;
+#endif
+        } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_BUILTIN_MIC) {
+            device = AudioSystem::DEVICE_IN_BUILTIN_MIC;
+        }
+        break;
+    case AUDIO_SOURCE_VOICE_COMMUNICATION:
+        device = AudioSystem::DEVICE_IN_COMMUNICATION;
+        break;
+    case AUDIO_SOURCE_CAMCORDER:
+        if (mAvailableInputDevices & AudioSystem::DEVICE_IN_BACK_MIC) {
+            device = AudioSystem::DEVICE_IN_BACK_MIC;
+        } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_BUILTIN_MIC) {
+            device = AudioSystem::DEVICE_IN_BUILTIN_MIC;
+        }
+        break;
+    case AUDIO_SOURCE_VOICE_UPLINK:
+    case AUDIO_SOURCE_VOICE_DOWNLINK:
+    case AUDIO_SOURCE_VOICE_CALL:
+        if (mAvailableInputDevices & AudioSystem::DEVICE_IN_VOICE_CALL) {
+            device = AudioSystem::DEVICE_IN_VOICE_CALL;
+        }
+        break;
+#ifdef QCOM_FM_ENABLED
+    case AUDIO_SOURCE_FM_RX:
+        device = AudioSystem::DEVICE_IN_FM_RX;
+        break;
+    case AUDIO_SOURCE_FM_RX_A2DP:
+        device = AudioSystem::DEVICE_IN_FM_RX_A2DP;
+        break;
+#endif
+    default:
+        ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
+        break;
+    }
+    ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
+    return (audio_devices_t)device;
+}
+
+/*
+Overwriting this function from base class to allow 2 acitve AudioRecord clients in case of FM.
+One for FM A2DP playbck and other for FM recording.
+*/
+status_t AudioPolicyManager::startInput(audio_io_handle_t input)
+{
+    ALOGV("startInput() input %d", input);
+    ssize_t index = mInputs.indexOfKey(input);
+    if (index < 0) {
+        ALOGW("startInput() unknow input %d", input);
+        return BAD_VALUE;
+    }
+    AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+    AudioParameter param = AudioParameter();
+    param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice);
+    // use Voice Recognition mode or not for this input based on input source
+    int vr_enabled = inputDesc->mInputSource == AUDIO_SOURCE_VOICE_RECOGNITION ? 1 : 0;
+    param.addInt(String8("vr_mode"), vr_enabled);
+    ALOGV("AudioPolicyManager::startInput(%d), setting vr_mode to %d", inputDesc->mInputSource, vr_enabled);
+    mpClientInterface->setParameters(input, param.toString());
+    inputDesc->mRefCount = 1;
+    return NO_ERROR;
+}
+
+//private function, no changes from AudioPolicyManagerBase
+void AudioPolicyManager::handleNotificationRoutingForStream(AudioSystem::stream_type stream) {
+    switch(stream) {
+    case AudioSystem::MUSIC:
+        checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL);
+        updateDevicesAndOutputs();
+        break; 
+    default:
+        break;
+    }
+}  
+}; // namespace android_audio_legacy
diff --git a/msm8660/AudioPolicyManager.h b/msm8660/AudioPolicyManager.h
new file mode 100755
index 0000000..5468a91
--- /dev/null
+++ b/msm8660/AudioPolicyManager.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2010-2012, Code Aurora Forum. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Timers.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <hardware_legacy/AudioPolicyManagerBase.h>
+
+namespace android_audio_legacy {
+
+class AudioPolicyManager: public AudioPolicyManagerBase
+{
+
+public:
+                AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+                : AudioPolicyManagerBase(clientInterface) {
+                }
+
+        virtual ~AudioPolicyManager() {}
+
+        // AudioPolicyInterface
+        virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device,
+                                                          AudioSystem::device_connection_state state,
+                                                          const char *device_address);
+
+        // return appropriate device for streams handled by the specified strategy according to current
+        // phone state, connected devices...
+        // if fromCache is true, the device is returned from mDeviceForStrategy[], otherwise it is determined
+        // by current state (device connected, phone state, force use, a2dp output...)
+        // This allows to:
+        //  1 speed up process when the state is stable (when starting or stopping an output)
+        //  2 access to either current device selection (fromCache == true) or
+        // "future" device selection (fromCache == false) when called from a context
+        //  where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND
+        //  before updateDeviceForStrategy() is called.
+        virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy, bool fromCache = true);
+        virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session = 0);
+        virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session = 0);
+        virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
+                // indicates to the audio policy manager that the input starts being used.
+        virtual status_t startInput(audio_io_handle_t input);
+
+protected:
+        // change the route of the specified output
+        uint32_t setOutputDevice(audio_io_handle_t output, audio_devices_t device, bool force = false, int delayMs = 0);
+        // check that volume change is permitted, compute and send new volume to audio hardware
+        status_t checkAndSetVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false);
+        // select input device corresponding to requested audio source
+        virtual audio_devices_t getDeviceForInputSource(int inputSource);
+        // Mute or unmute the stream on the specified output
+        status_t stopInput(audio_io_handle_t input);
+
+private:
+        void handleNotificationRoutingForStream(AudioSystem::stream_type stream);
+};
+};
diff --git a/msm8660/acdb.h b/msm8660/acdb.h
new file mode 100644
index 0000000..43b93e8
--- /dev/null
+++ b/msm8660/acdb.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod 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 __MSM_ACDB_CONTROL
+#define __MSM_ACDB_CONTROL
+
+__BEGIN_DECLS
+
+int acdb_loader_send_anc_cal(int id);
+void acdb_loader_send_audio_cal(int id, int capability);
+void acdb_loader_send_voice_cal(int tx_id, int rx_id);
+void acdb_mapper_get_acdb_id_from_dev_name(char *name, int *id);
+int acdb_loader_init_ACDB();
+void acdb_loader_deallocate_ACDB();
+
+__END_DECLS
+
+#endif
diff --git a/msm8660/audio_hw_hal.cpp b/msm8660/audio_hw_hal.cpp
new file mode 100644
index 0000000..4975737
--- /dev/null
+++ b/msm8660/audio_hw_hal.cpp
@@ -0,0 +1,717 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * 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.primary.msm8660"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <hardware/audio.h>
+
+#include <hardware_legacy/AudioHardwareInterface.h>
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+namespace android_audio_legacy {
+
+extern "C" {
+
+struct qcom_audio_module {
+    struct audio_module module;
+};
+
+struct qcom_audio_device {
+    struct audio_hw_device device;
+
+    struct AudioHardwareInterface *hwif;
+};
+
+struct qcom_stream_out {
+    struct audio_stream_out stream;
+
+    AudioStreamOut *qcom_out;
+};
+
+struct qcom_stream_in {
+    struct audio_stream_in stream;
+
+    AudioStreamIn *qcom_in;
+};
+
+/** audio_stream_out implementation **/
+static uint32_t out_get_sample_rate(const struct audio_stream *stream)
+{
+    const struct qcom_stream_out *out =
+        reinterpret_cast<const struct qcom_stream_out *>(stream);
+    return out->qcom_out->sampleRate();
+}
+
+static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+    struct qcom_stream_out *out =
+        reinterpret_cast<struct qcom_stream_out *>(stream);
+
+    ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+    /* TODO: implement this */
+    return 0;
+}
+
+static size_t out_get_buffer_size(const struct audio_stream *stream)
+{
+    const struct qcom_stream_out *out =
+        reinterpret_cast<const struct qcom_stream_out *>(stream);
+    return out->qcom_out->bufferSize();
+}
+
+static audio_channel_mask_t out_get_channels(const struct audio_stream *stream)
+{
+    const struct qcom_stream_out *out =
+        reinterpret_cast<const struct qcom_stream_out *>(stream);
+    return out->qcom_out->channels();
+}
+
+static audio_format_t out_get_format(const struct audio_stream *stream)
+{
+    const struct qcom_stream_out *out =
+        reinterpret_cast<const struct qcom_stream_out *>(stream);
+    return (audio_format_t)out->qcom_out->format();
+}
+
+static int out_set_format(struct audio_stream *stream, audio_format_t format)
+{
+    struct qcom_stream_out *out =
+        reinterpret_cast<struct qcom_stream_out *>(stream);
+    ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+    /* TODO: implement me */
+    return 0;
+}
+
+static int out_standby(struct audio_stream *stream)
+{
+    struct qcom_stream_out *out =
+        reinterpret_cast<struct qcom_stream_out *>(stream);
+    return out->qcom_out->standby();
+}
+
+static int out_dump(const struct audio_stream *stream, int fd)
+{
+    const struct qcom_stream_out *out =
+        reinterpret_cast<const struct qcom_stream_out *>(stream);
+    Vector<String16> args;
+    return out->qcom_out->dump(fd, args);
+}
+
+static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+    struct qcom_stream_out *out =
+        reinterpret_cast<struct qcom_stream_out *>(stream);
+    return out->qcom_out->setParameters(String8(kvpairs));
+}
+
+static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
+{
+    const struct qcom_stream_out *out =
+        reinterpret_cast<const struct qcom_stream_out *>(stream);
+    String8 s8;
+    s8 = out->qcom_out->getParameters(String8(keys));
+    return strdup(s8.string());
+}
+
+static uint32_t out_get_latency(const struct audio_stream_out *stream)
+{
+    const struct qcom_stream_out *out =
+        reinterpret_cast<const struct qcom_stream_out *>(stream);
+    return out->qcom_out->latency();
+}
+
+static int out_set_volume(struct audio_stream_out *stream, float left,
+                          float right)
+{
+    struct qcom_stream_out *out =
+        reinterpret_cast<struct qcom_stream_out *>(stream);
+    return out->qcom_out->setVolume(left, right);
+}
+
+static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
+                         size_t bytes)
+{
+    struct qcom_stream_out *out =
+        reinterpret_cast<struct qcom_stream_out *>(stream);
+    usleep(5);
+    return out->qcom_out->write(buffer, bytes);
+}
+
+static int out_get_render_position(const struct audio_stream_out *stream,
+                                   uint32_t *dsp_frames)
+{
+    const struct qcom_stream_out *out =
+        reinterpret_cast<const struct qcom_stream_out *>(stream);
+    return out->qcom_out->getRenderPosition(dsp_frames);
+}
+
+static int out_set_observer(const struct audio_stream_out *stream,
+                                   void *observer)
+{
+    const struct qcom_stream_out *out =
+        reinterpret_cast<const struct qcom_stream_out *>(stream);
+    return out->qcom_out->setObserver(observer);
+}
+
+static int out_get_buffer_info(const struct audio_stream_out *stream,
+                                   buf_info ** buf)
+{
+    const struct qcom_stream_out *out =
+        reinterpret_cast<const struct qcom_stream_out *>(stream);
+    return out->qcom_out->getBufferInfo(buf);
+}
+
+static int out_is_buffer_available(const struct audio_stream_out *stream,
+                                   int *isAvail)
+{
+    const struct qcom_stream_out *out =
+        reinterpret_cast<const struct qcom_stream_out *>(stream);
+    return out->qcom_out->isBufferAvailable(isAvail);
+}
+
+static status_t out_start(struct audio_stream_out *stream)
+{
+    struct qcom_stream_out *out =
+        reinterpret_cast<struct qcom_stream_out *>(stream);
+    return out->qcom_out->start();
+}
+
+static status_t out_pause(struct audio_stream_out *stream)
+{
+    struct qcom_stream_out *out =
+        reinterpret_cast<struct qcom_stream_out *>(stream);
+    return out->qcom_out->pause();
+}
+
+static status_t out_flush(struct audio_stream_out *stream)
+{
+    struct qcom_stream_out *out =
+        reinterpret_cast<struct qcom_stream_out *>(stream);
+    return out->qcom_out->flush();
+}
+
+static status_t out_stop(struct audio_stream_out *stream)
+{
+    struct qcom_stream_out *out =
+        reinterpret_cast<struct qcom_stream_out *>(stream);
+    return out->qcom_out->stop();
+}
+
+static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+    return 0;
+}
+
+static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+    return 0;
+}
+
+static int out_get_next_write_timestamp(const struct audio_stream_out *stream,
+                                        int64_t *timestamp)
+{
+    const struct qcom_stream_out *out =
+        reinterpret_cast<const struct qcom_stream_out *>(stream);
+    return out->qcom_out->getNextWriteTimestamp(timestamp);
+}
+
+/** audio_stream_in implementation **/
+static uint32_t in_get_sample_rate(const struct audio_stream *stream)
+{
+    const struct qcom_stream_in *in =
+        reinterpret_cast<const struct qcom_stream_in *>(stream);
+    return in->qcom_in->sampleRate();
+}
+
+static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+    struct qcom_stream_in *in =
+        reinterpret_cast<struct qcom_stream_in *>(stream);
+
+    ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+    /* TODO: implement this */
+    return 0;
+}
+
+static size_t in_get_buffer_size(const struct audio_stream *stream)
+{
+    const struct qcom_stream_in *in =
+        reinterpret_cast<const struct qcom_stream_in *>(stream);
+    return in->qcom_in->bufferSize();
+}
+
+static audio_channel_mask_t in_get_channels(const struct audio_stream *stream)
+{
+    const struct qcom_stream_in *in =
+        reinterpret_cast<const struct qcom_stream_in *>(stream);
+    return in->qcom_in->channels();
+}
+
+static audio_format_t in_get_format(const struct audio_stream *stream)
+{
+    const struct qcom_stream_in *in =
+        reinterpret_cast<const struct qcom_stream_in *>(stream);
+    return (audio_format_t)in->qcom_in->format();
+}
+
+static int in_set_format(struct audio_stream *stream, audio_format_t format)
+{
+    struct qcom_stream_in *in =
+        reinterpret_cast<struct qcom_stream_in *>(stream);
+    ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+    /* TODO: implement me */
+    return 0;
+}
+
+static int in_standby(struct audio_stream *stream)
+{
+    struct qcom_stream_in *in = reinterpret_cast<struct qcom_stream_in *>(stream);
+    return in->qcom_in->standby();
+}
+
+static int in_dump(const struct audio_stream *stream, int fd)
+{
+    const struct qcom_stream_in *in =
+        reinterpret_cast<const struct qcom_stream_in *>(stream);
+    Vector<String16> args;
+    return in->qcom_in->dump(fd, args);
+}
+
+static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+    struct qcom_stream_in *in =
+        reinterpret_cast<struct qcom_stream_in *>(stream);
+    return in->qcom_in->setParameters(String8(kvpairs));
+}
+
+static char * in_get_parameters(const struct audio_stream *stream,
+                                const char *keys)
+{
+    const struct qcom_stream_in *in =
+        reinterpret_cast<const struct qcom_stream_in *>(stream);
+    String8 s8;
+    s8 = in->qcom_in->getParameters(String8(keys));
+    return strdup(s8.string());
+}
+
+static int in_set_gain(struct audio_stream_in *stream, float gain)
+{
+    struct qcom_stream_in *in =
+        reinterpret_cast<struct qcom_stream_in *>(stream);
+    return in->qcom_in->setGain(gain);
+}
+
+static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
+                       size_t bytes)
+{
+    struct qcom_stream_in *in =
+        reinterpret_cast<struct qcom_stream_in *>(stream);
+    return in->qcom_in->read(buffer, bytes);
+}
+
+static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
+{
+    struct qcom_stream_in *in =
+        reinterpret_cast<struct qcom_stream_in *>(stream);
+    return in->qcom_in->getInputFramesLost();
+}
+
+static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+    const struct qcom_stream_in *in =
+        reinterpret_cast<const struct qcom_stream_in *>(stream);
+    return in->qcom_in->addAudioEffect(effect);
+}
+
+static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+    const struct qcom_stream_in *in =
+        reinterpret_cast<const struct qcom_stream_in *>(stream);
+    return in->qcom_in->removeAudioEffect(effect);
+}
+
+/** audio_hw_device implementation **/
+static inline struct qcom_audio_device * to_ladev(struct audio_hw_device *dev)
+{
+    return reinterpret_cast<struct qcom_audio_device *>(dev);
+}
+
+static inline const struct qcom_audio_device * to_cladev(const struct audio_hw_device *dev)
+{
+    return reinterpret_cast<const struct qcom_audio_device *>(dev);
+}
+
+static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev)
+{
+    /* XXX: The old AudioHardwareInterface interface is not smart enough to
+     * tell us this, so we'll lie and basically tell AF that we support the
+     * below input/output devices and cross our fingers. To do things properly,
+     * audio hardware interfaces that need advanced features (like this) should
+     * convert to the new HAL interface and not use this wrapper. */
+    return (/* OUT */
+            AUDIO_DEVICE_OUT_EARPIECE |
+            AUDIO_DEVICE_OUT_SPEAKER |
+            AUDIO_DEVICE_OUT_WIRED_HEADSET |
+            AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+            AUDIO_DEVICE_OUT_AUX_DIGITAL |
+            AUDIO_DEVICE_OUT_ALL_SCO |
+            AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
+            AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
+#ifdef QCOM_ANC_HEADSET_ENABLED
+            AUDIO_DEVICE_OUT_ANC_HEADSET |
+            AUDIO_DEVICE_OUT_ANC_HEADPHONE |
+#endif
+#ifdef QCOM_FM_ENABLED
+            AUDIO_DEVICE_OUT_FM |
+#endif
+#ifdef QCOM_FM_TX_ENABLED
+            AUDIO_DEVICE_OUT_FM_TX |
+#endif
+            AUDIO_DEVICE_OUT_DEFAULT |
+            /* IN */
+            AUDIO_DEVICE_IN_VOICE_CALL |
+            AUDIO_DEVICE_IN_COMMUNICATION |
+            AUDIO_DEVICE_IN_AMBIENT |
+            AUDIO_DEVICE_IN_BUILTIN_MIC |
+            AUDIO_DEVICE_IN_WIRED_HEADSET |
+            AUDIO_DEVICE_IN_AUX_DIGITAL |
+            AUDIO_DEVICE_IN_BACK_MIC |
+            AUDIO_DEVICE_IN_ALL_SCO |
+#ifdef QCOM_ANC_HEADSET_ENABLED
+            AUDIO_DEVICE_IN_ANC_HEADSET |
+#endif
+#ifdef QCOM_FM_ENABLED
+            AUDIO_DEVICE_IN_FM_RX |
+            AUDIO_DEVICE_IN_FM_RX_A2DP |
+#endif
+            AUDIO_DEVICE_IN_DEFAULT);
+}
+
+static int adev_init_check(const struct audio_hw_device *dev)
+{
+    const struct qcom_audio_device *qadev = to_cladev(dev);
+
+    return qadev->hwif->initCheck();
+}
+
+static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
+{
+    struct qcom_audio_device *qadev = to_ladev(dev);
+    return qadev->hwif->setVoiceVolume(volume);
+}
+
+static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
+{
+    struct qcom_audio_device *qadev = to_ladev(dev);
+    return qadev->hwif->setMasterVolume(volume);
+}
+
+static int adev_get_master_volume(struct audio_hw_device *dev, float *volume) {
+
+    struct qcom_audio_device *qadev = to_ladev(dev);
+    return qadev->hwif->getMasterVolume(volume);
+}
+
+#ifdef QCOM_FM_ENABLED
+static int adev_set_fm_volume(struct audio_hw_device *dev, float volume)
+{
+    struct qcom_audio_device *qadev = to_ladev(dev);
+    return qadev->hwif->setFmVolume(volume);
+}
+#endif
+
+static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
+{
+    struct qcom_audio_device *qadev = to_ladev(dev);
+    return qadev->hwif->setMode(mode);
+}
+
+static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
+{
+    struct qcom_audio_device *qadev = to_ladev(dev);
+    return qadev->hwif->setMicMute(state);
+}
+
+static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
+{
+    const struct qcom_audio_device *qadev = to_cladev(dev);
+    return qadev->hwif->getMicMute(state);
+}
+
+static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
+{
+    struct qcom_audio_device *qadev = to_ladev(dev);
+    return qadev->hwif->setParameters(String8(kvpairs));
+}
+
+static char * adev_get_parameters(const struct audio_hw_device *dev,
+                                  const char *keys)
+{
+    const struct qcom_audio_device *qadev = to_cladev(dev);
+    String8 s8;
+
+    s8 = qadev->hwif->getParameters(String8(keys));
+    return strdup(s8.string());
+}
+
+static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
+                                         const struct audio_config *config)
+{
+    const struct qcom_audio_device *qadev = to_cladev(dev);
+    return qadev->hwif->getInputBufferSize(config->sample_rate, config->format, popcount(config->channel_mask));
+}
+
+
+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)
+{
+    struct qcom_audio_device *qadev = to_ladev(dev);
+    status_t status;
+    struct qcom_stream_out *out;
+    int ret;
+
+    out = (struct qcom_stream_out *)calloc(1, sizeof(*out));
+    if (!out)
+        return -ENOMEM;
+
+    status = static_cast<audio_output_flags_t> (flags);
+
+    out->qcom_out = qadev->hwif->openOutputStream(devices,
+                                                    (int *)&config->format,
+                                                    &config->channel_mask,
+                                                    &config->sample_rate,
+                                                    &status);
+    if (!out->qcom_out) {
+        ret = status;
+        goto err_open;
+    }
+
+    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.start = out_start;
+    out->stream.pause = out_pause;
+    out->stream.flush = out_flush;
+    out->stream.stop = out_stop;
+    out->stream.set_observer = out_set_observer;
+    out->stream.get_buffer_info = out_get_buffer_info;
+    out->stream.is_buffer_available = out_is_buffer_available;
+
+    *stream_out = &out->stream;
+    return 0;
+
+err_open:
+    free(out);
+    *stream_out = NULL;
+    return ret;
+}
+
+static void adev_close_output_stream(struct audio_hw_device *dev,
+                                     struct audio_stream_out* stream)
+{
+    struct qcom_audio_device *qadev = to_ladev(dev);
+    struct qcom_stream_out *out = reinterpret_cast<struct qcom_stream_out *>(stream);
+
+    qadev->hwif->closeOutputStream(out->qcom_out);
+    free(out);
+}
+
+/** This method creates and opens the audio hardware input stream */
+static int adev_open_input_stream(struct audio_hw_device *dev,
+                                  audio_io_handle_t handle,
+                                  audio_devices_t devices,
+                                  audio_config *config,
+                                  audio_stream_in **stream_in)
+{
+    struct qcom_audio_device *qadev = to_ladev(dev);
+    status_t status;
+    struct qcom_stream_in *in;
+    int ret;
+
+    in = (struct qcom_stream_in *)calloc(1, sizeof(*in));
+    if (!in)
+        return -ENOMEM;
+
+    in->qcom_in = qadev->hwif->openInputStream(devices, (int *)&config->format,
+                                    &config->channel_mask,
+                                    &config->sample_rate,
+                                    &status,
+                                    (AudioSystem::audio_in_acoustics)0);
+    if (!in->qcom_in) {
+        ret = status;
+        goto err_open;
+    }
+
+    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;
+
+    *stream_in = &in->stream;
+    return 0;
+
+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)
+{
+    struct qcom_audio_device *qadev = to_ladev(dev);
+    struct qcom_stream_in *in =
+        reinterpret_cast<struct qcom_stream_in *>(stream);
+
+    qadev->hwif->closeInputStream(in->qcom_in);
+    free(in);
+}
+
+static int adev_dump(const struct audio_hw_device *dev, int fd)
+{
+    const struct qcom_audio_device *qadev = to_cladev(dev);
+    Vector<String16> args;
+
+    return qadev->hwif->dumpState(fd, args);
+}
+
+static int qcom_adev_close(hw_device_t* device)
+{
+    struct audio_hw_device *hwdev =
+                        reinterpret_cast<struct audio_hw_device *>(device);
+    struct qcom_audio_device *qadev = to_ladev(hwdev);
+
+    if (!qadev)
+        return 0;
+
+    if (qadev->hwif)
+        delete qadev->hwif;
+
+    free(qadev);
+    return 0;
+}
+
+static int qcom_adev_open(const hw_module_t* module, const char* name,
+                            hw_device_t** device)
+{
+    struct qcom_audio_device *qadev;
+    int ret;
+
+    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
+        return -EINVAL;
+
+    qadev = (struct qcom_audio_device *)calloc(1, sizeof(*qadev));
+    if (!qadev)
+        return -ENOMEM;
+
+    qadev->device.common.tag = HARDWARE_DEVICE_TAG;
+    qadev->device.common.version = AUDIO_DEVICE_API_VERSION_1_0;
+    qadev->device.common.module = const_cast<hw_module_t*>(module);
+    qadev->device.common.close = qcom_adev_close;
+
+    qadev->device.get_supported_devices = adev_get_supported_devices;
+    qadev->device.init_check = adev_init_check;
+    qadev->device.set_voice_volume = adev_set_voice_volume;
+    qadev->device.set_master_volume = adev_set_master_volume;
+    qadev->device.get_master_volume = adev_get_master_volume;
+#ifdef QCOM_FM_ENABLED
+    qadev->device.set_fm_volume = adev_set_fm_volume;
+#endif
+    qadev->device.set_mode = adev_set_mode;
+    qadev->device.set_mic_mute = adev_set_mic_mute;
+    qadev->device.get_mic_mute = adev_get_mic_mute;
+    qadev->device.set_parameters = adev_set_parameters;
+    qadev->device.get_parameters = adev_get_parameters;
+    qadev->device.get_input_buffer_size = adev_get_input_buffer_size;
+    qadev->device.open_output_stream = adev_open_output_stream;
+    qadev->device.close_output_stream = adev_close_output_stream;
+    qadev->device.open_input_stream = adev_open_input_stream;
+    qadev->device.close_input_stream = adev_close_input_stream;
+    qadev->device.dump = adev_dump;
+
+    qadev->hwif = createAudioHardware();
+    if (!qadev->hwif) {
+        ret = -EIO;
+        goto err_create_audio_hw;
+    }
+
+    *device = &qadev->device.common;
+
+    return 0;
+
+err_create_audio_hw:
+    free(qadev);
+    return ret;
+}
+
+static struct hw_module_methods_t qcom_audio_module_methods = {
+        open: qcom_adev_open
+};
+
+struct qcom_audio_module HAL_MODULE_INFO_SYM = {
+    module: {
+        common: {
+            tag: HARDWARE_MODULE_TAG,
+            version_major: 1,
+            version_minor: 0,
+            id: AUDIO_HARDWARE_MODULE_ID,
+            name: "QCOM Audio HW HAL",
+            author: "Code Aurora Forum",
+            methods: &qcom_audio_module_methods,
+            dso : NULL,
+            reserved : {0},
+        },
+    },
+};
+
+}; // extern "C"
+
+}; // namespace android_audio_legacy
diff --git a/msm8660/audio_policy.conf b/msm8660/audio_policy.conf
new file mode 100644
index 0000000..cbe793e
--- /dev/null
+++ b/msm8660/audio_policy.conf
@@ -0,0 +1,77 @@
+#
+# Audio policy configuration for generic device builds (goldfish audio HAL - emulator)
+#
+
+# Global configuration section: lists input and output devices always present on the device
+# as well as the output device selected by default.
+# Devices are designated by a string that corresponds to the enum in audio.h
+
+global_configuration {
+  attached_output_devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_EARPIECE
+  default_output_device AUDIO_DEVICE_OUT_SPEAKER
+  attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_VOICE_CALL
+}
+
+# audio hardware module section: contains descriptors for all audio hw modules present on the
+# device. Each hw module node is named after the corresponding hw module library base name.
+# For instance, "primary" corresponds to audio.primary.<device>.so.
+# The "primary" module is mandatory and must include at least one output with
+# AUDIO_OUTPUT_FLAG_PRIMARY flag.
+# Each module descriptor contains one or more output profile descriptors and zero or more
+# input profile descriptors. Each profile lists all the parameters supported by a given output
+# or input stream category.
+# The "channel_masks", "formats", "devices" and "flags" are specified using strings corresponding
+# to enums in audio.h and audio_policy.h. They are concatenated by use of "|" without space or "\n".
+
+audio_hw_modules {
+  primary {
+    outputs {
+      primary {
+        sampling_rates 44100
+        channel_masks AUDIO_CHANNEL_OUT_STEREO
+        formats AUDIO_FORMAT_PCM_16_BIT
+        devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_EARPIECE|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_ANC_HEADSET|AUDIO_DEVICE_OUT_ANC_HEADPHONE|AUDIO_DEVICE_OUT_ALL_SCO|AUDIO_DEVICE_OUT_AUX_DIGITAL|AUDIO_DEVICE_OUT_FM|AUDIO_DEVICE_OUT_FM_TX
+        flags AUDIO_OUTPUT_FLAG_PRIMARY
+      }
+      lpa {
+        sampling_rates 8000|11025|12000|16000|22050|24000|32000|44100|48000
+        channel_masks AUDIO_CHANNEL_OUT_STEREO|AUDIO_CHANNEL_OUT_MONO
+        formats AUDIO_FORMAT_PCM_16_BIT
+        devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_EARPIECE|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_ALL_SCO|AUDIO_DEVICE_OUT_AUX_DIGITAL
+        flags AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_LPA
+      }
+      voipout {
+        sampling_rates 8000|16000
+        channel_masks AUDIO_CHANNEL_OUT_MONO
+        formats AUDIO_FORMAT_PCM_16_BIT|AUDIO_FORMAT_AMR_NB|AUDIO_FORMAT_AMR_WB|AUDIO_FORMAT_QCELP|AUDIO_FORMAT_EVRC|AUDIO_FORMAT_EVRCB|AUDIO_FORMAT_EVRCWB
+        devices AUDIO_DEVICE_OUT_EARPIECE|AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE
+        flags AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_VOIP_RX
+      }
+    }
+    inputs {
+      primary {
+        sampling_rates 8000|11025|12000|16000|22050|24000|32000|44100|48000
+        channel_masks AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO|AUDIO_CHANNEL_IN_VOICE_CALL_MONO|AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO|AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO
+        formats AUDIO_FORMAT_PCM_16_BIT
+        devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_WIRED_HEADSET|AUDIO_DEVICE_IN_ANC_HEADSET|AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET|AUDIO_DEVICE_IN_AUX_DIGITAL|AUDIO_DEVICE_IN_VOICE_CALL
+      }
+      voipin {
+        sampling_rates 8000|16000
+        channel_masks AUDIO_CHANNEL_IN_MONO
+        formats AUDIO_FORMAT_PCM_16_BIT|AUDIO_FORMAT_AMR_NB|AUDIO_FORMAT_AMR_WB|AUDIO_FORMAT_QCELP|AUDIO_FORMAT_EVRC|AUDIO_FORMAT_EVRCB|AUDIO_FORMAT_EVRCWB
+        devices AUDIO_DEVICE_IN_COMMUNICATION
+      }
+    }
+  }
+  a2dp {
+    outputs {
+      primary {
+        sampling_rates 44100
+        channel_masks AUDIO_CHANNEL_OUT_STEREO
+        formats AUDIO_FORMAT_PCM_16_BIT
+        devices AUDIO_DEVICE_OUT_ALL_A2DP
+        flags AUDIO_OUTPUT_FLAG_PRIMARY
+      }
+    }
+  }
+}
diff --git a/msm8660/audio_policy_hal.cpp b/msm8660/audio_policy_hal.cpp
new file mode 100644
index 0000000..307dcc9
--- /dev/null
+++ b/msm8660/audio_policy_hal.cpp
@@ -0,0 +1,492 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * 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_policy.msm8660"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <system/audio_policy.h>
+#include <hardware/audio_policy.h>
+
+#include <hardware_legacy/AudioPolicyInterface.h>
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+#include "AudioPolicyCompatClient.h"
+
+namespace android_audio_legacy {
+//using android_audio_legacy::AudioSystem;
+
+extern "C" {
+
+struct qcom_ap_module {
+    struct audio_policy_module module;
+};
+
+struct qcom_ap_device {
+    struct audio_policy_device device;
+};
+
+struct qcom_audio_policy {
+    struct audio_policy policy;
+
+    void *service;
+    struct audio_policy_service_ops *aps_ops;
+    AudioPolicyCompatClient *service_client;
+    AudioPolicyInterface *apm;
+};
+
+static inline struct qcom_audio_policy * to_qap(struct audio_policy *pol)
+{
+    return reinterpret_cast<struct qcom_audio_policy *>(pol);
+}
+
+static inline const struct qcom_audio_policy * to_cqap(const struct audio_policy *pol)
+{
+    return reinterpret_cast<const struct qcom_audio_policy *>(pol);
+}
+
+
+static int ap_set_device_connection_state(struct audio_policy *pol,
+                                          audio_devices_t device,
+                                          audio_policy_dev_state_t state,
+                                          const char *device_address)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    return qap->apm->setDeviceConnectionState(
+                    (AudioSystem::audio_devices)device,
+                    (AudioSystem::device_connection_state)state,
+                    device_address);
+}
+
+static audio_policy_dev_state_t ap_get_device_connection_state(
+                                            const struct audio_policy *pol,
+                                            audio_devices_t device,
+                                            const char *device_address)
+{
+    const struct qcom_audio_policy *qap = to_cqap(pol);
+    return (audio_policy_dev_state_t)qap->apm->getDeviceConnectionState(
+                    (AudioSystem::audio_devices)device,
+                    device_address);
+}
+
+static void ap_set_phone_state(struct audio_policy *pol, audio_mode_t state)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    qap->apm->setPhoneState(state);
+}
+
+    /* force using a specific device category for the specified usage */
+static void ap_set_force_use(struct audio_policy *pol,
+                          audio_policy_force_use_t usage,
+                          audio_policy_forced_cfg_t config)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    qap->apm->setForceUse((AudioSystem::force_use)usage,
+                          (AudioSystem::forced_config)config);
+}
+
+    /* retreive current device category forced for a given usage */
+static audio_policy_forced_cfg_t ap_get_force_use(
+                                               const struct audio_policy *pol,
+                                               audio_policy_force_use_t usage)
+{
+    const struct qcom_audio_policy *qap = to_cqap(pol);
+    return (audio_policy_forced_cfg_t)qap->apm->getForceUse(
+                          (AudioSystem::force_use)usage);
+}
+
+/* if can_mute is true, then audio streams that are marked ENFORCED_AUDIBLE
+ * can still be muted. */
+static void ap_set_can_mute_enforced_audible(struct audio_policy *pol,
+                                             bool can_mute)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    qap->apm->setSystemProperty("ro.camera.sound.forced", can_mute ? "0" : "1");
+}
+
+static int ap_init_check(const struct audio_policy *pol)
+{
+    const struct qcom_audio_policy *qap = to_cqap(pol);
+    return qap->apm->initCheck();
+}
+
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+static audio_io_handle_t ap_get_session(struct audio_policy *pol,
+                                       audio_stream_type_t stream,
+                                       audio_format_t format,
+                                       audio_policy_output_flags_t flags,
+                                       int sessionId,
+                                       uint32_t samplingRate,
+                                       uint32_t channels)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+
+    ALOGV("%s: tid %d", __func__, gettid());
+    return qap->apm->getSession((AudioSystem::stream_type)stream,
+                               format, (AudioSystem::output_flags)flags,
+                               sessionId,
+                               samplingRate,
+                               channels);
+}
+
+static void ap_pause_session(struct audio_policy *pol, audio_io_handle_t output,
+                          audio_stream_type_t stream)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    qap->apm->pauseSession(output, (AudioSystem::stream_type)stream);
+}
+
+static void ap_resume_session(struct audio_policy *pol, audio_io_handle_t output,
+                          audio_stream_type_t stream)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    qap->apm->resumeSession(output, (AudioSystem::stream_type)stream);
+}
+
+static void ap_release_session(struct audio_policy *pol, audio_io_handle_t output)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    qap->apm->releaseSession(output);
+}
+#endif
+
+static audio_io_handle_t ap_get_output(struct audio_policy *pol,
+                                       audio_stream_type_t stream,
+                                       uint32_t sampling_rate,
+                                       audio_format_t format,
+                                       uint32_t channels,
+                                       audio_output_flags_t flags)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+
+    ALOGV("%s: tid %d", __func__, gettid());
+    return qap->apm->getOutput((AudioSystem::stream_type)stream,
+                               sampling_rate, format, channels,
+                               (AudioSystem::output_flags)flags);
+}
+
+static int ap_start_output(struct audio_policy *pol, audio_io_handle_t output,
+                           audio_stream_type_t stream, int session)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    return qap->apm->startOutput(output, (AudioSystem::stream_type)stream,
+                                 session);
+}
+
+static int ap_stop_output(struct audio_policy *pol, audio_io_handle_t output,
+                          audio_stream_type_t stream, int session)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    return qap->apm->stopOutput(output, (AudioSystem::stream_type)stream,
+                                session);
+}
+
+static void ap_release_output(struct audio_policy *pol,
+                              audio_io_handle_t output)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    qap->apm->releaseOutput(output);
+}
+
+static audio_io_handle_t ap_get_input(struct audio_policy *pol, audio_source_t inputSource,
+                                      uint32_t sampling_rate,
+                                      audio_format_t format,
+                                      uint32_t channels,
+                                      audio_in_acoustics_t acoustics)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    return qap->apm->getInput(inputSource, sampling_rate, format, channels,
+                              (AudioSystem::audio_in_acoustics)acoustics);
+}
+
+static int ap_start_input(struct audio_policy *pol, audio_io_handle_t input)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    return qap->apm->startInput(input);
+}
+
+static int ap_stop_input(struct audio_policy *pol, audio_io_handle_t input)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    return qap->apm->stopInput(input);
+}
+
+static void ap_release_input(struct audio_policy *pol, audio_io_handle_t input)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    qap->apm->releaseInput(input);
+}
+
+static void ap_init_stream_volume(struct audio_policy *pol,
+                                  audio_stream_type_t stream, int index_min,
+                                  int index_max)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    qap->apm->initStreamVolume((AudioSystem::stream_type)stream, index_min,
+                               index_max);
+}
+
+static int ap_set_stream_volume_index(struct audio_policy *pol,
+                                      audio_stream_type_t stream,
+                                      int index)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    return qap->apm->setStreamVolumeIndex((AudioSystem::stream_type)stream,
+                                          index,
+                                          AUDIO_DEVICE_OUT_DEFAULT); 
+}
+
+static int ap_get_stream_volume_index(const struct audio_policy *pol,
+                                      audio_stream_type_t stream,
+                                      int *index)
+{
+    const struct qcom_audio_policy *qap = to_cqap(pol);
+    return qap->apm->getStreamVolumeIndex((AudioSystem::stream_type)stream,
+                                          index,
+                                          AUDIO_DEVICE_OUT_DEFAULT);
+}
+
+static uint32_t ap_get_strategy_for_stream(const struct audio_policy *pol,
+                                           audio_stream_type_t stream)
+{
+    const struct qcom_audio_policy *qap = to_cqap(pol);
+    return qap->apm->getStrategyForStream((AudioSystem::stream_type)stream);
+}
+
+static int ap_set_stream_volume_index_for_device(struct audio_policy *pol,
+                                      audio_stream_type_t stream,
+                                      int index,
+                                      audio_devices_t device)
+{
+   const struct qcom_audio_policy *qap = to_cqap(pol);
+   return qap->apm->setStreamVolumeIndex((AudioSystem::stream_type)stream,
+                                          index,
+                                          device);
+}
+
+static int ap_get_stream_volume_index_for_device(const struct audio_policy *pol,
+                                      audio_stream_type_t stream,
+                                      int *index,
+                                      audio_devices_t device)
+{
+   const struct qcom_audio_policy *qap = to_cqap(pol);
+   return qap->apm->getStreamVolumeIndex((AudioSystem::stream_type)stream,
+                                          index,
+                                          AUDIO_DEVICE_OUT_DEFAULT);
+}
+
+static audio_devices_t ap_get_devices_for_stream(const struct audio_policy *pol,
+                                       audio_stream_type_t stream)
+{
+    const struct qcom_audio_policy *qap = to_cqap(pol);
+    return qap->apm->getDevicesForStream((AudioSystem::stream_type)stream);
+}
+
+static audio_io_handle_t ap_get_output_for_effect(struct audio_policy *pol,
+                                            const struct effect_descriptor_s *desc)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    return qap->apm->getOutputForEffect(desc);
+}
+
+static int ap_register_effect(struct audio_policy *pol,
+                              const struct effect_descriptor_s *desc,
+                              audio_io_handle_t io,
+                              uint32_t strategy,
+                              int session,
+                              int id)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    return qap->apm->registerEffect(desc, io, strategy, session, id);
+}
+
+static int ap_unregister_effect(struct audio_policy *pol, int id)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    return qap->apm->unregisterEffect(id);
+}
+
+static int ap_set_effect_enabled(struct audio_policy *pol, int id, bool enabled)
+{
+    struct qcom_audio_policy *qap = to_qap(pol);
+    return qap->apm->setEffectEnabled(id, enabled);
+}
+
+static bool ap_is_stream_active(const struct audio_policy *pol, 
+                                audio_stream_type_t stream,
+                                uint32_t in_past_ms)
+{
+    const struct qcom_audio_policy *qap = to_cqap(pol);
+    return qap->apm->isStreamActive(stream, in_past_ms);
+}
+
+static int ap_dump(const struct audio_policy *pol, int fd)
+{
+    const struct qcom_audio_policy *qap = to_cqap(pol);
+    return qap->apm->dump(fd);
+}
+
+static int create_qcom_ap(const struct audio_policy_device *device,
+                            struct audio_policy_service_ops *aps_ops,
+                            void *service,
+                            struct audio_policy **ap)
+{
+    struct qcom_audio_policy *qap;
+    int ret;
+
+    if (!service || !aps_ops)
+        return -EINVAL;
+
+    qap = (struct qcom_audio_policy *)calloc(1, sizeof(*qap));
+    if (!qap)
+        return -ENOMEM;
+
+    qap->policy.set_device_connection_state = ap_set_device_connection_state;
+    qap->policy.get_device_connection_state = ap_get_device_connection_state;
+    qap->policy.set_phone_state = ap_set_phone_state;
+    qap->policy.set_force_use = ap_set_force_use;
+    qap->policy.get_force_use = ap_get_force_use;
+    qap->policy.set_can_mute_enforced_audible =
+        ap_set_can_mute_enforced_audible;
+    qap->policy.init_check = ap_init_check;
+    qap->policy.get_output = ap_get_output;
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+    qap->policy.get_session = ap_get_session;
+    qap->policy.pause_session = ap_pause_session;
+    qap->policy.resume_session = ap_resume_session;
+    qap->policy.release_session = ap_release_session;
+#endif
+    qap->policy.start_output = ap_start_output;
+    qap->policy.stop_output = ap_stop_output;
+    qap->policy.release_output = ap_release_output;
+    qap->policy.get_input = ap_get_input;
+    qap->policy.start_input = ap_start_input;
+    qap->policy.stop_input = ap_stop_input;
+    qap->policy.release_input = ap_release_input;
+    qap->policy.init_stream_volume = ap_init_stream_volume;
+    qap->policy.set_stream_volume_index = ap_set_stream_volume_index;
+    qap->policy.get_stream_volume_index = ap_get_stream_volume_index;
+    qap->policy.set_stream_volume_index_for_device = ap_set_stream_volume_index_for_device;
+    qap->policy.get_stream_volume_index_for_device = ap_get_stream_volume_index_for_device;
+    qap->policy.get_strategy_for_stream = ap_get_strategy_for_stream;
+    qap->policy.get_devices_for_stream = ap_get_devices_for_stream;
+    qap->policy.get_output_for_effect = ap_get_output_for_effect;
+    qap->policy.register_effect = ap_register_effect;
+    qap->policy.unregister_effect = ap_unregister_effect;
+    qap->policy.set_effect_enabled = ap_set_effect_enabled;
+    qap->policy.is_stream_active = ap_is_stream_active;
+    qap->policy.dump = ap_dump;
+
+    qap->service = service;
+    qap->aps_ops = aps_ops;
+    qap->service_client =
+        new AudioPolicyCompatClient(aps_ops, service);
+    if (!qap->service_client) {
+        ret = -ENOMEM;
+        goto err_new_compat_client;
+    }
+
+    qap->apm = createAudioPolicyManager(qap->service_client);
+    if (!qap->apm) {
+        ret = -ENOMEM;
+        goto err_create_apm;
+    }
+
+    *ap = &qap->policy;
+    return 0;
+
+err_create_apm:
+    delete qap->service_client;
+err_new_compat_client:
+    free(qap);
+    *ap = NULL;
+    return ret;
+}
+
+static int destroy_qcom_ap(const struct audio_policy_device *ap_dev,
+                             struct audio_policy *ap)
+{
+    struct qcom_audio_policy *qap = to_qap(ap);
+
+    if (!qap)
+        return 0;
+
+    if (qap->apm)
+        destroyAudioPolicyManager(qap->apm);
+    if (qap->service_client)
+        delete qap->service_client;
+    free(qap);
+    return 0;
+}
+
+static int qcom_ap_dev_close(hw_device_t* device)
+{
+    if (device)
+        free(device);
+    return 0;
+}
+
+static int qcom_ap_dev_open(const hw_module_t* module, const char* name,
+                                    hw_device_t** device)
+{
+    struct qcom_ap_device *dev;
+
+    if (strcmp(name, AUDIO_POLICY_INTERFACE) != 0)
+        return -EINVAL;
+
+    dev = (struct qcom_ap_device *)calloc(1, sizeof(*dev));
+    if (!dev)
+        return -ENOMEM;
+
+    dev->device.common.tag = HARDWARE_DEVICE_TAG;
+    dev->device.common.version = 0;
+    dev->device.common.module = const_cast<hw_module_t*>(module);
+    dev->device.common.close = qcom_ap_dev_close;
+    dev->device.create_audio_policy = create_qcom_ap;
+    dev->device.destroy_audio_policy = destroy_qcom_ap;
+
+    *device = &dev->device.common;
+
+    return 0;
+}
+
+static struct hw_module_methods_t qcom_ap_module_methods = {
+        open: qcom_ap_dev_open
+};
+
+struct qcom_ap_module HAL_MODULE_INFO_SYM = {
+    module: {
+        common: {
+            tag: HARDWARE_MODULE_TAG,
+            version_major: 1,
+            version_minor: 0,
+            id: AUDIO_POLICY_HARDWARE_MODULE_ID,
+            name: "QCOM Audio Policy HAL",
+            author: "Code Aurora Forum",
+            methods: &qcom_ap_module_methods,
+            dso : NULL,
+            reserved : {0},
+        },
+    },
+};
+
+}; // extern "C"
+
+}; // namespace android_audio_legacy
diff --git a/msm8660/control.h b/msm8660/control.h
new file mode 100644
index 0000000..f21b59b
--- /dev/null
+++ b/msm8660/control.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2009 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 __MSM_AUDIO_ALSA_CONTROL
+#define __MSM_AUDIO_ALSA_CONTROL
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern const char **msm_get_device_list(void);
+extern int msm_mixer_count(void);
+extern int msm_mixer_open(const char *name, int id);
+extern void msm_mixer_close(void);
+extern int msm_get_device(const char *name);
+extern int msm_en_device(int device, short enable);
+extern int msm_route_stream(int dir, int dec_id, int dev_id, int set);
+extern int msm_route_voice(int tx, int rx, int set);
+extern int msm_set_volume(int dec_id, float vol);
+extern int msm_get_device_class(int dev_id);
+extern int msm_get_device_capability(int dev_id);
+extern int msm_get_device_count(void);
+extern void msm_start_voice(void);
+extern int msm_end_voice(void);
+extern void msm_set_voice_tx_mute(int mute);
+extern int msm_set_voice_rx_vol(int volume);
+extern void msm_set_device_volume(int dev_id, int volume);
+extern void msm_device_mute(int dev_id, int mute);
+extern int msm_reset_all_device(void);
+extern int msm_enable_anc(int dev_id, int enable);
+
+#ifndef LEGACY_QCOM_VOICE
+int msm_get_voc_session(const char *name);
+int msm_start_voice_ext(int id);
+int msm_end_voice_ext(int id);
+int msm_set_voice_tx_mute_ext(int mute, int id);
+int msm_set_voice_rx_vol_ext(int volume, int id);
+#endif
+
+__END_DECLS
+
+#endif