Merge branch 'jb_2.5' of git://codeaurora.org/platform/hardware/qcom/audio into cm-10.2

Change-Id: If58c40a26d116bbc9379237499682dcb4f700197
diff --git a/Android.mk b/Android.mk
index ac9c904..e1bdbc3 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,8 +1,28 @@
+ifneq ($(filter msm8960 msm8660 msm7x30,$(TARGET_BOARD_PLATFORM)),)
+
 AUDIO_HW_ROOT := $(call my-dir)
 
+ifeq ($(TARGET_QCOM_AUDIO_VARIANT),caf)
+
 ifeq ($(strip $(BOARD_USES_ALSA_AUDIO)),true)
     include $(AUDIO_HW_ROOT)/alsa_sound/Android.mk
     include $(AUDIO_HW_ROOT)/libalsa-intf/Android.mk
+	include $(AUDIO_HW_ROOT)/audiod/Android.mk
+endif
+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
+endif
+endif
+
+ifeq ($(TARGET_BOARD_PLATFORM),msm8960)
     include $(AUDIO_HW_ROOT)/mm-audio/Android.mk
-    include $(AUDIO_HW_ROOT)/audiod/Android.mk
+endif
+
+ifeq ($(TARGET_BOARD_PLATFORM),msm8660)
+    include $(AUDIO_HW_ROOT)/mm-audio/Android.mk
+endif
+
 endif
diff --git a/alsa_sound/ALSADevice.cpp b/alsa_sound/ALSADevice.cpp
index f4c5690..b87fd4b 100644
--- a/alsa_sound/ALSADevice.cpp
+++ b/alsa_sound/ALSADevice.cpp
@@ -17,8 +17,7 @@
  */
 
 #define LOG_TAG "ALSADevice"
-#define LOG_NDEBUG 0
-#define LOG_NDDEBUG 0
+//#define LOG_NDEBUG 0
 #include <utils/Log.h>
 #include <cutils/properties.h>
 #include <linux/ioctl.h>
@@ -26,10 +25,19 @@
 #include "AudioHardwareALSA.h"
 #include <media/AudioRecord.h>
 #include <dlfcn.h>
+#ifdef USE_A2220
+#include <sound/a2220.h>
+#endif
+
+#ifdef USES_AUDIO_AMPLIFIER
+#include <audio_amplifier.h>
+#endif
+
 extern "C" {
 #ifdef QCOM_CSDCLIENT_ENABLED
 static int (*csd_disable_device)();
 static int (*csd_enable_device)(int, int, uint32_t);
+#ifdef NEW_CSDCLIENT
 static int (*csd_enable_device_config)(int, int);
 static int (*csd_volume)(uint32_t, int);
 static int (*csd_mic_mute)(uint32_t, int);
@@ -38,6 +46,15 @@
 static int (*csd_fens)(uint32_t, uint8_t);
 static int (*csd_start_voice)(uint32_t);
 static int (*csd_stop_voice)(uint32_t);
+#else
+static int (*csd_volume)(int);
+static int (*csd_mic_mute)(int);
+static int (*csd_wide_voice)(uint8_t);
+static int (*csd_slow_talk)(uint8_t);
+static int (*csd_fens)(uint8_t);
+static int (*csd_start_voice)();
+static int (*csd_stop_voice)();
+#endif
 #endif
 #ifdef QCOM_ACDB_ENABLED
 static int (*acdb_loader_get_ecrx_device)(int acdb_id);
@@ -60,6 +77,9 @@
 // PCM_RECORD_PERIOD_COUNT to a value between 4-16.
 #define PCM_RECORD_PERIOD_COUNT 4
 #define PROXY_CAPTURE_DEVICE_NAME (const char *)("hw:0,8")
+#define ADSP_UP_CHK_TRIES 5
+#define ADSP_UP_CHK_SLEEP 1*1000*1000
+
 namespace sys_close {
     ssize_t lib_close(int fd) {
         return close(fd);
@@ -73,9 +93,9 @@
 #ifdef USES_FLUENCE_INCALL
     mDevSettingsFlag = TTY_OFF | DMIC_FLAG;
 #else
-    mSSRComplete = false;
     mDevSettingsFlag = TTY_OFF;
 #endif
+    mADSPState = ADSP_UP;
     mBtscoSamplerate = 8000;
     mCallMode = AUDIO_MODE_NORMAL;
     mInChannels = 0;
@@ -111,6 +131,15 @@
     mProxyParams.mProxyState = proxy_params::EProxyClosed;
     mProxyParams.mProxyPcmHandle = NULL;
 
+#ifdef USE_A2220
+    mA2220Fd = -1;
+    mA2220Mode = A2220_PATH_INCALL_RECEIVER_NSOFF;
+#endif
+
+#ifdef SEPERATED_AUDIO_INPUT
+    mInputSource = AUDIO_SOURCE_DEFAULT;
+#endif
+
     ALOGD("ALSA module opened");
 }
 
@@ -127,16 +156,47 @@
 }
 
 static bool isPlatformFusion3() {
-    char platform[128], baseband[128];
+    char platform[128], baseband[128], baseband_arch[128];
     property_get("ro.board.platform", platform, "");
     property_get("ro.baseband", baseband, "");
+    property_get("ro.baseband.arch", baseband_arch, "");
     if (!strcmp("msm8960", platform) &&
-        (!strcmp("mdm", baseband) || !strcmp("sglte2", baseband)))
+        (!strcmp("mdm", baseband) || !strcmp("sglte2", baseband) ||
+        !strcmp("mdm", baseband_arch)))
         return true;
     else
         return false;
 }
 
+#ifdef USE_A2220
+int ALSADevice::setA2220Mode(int mode)
+{
+    Mutex::Autolock autoLock(mA2220Lock);
+    int rc = -1;
+
+    if (mA2220Mode != mode) {
+        if (mA2220Fd < 0) {
+            mA2220Fd = ::open("/dev/audience_a2220", O_RDWR);
+            if (!mA2220Fd) {
+                ALOGE("%s: unable to open a2220 device!", __func__);
+                return rc;
+            } else {
+                ALOGI("%s: device opened, fd=%d", __func__, mA2220Fd);
+            }
+        }
+
+        rc = ioctl(mA2220Fd, A2220_SET_CONFIG, mode);
+        if (rc < 0)
+            ALOGE("%s: ioctl failed, errno=%d", __func__, errno);
+        else {
+            mA2220Mode = mode;
+            ALOGD("%s: set mode=%d", __func__, mode);
+        }
+    }
+    return rc;
+}
+#endif
+
 static bool shouldUseHandsetAnc(int flags, int inChannels)
 {
     if (!isPlatformFusion3()) {
@@ -153,6 +213,7 @@
            is the only adaptive mode CSD Client cares about */
         adjustedFlags &= ~(ANC_FLAG);
     }
+
     ALOGD("%s: current Rx device: %s, flags: %x, adjustedFlags: %x",
             __FUNCTION__, rxDevice, flags, adjustedFlags);
     return adjustedFlags;
@@ -364,7 +425,11 @@
                    format);
     param_set_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
                    SNDRV_PCM_SUBFORMAT_STD);
+#ifdef SET_MIN_PERIOD_BYTES
+    param_set_min(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, reqBuffSize);
+#else
     param_set_int(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, reqBuffSize);
+#endif
     //Setting number of periods to 4. If the system is loaded and record
     // obtain buffer is seen increase PCM_RECORD_PERIOD_COUNT to a value between 4-16.
     if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC,
@@ -490,7 +555,8 @@
             devices = devices | (AudioSystem::DEVICE_OUT_WIRED_HEADPHONE |
                       AudioSystem::DEVICE_IN_BUILTIN_MIC);
         } else if ((devices & AudioSystem::DEVICE_OUT_EARPIECE) ||
-                   (devices & AudioSystem::DEVICE_IN_BUILTIN_MIC)) {
+                  (devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) ||
+                  (devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)) {
             if ((mode == AudioSystem::MODE_IN_COMMUNICATION) &&
                  (devices & AudioSystem::DEVICE_IN_BUILTIN_MIC)) {
                  if (!strncmp(mCurRxUCMDevice, SND_USE_CASE_DEV_SPEAKER,
@@ -581,6 +647,9 @@
         if (csd_disable_device == NULL) {
             ALOGE("csd_client_disable_device is NULL");
         } else {
+#ifdef USE_ES325_2MIC
+            setMixerControl("ES325 2Mic Enable", 0, 0);
+#endif
             err = csd_disable_device();
             if (err < 0)
             {
@@ -594,7 +663,8 @@
     mods_size = snd_use_case_get_list(handle->ucMgr, "_enamods", &mods_list);
     if (rxDevice != NULL) {
         if ((strncmp(mCurRxUCMDevice, "None", 4)) &&
-            (mSSRComplete || (strncmp(rxDevice, mCurRxUCMDevice, MAX_STR_LEN)) || (inCallDevSwitch == true))) {
+            ((mADSPState == ADSP_UP_AFTER_SSR) ||
+             (strncmp(rxDevice, mCurRxUCMDevice, MAX_STR_LEN)) || (inCallDevSwitch == true))) {
             if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
                 strlen(SND_USE_CASE_VERB_INACTIVE)))) {
                 usecase_type = getUseCaseType(use_case);
@@ -621,7 +691,8 @@
     }
     if (txDevice != NULL) {
         if ((strncmp(mCurTxUCMDevice, "None", 4)) &&
-            (mSSRComplete || (strncmp(txDevice, mCurTxUCMDevice, MAX_STR_LEN)) || (inCallDevSwitch == true))) {
+            ((mADSPState == ADSP_UP_AFTER_SSR) ||
+             (strncmp(txDevice, mCurTxUCMDevice, MAX_STR_LEN)) || (inCallDevSwitch == true))) {
             if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
                 strlen(SND_USE_CASE_VERB_INACTIVE)))) {
                 usecase_type = getUseCaseType(use_case);
@@ -657,7 +728,8 @@
        snd_use_case_set(handle->ucMgr, "_enadev", txDevice);
        strlcpy(mCurTxUCMDevice, txDevice, sizeof(mCurTxUCMDevice));
     }
-#ifdef QCOM_CSDCLIENT_ENABLED
+
+#if defined(QCOM_CSDCLIENT_ENABLED) && defined (NEW_CSDCLIENT)
     if (isPlatformFusion3() && (inCallDevSwitch == true)) {
 
         /* Get tx acdb id */
@@ -746,25 +818,86 @@
 
 #ifdef QCOM_CSDCLIENT_ENABLED
     if (isPlatformFusion3() && (inCallDevSwitch == true)) {
-        if (rx_dev_id == DEVICE_SPEAKER_RX_ACDB_ID && tx_dev_id == DEVICE_HANDSET_TX_ACDB_ID) {
+
+#ifndef NEW_CSDCLIENT
+        /* get tx acdb id */
+        memset(&ident,0,sizeof(ident));
+        strlcpy(ident, "ACDBID/", sizeof(ident));
+        strlcat(ident, mCurTxUCMDevice, sizeof(ident));
+        tx_dev_id = snd_use_case_get(handle->ucMgr, ident, NULL);
+
+       /* get rx acdb id */
+        memset(&ident,0,sizeof(ident));
+        strlcpy(ident, "ACDBID/", sizeof(ident));
+        strlcat(ident, mCurRxUCMDevice, sizeof(ident));
+        rx_dev_id = snd_use_case_get(handle->ucMgr, ident, NULL);
+#endif
+
+        if (((rx_dev_id == DEVICE_SPEAKER_MONO_RX_ACDB_ID ) || (rx_dev_id == DEVICE_SPEAKER_STEREO_RX_ACDB_ID ))
+         && tx_dev_id == DEVICE_HANDSET_TX_ACDB_ID) {
             tx_dev_id = DEVICE_SPEAKER_TX_ACDB_ID;
         }
         ALOGV("rx_dev_id=%d, tx_dev_id=%d\n", rx_dev_id, tx_dev_id);
 
+#ifndef NEW_CSDCLIENT
         if (csd_enable_device == NULL) {
             ALOGE("csd_client_enable_device is NULL");
         } else {
+            int tmp_tx_id = tx_dev_id;
+            int tmp_rx_id = rx_dev_id;
+
+#ifdef USE_ES325_2MIC
+            if (!strcmp(rxDevice, SND_USE_CASE_DEV_VOC_EARPIECE) ||
+                    !strcmp(rxDevice, SND_USE_CASE_DEV_VOC_EARPIECE_XGAIN) ||
+                    !strcmp(rxDevice, SND_USE_CASE_DEV_VOC_SPEAKER)) {
+                if (tx_dev_id == 4) {
+                    tmp_tx_id = 34;
+                    setMixerControl("VEQ Enable", 1, 0);
+                    setMixerControl("ES325 2Mic Enable", 1, 0);
+                } else {
+                    setMixerControl("ES325 2Mic Enable", 0, 0);
+                }
+            }
+#endif
+#ifdef HTC_CSDCLIENT
+            if (tx_dev_id == DEVICE_BT_SCO_TX_ACDB_ID)
+            {
+                tmp_tx_id = 1027;
+            }
+            if (rx_dev_id == DEVICE_BT_SCO_RX_ACDB_ID)
+            {
+                tmp_rx_id = 1127;
+            }
+#endif
             int adjustedFlags = adjustFlagsForCsd(mDevSettingsFlag,
                     mCurRxUCMDevice);
-            err = csd_enable_device(rx_dev_id, tx_dev_id, adjustedFlags);
+            err = csd_enable_device(tmp_rx_id, tmp_tx_id, adjustedFlags);
             if (err < 0)
             {
                 ALOGE("csd_client_disable_device failed, error %d", err);
             }
         }
+#endif
     }
 #endif
 
+#ifdef USE_A2220
+    ALOGI("a2220: txDevice=%s rxDevice=%s", txDevice, rxDevice);
+    if (rxDevice != NULL && txDevice != NULL &&
+            (!strcmp(txDevice, SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE) ||
+            !strcmp(txDevice, SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE)) &&
+            (!strcmp(rxDevice, SND_USE_CASE_DEV_VOC_EARPIECE) ||
+             !strcmp(rxDevice, SND_USE_CASE_DEV_VOC_EARPIECE_XGAIN))) {
+        setA2220Mode(A2220_PATH_INCALL_RECEIVER_NSON);
+    } else {
+        setA2220Mode(A2220_PATH_INCALL_RECEIVER_NSOFF);
+    }
+#endif
+
+#ifdef USES_AUDIO_AMPLIFIER
+    amplifier_set_devices(devices);
+#endif
+
     if (rxDevice != NULL) {
         free(rxDevice);
         rxDevice = NULL;
@@ -789,7 +922,7 @@
 status_t ALSADevice::open(alsa_handle_t *handle)
 {
     char *devName = NULL;
-    unsigned flags = 0;
+    unsigned flags = 0, maxTries = ADSP_UP_CHK_TRIES;
     int err = NO_ERROR;
 
     if(mCurDevice & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
@@ -799,6 +932,25 @@
             return err;
         }
     }
+
+    // This fix is required to avoid calling device open when ADSP SSR
+    // is not complete.
+    // Fix me: USB/proxy/a2dp
+
+    ALOGV("mADSPState: %d", mADSPState);
+    while(mADSPState == ADSP_DOWN)
+    {
+       if(maxTries--)
+       {
+          ALOGD("ADSP is not UP! Sleep for 1 sec, tries: %d.", maxTries);
+          usleep(ADSP_UP_CHK_SLEEP);
+       }
+       else
+       {
+          ALOGE("Error opening device! ADSP is not UP!");
+          return NO_INIT;
+       }
+    }
     close(handle);
 
     ALOGD("open: handle %p, format 0x%x", handle, handle->format);
@@ -1115,7 +1267,11 @@
         if (csd_start_voice == NULL) {
             ALOGE("csd_client_start_voice is NULL");
         } else {
+#ifdef NEW_CSDCLIENT
             err = csd_start_voice(vsid);
+#else
+            err = csd_start_voice();
+#endif
             if (err < 0){
                 ALOGE("s_start_voice_call: csd_client error %d\n", err);
                 goto Error;
@@ -1325,7 +1481,11 @@
             if (csd_stop_voice == NULL) {
                 ALOGE("csd_client_disable_device is NULL");
             } else {
+#ifdef NEW_CSDCLIENT
                 err = csd_stop_voice(vsid);
+#else
+                err = csd_stop_voice();
+#endif
                 if (err < 0) {
                     ALOGE("s_close: csd_client error %d\n", err);
                 }
@@ -1553,6 +1713,8 @@
 
 char* ALSADevice::getUCMDevice(uint32_t devices, int input, char *rxDevice)
 {
+    char value[PROPERTY_VALUE_MAX];
+
     if (!input) {
         ALOGV("getUCMDevice for output device: devices:%x is input device:%d",devices,input);
         if (!(mDevSettingsFlag & TTY_OFF) &&
@@ -1583,11 +1745,23 @@
             return strdup(SND_USE_CASE_DEV_PROXY_RX);
         } else if ((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET ||
                     devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET) &&
+                    mCallMode != AUDIO_MODE_IN_CALL &&
                     devices & AudioSystem::DEVICE_OUT_SPEAKER) {
-             return strdup(SND_USE_CASE_DEV_USB_PROXY_RX_SPEAKER); /* USB PROXY RX + SPEAKER */
-        } else if ((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET) ||
-                  (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)) {
-             return strdup(SND_USE_CASE_DEV_USB_PROXY_RX); /* PROXY RX */
+#ifdef SAMSUNG_AUDIO
+            if (AudioUtil::isSamsungDockConnected()) {
+                return strdup(SND_USE_CASE_DEV_DOCK);
+            }
+#endif
+            return strdup(SND_USE_CASE_DEV_USB_PROXY_RX_SPEAKER); /* USB PROXY RX + SPEAKER */
+        } else if (((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET) ||
+                  (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)) &&
+                  mCallMode != AUDIO_MODE_IN_CALL) {
+#ifdef SAMSUNG_AUDIO
+            if (AudioUtil::isSamsungDockConnected()) {
+                return strdup(SND_USE_CASE_DEV_DOCK); /* Dock RX */
+            }
+#endif
+            return strdup(SND_USE_CASE_DEV_USB_PROXY_RX); /* PROXY RX */
 #ifdef QCOM_PROXY_DEVICE_ENABLED
         } else if( (devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
                    (devices & AudioSystem::DEVICE_OUT_PROXY) &&
@@ -1620,7 +1794,7 @@
             (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE))) {
             return strdup(SND_USE_CASE_DEV_SPEAKER_ANC_HEADSET); /* COMBO SPEAKER+ANC HEADSET RX */
 #endif
-#ifdef QCOM_FM_ENABLED
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
         } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
                  (devices & AudioSystem::DEVICE_OUT_FM_TX)) {
             return strdup(SND_USE_CASE_DEV_SPEAKER_FM_TX); /* COMBO SPEAKER+FM_TX RX */
@@ -1634,17 +1808,36 @@
             return strdup(SND_USE_CASE_DEV_PROXY_RX_HANDSET); /* COMBO EARPIECE + PROXY RX */
 #endif
         } else if (devices & AudioSystem::DEVICE_OUT_EARPIECE) {
+#ifdef SEPERATED_VOIP
+            if (mCallMode == AUDIO_MODE_IN_COMMUNICATION) {
+                return strdup(SND_USE_CASE_DEV_VOIP_EARPIECE);
+            } else if (mCallMode == AUDIO_MODE_IN_CALL) {
+#else
             if (mCallMode == AUDIO_MODE_IN_CALL ||
                 mCallMode == AUDIO_MODE_IN_COMMUNICATION) {
+#endif
                 if (shouldUseHandsetAnc(mDevSettingsFlag, mInChannels)) {
                     return strdup(SND_USE_CASE_DEV_ANC_HANDSET); /* ANC Handset RX */
                 } else {
-                    return strdup(SND_USE_CASE_DEV_VOC_EARPIECE); /* Voice HANDSET RX */
+                    property_get("persist.audio.voc_ep.xgain", value, "");
+                    return strdup(strcmp(value, "1") == 0 ?
+                                SND_USE_CASE_DEV_VOC_EARPIECE_XGAIN :
+                                SND_USE_CASE_DEV_VOC_EARPIECE); /* Voice HANDSET RX */
                 }
             } else {
                 return strdup(SND_USE_CASE_DEV_EARPIECE); /* HANDSET RX */
             }
         } else if (devices & AudioSystem::DEVICE_OUT_SPEAKER) {
+#ifdef SEPERATED_VOIP
+            if (mCallMode == AUDIO_MODE_IN_COMMUNICATION) {
+                return strdup(SND_USE_CASE_DEV_VOIP_SPEAKER);
+            }
+#endif
+#ifdef SEPERATED_VOICE_SPEAKER
+            if (mCallMode == AUDIO_MODE_IN_CALL) {
+                return strdup(SND_USE_CASE_DEV_VOC_SPEAKER); /* Voice SPEAKER RX */
+            }
+#endif
             return strdup(SND_USE_CASE_DEV_SPEAKER); /* SPEAKER RX */
         } else if ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
                    (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) {
@@ -1656,8 +1849,14 @@
                     return strdup(SND_USE_CASE_DEV_ANC_HEADSET); /* ANC HEADSET RX */
                 }
             } else {
+#ifdef SEPERATED_VOIP
+                if (mCallMode == AUDIO_MODE_IN_COMMUNICATION) {
+                    return strdup(SND_USE_CASE_DEV_VOIP_HEADPHONE);
+                } else if (mCallMode == AUDIO_MODE_IN_CALL) {
+#else
                 if (mCallMode == AUDIO_MODE_IN_CALL ||
                     mCallMode == AUDIO_MODE_IN_COMMUNICATION) {
+#endif
                     return strdup(SND_USE_CASE_DEV_VOC_HEADPHONE); /* Voice HEADSET RX */
                 } else {
                     return strdup(SND_USE_CASE_DEV_HEADPHONES); /* HEADSET RX */
@@ -1694,7 +1893,7 @@
         } else if (devices & AudioSystem::DEVICE_OUT_PROXY) {
             return strdup(SND_USE_CASE_DEV_PROXY_RX); /* PROXY RX */
 #endif
-#ifdef QCOM_FM_ENABLED
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
         } else if (devices & AudioSystem::DEVICE_OUT_FM_TX) {
             return strdup(SND_USE_CASE_DEV_FM_TX); /* FM Tx */
 #endif
@@ -1729,19 +1928,20 @@
             } else {
                 if ((mDevSettingsFlag & DMIC_FLAG) && (mInChannels == 1)) {
 #ifdef USES_FLUENCE_INCALL
-                    if(callMode == AUDIO_MODE_IN_CALL) {
-                        if (fluence_mode == FLUENCE_MODE_ENDFIRE) {
-                            return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE); /* DUALMIC EF TX */
-                        } else if (fluence_mode == FLUENCE_MODE_BROADSIDE) {
-                            return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE); /* DUALMIC BS TX */
-                        } else {
-                            return strdup(SND_USE_CASE_DEV_HANDSET); /* BUILTIN-MIC TX */
-                        }
-                    }
-#else
+                  if (mCallMode == AUDIO_MODE_IN_CALL
+#ifdef USES_FLUENCE_FOR_VOIP
+                          || mCallMode == AUDIO_MODE_IN_COMMUNICATION
+#endif
+                     ) {
+#endif
                     if (((rxDevice != NULL) &&
-                        !strncmp(rxDevice, SND_USE_CASE_DEV_SPEAKER,
-                        (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) ||
+                        (!strncmp(rxDevice, SND_USE_CASE_DEV_SPEAKER,
+                        (strlen(SND_USE_CASE_DEV_SPEAKER)+1))
+#ifdef SEPERATED_VOICE_SPEAKER
+                        || !strncmp(rxDevice, SND_USE_CASE_DEV_VOC_SPEAKER,
+                        (strlen(SND_USE_CASE_DEV_VOC_SPEAKER)+1))
+#endif
+                        )) ||
                         ((rxDevice == NULL) &&
                         !strncmp(mCurRxUCMDevice, SND_USE_CASE_DEV_SPEAKER,
                         (strlen(SND_USE_CASE_DEV_SPEAKER)+1)))) {
@@ -1774,6 +1974,8 @@
                             return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE); /* DUALMIC BS TX */
                         }
                     }
+#ifdef USES_FLUENCE_INCALL
+                  }
 #endif
                 } else if ((mDevSettingsFlag & DMIC_FLAG) && (mInChannels > 1)) {
                     if (((rxDevice != NULL) &&
@@ -1825,10 +2027,25 @@
                 }
 #endif
 #ifdef SEPERATED_AUDIO_INPUT
-                if(mInput_source == AUDIO_SOURCE_VOICE_RECOGNITION) {
+                if(mInputSource == AUDIO_SOURCE_VOICE_RECOGNITION) {
                     return strdup(SND_USE_CASE_DEV_VOICE_RECOGNITION ); /* VOICE RECOGNITION TX */
                 }
 #endif
+#ifdef SEPERATED_CAMCORDER
+                if (mInputSource == AUDIO_SOURCE_CAMCORDER) {
+                    return strdup(SND_USE_CASE_DEV_CAMCORDER_TX); /* CAMCORDER TX */
+                }
+#endif
+#ifdef SEPERATED_VOIP
+                if (mCallMode == AUDIO_MODE_IN_COMMUNICATION) {
+                    if (!strncmp(rxDevice, SND_USE_CASE_DEV_VOIP_EARPIECE,
+                                (strlen(SND_USE_CASE_DEV_VOIP_EARPIECE)+1))) {
+                        return strdup(SND_USE_CASE_DEV_VOIP_HANDSET);
+                    } else {
+                        return strdup(SND_USE_CASE_DEV_VOIP_LINE);
+                    }
+                }
+#endif
                 else {
                     if ((rxDevice != NULL) &&
                         !strncmp(rxDevice, SND_USE_CASE_DEV_ANC_HANDSET,
@@ -1842,6 +2059,19 @@
         } else if (devices & AudioSystem::DEVICE_IN_AUX_DIGITAL) {
             return strdup(SND_USE_CASE_DEV_HDMI_TX); /* HDMI TX */
         } else if ((devices & AudioSystem::DEVICE_IN_WIRED_HEADSET)) {
+#ifdef SEPERATED_HEADSET_MIC
+#ifdef SEPERATED_VOIP
+            if (mCallMode == AUDIO_MODE_IN_COMMUNICATION) {
+                return strdup(SND_USE_CASE_DEV_VOIP_HEADSET);
+            }
+#endif
+            if (mCallMode == AUDIO_MODE_IN_CALL) {
+                return strdup(SND_USE_CASE_DEV_VOC_HEADSET);
+            }
+            if (mInputSource == AUDIO_SOURCE_VOICE_RECOGNITION) {
+                return strdup(SND_USE_CASE_DEV_VOICE_RECOGNITION_HEADSET);
+            }
+#endif
             return strdup(SND_USE_CASE_DEV_HEADSET); /* HEADSET TX */
 #ifdef QCOM_ANC_HEADSET_ENABLED
         } else if (devices & AudioSystem::DEVICE_IN_ANC_HEADSET) {
@@ -1881,7 +2111,7 @@
             if (strncmp(mCurTxUCMDevice, "None", 4)) {
                 return strdup(mCurTxUCMDevice);
             }
-#ifdef QCOM_FM_ENABLED
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
         } else if ((devices & AudioSystem::DEVICE_IN_FM_RX) ||
                    (devices & AudioSystem::DEVICE_IN_FM_RX_A2DP)) {
             /* Nothing to be done, use current tx device or set dummy device */
@@ -1898,10 +2128,8 @@
                 return strdup(SND_USE_CASE_DEV_HANDSET); /* HANDSET TX */
             } else {
 #ifdef SEPERATED_AUDIO_INPUT
-                if (callMode == AUDIO_MODE_IN_CALL) {
+                if (mCallMode == AUDIO_MODE_IN_CALL) {
                     return strdup(SND_USE_CASE_DEV_VOC_LINE); /* Voice BUILTIN-MIC TX */
-                } else if(mInput_source == AUDIO_SOURCE_CAMCORDER) {
-                    return strdup(SND_USE_CASE_DEV_CAMCORDER_TX ); /* CAMCORDER TX */
                 } else
 #endif
                     return strdup(SND_USE_CASE_DEV_LINE); /* BUILTIN-MIC TX */
@@ -1925,7 +2153,11 @@
         if (csd_volume == NULL) {
             ALOGE("csd_client_volume is NULL");
         } else {
+#ifdef NEW_CSDCLIENT
             err = csd_volume(ALL_SESSION_VSID, vol);
+#else
+            err = csd_volume(vol);
+#endif
             if (err < 0) {
                 ALOGE("s_set_voice_volume: csd_client error %d", err);
             }
@@ -1946,7 +2178,11 @@
         if (csd_volume == NULL) {
             ALOGE("csd_client_volume is NULL");
         } else {
+#ifdef NEW_CSDCLIENT
             err = csd_volume(ALL_SESSION_VSID, vol);
+#else
+            err = csd_volume(vol);
+#endif
             if (err < 0) {
                 ALOGE("s_set_voice_volume: csd_client error %d", err);
             }
@@ -1967,7 +2203,11 @@
         if (csd_volume == NULL) {
             ALOGE("csd_client_volume is NULL");
         } else {
+#ifdef NEW_CSDCLIENT
             err = csd_volume(ALL_SESSION_VSID, vol);
+#else
+            err = csd_volume(vol);
+#endif
             if (err < 0) {
                 ALOGE("s_set_voice_volume: csd_client error %d", err);
             }
@@ -1994,7 +2234,11 @@
         if (csd_mic_mute == NULL) {
             ALOGE("csd_mic_mute is NULL");
         } else {
+#ifdef NEW_CSDCLIENT
             err = csd_mic_mute(ALL_SESSION_VSID, state);
+#else
+            err = csd_mic_mute(state);
+#endif
             if (err < 0) {
                 ALOGE("s_set_mic_mute: csd_client error %d", err);
             }
@@ -2015,7 +2259,11 @@
         if (csd_mic_mute == NULL) {
             ALOGE("csd_mic_mute is NULL");
         } else {
+#ifdef NEW_CSDCLIENT
             err = csd_mic_mute(ALL_SESSION_VSID, state);
+#else
+            err = csd_mic_mute(state);
+#endif
             if (err < 0) {
                 ALOGE("s_set_mic_mute: csd_client error %d", err);
             }
@@ -2037,7 +2285,11 @@
         if (csd_mic_mute == NULL) {
             ALOGE("csd_mic_mute is NULL");
         } else {
+#ifdef NEW_CSDCLIENT
             err = csd_mic_mute(ALL_SESSION_VSID, state);
+#else
+            err = csd_mic_mute(state);
+#endif
             if (err < 0) {
                 ALOGE("s_set_mic_mute: csd_client error %d", err);
             }
@@ -2105,7 +2357,11 @@
         if (csd_wide_voice == NULL) {
             ALOGE("csd_wide_voice is NULL");
         } else {
+#ifdef NEW_CSDCLIENT
             err = csd_wide_voice(vsid, flag);
+#else
+            err = csd_wide_voice(flag);
+#endif
             if (err < 0) {
                 ALOGE("enableWideVoice: csd_client_wide_voice error %d", err);
             }
@@ -2138,7 +2394,11 @@
         if (csd_fens == NULL) {
             ALOGE("csd_fens is NULL");
         } else {
+#ifdef NEW_CSDCLIENT
             err = csd_fens(vsid, flag);
+#else
+            err = csd_fens(flag);
+#endif
             if (err < 0) {
                 ALOGE("s_enable_fens: csd_client error %d", err);
             }
@@ -2163,7 +2423,11 @@
         if (csd_slow_talk == NULL) {
             ALOGE("csd_slow_talk is NULL");
         } else {
+#ifdef NEW_CSDCLIENT
             err = csd_slow_talk(vsid, flag);
+#else
+            err = csd_slow_talk(flag);
+#endif
             if (err < 0) {
                 ALOGE("s_enable_slow_talk: csd_client error %d", err);
             }
@@ -2443,69 +2707,32 @@
         *bufferSize = 0;
         return err;
     }
-
-    //Copy only if we have data
-    if(mProxyParams.mAvail > 0) {
-        /* if we have reached high watermark, flush data */
-        if(mProxyParams.mAvail > AFE_PROXY_HIGH_WATER_MARK_FRAME_COUNT) {
-            /* throw out everything over here */
-            ALOGE("available buffers in proxy %d has reached high water mark %d, throw it out ", mProxyParams.mAvail, AFE_PROXY_HIGH_WATER_MARK_FRAME_COUNT);
-            capture_handle->sync_ptr->c.control.appl_ptr += mProxyParams.mAvail;
-            capture_handle->sync_ptr->flags = 0;
-            err = sync_ptr(capture_handle);
-            if(err == EPIPE) {
-                ALOGV("Failed in sync_ptr \n");
-                capture_handle->running = 0;
-                err = sync_ptr(capture_handle);
-            }
-            err = FAILED_TRANSACTION;
-            *captureBuffer = NULL;
-            *bufferSize = 0;
-            return err;
-        }
-        if(mProxyParams.mX.frames > mProxyParams.mAvail) {
-            mProxyParams.mFrames = mProxyParams.mAvail;
-            ALOGE("Error mProxyParams.mFrames = %d", mProxyParams.mFrames);
-            /* Always copy only the data thats available */
-            /* case when we wake up with lesser no of bytes than 1 period */
-        }
-        else {
-            mProxyParams.mFrames = mProxyParams.mX.frames;
-        }
-
-        void *data  = dst_address(capture_handle);
-
-        if(mProxyParams.mCaptureBuffer == NULL)
-            mProxyParams.mCaptureBuffer =  malloc(mProxyParams.mCaptureBufferSize);
-
-        memcpy(mProxyParams.mCaptureBuffer, (char *)data,
-                (mProxyParams.mFrames * 2 * 2));
-
-        capture_handle->sync_ptr->c.control.appl_ptr += mProxyParams.mFrames;
-        capture_handle->sync_ptr->flags = 0;
-        *bufferSize = (mProxyParams.mFrames * 2 * 2);
-        mProxyParams.mFrames -= mProxyParams.mFrames;
-        ALOGV("Calling sync_ptr for proxy after sync with mFrames is %d", mProxyParams.mFrames);
+    if (mProxyParams.mX.frames > mProxyParams.mAvail)
+        mProxyParams.mFrames = mProxyParams.mAvail;
+    void *data  = dst_address(capture_handle);
+    //TODO: Return a pointer to AudioHardware
+    if(mProxyParams.mCaptureBuffer == NULL)
+        mProxyParams.mCaptureBuffer =  malloc(mProxyParams.mCaptureBufferSize);
+    memcpy(mProxyParams.mCaptureBuffer, (char *)data,
+             mProxyParams.mCaptureBufferSize);
+    mProxyParams.mX.frames -= mProxyParams.mFrames;
+    capture_handle->sync_ptr->c.control.appl_ptr += mProxyParams.mFrames;
+    capture_handle->sync_ptr->flags = 0;
+    ALOGV("Calling sync_ptr for proxy after sync");
+    err = sync_ptr(capture_handle);
+    if(err == EPIPE) {
+        ALOGV("Failed in sync_ptr \n");
+        capture_handle->running = 0;
         err = sync_ptr(capture_handle);
-        if(err == EPIPE) {
-            ALOGV("Failed in sync_ptr \n");
-            capture_handle->running = 0;
-            err = sync_ptr(capture_handle);
-        }
-        if(err != NO_ERROR ) {
-            ALOGE("Error: Sync ptr end returned %d", err);
-            *captureBuffer = NULL;
-            *bufferSize = 0;
-            return err;
-        }
-        *captureBuffer = mProxyParams.mCaptureBuffer;
-    } else {
-        /* If we dont have data to copy just return 0 */
+    }
+    if(err != NO_ERROR ) {
+        ALOGE("Error: Sync ptr end returned %d", err);
         *captureBuffer = NULL;
         *bufferSize = 0;
-        err = FAILED_TRANSACTION;
-        ALOGE("Error Nothing copied from Proxy");
+        return err;
     }
+    *captureBuffer = mProxyParams.mCaptureBuffer;
+    *bufferSize = mProxyParams.mCaptureBufferSize;
     return err;
 }
 
@@ -2780,10 +3007,10 @@
 }
 
 #ifdef SEPERATED_AUDIO_INPUT
-void s_setInput(int input)
+void ALSADevice::setInput(int input) 
 {
-    mInput_source = input;
-    ALOGD("s_setInput() : input_source = %d",input_source);
+    mInputSource = input;
+    ALOGD("s_setInput() : input_source = %d",mInputSource);
 }
 #endif
 
@@ -2797,6 +3024,7 @@
                                             "csd_client_disable_device");
     csd_enable_device = (int (*)(int,int,uint32_t))::dlsym(mcsd_handle,
                                                     "csd_client_enable_device");
+#ifdef NEW_CSDCLIENT
     csd_enable_device_config = (int (*)(int,int))::dlsym(mcsd_handle,
                                                     "csd_client_enable_device_config");
     csd_start_voice = (int (*)(uint32_t))::dlsym(mcsd_handle,
@@ -2813,6 +3041,27 @@
                                                    "csd_client_fens");
     csd_slow_talk = (int (*)(uint32_t, uint8_t))::dlsym(mcsd_handle,
                                                         "csd_client_slow_talk");
+#else
+    csd_start_voice = (int (*)())::dlsym(mcsd_handle,
+#ifdef SAMSUNG_CSDCLIENT
+            "csd_client_start_voice_og"
+#else
+            "csd_client_start_voice"
+#endif
+            );
+    csd_stop_voice = (int (*)())::dlsym(mcsd_handle,
+#ifdef SAMSUNG_CSDCLIENT
+            "csd_client_stop_voice_og"
+#else
+            "csd_client_stop_voice"
+#endif
+            );
+    csd_volume = (int (*)(int))::dlsym(mcsd_handle,"csd_client_volume");
+    csd_mic_mute = (int (*)(int))::dlsym(mcsd_handle,"csd_client_mic_mute");
+    csd_wide_voice = (int (*)(uint8_t))::dlsym(mcsd_handle,"csd_client_wide_voice");
+    csd_fens = (int (*)(uint8_t))::dlsym(mcsd_handle,"csd_client_fens");
+    csd_slow_talk = (int (*)(uint8_t))::dlsym(mcsd_handle,"csd_client_slow_talk");
+#endif
 }
 #endif
 
diff --git a/alsa_sound/Android.mk b/alsa_sound/Android.mk
index 4960e46..ac6a5af 100644
--- a/alsa_sound/Android.mk
+++ b/alsa_sound/Android.mk
@@ -7,45 +7,126 @@
 
 LOCAL_PATH := $(call my-dir)
 
-include $(CLEAR_VARS)
+ifneq ($(ALSA_DEFAULT_SAMPLE_RATE),)
+    LOCAL_CFLAGS += -DALSA_DEFAULT_SAMPLE_RATE=$(ALSA_DEFAULT_SAMPLE_RATE)
+endif
 
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -D_POSIX_SOURCE
-LOCAL_CFLAGS += -DQCOM_ACDB_ENABLED
-LOCAL_CFLAGS += -DQCOM_ANC_HEADSET_ENABLED
-LOCAL_CFLAGS += -DQCOM_AUDIO_FORMAT_ENABLED
-LOCAL_CFLAGS += -DQCOM_CSDCLIENT_ENABLED
-LOCAL_CFLAGS += -DQCOM_FM_ENABLED
-LOCAL_CFLAGS += -DQCOM_PROXY_DEVICE_ENABLED
-LOCAL_CFLAGS += -DQCOM_OUTPUT_FLAGS_ENABLED
-LOCAL_CFLAGS += -DQCOM_TUNNEL_LPA_ENABLED
-LOCAL_CFLAGS += -DQCOM_SSR_ENABLED
-LOCAL_CFLAGS += -DQCOM_USBAUDIO_ENABLED
+ifneq ($(strip $(QCOM_ACDB_ENABLED)),false)
+    common_cflags += -DQCOM_ACDB_ENABLED
+endif
+ifneq ($(strip $(QCOM_ANC_HEADSET_ENABLED)),false)
+    common_cflags += -DQCOM_ANC_HEADSET_ENABLED
+endif
+ifneq ($(strip $(QCOM_AUDIO_FORMAT_ENABLED)),false)
+    common_cflags += -DQCOM_AUDIO_FORMAT_ENABLED
+endif
+ifneq ($(strip $(QCOM_CSDCLIENT_ENABLED)),false)
+    common_cflags += -DQCOM_CSDCLIENT_ENABLED
+endif
+ifeq ($(strip $(QCOM_FM_ENABLED)),true)
+    common_cflags += -DQCOM_FM_ENABLED
+endif
+ifneq ($(strip $(QCOM_PROXY_DEVICE_ENABLED)),false)
+    common_cflags += -DQCOM_PROXY_DEVICE_ENABLED
+endif
+ifneq ($(strip $(QCOM_OUTPUT_FLAGS_ENABLED)),false)
+    common_cflags += -DQCOM_OUTPUT_FLAGS_ENABLED
+endif
+ifeq ($(strip $(QCOM_SSR_ENABLED)),true)
+    common_cflags += -DQCOM_SSR_ENABLED
+endif
+ifneq ($(strip $(QCOM_USBAUDIO_ENABLED)),false)
+    common_cflags += -DQCOM_USBAUDIO_ENABLED
+endif
+ifeq ($(strip $(QCOM_ADSP_SSR_ENABLED)),true)
+    common_cflags += -DQCOM_ADSP_SSR_ENABLED
+endif
+ifneq ($(strip $(QCOM_FLUENCE_ENABLED)),false)
+    common_cflags += -DQCOM_FLUENCE_ENABLED
+endif
+ifneq ($(strip $(QCOM_TUNNEL_LPA_ENABLED)),false)
+    common_cflags += -DQCOM_TUNNEL_LPA_ENABLED
+endif
 
 ifeq ($(call is-board-platform,msm8974),true)
-  LOCAL_CFLAGS += -DTARGET_8974
+    common_cflags += -DTARGET_8974
 endif
 
 ifneq ($(ALSA_DEFAULT_SAMPLE_RATE),)
-    LOCAL_CFLAGS += -DALSA_DEFAULT_SAMPLE_RATE=$(ALSA_DEFAULT_SAMPLE_RATE)
+    common_cflags += -DALSA_DEFAULT_SAMPLE_RATE=$(ALSA_DEFAULT_SAMPLE_RATE)
 endif
 
 #Do not use Dual MIC scenario in call feature
 #Dual MIC solution(Fluence) feature in Built-in MIC used scenarioes.
 # 1. Handset
 # 2. 3-Pole Headphones
-#ifeq ($(strip $(BOARD_USES_FLUENCE_INCALL)),true)
-#LOCAL_CFLAGS += -DUSES_FLUENCE_INCALL
-#endif
+ifeq ($(strip $(BOARD_USES_FLUENCE_INCALL)),true)
+    common_cflags += -DUSES_FLUENCE_INCALL
+endif
 
 #Do not use separate audio Input path feature
 #Separate audio input path can be set using input source of audio parameter
 # 1. Voice Recognition
 # 2. Camcording
 # 3. etc.
-#ifeq ($(strip $(BOARD_USES_SEPERATED_AUDIO_INPUT)),true)
-#LOCAL_CFLAGS += -DSEPERATED_AUDIO_INPUT
-#endif
+ifeq ($(strip $(BOARD_USES_SEPERATED_AUDIO_INPUT)),true)
+    common_cflags += -DSEPERATED_AUDIO_INPUT
+endif
+
+ifeq ($(strip $(BOARD_USES_SEPERATED_CAMCORDER)),true)
+    common_cflags += -DSEPERATED_CAMCORDER
+endif
+
+ifeq ($(strip $(BOARD_USES_SEPERATED_VOICE_SPEAKER)),true)
+    common_cflags += -DSEPERATED_VOICE_SPEAKER
+endif
+
+ifeq ($(strip $(BOARD_USES_SEPERATED_HEADSET_MIC)),true)
+    common_cflags += -DSEPERATED_HEADSET_MIC
+endif
+
+ifeq ($(strip $(BOARD_USES_SEPERATED_VOIP)),true)
+    common_cflags += -DSEPERATED_VOIP
+endif
+
+ifeq ($(BOARD_AUDIO_EXPECTS_MIN_BUFFERSIZE),true)
+    common_cflags += -DSET_MIN_PERIOD_BYTES
+endif
+
+ifeq ($(BOARD_AUDIO_CAF_LEGACY_INPUT_BUFFERSIZE),true)
+    common_cflags += -DCAF_LEGACY_INPUT_BUFFER_SIZE
+endif
+
+ifeq ($(BOARD_HAVE_AUDIENCE_A2220),true)
+    common_cflags += -DUSE_A2220
+endif
+
+ifeq ($(BOARD_HAVE_NEW_QCOM_CSDCLIENT),true)
+    common_cflags += -DNEW_CSDCLIENT
+endif
+
+ifeq ($(BOARD_HAVE_AUDIENCE_ES325_2MIC),true)
+    common_cflags += -DUSE_ES325_2MIC
+endif
+
+ifeq ($(BOARD_HAVE_SAMSUNG_CSDCLIENT),true)
+    common_cflags += -DSAMSUNG_CSDCLIENT
+endif
+
+ifeq ($(BOARD_HAVE_HTC_CSDCLIENT),true)
+    common_cflags += -DHTC_CSDCLIENT
+endif
+
+ifneq ($(TARGET_USES_QCOM_COMPRESSED_AUDIO),false)
+    common_cflags += -DQCOM_COMPRESSED_AUDIO_ENABLED
+endif
+
+
+include $(CLEAR_VARS)
+
+LOCAL_ARM_MODE := arm
+
+LOCAL_CFLAGS += $(common_cflags)
 
 LOCAL_SRC_FILES := \
   AudioHardwareALSA.cpp         \
@@ -71,15 +152,22 @@
     libc        \
     libpower    \
     libalsa-intf \
-    libsurround_proc\
     libaudioutils
 
+#    libsurround_proc
+
 ifeq ($(TARGET_SIMULATOR),true)
  LOCAL_LDLIBS += -ldl
 else
  LOCAL_SHARED_LIBRARIES += libdl
 endif
 
+ifneq ($(BOARD_AUDIO_AMPLIFIER),)
+LOCAL_CFLAGS += -DUSES_AUDIO_AMPLIFIER
+LOCAL_SHARED_LIBRARIES += libaudioamp
+LOCAL_C_INCLUDES += $(BOARD_AUDIO_AMPLIFIER)
+endif
+
 LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa
 LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/libalsa-intf
 LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/surround_sound/
@@ -112,14 +200,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_CFLAGS := -D_POSIX_SOURCE
-LOCAL_CFLAGS += -DQCOM_ACDB_ENABLED
-LOCAL_CFLAGS += -DQCOM_ANC_HEADSET_ENABLED
-LOCAL_CFLAGS += -DQCOM_AUDIO_FORMAT_ENABLED
-LOCAL_CFLAGS += -DQCOM_CSDCLIENT_ENABLED
-LOCAL_CFLAGS += -DQCOM_FM_ENABLED
-LOCAL_CFLAGS += -DQCOM_PROXY_DEVICE_ENABLED
-LOCAL_CFLAGS += -DQCOM_SSR_ENABLED
-LOCAL_CFLAGS += -DQCOM_USBAUDIO_ENABLED
+LOCAL_CFLAGS += $(common_cflags)
 
 LOCAL_SRC_FILES := \
     audio_policy_hal.cpp \
diff --git a/alsa_sound/AudioHardwareALSA.cpp b/alsa_sound/AudioHardwareALSA.cpp
index 77b78b9..c389418 100644
--- a/alsa_sound/AudioHardwareALSA.cpp
+++ b/alsa_sound/AudioHardwareALSA.cpp
@@ -26,8 +26,7 @@
 #include <math.h>
 
 #define LOG_TAG "AudioHardwareALSA"
-#define LOG_NDEBUG 0
-#define LOG_NDDEBUG 0
+//#define LOG_NDEBUG 0
 #include <utils/Log.h>
 #include <utils/String8.h>
 #include <sys/prctl.h>
@@ -69,10 +68,15 @@
 #ifdef QCOM_CSDCLIENT_ENABLED
     static int (*csd_client_init)();
     static int (*csd_client_deinit)();
+#ifdef NEW_CSDCLIENT
     static int (*csd_start_playback)(uint32_t);
     static int (*csd_stop_playback)(uint32_t);
     static int (*csd_standby_voice)(uint32_t);
     static int (*csd_resume_voice)(uint32_t);
+#else
+    static int (*csd_start_playback)();
+    static int (*csd_stop_playback)();
+#endif
 #endif
 }         // extern "C"
 
@@ -94,11 +98,11 @@
 
 AudioHardwareALSA::AudioHardwareALSA() :
     mALSADevice(0),mVoipInStreamCount(0),mVoipOutStreamCount(0),mVoipMicMute(false),
-    mVoipBitRate(0),mCallState(0),mAcdbHandle(NULL),mCsdHandle(NULL),mMicMute(0)
+    mVoipBitRate(0),mMicMute(0),mCallState(0),mAcdbHandle(NULL),mCsdHandle(NULL)
 {
     FILE *fp;
     char soundCardInfo[200];
-    char platform[128], baseband[128], audio_init[128], platformVer[128];
+    char platform[128], baseband[128], baseband_arch[128], audio_init[128], platformVer[128];
     int codec_rev = 2, verNum = 0;
 
     mDeviceList.clear();
@@ -156,7 +160,7 @@
         ALOGD("AudioHardware: DLOPEN successful for ACDBLOADER");
         acdb_init = (int (*)())::dlsym(mAcdbHandle,"acdb_loader_init_ACDB");
         if (acdb_init == NULL) {
-            ALOGE("dlsym:Error:%s Loading acdb_loader_init_ACDB");
+            ALOGE("dlsym:Error Loading acdb_loader_init_ACDB");
         }else {
            acdb_init();
            acdb_deallocate = (void (*)())::dlsym(mAcdbHandle,"acdb_loader_deallocate_ACDB");
@@ -202,6 +206,8 @@
             } else if (strstr(soundCardInfo, "msm8974-taiko-liquid-snd-card")) {
                 codec_rev = 43;
                 break;
+            } else if (strstr(soundCardInfo, "msm8230-tapan-snd-card")) {
+                break;
             } else if(strstr(soundCardInfo, "no soundcards")) {
                 ALOGE("NO SOUND CARD DETECTED");
                 if(sleep_retry < SOUND_CARD_SLEEP_RETRY) {
@@ -264,8 +270,10 @@
     } else {
         property_get("ro.board.platform", platform, "");
         property_get("ro.baseband", baseband, "");
+        property_get("ro.baseband.arch", baseband_arch, "");
         if (!strcmp("msm8960", platform) &&
-            (!strcmp("mdm", baseband) || !strcmp("sglte2", baseband))) {
+            (!strcmp("mdm", baseband) || !strcmp("sglte2", baseband) ||
+            !strcmp("mdm", baseband_arch))) {
             ALOGV("Detected Fusion tabla 2.x");
             mFusion3Platform = true;
             if((fp = fopen("/sys/devices/system/soc/soc0/platform_version","r")) == NULL) {
@@ -303,6 +311,7 @@
             csd_client_init = (int (*)())::dlsym(mCsdHandle, "csd_client_init");
             csd_client_deinit = (int (*)())::dlsym(mCsdHandle,
                                                    "csd_client_deinit");
+#ifdef NEW_CSDCLIENT
             csd_start_playback = (int (*)(uint32_t))::dlsym(mCsdHandle,
                                                    "csd_client_start_playback");
             csd_stop_playback = (int (*)(uint32_t))::dlsym(mCsdHandle,
@@ -311,6 +320,12 @@
                                                     "csd_client_standby_voice");
             csd_resume_voice = (int (*)(uint32_t))::dlsym(mCsdHandle,
                                                      "csd_client_resume_voice");
+#else
+            csd_start_playback = (int (*)())::dlsym(mCsdHandle,
+                                               "csd_client_start_playback");
+            csd_stop_playback = (int (*)())::dlsym(mCsdHandle,
+                                               "csd_client_stop_playback");
+#endif
 
             if (csd_client_init == NULL) {
                 ALOGE("csd_client_init is NULL");
@@ -330,6 +345,9 @@
     } else {
         ALOGI("ucm instance opened: %u", (unsigned)mUcMgr);
         mUcMgr->isFusion3Platform = mFusion3Platform;
+        if (mAcdbHandle) {
+            mUcMgr->acdb_handle = static_cast<void*> (mAcdbHandle);
+        }
     }
 
     //set default AudioParameters
@@ -338,7 +356,7 @@
     String8 value;
 
     //Set default AudioParameter for fluencetype
-    key  = String8(AudioParameter::keyFluenceType);
+    key  = String8(AUDIO_PARAMETER_KEY_FLUENCE_TYPE);
     property_get("ro.qc.sdk.audio.fluencetype",mFluenceKey,"0");
     if (0 == strncmp("fluencepro", mFluenceKey, sizeof("fluencepro"))) {
         mDevSettingsFlag |= QMIC_FLAG;
@@ -364,10 +382,10 @@
     property_get("ro.qc.sdk.audio.ssr",ssr_enabled,"0");
     if (!strncmp("true", ssr_enabled, 4)) {
         ALOGD("surround sound recording is supported");
-        param.add(String8(AudioParameter::keySSR), String8("true"));
+        param.add(String8(AUDIO_PARAMETER_KEY_SSR), String8("true"));
     } else {
         ALOGD("surround sound recording is not supported");
-        param.add(String8(AudioParameter::keySSR), String8("false"));
+        param.add(String8(AUDIO_PARAMETER_KEY_SSR), String8("false"));
     }
 
     mStatus = OK;
@@ -406,7 +424,7 @@
     delete mAudioUsbALSA;
 #endif
 
-#ifdef QCOM_CSDCLEINT_ENABLED
+#ifdef QCOM_CSDCLIENT_ENABLED
     if (mFusion3Platform) {
         if (mCsdHandle) {
             if (csd_client_deinit == NULL) {
@@ -514,7 +532,11 @@
         if (mCallState == CS_INACTIVE)
             mCallState = CS_ACTIVE;
     }else if (mode == AUDIO_MODE_NORMAL) {
-        mCallState = 0;
+        if (mCallState != 0) {
+            // Immediate routing update on mode transition to normal
+            mCallState = 0;
+            doRouting(0);
+        }
     }
 
     return status;
@@ -532,16 +554,16 @@
 
     ALOGV("setParameters() %s", keyValuePairs.string());
 
-    key = String8(AudioParameter::keyADSPStatus);
+    key = String8(AUDIO_PARAMETER_KEY_ADSP_STATUS);
     if (param.get(key, value) == NO_ERROR) {
        if (value == "ONLINE") {
            ALOGV("ADSP online set SSRcomplete");
-           mALSADevice->mSSRComplete = true;
+           mALSADevice->mADSPState = ADSP_UP_AFTER_SSR;
            return status;
        }
        else if (value == "OFFLINE") {
            ALOGV("ADSP online re-set SSRcomplete");
-           mALSADevice->mSSRComplete = false;
+           mALSADevice->mADSPState = ADSP_DOWN;
            if ( mRouteAudioToExtOut==true) {
                ALOGV("ADSP offline close EXT output");
                uint32_t activeUsecase = getExtOutActiveUseCases_l();
@@ -572,7 +594,7 @@
         param.remove(key);
     }
 
-    key = String8(AudioParameter::keyFluenceType);
+    key = String8(AUDIO_PARAMETER_KEY_FLUENCE_TYPE);
     if (param.get(key, value) == NO_ERROR) {
         if (value == "quadmic") {
             //Allow changing fluence type to "quadmic" only when fluence type is fluencepro
@@ -608,14 +630,22 @@
                 if (csd_start_playback == NULL) {
                     ALOGE("csd_client_start_playback is NULL");
                     } else {
+#ifdef NEW_CSDCLIENT
                         csd_start_playback(ALL_SESSION_VSID);
+#else
+                        csd_start_playback();
+#endif
                     }
             } else {
                 ALOGV("Disabling Incall Music setting in the setparameter\n");
                 if (csd_stop_playback == NULL) {
                     ALOGE("csd_client_stop_playback is NULL");
                 } else {
+#ifdef NEW_CSDCLIENT
                     csd_stop_playback(ALL_SESSION_VSID);
+#else
+                    csd_stop_playback();
+#endif
                 }
             }
             param.remove(key);
@@ -792,7 +822,7 @@
         param.add(key, value);
     }
 
-    key = String8(AudioParameter::keyFluenceType);
+    key = String8(AUDIO_PARAMETER_KEY_FLUENCE_TYPE);
     if (param.get(key, value) == NO_ERROR) {
     if ((mDevSettingsFlag & QMIC_FLAG) &&
                                (mDevSettingsFlag & ~DMIC_FLAG))
@@ -827,7 +857,7 @@
            param.addInt(String8("isVGS"), true);
     }
 #ifdef QCOM_SSR_ENABLED
-    key = String8(AudioParameter::keySSR);
+    key = String8(AUDIO_PARAMETER_KEY_SSR);
     if (param.get(key, value) == NO_ERROR) {
         char ssr_enabled[6] = "false";
         property_get("ro.qc.sdk.audio.ssr",ssr_enabled,"0");
@@ -854,12 +884,6 @@
         param.add(key, value);
     }
 
-    key = String8("tunneled-input-formats");
-    if ( param.get(key,value) == NO_ERROR ) {
-        ALOGD("Add tunnel AWB to audio parameter");
-        param.addInt(String8("AWB"), true );
-    }
-
     key = String8(AudioParameter::keyRouting);
     if (param.getInt(key, device) == NO_ERROR) {
         param.addInt(key, mCurDevice);
@@ -931,7 +955,7 @@
     if(device)
         mALSADevice->mCurDevice = device;
     if ((device == AudioSystem::DEVICE_IN_VOICE_CALL)
-#ifdef QCOM_FM_ENABLED
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
         || (device == AudioSystem::DEVICE_IN_FM_RX)
         || (device == AudioSystem::DEVICE_IN_FM_RX_A2DP)
 #endif
@@ -1209,7 +1233,7 @@
             it != mDeviceList.end(); ++it) {
                 if((!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
                    (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
-                    ALOGD("openOutput:  it->rxHandle %d it->handle %d",it->rxHandle,it->handle);
+                    ALOGD("openOutput:  it->rxHandle %p it->handle %p",it->rxHandle,it->handle);
                     voipstream_active = true;
                     break;
                 }
@@ -1728,8 +1752,22 @@
                                     sizeof(alsa_handle.useCase));
                         }
                     }
+                } else if (*channels & AUDIO_CHANNEL_IN_VOICE_UPLINK) {
+                    if (mFusion3Platform) {
+                        mALSADevice->setVocRecMode(INCALL_REC_MONO);
+                        strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
+                                sizeof(alsa_handle.useCase));
+                    } else {
+                        if (*format == AUDIO_FORMAT_AMR_WB) {
+                            strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED,
+                                    sizeof(alsa_handle.useCase));
+                        } else {
+                            strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC,
+                                    sizeof(alsa_handle.useCase));
+                        }
+                    }
                 }
-#ifdef QCOM_FM_ENABLED
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
             } else if((devices == AudioSystem::DEVICE_IN_FM_RX)) {
                 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_FM, sizeof(alsa_handle.useCase));
             } else if(devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
@@ -1782,7 +1820,7 @@
                         }
                     }
                 }
-#ifdef QCOM_FM_ENABLED
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
             } else if(devices == AudioSystem::DEVICE_IN_FM_RX) {
                 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_FM_REC, sizeof(alsa_handle.useCase));
             } else if (devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
@@ -1837,14 +1875,29 @@
             }
 #endif
         }
+#ifdef QCOM_USBAUDIO_ENABLED
+        if((devices == AudioSystem::DEVICE_IN_COMMUNICATION) &&
+           ((mCurDevice == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
+           (mCurDevice ==  AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET))){
+               ALOGD("Starting recording in openInputstream, musbRecordingState: %d", musbRecordingState);
+               startUsbRecordingIfNotStarted();
+               musbRecordingState |= USBRECBIT_VOIPCALL;
+        }
+#endif
         if(sampleRate) {
             it->sampleRate = *sampleRate;
         }
+#ifdef CAF_LEGACY_INPUT_BUFFER_SIZE
+	if (6 == it->channels) {
+#endif
         if (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
             || !strncmp(it->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
             ALOGV("OpenInoutStream: getInputBufferSize sampleRate:%d format:%d, channels:%d", it->sampleRate,*format,it->channels);
             it->bufferSize = getInputBufferSize(it->sampleRate,*format,it->channels);
         }
+#ifdef CAF_LEGACY_INPUT_BUFFER_SIZE
+	}
+#endif
 
 #ifdef QCOM_SSR_ENABLED
         if (6 == it->channels) {
@@ -2246,7 +2299,7 @@
                     alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
                     mCSCallActive = CS_ACTIVE;
 
-#ifdef QCOM_CSDCLIENT_ENABLED
+#if defined(QCOM_CSDCLIENT_ENABLED) && defined(NEW_CSDCLIENT)
                     if (mFusion3Platform) {
                         if (csd_resume_voice == NULL)
                             ALOGE("csd_client_resume_voice is NULL");
@@ -2280,7 +2333,7 @@
                          strlen(SND_USE_CASE_MOD_PLAY_VOICE)))) {
                          mCSCallActive = CS_HOLD;
                          alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
-#ifdef QCOM_CSDCLIENT_ENABLED
+#if defined(QCOM_CSDCLIENT_ENABLED) && defined(NEW_CSDCLIENT)
                          if (mFusion3Platform) {
                              if (csd_standby_voice == NULL)
                                  ALOGE("csd_standby_voice is NULL");
@@ -2352,7 +2405,7 @@
                      strlen(SND_USE_CASE_MOD_PLAY_VOICE2)))) {
                      alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
                      mVoice2CallActive = CS_ACTIVE_SESSION2;
-#ifdef QCOM_CSDCLIENT_ENABLED
+#if defined(QCOM_CSDCLIENT_ENABLED) && defined(NEW_CSDCLIENT)
                      if (mFusion3Platform) {
                          if (csd_resume_voice == NULL)
                              ALOGE("csd_client_resume_voice is NULL");
@@ -2387,7 +2440,7 @@
                          strlen(SND_USE_CASE_MOD_PLAY_VOICE2)))) {
                          mCSCallActive = CS_HOLD_SESSION2;
                          alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
-#ifdef QCOM_CSDCLIENT_ENABLED
+#if defined(QCOM_CSDCLIENT_ENABLED) && defined(NEW_CSDCLIENT)
                          if (mFusion3Platform) {
                              if (csd_standby_voice == NULL)
                                  ALOGE("csd_standby_voice is NULL");
@@ -2460,7 +2513,7 @@
                      strlen(SND_USE_CASE_MOD_PLAY_VOLTE)))) {
                      alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
                      mVolteCallActive = IMS_ACTIVE;
-#ifdef QCOM_CSDCLIENT_ENABLED
+#if defined(QCOM_CSDCLIENT_ENABLED) && defined(NEW_CSDCLIENT)
                      if (mFusion3Platform) {
                          if (csd_resume_voice == NULL)
                              ALOGE("csd_client_resume_voice is NULL");
@@ -2493,7 +2546,7 @@
                          strlen(SND_USE_CASE_MOD_PLAY_VOLTE)))) {
                           mVolteCallActive = IMS_HOLD;
                          alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
-#ifdef QCOM_CSDCLIENT_ENABLED
+#if defined(QCOM_CSDCLIENT_ENABLED) && defined(NEW_CSDCLIENT)
                          if (mFusion3Platform) {
                              if (csd_standby_voice == NULL)
                                  ALOGE("csd_standby_voice is NULL");
@@ -2904,7 +2957,7 @@
     uint32_t bytesAvailInBuffer = 0;
     uint32_t proxyBufferTime = 0;
     void  *data;
-    status_t err = NO_ERROR;
+    int err = NO_ERROR;
     ssize_t size = 0;
     void * outbuffer= malloc(AFE_PROXY_PERIOD_SIZE);
 
@@ -2934,15 +2987,10 @@
             }
         }
         err = mALSADevice->readFromProxy(&data, &size);
-        if(err == (status_t) FAILED_TRANSACTION) {
-            ALOGE("readFromProxy returned an error, mostly a flush or an under run continuing");
-            err = NO_ERROR;
-            continue;
-        }
-        if(err < 0) {
-           ALOGE("ALSADevice readFromProxy returned err = %d,data = %p,\
+        if (err < 0) {
+            ALOGE("ALSADevice readFromProxy returned err = %d,data = %p,\
                     size = %ld", err, data, size);
-           continue;
+            continue;
         }
 
 #ifdef OUTPUT_BUFFER_LOG
@@ -3007,19 +3055,19 @@
 void AudioHardwareALSA::setExtOutActiveUseCases_l(uint32_t activeUsecase)
 {
    mExtOutActiveUseCases |= activeUsecase;
-   ALOGD("mExtOutActiveUseCases = %u, activeUsecase = %u", mExtOutActiveUseCases, activeUsecase);
+   ALOGV("mExtOutActiveUseCases = %u, activeUsecase = %u", mExtOutActiveUseCases, activeUsecase);
 }
 
 uint32_t AudioHardwareALSA::getExtOutActiveUseCases_l()
 {
-   ALOGD("getExtOutActiveUseCases_l: mExtOutActiveUseCases = %u", mExtOutActiveUseCases);
+   ALOGV("getExtOutActiveUseCases_l: mExtOutActiveUseCases = %u", mExtOutActiveUseCases);
    return mExtOutActiveUseCases;
 }
 
 void AudioHardwareALSA::clearExtOutActiveUseCases_l(uint32_t activeUsecase) {
 
    mExtOutActiveUseCases &= ~activeUsecase;
-   ALOGD("clear - mExtOutActiveUseCases = %u, activeUsecase = %u", mExtOutActiveUseCases, activeUsecase);
+   ALOGV("clear - mExtOutActiveUseCases = %u, activeUsecase = %u", mExtOutActiveUseCases, activeUsecase);
 
 }
 
diff --git a/alsa_sound/AudioHardwareALSA.h b/alsa_sound/AudioHardwareALSA.h
index 5d2d420..0a96166 100644
--- a/alsa_sound/AudioHardwareALSA.h
+++ b/alsa_sound/AudioHardwareALSA.h
@@ -36,8 +36,10 @@
 
 extern "C" {
     #include <sound/asound.h>
+#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
     #include <sound/compress_params.h>
     #include <sound/compress_offload.h>
+#endif
     #include "alsa_audio.h"
     #include "msm8960_use_cases.h"
 }
@@ -166,7 +168,6 @@
 #define AFE_PROXY_SAMPLE_RATE 48000
 #define AFE_PROXY_CHANNEL_COUNT 2
 #define AFE_PROXY_PERIOD_SIZE 3072
-#define AFE_PROXY_HIGH_WATER_MARK_FRAME_COUNT 40000
 
 #define MAX_SLEEP_RETRY 100  /*  Will check 100 times before continuing */
 #define AUDIO_INIT_SLEEP_WAIT 50 /* 50 ms */
@@ -221,6 +222,13 @@
     INCALL_REC_STEREO,
 };
 
+/* ADSP States */
+enum {
+    ADSP_UP = 0x0,
+    ADSP_DOWN = 0x1,
+    ADSP_UP_AFTER_SSR = 0x2,
+};
+
 enum audio_call_mode {
     CS_INACTIVE   = 0x0,
     CS_ACTIVE     = 0x1,
@@ -233,6 +241,30 @@
     IMS_HOLD      = 0x20
 };
 
+
+//Audio parameter definitions
+
+/* Query handle fm parameter*/
+#define AUDIO_PARAMETER_KEY_HANDLE_FM "handle_fm"
+
+/* Query voip flag */
+#define AUDIO_PARAMETER_KEY_VOIP_CHECK "voip_flag"
+
+/* Query Fluence type */
+#define AUDIO_PARAMETER_KEY_FLUENCE_TYPE "fluence"
+
+/* Query if surround sound recording is supported */
+#define AUDIO_PARAMETER_KEY_SSR "ssr"
+
+/* Query if a2dp  is supported */
+#define AUDIO_PARAMETER_KEY_HANDLE_A2DP_DEVICE "isA2dpDeviceSupported"
+
+/* Query ADSP Status */
+#define AUDIO_PARAMETER_KEY_ADSP_STATUS "ADSP_STATUS"
+
+/* Query if Proxy can be Opend */
+#define AUDIO_CAN_OPEN_PROXY "can_open_proxy"
+
 class AudioSessionOutALSA;
 struct alsa_handle_t {
     ALSADevice*         module;
@@ -317,6 +349,7 @@
     void     setACDBHandle(void*);
 #endif
 
+    int mADSPState;
     bool mSSRComplete;
     int mCurDevice;
     long mAvailInMs;
@@ -368,7 +401,7 @@
     bool mIsSglte;
     bool mIsFmEnabled;
 #ifdef SEPERATED_AUDIO_INPUT
-    int mInput_source
+    int mInputSource;
 #endif
 //   ALSAHandleList  *mDeviceList;
 
@@ -393,6 +426,14 @@
     };
     struct proxy_params mProxyParams;
 
+#ifdef USE_A2220
+    int mA2220Fd;
+    int mA2220Mode;
+    Mutex mA2220Lock;
+
+    int setA2220Mode(int mode);
+#endif
+
 };
 
 // ----------------------------------------------------------------------------
diff --git a/alsa_sound/AudioPolicyManagerALSA.cpp b/alsa_sound/AudioPolicyManagerALSA.cpp
index e9f6e37..69a7100 100644
--- a/alsa_sound/AudioPolicyManagerALSA.cpp
+++ b/alsa_sound/AudioPolicyManagerALSA.cpp
@@ -29,6 +29,9 @@
 // A device mask for all audio input devices that are considered "virtual" when evaluating
 // active inputs in getActiveInput()
 #define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL  AUDIO_DEVICE_IN_REMOTE_SUBMIX
+// A device mask for all audio output devices that are considered "remote" when evaluating
+// active output devices in isStreamActiveRemotely()
+#define APM_AUDIO_OUT_DEVICE_REMOTE_ALL  AUDIO_DEVICE_OUT_REMOTE_SUBMIX
 
 #include <utils/Log.h>
 
@@ -63,6 +66,46 @@
     }
 }
 
+void AudioPolicyManager::releaseOutput(audio_io_handle_t output)
+{
+    ALOGV("releaseOutput() %d", output);
+    ssize_t index = mOutputs.indexOfKey(output);
+    if (index < 0) {
+        ALOGW("releaseOutput() releasing unknown output %d", output);
+        return;
+    }
+
+#ifdef AUDIO_POLICY_TEST
+    int testIndex = testOutputIndex(output);
+    if (testIndex != 0) {
+        AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+        if (outputDesc->isActive()) {
+            mpClientInterface->closeOutput(output);
+            delete mOutputs.valueAt(index);
+            mOutputs.removeItem(output);
+            mTestOutputs[testIndex] = 0;
+        }
+        return;
+    }
+#endif //AUDIO_POLICY_TEST
+
+    AudioOutputDescriptor *desc = mOutputs.valueAt(index);
+    if (desc->mFlags & AudioSystem::OUTPUT_FLAG_DIRECT) {
+        if ((desc->mDirectOpenCount <= 0) && !(desc->mFlags & AUDIO_OUTPUT_FLAG_LPA || desc->mFlags & AUDIO_OUTPUT_FLAG_TUNNEL ||
+                desc->mFlags & AUDIO_OUTPUT_FLAG_VOIP_RX)) {
+            ALOGW("releaseOutput() invalid open count %d for output %d",
+                                                              desc->mDirectOpenCount, output);
+            return;
+        }
+        if ((--desc->mDirectOpenCount == 0) || ((desc->mFlags & AUDIO_OUTPUT_FLAG_LPA || desc->mFlags & AUDIO_OUTPUT_FLAG_TUNNEL ||
+                desc->mFlags & AUDIO_OUTPUT_FLAG_VOIP_RX))) {
+            ALOGV("releaseOutput() closing output");
+            closeOutput(output);
+        }
+    }
+
+}
+
 uint32_t AudioPolicyManager::checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc,
                                                        audio_devices_t prevDevice,
                                                        uint32_t delayMs)
@@ -76,11 +119,11 @@
 
     uint32_t muteWaitMs = 0;
     audio_devices_t device = outputDesc->device();
-    bool shouldMute = (outputDesc->refCount() != 0) &&
+    bool shouldMute = (outputDesc->isActive()) &&
                     (AudioSystem::popCount(device) >= 2);
     // temporary mute output if device selection changes to avoid volume bursts due to
     // different per device volumes
-    bool tempMute = (outputDesc->refCount() != 0) && (device != prevDevice);
+    bool tempMute = (outputDesc->isActive()) && (device != prevDevice);
 
     for (size_t i = 0; i < NUM_STRATEGIES; i++) {
         audio_devices_t curDevice = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/);
@@ -104,27 +147,16 @@
                 audio_io_handle_t curOutput = mOutputs.keyAt(j);
                 ALOGVV("checkDeviceMuteStrategies() %s strategy %d (curDevice %04x) on output %d",
                       mute ? "muting" : "unmuting", i, curDevice, curOutput);
-                setStrategyMute((routing_strategy)i, mute, curOutput, mute ? 0 : delayMs * 4);
-                if (desc->strategyRefCount((routing_strategy)i) != 0) {
-                    if (tempMute) {
-                        if ((desc != outputDesc) && (desc->device() == device)) {
-                            ALOGD("avoid tempmute on curOutput %d as device is same", curOutput);
-                        } else {
-                            setStrategyMute((routing_strategy)i, true, curOutput);
-
-                            //Change latency for tunnel/LPA player to make sure no noise on device switch
-                            //Routing to  BTA2DP,  USB device ,  Proxy(WFD) will take time, increasing latency time
-                            if((desc->mFlags & AUDIO_OUTPUT_FLAG_LPA) || (desc->mFlags & AUDIO_OUTPUT_FLAG_TUNNEL)
-                                || (device & AUDIO_DEVICE_OUT_USB_DEVICE) || (device & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP)
-                                || (device & AUDIO_DEVICE_OUT_PROXY) || (device & AUDIO_DEVICE_OUT_FM))
-                            {
-                               setStrategyMute((routing_strategy)i, false, curOutput,desc->latency()*4 ,device);
-                            }
-                            else
-                               setStrategyMute((routing_strategy)i, false, curOutput,desc->latency()*2 ,device);
-                        }
+                setStrategyMute((routing_strategy)i, mute, curOutput, mute ? 0 : delayMs);
+                if (desc->isStrategyActive((routing_strategy)i)) {
+                    // do tempMute only for current output
+                    if (tempMute && (desc == outputDesc)) {
+                        setStrategyMute((routing_strategy)i, true, curOutput);
+                        setStrategyMute((routing_strategy)i, false, curOutput,
+                                            desc->latency() * ((desc->mFlags & AUDIO_OUTPUT_FLAG_LPA) ? 4 : 2),
+                                            device);
                     }
-                    if (tempMute || mute) {
+                    if ((tempMute && (desc == outputDesc)) || mute) {
                         if (muteWaitMs < desc->latency()) {
                             muteWaitMs = desc->latency();
                         }
@@ -448,7 +480,6 @@
     return BAD_VALUE;
 }
 
-
 AudioSystem::device_connection_state AudioPolicyManager::getDeviceConnectionState(audio_devices_t device,
                                                   const char *device_address)
 {
@@ -483,7 +514,6 @@
     return state;
 }
 
-
 void AudioPolicyManager::setPhoneState(int state)
 {
     ALOGV("setPhoneState() state %d", state);
@@ -545,21 +575,7 @@
         newDevice = hwOutputDesc->device();
     }
 
-    // when changing from ring tone to in call mode, mute the ringing tone
-    // immediately and delay the route change to avoid sending the ring tone
-    // tail into the earpiece or headset.
     int delayMs = 0;
-    if (isStateInCall(state) && oldState == AudioSystem::MODE_RINGTONE) {
-        // delay the device change command by twice the output latency to have some margin
-        // and be sure that audio buffers not yet affected by the mute are out when
-        // we actually apply the route change
-        delayMs = hwOutputDesc->mLatency*2;
-        setStreamMute(AudioSystem::RING, true, mPrimaryOutput);
-    }
-
-    // Ignore the delay to enable voice call on this target as the enabling the
-    // voice call has enough delay to make sure the ringtone audio completely
-    // played out
     if (state == AUDIO_MODE_IN_CALL &&
 #ifdef QCOM_CSDCLIENT_ENABLED
         platform_is_Fusion3() &&
@@ -569,18 +585,27 @@
     }
 
     if (isStateInCall(state)) {
+        nsecs_t sysTime = systemTime();
         for (size_t i = 0; i < mOutputs.size(); i++) {
             AudioOutputDescriptor *desc = mOutputs.valueAt(i);
-            //take the biggest latency for all outputs
-            if (delayMs < desc->mLatency*2) {
+            // mute media and sonification strategies and delay device switch by the largest
+            // latency of any output where either strategy is active.
+            // This avoid sending the ring tone or music tail into the earpiece or headset.
+            if ((desc->isStrategyActive(STRATEGY_MEDIA,
+                                     SONIFICATION_HEADSET_MUSIC_DELAY,
+                                     sysTime) ||
+                    desc->isStrategyActive(STRATEGY_SONIFICATION,
+                                         SONIFICATION_HEADSET_MUSIC_DELAY,
+                                         sysTime)) &&
+                    (delayMs < (int)desc->mLatency*2)) {
                 delayMs = desc->mLatency*2;
             }
-            //mute STRATEGY_MEDIA on all outputs
-            if (desc->strategyRefCount(STRATEGY_MEDIA) != 0) {
-                setStrategyMute(STRATEGY_MEDIA, true, mOutputs.keyAt(i));
-                setStrategyMute(STRATEGY_MEDIA, false, mOutputs.keyAt(i), MUTE_TIME_MS,
-                    getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/));
-            }
+            setStrategyMute(STRATEGY_MEDIA, true, mOutputs.keyAt(i));
+            setStrategyMute(STRATEGY_MEDIA, false, mOutputs.keyAt(i), MUTE_TIME_MS,
+                getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/));
+            setStrategyMute(STRATEGY_SONIFICATION, true, mOutputs.keyAt(i));
+            setStrategyMute(STRATEGY_SONIFICATION, false, mOutputs.keyAt(i), MUTE_TIME_MS,
+                getDeviceForStrategy(STRATEGY_SONIFICATION, true /*fromCache*/));
         }
     }
 
@@ -600,11 +625,6 @@
     // pertaining to sonification strategy see handleIncallSonification()
     if (isStateInCall(state)) {
         ALOGV("setPhoneState() in call state management: new state is %d", state);
-        // unmute the ringing tone after a sufficient delay if it was muted before
-        // setting output device above
-        if (oldState == AudioSystem::MODE_RINGTONE) {
-            setStreamMute(AudioSystem::RING, false, mPrimaryOutput, MUTE_TIME_MS);
-        }
         for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
             handleIncallSonification(stream, true, true);
         }
@@ -619,7 +639,6 @@
     }
 }
 
-
 void AudioPolicyManager::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
 {
     ALOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState);
@@ -752,17 +771,35 @@
     }
 #endif //AUDIO_POLICY_TEST
 
+    // open a direct output if required by specified parameters
     IOProfile *profile = getProfileForDirectOutput(device,
-                                            samplingRate,
-                                            format,
-                                            channelMask,
-                                            (audio_output_flags_t)flags);
-
+                                                   samplingRate,
+                                                   format,
+                                                   channelMask,
+                                                   (audio_output_flags_t)flags);
     if (profile != NULL) {
+        AudioOutputDescriptor *outputDesc = NULL;
 
-        ALOGV("getOutput() opening direct output device %x", device);
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+            if (!desc->isDuplicated() && (profile == desc->mProfile)) {
+                outputDesc = desc;
+                // reuse direct output if currently open and configured with same parameters
+                if ((samplingRate == outputDesc->mSamplingRate) &&
+                        (format == outputDesc->mFormat) &&
+                        (channelMask == outputDesc->mChannelMask)) {
+                    outputDesc->mDirectOpenCount++;
+                    ALOGV("getOutput() reusing direct output %d", output);
+                    return mOutputs.keyAt(i);
+                }
+            }
+        }
 
-        AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(profile);
+        // close direct output if currently open and configured with different parameters
+        if (outputDesc != NULL) {
+            closeOutput(outputDesc->mId);
+        }
+        outputDesc = new AudioOutputDescriptor(profile);
         outputDesc->mDevice = device;
         outputDesc->mSamplingRate = samplingRate;
         outputDesc->mFormat = (audio_format_t)format;
@@ -771,6 +808,7 @@
         outputDesc->mFlags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT);;
         outputDesc->mRefCount[stream] = 0;
         outputDesc->mStopTime[stream] = 0;
+        outputDesc->mDirectOpenCount = 1;
         output = mpClientInterface->openOutput(profile->mModule->mHandle,
                                         &outputDesc->mDevice,
                                         &outputDesc->mSamplingRate,
@@ -795,7 +833,8 @@
             return 0;
         }
         addOutput(output, outputDesc);
-        ALOGV("getOutput() returns direct output %d", output);
+        mPreviousOutputs = mOutputs;
+        ALOGV("getOutput() returns new direct output %d", output);
         return output;
     }
 
@@ -855,8 +894,9 @@
                 }
                 // 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();
+                uint32_t latency = desc->latency();
+                if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) {
+                    waitMs = latency;
                 }
             }
         }
@@ -896,6 +936,7 @@
     return NO_ERROR;
 }
 
+
 status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
                                             AudioSystem::stream_type stream,
                                             int session)
@@ -941,7 +982,7 @@
                 audio_io_handle_t curOutput = mOutputs.keyAt(i);
                 AudioOutputDescriptor *desc = mOutputs.valueAt(i);
                 if (curOutput != output &&
-                        desc->refCount() != 0 &&
+                        desc->isActive() &&
                         outputDesc->sharesHwModuleWith(desc) &&
                         newDevice != desc->device()) {
                     setOutputDevice(curOutput,
@@ -1066,7 +1107,10 @@
         }
     }
 */
-
+    audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+    if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
+        inputDesc->mDevice = newDevice;
+    }
     AudioParameter param = AudioParameter();
     param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice);
 
@@ -1260,6 +1304,7 @@
                          ((profile->mFormats[0] == 0) &&
                              (profile->mChannelMasks.size() < 2))) {
                         ALOGW("checkOutputsForDevice() direct output missing param");
+                        mpClientInterface->closeOutput(output);
                         output = 0;
                     } else {
                         addOutput(output, desc);
@@ -1371,19 +1416,19 @@
     //      use device for strategy media
     // 6: the strategy DTMF is active on the output:
     //      use device for strategy DTMF
-    if (outputDesc->isUsedByStrategy(STRATEGY_ENFORCED_AUDIBLE)) {
+    if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE)) {
         device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
     } else if (isInCall() ||
-                    outputDesc->isUsedByStrategy(STRATEGY_PHONE)) {
+                    outputDesc->isStrategyActive(STRATEGY_PHONE)) {
         device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
-    } else if (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION)||
-                (primaryOutputDesc->isUsedByStrategy(STRATEGY_SONIFICATION)&& !primaryOutputDesc->strategyRefCount(STRATEGY_MEDIA))){
+    } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION)||
+                (primaryOutputDesc->isStrategyActive(STRATEGY_SONIFICATION)&& !primaryOutputDesc->isStrategyActive(STRATEGY_MEDIA))){
         device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
-    } else if (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION_RESPECTFUL)) {
+    } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION_RESPECTFUL)) {
         device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache);
-    } else if (outputDesc->isUsedByStrategy(STRATEGY_MEDIA)) {
+    } else if (outputDesc->isStrategyActive(STRATEGY_MEDIA)) {
         device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache);
-    } else if (outputDesc->isUsedByStrategy(STRATEGY_DTMF)) {
+    } else if (outputDesc->isStrategyActive(STRATEGY_DTMF)) {
         device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
     }
 
@@ -1436,6 +1481,13 @@
     case STRATEGY_SONIFICATION_RESPECTFUL:
         if (isInCall()) {
             device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+        } else if (isStreamActiveRemotely(AudioSystem::MUSIC,
+                SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+            // while media is playing on a remote device, use the the sonification behavior.
+            // Note that we test this usecase before testing if media is playing because
+            //   the isStreamActive() method only informs about the activity of a stream, not
+            //   if it's for local playback. Note also that we use the same delay between both tests
+            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*/);
@@ -1542,7 +1594,7 @@
             }
             break;
         }
-#ifdef QCOM_FM_ENABLED
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
         if (mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM) {
             if (mForceUse[AudioSystem::FOR_MEDIA] == AudioSystem::FORCE_SPEAKER) {
                 device &= ~(AUDIO_DEVICE_OUT_WIRED_HEADSET);
@@ -1584,7 +1636,7 @@
         uint32_t device2 = AUDIO_DEVICE_NONE;
         if (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_SPEAKER) {
             if (strategy != STRATEGY_SONIFICATION) {
-#ifdef QCOM_PROXY_DEVICE_ENABLED
+#ifdef QCOM_WFD_ENABLED
                 // no sonification on WFD sink
                 device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_PROXY;
 #else
@@ -1635,7 +1687,7 @@
             if (device2 == AUDIO_DEVICE_NONE) {
                 device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
             }
-#ifdef QCOM_FM_ENABLED
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
             if (device2 == AUDIO_DEVICE_NONE) {
                 device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM_TX;
             }
@@ -1691,6 +1743,13 @@
         muteWaitMs += setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
         return muteWaitMs;
     }
+    // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
+    // output profile
+    if ((device != AUDIO_DEVICE_NONE) &&
+            ((device & outputDesc->mProfile->mSupportedDevices) == 0)) {
+        return 0;
+    }
+
     // filter devices according to output selected
     device = (audio_devices_t)(device & outputDesc->mProfile->mSupportedDevices);
 
@@ -1730,7 +1789,14 @@
 {
     uint32_t device = AUDIO_DEVICE_NONE;
 
-    switch(inputSource) {
+    switch (inputSource) {
+    case AUDIO_SOURCE_VOICE_UPLINK:
+      if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {
+          device = AUDIO_DEVICE_IN_VOICE_CALL;
+          break;
+      }
+      // FALL THROUGH
+
     case AUDIO_SOURCE_DEFAULT:
     case AUDIO_SOURCE_MIC:
     case AUDIO_SOURCE_VOICE_RECOGNITION:
@@ -1765,7 +1831,6 @@
             device = AUDIO_DEVICE_IN_BUILTIN_MIC;
         }
         break;
-    case AUDIO_SOURCE_VOICE_UPLINK:
     case AUDIO_SOURCE_VOICE_DOWNLINK:
     case AUDIO_SOURCE_VOICE_CALL:
         if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {
@@ -1777,7 +1842,7 @@
             device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
         }
         break;
-#ifdef QCOM_FM_ENABLED
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
    case AUDIO_SOURCE_FM_RX:
         device = AUDIO_DEVICE_IN_FM_RX;
         break;
@@ -1839,7 +1904,7 @@
         case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
         case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
         case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
-#ifdef QCOM_FM_ENABLED
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
         case AUDIO_DEVICE_OUT_FM:
 #endif
             return DEVICE_CATEGORY_HEADSET;
@@ -2096,10 +2161,11 @@
 
 bool AudioPolicyManager::platform_is_Fusion3()
 {
-    char platform[128], baseband[128];
+    char platform[128], baseband[128], baseband_arch[128];
     property_get("ro.board.platform", platform, "");
     property_get("ro.baseband", baseband, "");
-    if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband))
+    property_get("ro.baseband.arch", baseband_arch, "");
+    if (!strcmp("msm8960", platform) && (!strcmp("mdm", baseband) || !strcmp("mdm", baseband_arch)))
         return true;
     else
         return false;
diff --git a/alsa_sound/AudioPolicyManagerALSA.h b/alsa_sound/AudioPolicyManagerALSA.h
index f89d9d3..f0f0237 100644
--- a/alsa_sound/AudioPolicyManagerALSA.h
+++ b/alsa_sound/AudioPolicyManagerALSA.h
@@ -70,6 +70,7 @@
         virtual status_t stopOutput(audio_io_handle_t output,
                                     AudioSystem::stream_type stream,
                                     int session = 0);
+        virtual void releaseOutput(audio_io_handle_t output);
         virtual audio_io_handle_t getInput(int inputSource,
                                             uint32_t samplingRate,
                                             uint32_t format,
diff --git a/alsa_sound/AudioSessionOut.cpp b/alsa_sound/AudioSessionOut.cpp
index caa87bc..6e5d31c 100644
--- a/alsa_sound/AudioSessionOut.cpp
+++ b/alsa_sound/AudioSessionOut.cpp
@@ -29,8 +29,7 @@
 #include <math.h>
 
 #define LOG_TAG "AudioSessionOutALSA"
-#define LOG_NDEBUG 0
-#define LOG_NDDEBUG 0
+//#define LOG_NDEBUG 0
 #include <utils/Log.h>
 #include <utils/String8.h>
 
@@ -60,7 +59,10 @@
 #define NUM_FDS 2
 #define KILL_EVENT_THREAD 1
 #define BUFFER_COUNT 4
-#define LPA_BUFFER_SIZE 256*1024
+#ifndef LPA_DEFAULT_BUFFER_SIZE
+#define LPA_DEFAULT_BUFFER_SIZE 256
+#endif
+#define LPA_BUFFER_SIZE LPA_DEFAULT_BUFFER_SIZE*1024
 #define TUNNEL_BUFFER_SIZE 240*1024
 #define TUNNEL_METADATA_SIZE 64
 #define MONO_CHANNEL_MODE 1
@@ -305,7 +307,12 @@
         mSkipWrite = false;
         ALOGD("mSkipWrite is false now write bytes %d", bytes);
         ALOGD("skipping buffer in write");
-        return 0;
+
+        /* returning the bytes itself as we are skipping write.
+         * This is considered as successfull write.
+         * Skipping write could be because of a flush.
+         */
+        return bytes;
     }
 
     ALOGV("not skipping buffer in write since mSkipWrite = %d, "
@@ -319,7 +326,7 @@
     updateMetaData(bytes);
 
     memcpy(buf.memBuf, &mOutputMetadataTunnel, mOutputMetadataLength);
-    ALOGD("buf.memBuf  =%x , Copy Metadata = %d,  bytes = %d", buf.memBuf,mOutputMetadataLength, bytes);
+    ALOGV("buf.memBuf  =%x , Copy Metadata = %d,  bytes = %d", buf.memBuf,mOutputMetadataLength, bytes);
 
     if (bytes == 0) {
         buf.bytesToWrite = 0;
@@ -338,6 +345,7 @@
             if (mFilledQueue.empty()) {
                 mFilledQueue.push_back(buf);
             }
+            return bytes;
         }
 
         return err;
@@ -364,9 +372,15 @@
         if (!mTunnelMode) mReachedEOS = true;
     }
     int32_t * Buf = (int32_t *) buf.memBuf;
-    ALOGD(" buf.memBuf [0] = %x , buf.memBuf [1] = %x",  Buf[0], Buf[1]);
+    ALOGV(" buf.memBuf [0] = %x , buf.memBuf [1] = %x",  Buf[0], Buf[1]);
     mFilledQueue.push_back(buf);
-    return err;
+    if(!err) {
+       //return the bytes written to HAL if write is successful.
+       return bytes;
+    } else {
+       //else condition return err value returned
+       return err;
+    }
 }
 
 void AudioSessionOutALSA::bufferAlloc(alsa_handle_t *handle) {
@@ -717,11 +731,12 @@
 
 status_t AudioSessionOutALSA::standby()
 {
-    Mutex::Autolock autoLock(mParent->mLock);
     // At this point, all the buffers with the driver should be
     // flushed.
     status_t err = NO_ERROR;
     flush();
+    Mutex::Autolock autoLock(mParent->mLock);
+
     mAlsaHandle->module->standby(mAlsaHandle);
     if (mParent->mRouteAudioToExtOut) {
          ALOGD("Standby - stopPlaybackOnExtOut_l - mUseCase = %d",mUseCase);
@@ -938,7 +953,7 @@
         }
         param.remove(key);
     }
-    key = String8(AudioParameter::keyADSPStatus);
+    key = String8(AUDIO_PARAMETER_KEY_ADSP_STATUS);
     if (param.get(key, value) == NO_ERROR) {
        if (value == "ONLINE"){
            mReachedEOS = true;
@@ -1020,7 +1035,7 @@
     mOutputMetadataTunnel.metadataLength = sizeof(mOutputMetadataTunnel);
     mOutputMetadataTunnel.timestamp = 0;
     mOutputMetadataTunnel.bufferLength =  bytes;
-    ALOGD("bytes = %d , mAlsaHandle->handle->period_size = %d, metadata = %d ",
+    ALOGV("bytes = %d , mAlsaHandle->handle->period_size = %d, metadata = %d ",
             mOutputMetadataTunnel.bufferLength, mAlsaHandle->handle->period_size, mOutputMetadataTunnel.metadataLength);
 }
 
diff --git a/alsa_sound/AudioStreamInALSA.cpp b/alsa_sound/AudioStreamInALSA.cpp
index a6a088a..daa8bd8 100644
--- a/alsa_sound/AudioStreamInALSA.cpp
+++ b/alsa_sound/AudioStreamInALSA.cpp
@@ -26,7 +26,6 @@
 
 #define LOG_TAG "AudioStreamInALSA"
 //#define LOG_NDEBUG 0
-#define LOG_NDDEBUG 0
 #include <utils/Log.h>
 #include <utils/String8.h>
 
@@ -38,8 +37,13 @@
 
 extern "C" {
 #ifdef QCOM_CSDCLIENT_ENABLED
+#ifdef NEW_CSDCLIENT
 static int (*csd_start_record)(uint32_t, int);
 static int (*csd_stop_record)(uint32_t);
+#else
+static int (*csd_start_record)(int);
+static int (*csd_stop_record)(void);
+#endif
 #endif
 #ifdef QCOM_SSR_ENABLED
 #include "surround_filters_interface.h"
@@ -68,8 +72,8 @@
         AudioSystem::audio_in_acoustics audio_acoustics) :
     ALSAStreamOps(parent, handle),
     mFramesLost(0),
-    mParent(parent),
-    mAcoustics(audio_acoustics)
+    mAcoustics(audio_acoustics),
+    mParent(parent)
 #ifdef QCOM_SSR_ENABLED
     , mFp_4ch(NULL),
     mFp_6ch(NULL),
@@ -114,10 +118,17 @@
 #endif
 #ifdef QCOM_CSDCLIENT_ENABLED
     if (mParent->mCsdHandle != NULL) {
+#ifdef NEW_CSDCLIENT
         csd_start_record = (int (*)(uint32_t, int))::dlsym(mParent->mCsdHandle,
                                                       "csd_client_start_record");
         csd_stop_record = (int (*)(uint32_t))::dlsym(mParent->mCsdHandle,
                                                 "csd_client_stop_record");
+#else
+        csd_start_record = (int (*)(int))::dlsym(mParent->mCsdHandle,
+                                                      "csd_client_start_record");
+        csd_stop_record = (int (*)())::dlsym(mParent->mCsdHandle,
+                                                "csd_client_stop_record");
+#endif
     }
 #endif
 }
@@ -163,7 +174,11 @@
                         if (csd_start_record == NULL) {
                             ALOGE("csd_start_record is NULL");
                         } else {
+#ifdef NEW_CSDCLIENT
                             csd_start_record(ALL_SESSION_VSID, INCALL_REC_STEREO);
+#else
+                            csd_start_record(INCALL_REC_STEREO);
+#endif
                         }
                     } else
 #endif
@@ -185,7 +200,11 @@
                         if (csd_start_record == NULL) {
                             ALOGE("csd_start_record is NULL");
                         } else {
+#ifdef NEW_CSDCLIENT
                             csd_start_record(ALL_SESSION_VSID, INCALL_REC_MONO);
+#else
+                            csd_start_record(INCALL_REC_MONO);
+#endif
                         }
                     } else
 #endif
@@ -199,7 +218,7 @@
                         }
                     }
                 }
-#ifdef QCOM_FM_ENABLED
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
             } else if(mHandle->devices == AudioSystem::DEVICE_IN_FM_RX) {
                 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_FM, sizeof(mHandle->useCase));
             } else if (mHandle->devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
@@ -233,8 +252,12 @@
                        if (csd_start_record == NULL) {
                            ALOGE("csd_start_record is NULL");
                        } else {
+#ifdef NEW_CSDCLIENT
                            csd_start_record(ALL_SESSION_VSID,
                                             INCALL_REC_STEREO);
+#else
+                           csd_start_record(INCALL_REC_STEREO);
+#endif
                        }
                     } else
 #endif
@@ -257,7 +280,11 @@
                        if (csd_start_record == NULL) {
                            ALOGE("csd_start_record is NULL");
                        } else {
+#ifdef NEW_CSDCLIENT
                            csd_start_record(ALL_SESSION_VSID, INCALL_REC_MONO);
+#else
+                           csd_start_record(INCALL_REC_MONO);
+#endif
                        }
                    } else
 #endif
@@ -272,7 +299,7 @@
                         }
                    }
                 }
-#ifdef QCOM_FM_ENABLED
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
             } else if(mHandle->devices == AudioSystem::DEVICE_IN_FM_RX) {
                 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_FM_REC, sizeof(mHandle->useCase));
         } else if (mHandle->devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
@@ -523,10 +550,12 @@
                     }
                     else
                     {
-                        if (mParent->mALSADevice->mSSRComplete) {
+                        if (mParent->mALSADevice->mADSPState == ADSP_UP_AFTER_SSR) {
                             ALOGD("SSR Case: Call device switch to apply AMIX controls.");
                             mHandle->module->route(mHandle, mDevices , mParent->mode());
-                            mParent->mALSADevice->mSSRComplete = false;
+                            // In-case of multiple streams only one stream will be resumed
+                            // after resetting mADSPState to ADSP_UP with output device routed
+                            mParent->mALSADevice->mADSPState = ADSP_UP;
                         }
                         mHandle->module->open(mHandle);
                     }
@@ -610,7 +639,11 @@
            if (csd_stop_record == NULL) {
                ALOGE("csd_stop_record is NULL");
            } else {
+#ifdef NEW_CSDCLIENT
                csd_stop_record(ALL_SESSION_VSID);
+#else
+               csd_stop_record();
+#endif
            }
        }
     }
@@ -684,7 +717,11 @@
            if (csd_stop_record == NULL) {
                ALOGE("csd_stop_record is NULL");
            } else {
+#ifdef NEW_CSDCLIENT
                csd_stop_record(ALL_SESSION_VSID);
+#else
+               csd_stop_record();
+#endif
            }
        }
     }
diff --git a/alsa_sound/AudioStreamOutALSA.cpp b/alsa_sound/AudioStreamOutALSA.cpp
index 8e0c305..22dbbe6 100644
--- a/alsa_sound/AudioStreamOutALSA.cpp
+++ b/alsa_sound/AudioStreamOutALSA.cpp
@@ -27,7 +27,6 @@
 
 #define LOG_TAG "AudioStreamOutALSA"
 //#define LOG_NDEBUG 0
-#define LOG_NDDEBUG 0
 #include <utils/Log.h>
 #include <utils/String8.h>
 
@@ -52,9 +51,9 @@
 
 AudioStreamOutALSA::AudioStreamOutALSA(AudioHardwareALSA *parent, alsa_handle_t *handle) :
     ALSAStreamOps(parent, handle),
-    mParent(parent),
     mFrameCount(0),
-    mUseCase(AudioHardwareALSA::USECASE_NONE)
+    mUseCase(AudioHardwareALSA::USECASE_NONE),
+    mParent(parent)
 {
 }
 
@@ -266,7 +265,7 @@
         if (n < 0) {
             mParent->mLock.lock();
             if (mHandle->handle != NULL) {
-                ALOGE("pcm_write returned error %d, trying to recover\n", n);
+                ALOGE("pcm_write returned error %ld, trying to recover\n", n);
                 pcm_close(mHandle->handle);
                 mHandle->handle = NULL;
                 if((!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) ||
@@ -277,10 +276,10 @@
                 }
                 else
                 {
-                    if (mParent->mALSADevice->mSSRComplete) {
+                    if (mParent->mALSADevice->mADSPState == ADSP_UP_AFTER_SSR) {
                         ALOGD("SSR Case: Call device switch to apply AMIX controls.");
                         mHandle->module->route(mHandle, mParent->mCurRxDevice , mParent->mode());
-                        mParent->mALSADevice->mSSRComplete = false;
+                        mParent->mALSADevice->mADSPState = ADSP_UP;
 
                         if(mParent->isExtOutDevice(mParent->mCurRxDevice)) {
                            ALOGV("StreamOut write - mRouteAudioToExtOut = %d ", mParent->mRouteAudioToExtOut);
diff --git a/alsa_sound/AudioUsbALSA.cpp b/alsa_sound/AudioUsbALSA.cpp
index d029c63..d2b1c25 100644
--- a/alsa_sound/AudioUsbALSA.cpp
+++ b/alsa_sound/AudioUsbALSA.cpp
@@ -28,8 +28,7 @@
 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
 
 #define LOG_TAG "AudioUsbALSA"
-#define LOG_NDEBUG 0
-#define LOG_NDDEBUG 0
+//#define LOG_NDEBUG 0
 #include <utils/Log.h>
 #include <utils/String8.h>
 
diff --git a/alsa_sound/AudioUtil.cpp b/alsa_sound/AudioUtil.cpp
index 7f74530..023d1cd 100644
--- a/alsa_sound/AudioUtil.cpp
+++ b/alsa_sound/AudioUtil.cpp
@@ -19,6 +19,9 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#include <fcntl.h>
+#include <stdlib.h>
+
 #include "AudioUtil.h"
 
 int AudioUtil::printFormatFromEDID(unsigned char format) {
@@ -735,3 +738,20 @@
         }
     }
 }
+
+#ifdef SAMSUNG_AUDIO
+bool AudioUtil::isSamsungDockConnected()
+{
+    FILE *dockNode = NULL;
+    char buf[32];
+    bool connected = false;
+
+    dockNode = fopen(SAMSUNG_DOCK_SWITCH, "r");
+    if (dockNode) {
+        fread(buf, sizeof(char), 32, dockNode);
+        connected = atoi(buf) > 0;
+        fclose(dockNode);
+    }
+    return connected;
+}
+#endif
diff --git a/alsa_sound/AudioUtil.h b/alsa_sound/AudioUtil.h
index e86c9e7..35585d8 100644
--- a/alsa_sound/AudioUtil.h
+++ b/alsa_sound/AudioUtil.h
@@ -90,6 +90,8 @@
     int  channelAllocation;
 } EDID_AUDIO_INFO;
 
+#define SAMSUNG_DOCK_SWITCH "/sys/devices/virtual/switch/dock/state"
+
 class AudioUtil {
 public:
 
@@ -97,6 +99,10 @@
     static bool getHDMIAudioSinkCaps(EDID_AUDIO_INFO*);
     static bool getHDMIAudioSinkCaps(EDID_AUDIO_INFO*, char *hdmiEDIDData);
 
+#ifdef SAMSUNG_AUDIO
+    static bool isSamsungDockConnected();
+#endif
+
 private:
     static int printFormatFromEDID(unsigned char format);
     static int getSamplingFrequencyFromEDID(unsigned char byte);
diff --git a/alsa_sound/audio_hw_hal.cpp b/alsa_sound/audio_hw_hal.cpp
index f050f56..6b34090 100644
--- a/alsa_sound/audio_hw_hal.cpp
+++ b/alsa_sound/audio_hw_hal.cpp
@@ -24,6 +24,10 @@
 #include <system/audio.h>
 #include <hardware/audio.h>
 
+#ifdef USES_AUDIO_AMPLIFIER
+#include <audio_amplifier.h>
+#endif
+
 #include <hardware_legacy/AudioHardwareInterface.h>
 #include <hardware_legacy/AudioSystemLegacy.h>
 
@@ -85,7 +89,7 @@
 #ifdef QCOM_PROXY_DEVICE_ENABLED
     { AudioSystem::DEVICE_OUT_PROXY, AUDIO_DEVICE_OUT_PROXY },
 #endif
-#ifdef QCOM_FM_ENABLED
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
     { AudioSystem::DEVICE_OUT_FM, AUDIO_DEVICE_OUT_FM },
     { AudioSystem::DEVICE_OUT_FM_TX, AUDIO_DEVICE_OUT_FM_TX },
 #endif
@@ -106,7 +110,7 @@
 #ifdef QCOM_PROXY_DEVICE_ENABLED
     { AudioSystem::DEVICE_IN_PROXY, AUDIO_DEVICE_IN_PROXY },
 #endif
-#ifdef QCOM_FM_ENABLED
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
     { AudioSystem::DEVICE_IN_FM_RX, AUDIO_DEVICE_IN_FM_RX },
     { AudioSystem::DEVICE_IN_FM_RX_A2DP, AUDIO_DEVICE_IN_FM_RX_A2DP },
 #endif
@@ -524,7 +528,7 @@
 #ifdef QCOM_PROXY_DEVICE_ENABLED
             AUDIO_DEVICE_OUT_PROXY |
 #endif
-#ifdef QCOM_FM_ENABLED
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
             AUDIO_DEVICE_OUT_FM |
             AUDIO_DEVICE_OUT_FM_TX |
 #endif
@@ -549,7 +553,7 @@
 #ifdef QCOM_PROXY_DEVICE_ENABLED
             AUDIO_DEVICE_IN_PROXY |
 #endif
-#ifdef QCOM_FM_ENABLED
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
             AUDIO_DEVICE_IN_FM_RX |
             AUDIO_DEVICE_IN_FM_RX_A2DP |
 #endif
@@ -592,6 +596,12 @@
 static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
 {
     struct qcom_audio_device *qadev = to_ladev(dev);
+
+#ifdef USES_AUDIO_AMPLIFIER
+    if (amplifier_set_mode(mode) != 0)
+        ALOGE("Failed setting amplifier mode");
+#endif
+
     return qadev->hwif->setMode(mode);
 }
 
@@ -782,6 +792,11 @@
                         reinterpret_cast<struct audio_hw_device *>(device);
     struct qcom_audio_device *qadev = to_ladev(hwdev);
 
+#ifdef USES_AUDIO_AMPLIFIER
+    if (amplifier_close() != 0)
+        ALOGE("Amplifier close failed");
+#endif
+
     if (!qadev)
         return 0;
 
@@ -838,6 +853,11 @@
 
     *device = &qadev->device.common;
 
+#ifdef USES_AUDIO_AMPLIFIER
+    if (amplifier_open() != 0)
+        ALOGE("Amplifier initialization failed");
+#endif
+
     return 0;
 
 err_create_audio_hw:
diff --git a/alsa_sound/audio_policy_hal.cpp b/alsa_sound/audio_policy_hal.cpp
index 41b6a9a..f494d23 100644
--- a/alsa_sound/audio_policy_hal.cpp
+++ b/alsa_sound/audio_policy_hal.cpp
@@ -303,6 +303,13 @@
     return qap->apm->isStreamActive(stream, in_past_ms);
 }
 
+static bool ap_is_stream_active_remotely(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->isStreamActiveRemotely((int) stream, in_past_ms);
+}
+
 static bool ap_is_source_active(const struct audio_policy *pol, audio_source_t source)
 {
     const struct qcom_audio_policy *qap = to_cqap(pol);
@@ -359,6 +366,8 @@
     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.is_stream_active_remotely = ap_is_stream_active_remotely;
     qap->policy.is_source_active = ap_is_source_active;
     qap->policy.dump = ap_dump;
 
diff --git a/libalsa-intf/Android.mk b/libalsa-intf/Android.mk
index 9fad5c8..6366789 100644
--- a/libalsa-intf/Android.mk
+++ b/libalsa-intf/Android.mk
@@ -1,6 +1,16 @@
 LOCAL_PATH:= $(call my-dir)
 
 ifeq ($(strip $(BOARD_USES_ALSA_AUDIO)),true)
+
+ifneq ($(TARGET_USES_QCOM_COMPRESSED_AUDIO),false)
+    common_cflags += -DQCOM_COMPRESSED_AUDIO_ENABLED
+endif
+
+$(shell mkdir -p $(OUT)/obj/SHARED_LIBRARIES/libalsa-intf_intermediates)
+$(shell touch $(OUT)/obj/SHARED_LIBRARIES/libalsa-intf_intermediates/export_includes)
+$(shell mkdir -p $(OUT)/obj/SHARED_LIBRARIES/libacdbloader_intermediates)
+$(shell touch $(OUT)/obj/SHARED_LIBRARIES/libacdbloader_intermediates/export_includes)
+
 # Any prebuilt files with default TAGS can use the below:
 include $(CLEAR_VARS)
 #LOCAL_SRC_FILES:= aplay.c alsa_pcm.c alsa_mixer.c
@@ -9,6 +19,7 @@
 LOCAL_SHARED_LIBRARIES:= libc libcutils libalsa-intf
 LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
 LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+LOCAL_CFLAGS := $(common_cflags)
 LOCAL_MODULE_TAGS:= debug
 include $(BUILD_EXECUTABLE)
 
@@ -21,6 +32,7 @@
 LOCAL_SHARED_LIBRARIES:= libc libcutils libalsa-intf
 LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
 LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+LOCAL_CFLAGS := $(common_cflags)
 LOCAL_MODULE_TAGS:= debug
 include $(BUILD_EXECUTABLE)
 
@@ -30,6 +42,7 @@
 LOCAL_SHARED_LIBRARIES := libc libcutils libalsa-intf
 LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
 LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+LOCAL_CFLAGS := $(common_cflags)
 LOCAL_MODULE_TAGS:= debug
 include $(BUILD_EXECUTABLE)
 
@@ -39,6 +52,7 @@
 LOCAL_SHARED_LIBRARIES:= libc libcutils libalsa-intf
 LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
 LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+LOCAL_CFLAGS := $(common_cflags)
 LOCAL_MODULE_TAGS:= debug
 include $(BUILD_EXECUTABLE)
 
@@ -52,13 +66,8 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_SHARED_LIBRARIES:= libc libcutils #libutils #libmedia libhardware_legacy
 LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
-ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true)
-LOCAL_CFLAGS := -DQC_PROP -DCONFIG_DIR=\"/system/etc/snd_soc_msm/\"
+LOCAL_CFLAGS := $(common_cflags) -DQC_PROP -DCONFIG_DIR=\"/system/etc/snd_soc_msm/\"
 LOCAL_CFLAGS += -DCONFIG_DIR=\"/system/etc/snd_soc_msm/\"
-LOCAL_SHARED_LIBRARIES += libacdbloader
-LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audio-acdb-util
-LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audcal
-endif
 LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
 ifeq ($(TARGET_SIMULATOR),true)
  LOCAL_LDLIBS += -ldl
diff --git a/libalsa-intf/alsa_audio.h b/libalsa-intf/alsa_audio.h
index b4c033d..f538f00 100644
--- a/libalsa-intf/alsa_audio.h
+++ b/libalsa-intf/alsa_audio.h
@@ -187,4 +187,522 @@
 
 #define MAX_NUM_CODECS 32
 
+#ifndef QCOM_COMPRESSED_AUDIO_ENABLED
+/* compressed audio support */
+
+/* AUDIO CODECS SUPPORTED */
+#define MAX_NUM_CODECS 32
+#define MAX_NUM_CODEC_DESCRIPTORS 32
+#define MAX_NUM_BITRATES 32
+
+/* compressed TX */
+#define MAX_NUM_FRAMES_PER_BUFFER 1
+#define COMPRESSED_META_DATA_MODE 0x10
+#define META_DATA_LEN_BYTES 36
+#define Q6_AC3_DECODER	0x00010BF6
+#define Q6_EAC3_DECODER 0x00010C3C
+#define Q6_DTS		0x00010D88
+#define Q6_DTS_LBR	0x00010DBB
+
+/* Codecs are listed linearly to allow for extensibility */
+#define SND_AUDIOCODEC_PCM                   ((__u32) 0x00000001)
+#define SND_AUDIOCODEC_MP3                   ((__u32) 0x00000002)
+#define SND_AUDIOCODEC_AMR                   ((__u32) 0x00000003)
+#define SND_AUDIOCODEC_AMRWB                 ((__u32) 0x00000004)
+#define SND_AUDIOCODEC_AMRWBPLUS             ((__u32) 0x00000005)
+#define SND_AUDIOCODEC_AAC                   ((__u32) 0x00000006)
+#define SND_AUDIOCODEC_WMA                   ((__u32) 0x00000007)
+#define SND_AUDIOCODEC_REAL                  ((__u32) 0x00000008)
+#define SND_AUDIOCODEC_VORBIS                ((__u32) 0x00000009)
+#define SND_AUDIOCODEC_FLAC                  ((__u32) 0x0000000A)
+#define SND_AUDIOCODEC_IEC61937              ((__u32) 0x0000000B)
+#define SND_AUDIOCODEC_G723_1                ((__u32) 0x0000000C)
+#define SND_AUDIOCODEC_G729                  ((__u32) 0x0000000D)
+#define SND_AUDIOCODEC_AC3                   ((__u32) 0x0000000E)
+#define SND_AUDIOCODEC_DTS                   ((__u32) 0x0000000F)
+#define SND_AUDIOCODEC_AC3_PASS_THROUGH      ((__u32) 0x00000010)
+#define SND_AUDIOCODEC_WMA_PRO               ((__u32) 0x00000011)
+#define SND_AUDIOCODEC_DTS_PASS_THROUGH      ((__u32) 0x00000012)
+#define SND_AUDIOCODEC_DTS_LBR               ((__u32) 0x00000013)
+#define SND_AUDIOCODEC_DTS_TRANSCODE_LOOPBACK ((__u32) 0x00000014)
+#define SND_AUDIOCODEC_PASS_THROUGH          ((__u32) 0x00000015)
+#define SND_AUDIOCODEC_MP2                   ((__u32) 0x00000016)
+#define SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH  ((__u32) 0x00000017)
+/*
+ * Profile and modes are listed with bit masks. This allows for a
+ * more compact representation of fields that will not evolve
+ * (in contrast to the list of codecs)
+ */
+
+#define SND_AUDIOPROFILE_PCM                 ((__u32) 0x00000001)
+
+/* MP3 modes are only useful for encoders */
+#define SND_AUDIOCHANMODE_MP3_MONO           ((__u32) 0x00000001)
+#define SND_AUDIOCHANMODE_MP3_STEREO         ((__u32) 0x00000002)
+#define SND_AUDIOCHANMODE_MP3_JOINTSTEREO    ((__u32) 0x00000004)
+#define SND_AUDIOCHANMODE_MP3_DUAL           ((__u32) 0x00000008)
+
+#define SND_AUDIOPROFILE_AMR                 ((__u32) 0x00000001)
+
+/* AMR modes are only useful for encoders */
+#define SND_AUDIOMODE_AMR_DTX_OFF            ((__u32) 0x00000001)
+#define SND_AUDIOMODE_AMR_VAD1               ((__u32) 0x00000002)
+#define SND_AUDIOMODE_AMR_VAD2               ((__u32) 0x00000004)
+
+#define SND_AUDIOSTREAMFORMAT_UNDEFINED	     ((__u32) 0x00000000)
+#define SND_AUDIOSTREAMFORMAT_CONFORMANCE    ((__u32) 0x00000001)
+#define SND_AUDIOSTREAMFORMAT_IF1            ((__u32) 0x00000002)
+#define SND_AUDIOSTREAMFORMAT_IF2            ((__u32) 0x00000004)
+#define SND_AUDIOSTREAMFORMAT_FSF            ((__u32) 0x00000008)
+#define SND_AUDIOSTREAMFORMAT_RTPPAYLOAD     ((__u32) 0x00000010)
+#define SND_AUDIOSTREAMFORMAT_ITU            ((__u32) 0x00000020)
+
+#define SND_AUDIOPROFILE_AMRWB               ((__u32) 0x00000001)
+
+/* AMRWB modes are only useful for encoders */
+#define SND_AUDIOMODE_AMRWB_DTX_OFF          ((__u32) 0x00000001)
+#define SND_AUDIOMODE_AMRWB_VAD1             ((__u32) 0x00000002)
+#define SND_AUDIOMODE_AMRWB_VAD2             ((__u32) 0x00000004)
+
+#define SND_AUDIOPROFILE_AMRWBPLUS           ((__u32) 0x00000001)
+
+#define SND_AUDIOPROFILE_AAC                 ((__u32) 0x00000001)
+
+/* AAC modes are required for encoders and decoders */
+#define SND_AUDIOMODE_AAC_MAIN               ((__u32) 0x00000001)
+#define SND_AUDIOMODE_AAC_LC                 ((__u32) 0x00000002)
+#define SND_AUDIOMODE_AAC_SSR                ((__u32) 0x00000004)
+#define SND_AUDIOMODE_AAC_LTP                ((__u32) 0x00000008)
+#define SND_AUDIOMODE_AAC_HE                 ((__u32) 0x00000010)
+#define SND_AUDIOMODE_AAC_SCALABLE           ((__u32) 0x00000020)
+#define SND_AUDIOMODE_AAC_ERLC               ((__u32) 0x00000040)
+#define SND_AUDIOMODE_AAC_LD                 ((__u32) 0x00000080)
+#define SND_AUDIOMODE_AAC_HE_PS              ((__u32) 0x00000100)
+#define SND_AUDIOMODE_AAC_HE_MPS             ((__u32) 0x00000200)
+
+/* AAC formats are required for encoders and decoders */
+#define SND_AUDIOSTREAMFORMAT_MP2ADTS        ((__u32) 0x00000001)
+#define SND_AUDIOSTREAMFORMAT_MP4ADTS        ((__u32) 0x00000002)
+#define SND_AUDIOSTREAMFORMAT_MP4LOAS        ((__u32) 0x00000004)
+#define SND_AUDIOSTREAMFORMAT_MP4LATM        ((__u32) 0x00000008)
+#define SND_AUDIOSTREAMFORMAT_ADIF           ((__u32) 0x00000010)
+#define SND_AUDIOSTREAMFORMAT_MP4FF          ((__u32) 0x00000020)
+#define SND_AUDIOSTREAMFORMAT_RAW            ((__u32) 0x00000040)
+
+#define SND_AUDIOPROFILE_WMA7                ((__u32) 0x00000001)
+#define SND_AUDIOPROFILE_WMA8                ((__u32) 0x00000002)
+#define SND_AUDIOPROFILE_WMA9                ((__u32) 0x00000004)
+#define SND_AUDIOPROFILE_WMA10               ((__u32) 0x00000008)
+
+#define SND_AUDIOMODE_WMA_LEVEL1             ((__u32) 0x00000001)
+#define SND_AUDIOMODE_WMA_LEVEL2             ((__u32) 0x00000002)
+#define SND_AUDIOMODE_WMA_LEVEL3             ((__u32) 0x00000004)
+#define SND_AUDIOMODE_WMA_LEVEL4             ((__u32) 0x00000008)
+#define SND_AUDIOMODE_WMAPRO_LEVELM0         ((__u32) 0x00000010)
+#define SND_AUDIOMODE_WMAPRO_LEVELM1         ((__u32) 0x00000020)
+#define SND_AUDIOMODE_WMAPRO_LEVELM2         ((__u32) 0x00000040)
+#define SND_AUDIOMODE_WMAPRO_LEVELM3         ((__u32) 0x00000080)
+
+#define SND_AUDIOSTREAMFORMAT_WMA_ASF        ((__u32) 0x00000001)
+/*
+ * Some implementations strip the ASF header and only send ASF packets
+ * to the DSP
+ */
+#define SND_AUDIOSTREAMFORMAT_WMA_NOASF_HDR  ((__u32) 0x00000002)
+
+#define SND_AUDIOPROFILE_REALAUDIO           ((__u32) 0x00000001)
+
+#define SND_AUDIOMODE_REALAUDIO_G2           ((__u32) 0x00000001)
+#define SND_AUDIOMODE_REALAUDIO_8            ((__u32) 0x00000002)
+#define SND_AUDIOMODE_REALAUDIO_10           ((__u32) 0x00000004)
+#define SND_AUDIOMODE_REALAUDIO_SURROUND     ((__u32) 0x00000008)
+
+#define SND_AUDIOPROFILE_VORBIS              ((__u32) 0x00000001)
+
+#define SND_AUDIOMODE_VORBIS                 ((__u32) 0x00000001)
+
+#define SND_AUDIOPROFILE_FLAC                ((__u32) 0x00000001)
+
+/*
+ * Define quality levels for FLAC encoders, from LEVEL0 (fast)
+ * to LEVEL8 (best)
+ */
+#define SND_AUDIOMODE_FLAC_LEVEL0            ((__u32) 0x00000001)
+#define SND_AUDIOMODE_FLAC_LEVEL1            ((__u32) 0x00000002)
+#define SND_AUDIOMODE_FLAC_LEVEL2            ((__u32) 0x00000004)
+#define SND_AUDIOMODE_FLAC_LEVEL3            ((__u32) 0x00000008)
+#define SND_AUDIOMODE_FLAC_LEVEL4            ((__u32) 0x00000010)
+#define SND_AUDIOMODE_FLAC_LEVEL5            ((__u32) 0x00000020)
+#define SND_AUDIOMODE_FLAC_LEVEL6            ((__u32) 0x00000040)
+#define SND_AUDIOMODE_FLAC_LEVEL7            ((__u32) 0x00000080)
+#define SND_AUDIOMODE_FLAC_LEVEL8            ((__u32) 0x00000100)
+
+#define SND_AUDIOSTREAMFORMAT_FLAC           ((__u32) 0x00000001)
+#define SND_AUDIOSTREAMFORMAT_FLAC_OGG       ((__u32) 0x00000002)
+
+/* IEC61937 payloads without CUVP and preambles */
+#define SND_AUDIOPROFILE_IEC61937            ((__u32) 0x00000001)
+/* IEC61937 with S/PDIF preambles+CUVP bits in 32-bit containers */
+#define SND_AUDIOPROFILE_IEC61937_SPDIF      ((__u32) 0x00000002)
+
+/*
+ * IEC modes are mandatory for decoders. Format autodetection
+ * will only happen on the DSP side with mode 0. The PCM mode should
+ * not be used, the PCM codec should be used instead.
+ */
+#define SND_AUDIOMODE_IEC_REF_STREAM_HEADER  ((__u32) 0x00000000)
+#define SND_AUDIOMODE_IEC_LPCM		     ((__u32) 0x00000001)
+#define SND_AUDIOMODE_IEC_AC3		     ((__u32) 0x00000002)
+#define SND_AUDIOMODE_IEC_MPEG1		     ((__u32) 0x00000004)
+#define SND_AUDIOMODE_IEC_MP3		     ((__u32) 0x00000008)
+#define SND_AUDIOMODE_IEC_MPEG2		     ((__u32) 0x00000010)
+#define SND_AUDIOMODE_IEC_AACLC		     ((__u32) 0x00000020)
+#define SND_AUDIOMODE_IEC_DTS		     ((__u32) 0x00000040)
+#define SND_AUDIOMODE_IEC_ATRAC		     ((__u32) 0x00000080)
+#define SND_AUDIOMODE_IEC_SACD		     ((__u32) 0x00000100)
+#define SND_AUDIOMODE_IEC_EAC3		     ((__u32) 0x00000200)
+#define SND_AUDIOMODE_IEC_DTS_HD	     ((__u32) 0x00000400)
+#define SND_AUDIOMODE_IEC_MLP		     ((__u32) 0x00000800)
+#define SND_AUDIOMODE_IEC_DST		     ((__u32) 0x00001000)
+#define SND_AUDIOMODE_IEC_WMAPRO	     ((__u32) 0x00002000)
+#define SND_AUDIOMODE_IEC_REF_CXT            ((__u32) 0x00004000)
+#define SND_AUDIOMODE_IEC_HE_AAC	     ((__u32) 0x00008000)
+#define SND_AUDIOMODE_IEC_HE_AAC2	     ((__u32) 0x00010000)
+#define SND_AUDIOMODE_IEC_MPEG_SURROUND	     ((__u32) 0x00020000)
+
+#define SND_AUDIOPROFILE_G723_1              ((__u32) 0x00000001)
+
+#define SND_AUDIOMODE_G723_1_ANNEX_A         ((__u32) 0x00000001)
+#define SND_AUDIOMODE_G723_1_ANNEX_B         ((__u32) 0x00000002)
+#define SND_AUDIOMODE_G723_1_ANNEX_C         ((__u32) 0x00000004)
+
+#define SND_AUDIOPROFILE_G729                ((__u32) 0x00000001)
+
+#define SND_AUDIOMODE_G729_ANNEX_A           ((__u32) 0x00000001)
+#define SND_AUDIOMODE_G729_ANNEX_B           ((__u32) 0x00000002)
+
+/* <FIXME: multichannel encoders aren't supported for now. Would need
+   an additional definition of channel arrangement> */
+
+/* VBR/CBR definitions */
+#define SND_RATECONTROLMODE_CONSTANTBITRATE  ((__u32) 0x00000001)
+#define SND_RATECONTROLMODE_VARIABLEBITRATE  ((__u32) 0x00000002)
+
+/* Encoder options */
+
+struct snd_enc_wma {
+	__u32 super_block_align; /* WMA Type-specific data */
+	__u32 bits_per_sample;
+	__u32 channelmask;
+	__u32 encodeopt;
+	__u32 encodeopt1;
+	__u32 encodeopt2;
+};
+
+
+/**
+ * struct snd_enc_vorbis
+ * @quality: Sets encoding quality to n, between -1 (low) and 10 (high).
+ * In the default mode of operation, the quality level is 3.
+ * Normal quality range is 0 - 10.
+ * @managed: Boolean. Set  bitrate  management  mode. This turns off the
+ * normal VBR encoding, but allows hard or soft bitrate constraints to be
+ * enforced by the encoder. This mode can be slower, and may also be
+ * lower quality. It is primarily useful for streaming.
+ * @max_bit_rate: Enabled only if managed is TRUE
+ * @min_bit_rate: Enabled only if managed is TRUE
+ * @downmix: Boolean. Downmix input from stereo to mono (has no effect on
+ * non-stereo streams). Useful for lower-bitrate encoding.
+ *
+ * These options were extracted from the OpenMAX IL spec and Gstreamer vorbisenc
+ * properties
+ *
+ * For best quality users should specify VBR mode and set quality levels.
+ */
+
+struct snd_enc_vorbis {
+	__s32 quality;
+	__u32 managed;
+	__u32 max_bit_rate;
+	__u32 min_bit_rate;
+	__u32 downmix;
+};
+
+
+/**
+ * struct snd_enc_real
+ * @quant_bits: number of coupling quantization bits in the stream
+ * @start_region: coupling start region in the stream
+ * @num_regions: number of regions value
+ *
+ * These options were extracted from the OpenMAX IL spec
+ */
+
+struct snd_enc_real {
+	__u32 quant_bits;
+	__u32 start_region;
+	__u32 num_regions;
+};
+
+/**
+ * struct snd_enc_flac
+ * @num: serial number, valid only for OGG formats
+ *	needs to be set by application
+ * @gain: Add replay gain tags
+ *
+ * These options were extracted from the FLAC online documentation
+ * at http://flac.sourceforge.net/documentation_tools_flac.html
+ *
+ * To make the API simpler, it is assumed that the user will select quality
+ * profiles. Additional options that affect encoding quality and speed can
+ * be added at a later stage if needed.
+ *
+ * By default the Subset format is used by encoders.
+ *
+ * TAGS such as pictures, etc, cannot be handled by an offloaded encoder and are
+ * not supported in this API.
+ */
+
+struct snd_enc_flac {
+	__u32 num;
+	__u32 gain;
+};
+
+struct snd_enc_generic {
+	__u32 bw;	/* encoder bandwidth */
+	__s32 reserved[15];
+};
+struct snd_dec_dts {
+	__u32 modelIdLength;
+	__u8 *modelId;
+};
+
+union snd_codec_options {
+	struct snd_enc_wma wma;
+	struct snd_enc_vorbis vorbis;
+	struct snd_enc_real real;
+	struct snd_enc_flac flac;
+	struct snd_enc_generic generic;
+	struct snd_dec_dts dts;
+};
+
+/** struct snd_codec_desc - description of codec capabilities
+ * @max_ch: Maximum number of audio channels
+ * @sample_rates: Sampling rates in Hz, use SNDRV_PCM_RATE_xxx for this
+ * @bit_rate: Indexed array containing supported bit rates
+ * @num_bitrates: Number of valid values in bit_rate array
+ * @rate_control: value is specified by SND_RATECONTROLMODE defines.
+ * @profiles: Supported profiles. See SND_AUDIOPROFILE defines.
+ * @modes: Supported modes. See SND_AUDIOMODE defines
+ * @formats: Supported formats. See SND_AUDIOSTREAMFORMAT defines
+ * @min_buffer: Minimum buffer size handled by codec implementation
+ * @reserved: reserved for future use
+ *
+ * This structure provides a scalar value for profiles, modes and stream
+ * format fields.
+ * If an implementation supports multiple combinations, they will be listed as
+ * codecs with different descriptors, for example there would be 2 descriptors
+ * for AAC-RAW and AAC-ADTS.
+ * This entails some redundancy but makes it easier to avoid invalid
+ * configurations.
+ *
+ */
+
+struct snd_codec_desc {
+	__u32 max_ch;
+	__u32 sample_rates;
+	__u32 bit_rate[MAX_NUM_BITRATES];
+	__u32 num_bitrates;
+	__u32 rate_control;
+	__u32 profiles;
+	__u32 modes;
+	__u32 formats;
+	__u32 min_buffer;
+	__u32 reserved[15];
+};
+
+/** struct snd_codec
+ * @id: Identifies the supported audio encoder/decoder.
+ *		See SND_AUDIOCODEC macros.
+ * @ch_in: Number of input audio channels
+ * @ch_out: Number of output channels. In case of contradiction between
+ *		this field and the channelMode field, the channelMode field
+ *		overrides.
+ * @sample_rate: Audio sample rate of input data
+ * @bit_rate: Bitrate of encoded data. May be ignored by decoders
+ * @rate_control: Encoding rate control. See SND_RATECONTROLMODE defines.
+ *               Encoders may rely on profiles for quality levels.
+ *		 May be ignored by decoders.
+ * @profile: Mandatory for encoders, can be mandatory for specific
+ *		decoders as well. See SND_AUDIOPROFILE defines.
+ * @level: Supported level (Only used by WMA at the moment)
+ * @ch_mode: Channel mode for encoder. See SND_AUDIOCHANMODE defines
+ * @format: Format of encoded bistream. Mandatory when defined.
+ *		See SND_AUDIOSTREAMFORMAT defines.
+ * @align: Block alignment in bytes of an audio sample.
+ *		Only required for PCM or IEC formats.
+ * @options: encoder-specific settings
+ * @reserved: reserved for future use
+ */
+
+struct snd_codec {
+	__u32 id;
+	__u32 ch_in;
+	__u32 ch_out;
+	__u32 sample_rate;
+	__u32 bit_rate;
+	__u32 rate_control;
+	__u32 profile;
+	__u32 level;
+	__u32 ch_mode;
+	__u32 format;
+	__u32 align;
+	__u32 transcode_dts;
+	struct snd_dec_dts dts;
+	union snd_codec_options options;
+	__u32 reserved[3];
+};
+
+
+
+#define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 1, 0)
+/**
+ * struct snd_compressed_buffer: compressed buffer
+ * @fragment_size: size of buffer fragment in bytes
+ * @fragments: number of such fragments
+ */
+struct snd_compressed_buffer {
+	__u32 fragment_size;
+	__u32 fragments;
+};
+
+/**
+ * struct snd_compr_params: compressed stream params
+ * @buffer: buffer description
+ * @codec: codec parameters
+ * @no_wake_mode: dont wake on fragment elapsed
+ */
+struct snd_compr_params {
+	struct snd_compressed_buffer buffer;
+	struct snd_codec codec;
+	__u8 no_wake_mode;
+};
+
+/**
+ * struct snd_compr_tstamp: timestamp descriptor
+ * @byte_offset: Byte offset in ring buffer to DSP
+ * @copied_total: Total number of bytes copied from/to ring buffer to/by DSP
+ * @pcm_frames: Frames decoded or encoded by DSP. This field will evolve by
+ *	large steps and should only be used to monitor encoding/decoding
+ *	progress. It shall not be used for timing estimates.
+ * @pcm_io_frames: Frames rendered or received by DSP into a mixer or an audio
+ * output/input. This field should be used for A/V sync or time estimates.
+ * @sampling_rate: sampling rate of audio
+ */
+struct snd_compr_tstamp {
+	__u32 byte_offset;
+	__u32 copied_total;
+	snd_pcm_uframes_t pcm_frames;
+	snd_pcm_uframes_t pcm_io_frames;
+	__u32 sampling_rate;
+	uint64_t timestamp;
+};
+
+/**
+ * struct snd_compr_avail: avail descriptor
+ * @avail: Number of bytes available in ring buffer for writing/reading
+ * @tstamp: timestamp infomation
+ */
+struct snd_compr_avail {
+	__u64 avail;
+	struct snd_compr_tstamp tstamp;
+};
+
+enum snd_compr_direction {
+	SND_COMPRESS_PLAYBACK = 0,
+	SND_COMPRESS_CAPTURE
+};
+
+/**
+ * struct snd_compr_caps: caps descriptor
+ * @codecs: pointer to array of codecs
+ * @direction: direction supported. Of type snd_compr_direction
+ * @min_fragment_size: minimum fragment supported by DSP
+ * @max_fragment_size: maximum fragment supported by DSP
+ * @min_fragments: min fragments supported by DSP
+ * @max_fragments: max fragments supported by DSP
+ * @num_codecs: number of codecs supported
+ * @reserved: reserved field
+ */
+struct snd_compr_caps {
+	__u32 num_codecs;
+	__u32 direction;
+	__u32 min_fragment_size;
+	__u32 max_fragment_size;
+	__u32 min_fragments;
+	__u32 max_fragments;
+	__u32 codecs[MAX_NUM_CODECS];
+	__u32 reserved[11];
+};
+
+/**
+ * struct snd_compr_codec_caps: query capability of codec
+ * @codec: codec for which capability is queried
+ * @num_descriptors: number of codec descriptors
+ * @descriptor: array of codec capability descriptor
+ */
+struct snd_compr_codec_caps {
+	__u32 codec;
+	__u32 num_descriptors;
+	struct snd_codec_desc descriptor[MAX_NUM_CODEC_DESCRIPTORS];
+};
+
+/**
+ * struct snd_compr_audio_info: compressed input audio information
+ * @frame_size: legth of the encoded frame with valid data
+ * @reserved: reserved for furture use
+ */
+struct snd_compr_audio_info {
+	uint32_t frame_size;
+	uint32_t reserved[15];
+};
+
+/**
+ * compress path ioctl definitions
+ * SNDRV_COMPRESS_GET_CAPS: Query capability of DSP
+ * SNDRV_COMPRESS_GET_CODEC_CAPS: Query capability of a codec
+ * SNDRV_COMPRESS_SET_PARAMS: Set codec and stream parameters
+ * Note: only codec params can be changed runtime and stream params cant be
+ * SNDRV_COMPRESS_GET_PARAMS: Query codec params
+ * SNDRV_COMPRESS_TSTAMP: get the current timestamp value
+ * SNDRV_COMPRESS_AVAIL: get the current buffer avail value.
+ * This also queries the tstamp properties
+ * SNDRV_COMPRESS_PAUSE: Pause the running stream
+ * SNDRV_COMPRESS_RESUME: resume a paused stream
+ * SNDRV_COMPRESS_START: Start a stream
+ * SNDRV_COMPRESS_STOP: stop a running stream, discarding ring buffer content
+ * and the buffers currently with DSP
+ * SNDRV_COMPRESS_DRAIN: Play till end of buffers and stop after that
+ * SNDRV_COMPRESS_IOCTL_VERSION: Query the API version
+ */
+#define SNDRV_COMPRESS_GET_CAPS         _IOWR('C', 0x00, struct snd_compr_caps *)
+#define SNDRV_COMPRESS_GET_CODEC_CAPS   _IOWR('C', 0x01, struct snd_compr_codec_caps *)
+#define SNDRV_COMPRESS_SET_PARAMS       _IOW('C', 0x02, struct snd_compr_params *)
+#define SNDRV_COMPRESS_GET_PARAMS       _IOR('C', 0x03, struct snd_compr_params *)
+#define SNDRV_COMPRESS_TSTAMP           _IOR('C', 0x10, struct snd_compr_tstamp *)
+#define SNDRV_COMPRESS_AVAIL            _IOR('C', 0x11, struct snd_compr_avail *)
+#define SNDRV_COMPRESS_PAUSE            _IO('C', 0x20)
+#define SNDRV_COMPRESS_RESUME           _IO('C', 0x21)
+#define SNDRV_COMPRESS_START            _IO('C', 0x22)
+#define SNDRV_COMPRESS_STOP             _IO('C', 0x23)
+#define SNDRV_COMPRESS_DRAIN            _IO('C', 0x24)
+/*
+ * TODO
+ * 1. add mmap support
+ *
+ */
+#define SND_COMPR_TRIGGER_DRAIN 7 /*FIXME move this to pcm.h */
+
+#endif
+
 #endif
diff --git a/libalsa-intf/alsa_mixer.c b/libalsa-intf/alsa_mixer.c
index 7bf6557..5fd1839 100644
--- a/libalsa-intf/alsa_mixer.c
+++ b/libalsa-intf/alsa_mixer.c
@@ -128,6 +128,10 @@
 {
     unsigned n,m;
 
+    if (!mixer) {
+         ALOGE("mixer_close:Invalid Mixer Control");
+         return;
+    }
     if (mixer->fd >= 0)
         close(mixer->fd);
 
diff --git a/libalsa-intf/alsa_pcm.c b/libalsa-intf/alsa_pcm.c
index a844eb6..8dd873f 100644
--- a/libalsa-intf/alsa_pcm.c
+++ b/libalsa-intf/alsa_pcm.c
@@ -43,7 +43,9 @@
 #include <sys/poll.h>
 #include <linux/ioctl.h>
 #include <linux/types.h>
+#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
 #include <sound/compress_params.h>
+#endif
 #include "alsa_audio.h"
 
 #define __force
@@ -467,9 +469,26 @@
      }
 }
 
+void appl_pt_forward(struct pcm *pcm)
+{
+	struct snd_pcm_sync_ptr *sync_ptr = pcm->sync_ptr;
+	snd_pcm_uframes_t appl_ptr = sync_ptr->c.control.appl_ptr;
+
+	if (appl_ptr >= pcm->sw_p->boundary) {
+		appl_ptr -= pcm->sw_p->boundary;
+		ALOGE("appl_ptr %ld set to ld",
+			sync_ptr->c.control.appl_ptr, appl_ptr);
+		sync_ptr->c.control.appl_ptr = appl_ptr;
+	}
+}
+
 int sync_ptr(struct pcm *pcm)
 {
     int err;
+
+    if (pcm->flags & PCM_MMAP)
+        appl_pt_forward(pcm);
+
     err = ioctl(pcm->fd, SNDRV_PCM_IOCTL_SYNC_PTR, pcm->sync_ptr);
     if (err < 0) {
         err = errno;
diff --git a/libalsa-intf/alsa_ucm.c b/libalsa-intf/alsa_ucm.c
index bcd0b1b..cafd154 100644
--- a/libalsa-intf/alsa_ucm.c
+++ b/libalsa-intf/alsa_ucm.c
@@ -50,6 +50,7 @@
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
+#include <dlfcn.h>
 #include <pthread.h>
 #include <ctype.h>
 #include <sys/stat.h>
@@ -61,13 +62,9 @@
 
 #include <linux/ioctl.h>
 #include "msm8960_use_cases.h"
-#if defined(QC_PROP)
-    #include "acdb-loader.h"
-#else
-    #define acdb_loader_send_voice_cal(rxacdb_id, txacdb_id) (-EPERM)
-    #define acdb_loader_send_audio_cal(acdb_id, capability) (-EPERM)
-    #define acdb_loader_send_anc_cal(acdb_id) (-EPERM)
-#endif
+    static void (*acdb_send_voice_cal)(int, int);
+    static void (*acdb_send_audio_cal)(int, int);
+    static void (*acdb_send_anc_cal)(int);
 #define PARSE_DEBUG 0
 
 /**
@@ -816,10 +813,18 @@
                           strlen(SND_USE_CASE_VERB_IP_VOICECALL)) ||
                           (!strncmp(current_mod, SND_USE_CASE_MOD_PLAY_VOIP,
                            strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) ||
-                          (!uc_mgr->isFusion3Platform))
-                           acdb_loader_send_voice_cal(uc_mgr->current_rx_device,
-                                                    uc_mgr->current_tx_device);
-             }
+                          (!uc_mgr->isFusion3Platform)) {
+                        if (uc_mgr->acdb_handle) {
+                            acdb_send_voice_cal = dlsym(uc_mgr->acdb_handle,"acdb_loader_send_voice_cal");
+                            if (acdb_send_voice_cal == NULL) {
+                                ALOGE("Voice acdb: dlsym: Error:%s Loading acdb_loader_send_voice_cal", dlerror());
+                            } else {
+                                acdb_send_voice_cal(uc_mgr->current_rx_device,
+                                        uc_mgr->current_tx_device);
+                            }
+                        }
+                    }
+            }
             free(ident_value);
             ident_value = NULL;
         }
@@ -936,9 +941,15 @@
                     ALOGD("acdb_id %d cap %d enable %d",
                                         ctrl_list[uc_index].acdb_id,
                             ctrl_list[uc_index].capability, enable);
-                    acdb_loader_send_audio_cal(
-                            ctrl_list[uc_index].acdb_id,
-                            ctrl_list[uc_index].capability);
+                    if (uc_mgr->acdb_handle) {
+                        acdb_send_audio_cal = dlsym(uc_mgr->acdb_handle,"acdb_loader_send_audio_cal");
+                        if (acdb_send_audio_cal == NULL) {
+                            ALOGE("dlsym: Error:%s Loading acdb_loader_send_audio_cal", dlerror());
+                        } else {
+                            acdb_send_audio_cal(ctrl_list[uc_index].acdb_id,
+                                    ctrl_list[uc_index].capability);
+                        }
+                    }
                 }
             }
             if (enable) {
diff --git a/libalsa-intf/alsa_ucm.h b/libalsa-intf/alsa_ucm.h
index a72ca27..ef64074 100644
--- a/libalsa-intf/alsa_ucm.h
+++ b/libalsa-intf/alsa_ucm.h
@@ -124,6 +124,7 @@
 #define SND_USE_CASE_DEV_EARPIECE	"Earpiece"
 #define SND_USE_CASE_DEV_SPDIF		"SPDIF"
 #define SND_USE_CASE_DEV_HDMI		"HDMI"
+#define SND_USE_CASE_DEV_DOCK		"Dock"
 /* add new devices to end of list */
 
 
diff --git a/libalsa-intf/aplay.c b/libalsa-intf/aplay.c
index e82582c..4a3897f 100644
--- a/libalsa-intf/aplay.c
+++ b/libalsa-intf/aplay.c
@@ -27,8 +27,10 @@
 #include <getopt.h>
 
 #include <sound/asound.h>
+#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
 #include <sound/compress_params.h>
 #include <sound/compress_offload.h>
+#endif
 #include "alsa_audio.h"
 
 #ifndef ANDROID
diff --git a/libalsa-intf/arec.c b/libalsa-intf/arec.c
index edd4af4..a941545 100644
--- a/libalsa-intf/arec.c
+++ b/libalsa-intf/arec.c
@@ -29,8 +29,10 @@
 #include <limits.h>
 
 #include <sound/asound.h>
+#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
 #include <sound/compress_params.h>
 #include <sound/compress_offload.h>
+#endif
 
 #include "alsa_audio.h"
 
diff --git a/libalsa-intf/msm8960_use_cases.h b/libalsa-intf/msm8960_use_cases.h
index cdaba86..2d18f15 100644
--- a/libalsa-intf/msm8960_use_cases.h
+++ b/libalsa-intf/msm8960_use_cases.h
@@ -175,6 +175,7 @@
     card_ctxt_t *card_ctxt_ptr;
     pthread_t thr;
     bool isFusion3Platform;
+    void *acdb_handle;
 };
 
 #define MAX_NUM_CARDS (sizeof(card_list)/sizeof(char *))
@@ -296,7 +297,9 @@
 #define SND_USE_CASE_DEV_PROXY_RX_SPEAKER_ANC_HEADSET "PROXY Rx Speaker ANC Headset"
 #define SND_USE_CASE_DEV_CAMCORDER_TX       "Camcorder Tx"
 #define SND_USE_CASE_DEV_VOICE_RECOGNITION  "Voice Recognition"
+#define SND_USE_CASE_DEV_VOICE_RECOGNITION_HEADSET  "Voice Recognition Headset"
 #define SND_USE_CASE_DEV_VOC_EARPIECE       "Voice Earpiece"
+#define SND_USE_CASE_DEV_VOC_EARPIECE_XGAIN "Voice Earpiece Extra Gain"
 #define SND_USE_CASE_DEV_VOC_HEADPHONE      "Voice Headphones"
 #define SND_USE_CASE_DEV_VOC_HEADSET        "Voice Headset"
 #define SND_USE_CASE_DEV_VOC_ANC_HEADSET    "Voice ANC Headset"
@@ -304,6 +307,12 @@
 #define SND_USE_CASE_DEV_VOC_LINE           "Voice Line"
 #define SND_USE_CASE_DEV_AANC_LINE          "AANC Line"
 #define SND_USE_CASE_DEV_AANC_DMIC_ENDFIRE  "AANC DMIC Endfire"
+#define SND_USE_CASE_DEV_VOIP_EARPIECE      "VOIP Earpiece"
+#define SND_USE_CASE_DEV_VOIP_HEADPHONE     "VOIP Headphones"
+#define SND_USE_CASE_DEV_VOIP_HEADSET       "VOIP Headset"
+#define SND_USE_CASE_DEV_VOIP_SPEAKER       "VOIP Speaker"
+#define SND_USE_CASE_DEV_VOIP_LINE          "VOIP Line"
+#define SND_USE_CASE_DEV_VOIP_HANDSET       "VOIP Handset"
 
 #define SND_USE_CASE_MOD_PLAY_FM         "Play FM"
 #define SND_USE_CASE_MOD_CAPTURE_FM      "Capture FM"
diff --git a/mm-audio/aenc-aac/qdsp6/Android.mk b/mm-audio/aenc-aac/qdsp6/Android.mk
index e339f5d..9e26367 100755
--- a/mm-audio/aenc-aac/qdsp6/Android.mk
+++ b/mm-audio/aenc-aac/qdsp6/Android.mk
@@ -12,7 +12,6 @@
 libOmxAacEnc-def += -D_ANDROID_
 libOmxAacEnc-def += -D_ENABLE_QC_MSG_LOG_
 libOmxAacEnc-def += -DVERBOSE
-libOmxAacEnc-def += -D_DEBUG
 ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true)
 libOmxAacEnc-def += -DAUDIOV2
 endif
diff --git a/mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h b/mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h
index 72bfebe..7b5006f 100755
--- a/mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h
+++ b/mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h
@@ -60,7 +60,11 @@
 #endif
 
 #define DEBUG_PRINT_ERROR LOGE
+#ifdef _DEBUG
 #define DEBUG_PRINT       LOGI
+#else
+#define DEBUG_PRINT       LOGV
+#endif
 #define DEBUG_DETAIL      LOGV
 
 typedef void (*message_func)(void* client_data, unsigned char id);
diff --git a/msm7x30/Android.mk b/msm7x30/Android.mk
new file mode 100644
index 0000000..a98548f
--- /dev/null
+++ b/msm7x30/Android.mk
@@ -0,0 +1,122 @@
+#AUDIO_POLICY_TEST := true
+#ENABLE_AUDIO_DUMP := true
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+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_USES_QCOM_AUDIO_LPA),true)
+    LOCAL_CFLAGS += -DQCOM_TUNNEL_LPA_ENABLED
+endif
+
+ifeq ($(BOARD_USES_QCOM_AUDIO_SPEECH),true)
+    LOCAL_CFLAGS += -DWITH_QCOM_SPEECH
+endif
+
+ifeq ($(BOARD_USES_QCOM_AUDIO_VOIPMUTE),true)
+    LOCAL_CFLAGS += -DWITH_QCOM_VOIPMUTE
+endif
+
+ifeq ($(BOARD_USES_QCOM_AUDIO_RESETALL),true)
+    LOCAL_CFLAGS += -DWITH_QCOM_RESETALL
+endif
+
+ifeq ($(BOARD_USES_STEREO_HW_SPEAKER),true)
+    LOCAL_CFLAGS += -DWITH_STEREO_HW_SPEAKER
+endif
+
+ifeq ($(BOARD_HAVE_HTC_AUDIO),true)
+    LOCAL_CFLAGS += -DHTC_AUDIO
+endif
+
+ifeq ($(BOARD_HAVE_SAMSUNG_AUDIO),true)
+    LOCAL_CFLAGS += -DSAMSUNG_AUDIO
+endif
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils       \
+    libutils        \
+    libmedia        \
+    libaudioalsa
+
+# hack for prebuilt
+$(shell mkdir -p $(OUT)/obj/SHARED_LIBRARIES/libaudioalsa_intermediates/)
+$(shell touch $(OUT)/obj/SHARED_LIBRARIES/libaudioalsa_intermediates/export_includes)
+
+ifeq ($(BOARD_USES_QCOM_AUDIO_CALIBRATION),true)
+    LOCAL_SHARED_LIBRARIES += libaudcal
+    LOCAL_CFLAGS += -DWITH_QCOM_CALIBRATION
+endif
+
+ifneq ($(TARGET_SIMULATOR),true)
+    LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_STATIC_LIBRARIES := \
+    libmedia_helper \
+    libaudiohw_legacy
+
+LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM)
+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
+ifeq ($(BOARD_USES_QCOM_AUDIO_CALIBRATION),true)
+    LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audcal
+endif
+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
+
+ifneq ($(TARGET_KERNEL_SOURCE),)
+    LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+    LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+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 := \
+    libmedia_helper \
+    libaudiopolicy_legacy
+
+LOCAL_MODULE := audio_policy.$(TARGET_BOARD_PLATFORM)
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_TAGS := optional
+
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+    LOCAL_CFLAGS += -DWITH_A2DP
+endif
+
+ifeq ($(BOARD_USES_QCOM_AUDIO_LPA),true)
+    LOCAL_CFLAGS += -DQCOM_TUNNEL_LPA_ENABLED
+endif
+
+LOCAL_C_INCLUDES := hardware/libhardware_legacy/audio
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/msm7x30/AudioHardware.cpp b/msm7x30/AudioHardware.cpp
new file mode 100644
index 0000000..2b4d522
--- /dev/null
+++ b/msm7x30/AudioHardware.cpp
@@ -0,0 +1,5163 @@
+/*
+** Copyright 2008, The Android Open-Source Project
+** Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+** Copyright (c) 2011-2013, The CyanogenMod Project
+** Not a Contribution, Apache license notifications and license are retained
+** for attribution purposes only.
+**
+** 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_TAG "AudioHardware7x30"
+//#define LOG_NDDEBUG 0
+#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 <cutils/properties.h>
+#include <media/AudioSystem.h>
+
+#include "control.h"
+extern "C" {
+#include "initialize_audcal7x30.h"
+#ifdef HTC_AUDIO
+#include <linux/spi_aic3254.h>
+#include <linux/tpa2051d3.h>
+#endif
+}
+// hardware specific functions
+
+#include "AudioHardware.h"
+//#include <media/AudioSystem.h>
+//#include <media/AudioRecord.h>
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+#include <linux/msm_audio_mvs.h>
+#endif
+
+#define LOG_SND_RPC 0  // Set to 1 to log sound RPC's
+
+#define ECHO_SUPRESSION "ec_supported"
+
+#define DUALMIC_KEY "dualmic_enabled"
+#define TTY_MODE_KEY "tty_mode"
+#define BTHEADSET_VGS "bt_headset_vgs"
+#ifdef HTC_AUDIO
+#define DSP_EFFECT_KEY "dolby_srs_eq"
+#endif
+#define AMRNB_DEVICE_IN "/dev/msm_amrnb_in"
+#define EVRC_DEVICE_IN "/dev/msm_evrc_in"
+#define QCELP_DEVICE_IN "/dev/msm_qcelp_in"
+#define AAC_DEVICE_IN "/dev/msm_aac_in"
+#ifdef QCOM_FM_ENABLED
+#define FM_DEVICE  "/dev/msm_fm"
+#define FM_A2DP_REC 1
+#define FM_FILE_REC 2
+#endif
+
+#define MVS_DEVICE "/dev/msm_mvs"
+
+#define AMRNB_FRAME_SIZE 32
+#define EVRC_FRAME_SIZE 23
+#define QCELP_FRAME_SIZE 35
+
+
+
+namespace android_audio_legacy {
+//using android_audio_legacy::AudioSystem;
+//using android_audio_legacy::AudioHardwareInterface;
+
+Mutex   mDeviceSwitchLock;
+#ifdef HTC_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_FM_TX = 16;
+static const uint32_t SND_DEVICE_FM_TX_AND_SPEAKER = 17;
+static const uint32_t SND_DEVICE_HEADPHONE_AND_SPEAKER = 18;
+#ifdef HTC_AUDIO
+static const uint32_t SND_DEVICE_CARKIT = 19;
+static const uint32_t SND_DEVICE_HANDSET_BACK_MIC = 20;
+static const uint32_t SND_DEVICE_SPEAKER_BACK_MIC = 21;
+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_CARKIT = -1;
+static const uint32_t SND_DEVICE_BT_EC_OFF = -1;
+#endif
+#ifdef SAMSUNG_AUDIO
+static const uint32_t SND_DEVICE_VOIP_HANDSET = 50;
+static const uint32_t SND_DEVICE_VOIP_SPEAKER = 51;
+static const uint32_t SND_DEVICE_VOIP_HEADSET = 52;
+static const uint32_t SND_DEVICE_CALL_HANDSET = 60;
+static const uint32_t SND_DEVICE_CALL_SPEAKER = 61;
+static const uint32_t SND_DEVICE_CALL_HEADSET = 62;
+#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;           /* caf: speaker_stereo_rx
+                                                          htc: speaker_mono_rx
+                                                          sam: speaker_rx */
+static const uint32_t DEVICE_SPEAKER_TX = 3;           /* caf: speaker_mono_tx
+                                                          sam: speaker_tx */
+static const uint32_t DEVICE_HEADSET_RX = 4;           /* caf: headset_stereo_rx
+                                                          sam: headset_rx */
+static const uint32_t DEVICE_HEADSET_TX = 5;           /* caf: headset_mono_tx
+                                                          sam: headset_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;  /* caf: headset_stereo_speaker_stereo_rx
+                                                          htc: headset_speaker_stereo_rx
+                                                          sam: speaker_headset_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_FMRADIO_STEREO_RX = 16;
+static const uint32_t DEVICE_BT_SCO_RX = 17;           /* bt_sco_rx */
+static const uint32_t DEVICE_BT_SCO_TX = 18;           /* bt_sco_tx */
+#if defined(SAMSUNG_AUDIO)
+static const uint32_t DEVICE_HANDSET_VOIP_RX = 40;     /* handset_voip_rx */
+static const uint32_t DEVICE_HANDSET_VOIP_TX = 41;     /* handset_voip_tx */
+static const uint32_t DEVICE_SPEAKER_VOIP_RX = 42;     /* speaker_voip_rx */
+static const uint32_t DEVICE_SPEAKER_VOIP_TX = 43;     /* speaker_voip_tx */
+static const uint32_t DEVICE_HEADSET_VOIP_RX = 44;     /* headset_voip_rx */
+static const uint32_t DEVICE_HEADSET_VOIP_TX = 45;     /* headset_voip_tx */
+static const uint32_t DEVICE_HANDSET_CALL_RX = 60;     /* handset_call_rx */
+static const uint32_t DEVICE_HANDSET_CALL_TX = 61;     /* handset_call_tx */
+static const uint32_t DEVICE_SPEAKER_CALL_RX = 62;     /* speaker_call_rx */
+static const uint32_t DEVICE_SPEAKER_CALL_TX = 63;     /* speaker_call_tx */
+static const uint32_t DEVICE_HEADSET_CALL_RX = 64;     /* headset_call_rx */
+static const uint32_t DEVICE_HEADSET_CALL_TX = 65;     /* headset_call_tx */
+static const uint32_t DEVICE_COUNT = DEVICE_HEADSET_CALL_TX +1;
+#elif defined(HTC_AUDIO)
+static const uint32_t DEVICE_USB_HEADSET_RX = 19;      /* usb_headset_stereo_rx */
+static const uint32_t DEVICE_HAC_RX = 20;              /* hac_mono_rx */
+static const uint32_t DEVICE_ALT_RX = 21;              /* alt_mono_rx */
+static const uint32_t DEVICE_VR_HANDSET = 22;          /* handset_vr_tx */
+static const uint32_t DEVICE_COUNT = DEVICE_VR_HANDSET +1;
+#else
+static uint32_t DEVICE_COUNT = DEVICE_BT_SCO_TX +1;
+#endif
+
+#ifdef HTC_AUDIO
+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
+
+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;
+bool vMicMute = false;
+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 class_id;
+    int capability;
+}Device_table;
+Device_table* device_list;
+
+static unsigned char build_id[20];
+
+static void amr_transcode(unsigned char *src, unsigned char *dst);
+
+enum STREAM_TYPES {
+PCM_PLAY=1,
+PCM_REC,
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+LPA_DECODE,
+#endif
+VOICE_CALL,
+#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 DEV_ID(X) device_list[X].dev_id
+void addToTable(int decoder_id,int device_id,int device_id_tx,int stream_type,bool active) {
+    Routing_table* temp_ptr;
+    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;
+    //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;
+            return;
+        }
+        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;
+            return;
+        }
+        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;
+    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;
+}
+
+int enableDevice(int device,short enable) {
+    ALOGV("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;
+}
+
+#ifdef HTC_AUDIO
+void updateACDB(uint32_t new_rx_device, uint32_t new_tx_device,
+                uint32_t new_rx_acdb, uint32_t new_tx_acdb) {
+
+    ALOGD("updateACDB: (%d, %d, %d, %d) ", new_tx_device, new_rx_device, new_tx_acdb, new_rx_acdb);
+
+    int rc = -1;
+    int (*update_acdb_id)(uint32_t, uint32_t, uint32_t, uint32_t);
+
+    update_acdb_id = (int (*)(uint32_t, uint32_t, uint32_t, uint32_t))::dlsym(acoustic, "update_acdb_id");
+    if ((*update_acdb_id) == 0)
+        ALOGE("Could not open update_acdb_id()");
+    else {
+        rc = update_acdb_id(new_tx_device, new_rx_device, new_tx_acdb, new_rx_acdb);
+        if (rc < 0)
+            ALOGE("Could not set update_acdb_id: %d", rc);
+    }
+}
+
+static status_t updateDeviceInfo(int rx_device,int tx_device,
+                                 uint32_t rx_acdb_id, uint32_t tx_acdb_id) {
+#else
+static status_t updateDeviceInfo(int rx_device,int tx_device) {
+#endif
+    ALOGV("updateDeviceInfo: E rx_device %d and tx_device %d", rx_device, tx_device);
+    bool isRxDeviceEnabled = false,isTxDeviceEnabled = false;
+    Routing_table *temp_ptr,*temp_head;
+    int tx_dev_prev = INVALID_DEVICE;
+    temp_head = head;
+    Mutex::Autolock lock(mDeviceSwitchLock);
+
+    if (!getNodeByStreamType(VOICE_CALL) && !getNodeByStreamType(PCM_PLAY)
+#ifdef QCOM_FM_ENABLED
+        && !getNodeByStreamType(FM_RADIO)
+#endif
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+        && !getNodeByStreamType(LPA_DECODE)
+#endif
+       ) {
+        ALOGV("No active voicecall/playback, disabling cur_rx %d", cur_rx);
+        if(cur_rx != INVALID_DEVICE && enableDevice(cur_rx, 0)) {
+            ALOGE("Disabling device failed for cur_rx %d", cur_rx);
+        }
+        cur_rx = rx_device;
+    }
+
+    if(!getNodeByStreamType(VOICE_CALL) && !getNodeByStreamType(PCM_REC)) {
+        ALOGV("No active voicecall/recording, disabling cur_tx %d", cur_tx);
+        if(cur_tx != INVALID_DEVICE && enableDevice(cur_tx, 0)) {
+            ALOGE("Disabling device failed for cur_tx %d", cur_tx);
+        }
+        cur_tx = tx_device;
+    }
+    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:
+#endif
+                ALOGD("The node type is %d and cur device %d new device %d ", temp_ptr->stream_type, temp_ptr->dev_id, rx_device);
+                if(rx_device == INVALID_DEVICE)
+                    return -1;
+                if(rx_device == temp_ptr->dev_id)
+                    break;
+                ALOGV("rx_device = %d,temp_ptr->dev_id = %d",rx_device,temp_ptr->dev_id);
+                if(isRxDeviceEnabled == false) {
+                    enableDevice(temp_ptr->dev_id,0);
+                    enableDevice(rx_device,1);
+                    isRxDeviceEnabled = true;
+                }
+                if(msm_route_stream(PCM_PLAY,temp_ptr->dec_id,DEV_ID(temp_ptr->dev_id),0)) {
+                    ALOGE("msm_route_stream(PCM_PLAY,%d,%d,0) failed",temp_ptr->dec_id,DEV_ID(temp_ptr->dev_id));
+                }
+                if(msm_route_stream(PCM_PLAY,temp_ptr->dec_id,DEV_ID(rx_device),1)) {
+                    ALOGE("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:
+
+                ALOGD("case PCM_REC");
+                if(tx_device == INVALID_DEVICE)
+                    return -1;
+                if(tx_device == temp_ptr->dev_id)
+                    break;
+
+                if(isTxDeviceEnabled == false) {
+                    enableDevice(temp_ptr->dev_id,0);
+                    enableDevice(tx_device,1);
+                   isTxDeviceEnabled = true;
+                }
+                if(msm_route_stream(PCM_REC,temp_ptr->dec_id,DEV_ID(temp_ptr->dev_id),0)) {
+                    ALOGE("msm_route_stream(PCM_REC,%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)) {
+                    ALOGE("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 ;
+#ifdef WITH_QCOM_VOIPMUTE
+                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);
+                }
+#endif
+                break;
+            case VOICE_CALL:
+
+                ALOGD("case VOICE_CALL");
+                if(rx_device == INVALID_DEVICE || tx_device == INVALID_DEVICE)
+                    return -1;
+                if(rx_device == temp_ptr->dev_id && tx_device == temp_ptr->dev_id_tx)
+                    break;
+
+#ifdef HTC_AUDIO
+                updateACDB(rx_device, tx_device, rx_acdb_id, tx_acdb_id);
+#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(VOICE_CALL,cur_rx,cur_tx);
+                break;
+            default:
+                break;
+        }
+        temp_head = temp_head->next;
+    }
+
+    ALOGV("updateDeviceInfo: X cur_rx %d cur_tx %d", cur_rx, cur_tx);
+    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), mFmFd(-1), mBluetoothNrec(true),
+    mBluetoothVGS(false), mBluetoothId(0), mVoiceVolume(1), mOutput(0),
+    mCurSndDevice(SND_DEVICE_CURRENT), mDualMicEnabled(false), mTtyMode(TTY_OFF)
+#ifdef HTC_AUDIO
+    , mHACSetting(false), mBluetoothIdTx(0), mBluetoothIdRx(0),
+    mRecordState(false), mEffectEnabled(false)
+#endif
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+    , mVoipFd(-1), mVoipInActive(false), mVoipOutActive(false), mDirectOutput(0)
+#endif
+{
+#ifdef HTC_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
+
+        int control;
+        int i = 0,index = 0;
+
+        head = (Routing_table* ) malloc(sizeof(Routing_table));
+        head->next = NULL;
+
+#ifdef HTC_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");
+
+        if((fp = fopen("/sys/devices/system/soc/soc0/build_id","r")) == NULL) {
+            ALOGE("Cannot open build_id file.");
+        }
+        else {
+            (void)fgets((char *)build_id,sizeof(build_id),fp);
+        }
+
+#ifdef WITH_QCOM_RESETALL
+        if(msm_reset_all_device() < 0)
+            ALOGE("msm_reset_all_device() failed");
+#endif
+
+        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;
+        }
+        name = msm_get_device_list();
+        device_list = (Device_table* )malloc(sizeof(Device_table)*DEVICE_COUNT);
+        if(device_list == NULL) {
+            ALOGE("malloc failed for device list");
+            return;
+        }
+        for(i = 0;i<DEVICE_COUNT;i++)
+            device_list[i].dev_id = INVALID_DEVICE;
+
+        for(i = 0; i < dev_cnt;i++) {
+            ALOGI("******* name[%d] = [%s] *********", i, (char* )name[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) ||
+#ifndef WITH_STEREO_HW_SPEAKER
+                    (strcmp((char* )name[i],"speaker_mono_rx") == 0) ||
+#endif
+                    (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)
+                index = DEVICE_FMRADIO_HEADSET_RX;
+            else if(strcmp((char* )name[i],"fmradio_speaker_rx") == 0)
+                index = DEVICE_FMRADIO_SPEAKER_RX;
+            else if(strcmp((char* )name[i],"handset_dual_mic_endfire_tx") == 0)
+                index = DEVICE_DUALMIC_HANDSET_TX;
+            else if(strcmp((char* )name[i],"speaker_dual_mic_endfire_tx") == 0)
+                index = DEVICE_DUALMIC_SPEAKER_TX;
+            else if(strcmp((char* )name[i],"tty_headset_mono_rx") == 0)
+                index = DEVICE_TTY_HEADSET_MONO_RX;
+            else if(strcmp((char* )name[i],"tty_headset_mono_tx") == 0)
+                index = DEVICE_TTY_HEADSET_MONO_TX;
+            else if(strcmp((char* )name[i],"bt_sco_rx") == 0)
+                index = DEVICE_BT_SCO_RX;
+            else if(strcmp((char* )name[i],"bt_sco_tx") == 0)
+                index = DEVICE_BT_SCO_TX;
+            else if((strcmp((char*)name[i],"headset_stereo_speaker_stereo_rx") == 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)
+                index = DEVICE_FMRADIO_STEREO_TX;
+            else if(strcmp((char*)name[i],"hdmi_stereo_rx") == 0)
+                index = DEVICE_HDMI_STERO_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;
+#endif
+            else
+                continue;
+            ALOGV("index = %d",index);
+
+            device_list[index].dev_id = msm_get_device((char* )name[i]);
+            if(device_list[index].dev_id >= 0) {
+                    ALOGV("Found device: %s:index = %d,dev_id: %d",( char* )name[i], index,device_list[index].dev_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);
+            ALOGV("class ID = %d,capablity = %d for device %d",device_list[index].class_id,device_list[index].capability,device_list[index].dev_id);
+        }
+#ifdef WITH_QCOM_CALIBRATION
+        audcal_initialize();
+#endif
+
+        CurrentComboDeviceData.DeviceId = INVALID_DEVICE;
+        CurrentComboDeviceData.StreamType = INVALID_STREAM;
+
+#ifdef HTC_AUDIO
+    // HTC specific functions
+    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);
+    }
+
+    char value[PROPERTY_VALUE_MAX];
+    /* 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();
+    closeOutputStream((AudioStreamOut*)mOutput);
+    if (acoustic) {
+        ::dlclose(acoustic);
+        acoustic = 0;
+    }
+    msm_mixer_close();
+#ifdef WITH_QCOM_CALIBRATION
+    audcal_deinitialize();
+#endif
+    freeMemory();
+    fclose(fp);
+    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)
+
+{
+     ALOGD("AudioHardware::openOutputStream devices %x format %d channels %d samplerate %d",
+        devices, *format, *channels, *sampleRate);
+
+     audio_output_flags_t flags = static_cast<audio_output_flags_t> (*status);
+
+
+    { // scope for the lock
+        Mutex::Autolock lock(mLock);
+
+        // only one output stream allowed
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+        if (mOutput && !(flags & AUDIO_OUTPUT_FLAG_DIRECT) ) {
+#else
+        if (mOutput) {
+#endif
+            if (status) {
+                *status = INVALID_OPERATION;
+            }
+            ALOGE(" AudioHardware::openOutputStream Only one output stream allowed \n");
+            return 0;
+        }
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+        status_t lStatus;
+        if(flags & AUDIO_OUTPUT_FLAG_DIRECT) {
+            if(mDirectOutput == 0) {
+                // open direct output stream
+                ALOGV(" AudioHardware::openOutputStream Direct output stream \n");
+                AudioStreamOutDirect* out = new AudioStreamOutDirect();
+                status_t 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
+        {
+            ALOGV(" AudioHardware::openOutputStream AudioStreamOutMSM72xx 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;
+            }
+
+            // create new output stream
+            AudioStreamOutMSM72xx* out = new AudioStreamOutMSM72xx();
+            lStatus = out->set(this, devices, format, channels, sampleRate);
+            if (status) {
+                *status = lStatus;
+            }
+            if (lStatus == NO_ERROR) {
+                mOutput = out;
+            } else {
+                delete out;
+            }
+            return mOutput;
+         }
+     }
+#else
+        // create new output stream
+        AudioStreamOutMSM72xx* out = new AudioStreamOutMSM72xx();
+        status_t lStatus = out->set(this, devices, format, channels, sampleRate);
+        if (status) {
+            *status = lStatus;
+        }
+        if (lStatus == NO_ERROR) {
+            mOutput = out;
+        } else {
+            delete out;
+        }
+    }
+    return mOutput;
+#endif
+}
+
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+AudioStreamOut* AudioHardware::openOutputSession(
+        uint32_t devices, int *format, status_t *status, int sessionId,
+        uint32_t samplingRate, uint32_t channels)
+{
+    AudioSessionOutMSM7xxx* out;
+    { // scope for the lock
+        Mutex::Autolock lock(mLock);
+
+        // create new output stream
+        out = new AudioSessionOutMSM7xxx();
+        status_t lStatus = out->set(this, devices, format, sessionId);
+        if (status) {
+            *status = lStatus;
+        }
+        if (lStatus != NO_ERROR) {
+            delete out;
+            out = NULL;
+        }
+    }
+    return out;
+}
+#endif /* QCOM_TUNNEL_LPA_ENABLED */
+
+void AudioHardware::closeOutputStream(AudioStreamOut* out) {
+    Mutex::Autolock lock(mLock);
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+    if ((mOutput == 0 && mDirectOutput == 0) || ((mOutput != out) && (mDirectOutput != out))){
+#else
+    if (mOutput == 0 || mOutput != out) {
+#endif
+        ALOGW("Attempt to close invalid output stream");
+    }
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+    else if (mOutput == out) {
+#else
+    else {
+#endif
+        delete mOutput;
+        mOutput = 0;
+    }
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+    else if (mDirectOutput == out){
+        ALOGV(" deleting  mDirectOutput \n");
+        delete mDirectOutput;
+        mDirectOutput = 0;
+    }
+#endif
+}
+
+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
+    ALOGD("AudioHardware::openInputStream devices %x format %d channels %d samplerate %d",
+        devices, *format, *channels, *sampleRate);
+
+    if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) {
+        return 0;
+    }
+
+    mLock.lock();
+
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+    AudioStreamIn *in;
+    if((devices == AudioSystem::DEVICE_IN_COMMUNICATION)&& (*sampleRate == 8000)) {
+        ALOGV("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);
+#else
+        AudioStreamInMSM72xx* in = new AudioStreamInMSM72xx();
+        status_t lStatus = in->set(this, devices, format, channels, sampleRate, acoustic_flags);
+        if (status) {
+            *status = lStatus;
+        }
+        if (lStatus != NO_ERROR) {
+#endif
+        mLock.unlock();
+#ifndef WITH_QCOM_VOIP_OVER_MVS
+        delete in;
+        return 0;
+#else
+        return inVoip;
+    } else {
+        AudioStreamInMSM72xx* in72xx = new AudioStreamInMSM72xx();
+        status_t lStatus = in72xx->set(this, devices, format, channels, sampleRate, acoustic_flags);
+        if (status) {
+            *status = lStatus;
+        }
+        if (lStatus != NO_ERROR) {
+            ALOGE("Error creating Audio stream AudioStreamInMSM72xx \n");
+            mLock.unlock();
+            delete in72xx;
+            return 0;
+        }
+        mInputs.add(in72xx);
+        mLock.unlock();
+        return in72xx;
+#endif
+    }
+#ifndef WITH_QCOM_VOIP_OVER_MVS
+    mInputs.add(in);
+    mLock.unlock();
+
+    return in;
+#endif
+}
+
+void AudioHardware::closeInputStream(AudioStreamIn* in) {
+    Mutex::Autolock lock(mLock);
+
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+    ssize_t index = -1;
+    if((index = mInputs.indexOf((AudioStreamInMSM72xx *)in)) >= 0) {
+        ALOGV("closeInputStream AudioStreamInMSM72xx");
+#else
+    ssize_t index = mInputs.indexOf((AudioStreamInMSM72xx *)in);
+    if (index < 0) {
+        ALOGW("Attempt to close invalid input stream");
+    } else {
+#endif
+        mLock.unlock();
+        delete mInputs[index];
+        mLock.lock();
+        mInputs.removeAt(index);
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+    } else if ((index = mVoipInputs.indexOf((AudioStreamInVoip *)in)) >= 0) {
+        ALOGV("closeInputStream mVoipInputs");
+        mLock.unlock();
+        delete mVoipInputs[index];
+        mLock.lock();
+        mVoipInputs.removeAt(index);
+    } else {
+        ALOGE("Attempt to close invalid input stream");
+#endif
+     }
+}
+
+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)
+{
+    if (mMicMute != state) {
+        mMicMute = state;
+        ALOGD("setMicMute_nosync calling voice mute with the mMicMute %d", mMicMute);
+#ifdef WITH_QCOM_VOIPMUTE
+        if (isStreamOnAndActive(PCM_REC) && (mMode == AudioSystem::MODE_IN_COMMUNICATION)) {
+            vMicMute = state;
+            ALOGD("VOIP Active: vMicMute %d\n", vMicMute);
+            msm_device_mute(DEV_ID(cur_tx), vMicMute);
+        } else {
+#endif
+            ALOGD("setMicMute_nosync:voice_mute\n");
+            msm_set_voice_tx_mute(mMicMute);
+#ifdef WITH_QCOM_VOIPMUTE
+        }
+#endif
+    }
+    return NO_ERROR;
+}
+
+status_t AudioHardware::getMicMute(bool* state)
+{
+    *state = mMicMute;
+    return NO_ERROR;
+}
+
+status_t AudioHardware::setParameters(const String8& keyValuePairs)
+{
+    AudioParameter param = AudioParameter(keyValuePairs);
+    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_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_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") {
+            mDualMicEnabled = true;
+            ALOGI("DualMike feature Enabled");
+        } else {
+            mDualMicEnabled = false;
+            ALOGI("DualMike feature Disabled");
+        }
+        doRouting(NULL);
+    }
+
+    key = String8(TTY_MODE_KEY);
+    if (param.get(key, value) == NO_ERROR) {
+        if (value == "full" || value == "tty_full") {
+            mTtyMode = TTY_FULL;
+        } else if (value == "hco" || value == "tty_hco") {
+            mTtyMode = TTY_HCO;
+        } else if (value == "vco" || value == "tty_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_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(mDualMicEnabled ? "true" : "false");
+        param.add(key, value);
+    }
+    key = String8(BTHEADSET_VGS);
+    if (param.get(key, value) == NO_ERROR) {
+        if(mBluetoothVGS)
+           param.addInt(String8("isVGS"), true);
+    }
+#ifdef WITH_QCOM_SPEECH
+    key = String8("tunneled-input-formats");
+    if ( param.get(key,value) == NO_ERROR ) {
+        param.addInt(String8("AMR"), true );
+        if (build_id[17] != '1') {
+            param.addInt(String8("EVRC"), true );
+            param.addInt(String8("QCELP"), true );
+        }
+    }
+#endif
+
+#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
+
+#ifdef HTC_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) &&
+#ifdef WITH_QCOM_SPEECH
+        (format != AudioSystem::AMR_NB)      &&
+        (format != AudioSystem::EVRC)      &&
+        (format != AudioSystem::QCELP)  &&
+#endif
+        (format != AudioSystem::AAC)){
+        ALOGW("getInputBufferSize bad format: %d", format);
+        return 0;
+    }
+    if (channelCount < 1 || channelCount > 2) {
+        ALOGW("getInputBufferSize bad channel count: %d", channelCount);
+        return 0;
+    }
+
+    if (format == AudioSystem::AAC)
+       return 2048;
+#ifdef WITH_QCOM_SPEECH
+    else if (format == AudioSystem::AMR_NB)
+       return 320*channelCount;
+    else if (format == AudioSystem::EVRC)
+       return 230*channelCount;
+    else if (format == AudioSystem::QCELP)
+       return 350*channelCount;
+#endif
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+    else if (sampleRate == AUDIO_HW_VOIP_SAMPLERATE_8K)
+       return 320*channelCount;
+    else if (sampleRate == AUDIO_HW_VOIP_SAMPLERATE_16K)
+       return 640*channelCount;
+#endif
+    else
+    {
+        if (build_id[17] == '1') {
+            /*
+            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;
+        }
+        else {
+           return 2048*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)
+{
+    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;
+    }
+
+    mVoiceVolume = v;
+
+    int vol = lrint(v * 100.0);
+    ALOGD("setVoiceVolume(%f)\n", v);
+    ALOGI("Setting in-call volume to %d (available range is 0 to 100)\n", vol);
+
+    if(msm_set_voice_rx_vol(vol)) {
+        ALOGE("msm_set_voice_rx_vol(%d) failed errno = %d",vol,errno);
+        return -1;
+    }
+    ALOGV("msm_set_voice_rx_vol(%d) succeeded",vol);
+
+#ifdef HTC_AUDIO
+    if (mMode == AudioSystem::MODE_IN_CALL &&
+        mCurSndDevice != SND_DEVICE_BT &&
+        mCurSndDevice != SND_DEVICE_CARKIT &&
+        mCurSndDevice != SND_DEVICE_BT_EC_OFF)
+    {
+        uint32_t new_tx_acdb = getACDB(MOD_TX, mCurSndDevice);
+        uint32_t new_rx_acdb = getACDB(MOD_RX, mCurSndDevice);
+
+        int (*update_voice_acdb)(uint32_t, uint32_t);
+
+        update_voice_acdb = (int (*)(uint32_t, uint32_t))::dlsym(acoustic, "update_voice_acdb");
+        if ((*update_voice_acdb) == 0 ) {
+            ALOGE("Could not open update_voice_acdb()");
+        }
+
+        int rc = update_voice_acdb(new_tx_acdb, new_rx_acdb);
+        if (rc < 0)
+            ALOGE("Could not set update_voice_acdb: %d", rc);
+        else
+            ALOGI("update_voice_acdb(%d, %d) succeeded", new_tx_acdb, new_rx_acdb);
+    }
+#endif
+
+    return NO_ERROR;
+}
+#ifdef QCOM_FM_ENABLED
+status_t AudioHardware::setFmVolume(float v)
+{
+    int vol = android::AudioSystem::logToLinear( v );
+    if ( vol > 100 ) {
+        vol = 100;
+    }
+    else if ( vol < 0 ) {
+        vol = 0;
+    }
+    ALOGV("setFmVolume(%f)\n", v);
+    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_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/devices/platform/rs30100001:00000000.0/power_supply/battery/batt_temp",
+         "/sys/devices/platform/rs30100001:00000000/power_supply/battery/batt_temp" };
+
+    for (i = 0; i < 2; i++) {
+       if ((fd = open(fn[i], O_RDONLY)) >= 0)
+           break;
+    }
+    if (fd <= 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;
+    int batt_temp = 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);
+    }
+
+    if (alt_enable && cur_rx == DEVICE_SPEAKER_RX) {
+        if (get_batt_temp(&batt_temp) == NO_ERROR) {
+            if (batt_temp < 50) {
+                tpa_mode = 629276672;
+                rc = ioctl(fd, TPA2051_SET_CONFIG, &tpa_mode);
+                if (rc < 0)
+                    ALOGE("ioctl TPA2051_SET_CONFIG failed: %s", strerror(errno));
+                else
+                    ALOGD("update TPA2051_SET_CONFIG to mode %d success", tpa_mode);
+            }
+        }
+    }
+
+    close(fd);
+    return 0;
+}
+
+static status_t do_route_audio_rpc(uint32_t device,
+                                   bool ear_mute, bool mic_mute,
+                                   uint32_t rx_acdb_id, uint32_t tx_acdb_id)
+#else
+static status_t do_route_audio_rpc(uint32_t device,
+                                   bool ear_mute, bool mic_mute)
+#endif
+{
+    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, ear_mute, 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
+    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");
+    }
+    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");
+    }
+    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_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");
+    }
+    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");
+    }
+    else if (device == SND_DEVICE_HDMI) {
+        new_rx_device = DEVICE_HDMI_STERO_RX;
+        new_tx_device = cur_tx;
+        ALOGV("In DEVICE_HDMI_STERO_RX and cur_tx");
+    }
+#ifdef QCOM_FM_ENABLED
+    else if (device == SND_DEVICE_FM_TX) {
+        new_rx_device = DEVICE_FMRADIO_STEREO_RX;
+        new_tx_device = cur_tx;
+        ALOGV("In DEVICE_FMRADIO_STEREO_RX and cur_tx");
+    }
+#endif
+#ifdef SAMSUNG_AUDIO
+    else if (device == SND_DEVICE_VOIP_HANDSET) {
+        new_rx_device = DEVICE_HANDSET_VOIP_RX;
+        new_tx_device = DEVICE_HANDSET_VOIP_TX;
+        ALOGV("In VOIP HANDSET");
+    }
+    else if (device == SND_DEVICE_VOIP_SPEAKER) {
+        new_rx_device = DEVICE_SPEAKER_VOIP_RX;
+        new_tx_device = DEVICE_SPEAKER_VOIP_TX;
+        ALOGV("In VOIP SPEAKER");
+    }
+    else if (device == SND_DEVICE_VOIP_HEADSET) {
+        new_rx_device = DEVICE_HEADSET_VOIP_RX;
+        new_tx_device = DEVICE_HEADSET_VOIP_TX;
+        ALOGV("In VOIP HEADSET");
+    }
+    else if (device == SND_DEVICE_CALL_HANDSET) {
+        new_rx_device = DEVICE_HANDSET_CALL_RX;
+        new_tx_device = DEVICE_HANDSET_CALL_TX;
+        ALOGV("In CALL HANDSET");
+    }
+    else if (device == SND_DEVICE_CALL_SPEAKER) {
+        new_rx_device = DEVICE_SPEAKER_CALL_RX;
+        new_tx_device = DEVICE_SPEAKER_CALL_TX;
+        ALOGV("In CALL SPEAKER");
+    }
+    else if (device == SND_DEVICE_CALL_HEADSET) {
+        new_rx_device = DEVICE_HEADSET_CALL_RX;
+        new_tx_device = DEVICE_HEADSET_CALL_TX;
+        ALOGV("In CALL HEADSET");
+    }
+#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 (ear_mute == false && !isStreamOn(VOICE_CALL)) {
+        ALOGV("Going to enable RX/TX device for voice stream");
+            // Routing Voice
+            if ( (new_rx_device != INVALID_DEVICE) && (new_tx_device != INVALID_DEVICE))
+            {
+                ALOGD("Starting voice on Rx %d and Tx %d device", DEV_ID(new_rx_device), DEV_ID(new_tx_device));
+
+#ifdef HTC_AUDIO
+                updateACDB(new_rx_device, new_tx_device, rx_acdb_id, tx_acdb_id);
+#endif
+
+                msm_route_voice(DEV_ID(new_rx_device),DEV_ID(new_tx_device), 1);
+            }
+            else
+            {
+                return -1;
+            }
+
+            if(cur_rx == INVALID_DEVICE || new_rx_device == INVALID_DEVICE)
+                return -1;
+
+            if(cur_tx == INVALID_DEVICE || new_tx_device == INVALID_DEVICE)
+                return -1;
+
+           //Enable RX device
+           if(new_rx_device != cur_rx) {
+               enableDevice(cur_rx,0);
+           }
+           enableDevice(new_rx_device,1);
+
+           //Enable TX device
+           if(new_tx_device != cur_tx) {
+               enableDevice(cur_tx,0);
+           }
+           enableDevice(new_tx_device,1);
+
+            // start Voice call
+            ALOGD("Starting voice call and UnMuting the call");
+            msm_start_voice();
+            msm_set_voice_tx_mute(0);
+            cur_rx = new_rx_device;
+            cur_tx = new_tx_device;
+            addToTable(0,cur_rx,cur_tx,VOICE_CALL,true);
+#ifdef HTC_AUDIO
+            updateDeviceInfo(new_rx_device,new_tx_device, rx_acdb_id, tx_acdb_id);
+#else
+            updateDeviceInfo(new_rx_device,new_tx_device);
+#endif
+    }
+    else if (ear_mute == true && 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");
+        msm_end_voice();
+        deleteFromTable(VOICE_CALL);
+#ifdef HTC_AUDIO
+        updateDeviceInfo(new_rx_device,new_tx_device, 0, 0);
+#else
+        updateDeviceInfo(new_rx_device,new_tx_device);
+#endif
+        if(new_rx_device != INVALID_DEVICE && new_tx_device != INVALID_DEVICE) {
+            cur_rx = new_rx_device;
+            cur_tx = new_tx_device;
+        }
+    }
+    else {
+#ifdef HTC_AUDIO
+        updateDeviceInfo(new_rx_device,new_tx_device, rx_acdb_id, tx_acdb_id);
+    }
+
+    if (support_tpa2051)
+        do_tpa2051_control(ear_mute ^1);
+#else
+        updateDeviceInfo(new_rx_device,new_tx_device);
+    }
+#endif
+
+    return NO_ERROR;
+}
+
+#ifdef HTC_AUDIO
+status_t AudioHardware::doAudioRouteOrMuteHTC(uint32_t device)
+{
+    uint32_t rx_acdb_id = 0;
+    uint32_t tx_acdb_id = 0;
+
+    if (device == SND_DEVICE_BT) {
+        if (!mBluetoothNrec)
+            device = SND_DEVICE_BT_EC_OFF;
+    }
+
+    if (support_aic3254) {
+        aic3254_config(device);
+        do_aic3254_control(device);
+    }
+
+    if (device == SND_DEVICE_BT) {
+        if (mBluetoothIdTx != 0) {
+            rx_acdb_id = mBluetoothIdRx;
+            tx_acdb_id = mBluetoothIdTx;
+        } else {
+            /* use default BT entry defined in AudioBTID.csv */
+            rx_acdb_id = mBTEndpoints[0].rx;
+            tx_acdb_id = mBTEndpoints[0].tx;
+            ALOGD("Update ACDB ID to default BT setting");
+        }
+    } else if (device == SND_DEVICE_CARKIT ||
+               device == SND_DEVICE_BT_EC_OFF) {
+        if (mBluetoothIdTx != 0) {
+            rx_acdb_id = mBluetoothIdRx;
+            tx_acdb_id = mBluetoothIdTx;
+        } else {
+            /* use default carkit entry defined in AudioBTID.csv */
+            rx_acdb_id = mBTEndpoints[1].rx;
+            tx_acdb_id = mBTEndpoints[1].tx;
+            ALOGD("Update ACDB ID to default carkit setting");
+        }
+    } else if (isInCall() && hac_enable && mHACSetting &&
+               device == SND_DEVICE_HANDSET) {
+        ALOGD("Update acdb id to hac profile.");
+        rx_acdb_id = ACDB_ID_HAC_HANDSET_SPKR;
+        tx_acdb_id = ACDB_ID_HAC_HANDSET_MIC;
+    } else {
+        if (isInCall()) {
+            rx_acdb_id = getACDB(MOD_RX, device);
+            tx_acdb_id = getACDB(MOD_TX, device);
+        } else {
+            if (!checkOutputStandby())
+                rx_acdb_id = getACDB(MOD_PLAY, device);
+
+            if (mRecordState)
+                tx_acdb_id = getACDB(MOD_REC, device);
+        }
+    }
+
+    ALOGV("doAudioRouteOrMuteHTC: rx acdb %d, tx acdb %d", rx_acdb_id, tx_acdb_id);
+    ALOGV("doAudioRouteOrMuteHTC() device %x, mMode %d, mMicMute %d", device, mMode, mMicMute);
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+    int earMute = (mMode != AudioSystem::MODE_IN_CALL) && (mMode != AudioSystem::MODE_IN_COMMUNICATION);
+    return do_route_audio_rpc(device,earMute, mMicMute, rx_acdb_id, tx_acdb_id);
+#else
+    return do_route_audio_rpc(device, !isInCall(), mMicMute, rx_acdb_id, tx_acdb_id);
+#endif
+}
+#endif
+
+// 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
+
+    status_t ret = NO_ERROR;
+
+#ifdef HTC_AUDIO
+    ret = doAudioRouteOrMuteHTC(device);
+#else
+    ALOGV("doAudioRouteOrMute() device %d, mMode %d, mMicMute %d", device, mMode, mMicMute);
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+    int earMute = (mMode != AudioSystem::MODE_IN_CALL) && (mMode != AudioSystem::MODE_IN_COMMUNICATION);
+    ret = do_route_audio_rpc(device, earMute, mMicMute);
+#else
+    ret = do_route_audio_rpc(device, !isInCall(), mMicMute);
+#endif
+#endif
+
+    if (isStreamOnAndActive(VOICE_CALL) && mMicMute == false)
+        msm_set_voice_tx_mute(0);
+
+    if (isInCall())
+        setVoiceVolume(mVoiceVolume);
+
+    return ret;
+}
+
+
+#ifdef HTC_AUDIO
+status_t AudioHardware::get_mMode(void) {
+    return mMode;
+}
+
+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;
+}
+
+uint32_t AudioHardware::getACDB(int mode, uint32_t device) {
+
+    uint32_t acdb_id = 0;
+    int batt_temp = 0;
+    int vol = lrint(mVoiceVolume * 100.0);
+
+    if (mMode == AudioSystem::MODE_IN_CALL &&
+        device <= SND_DEVICE_NO_MIC_HEADSET) {
+        if (mode == MOD_RX) {
+            switch (device) {
+                case SND_DEVICE_HANDSET:
+                    acdb_id = vol / 20 + 201;
+                    break;
+                case SND_DEVICE_HEADSET:
+                case SND_DEVICE_NO_MIC_HEADSET:
+                    acdb_id = vol / 20 + 401;
+                    break;
+                case SND_DEVICE_SPEAKER:
+                    acdb_id = vol / 20 + 601;
+                    break;
+                default:
+                    break;
+            }
+        } else if (mode == MOD_TX) {
+            switch (device) {
+                case SND_DEVICE_HANDSET:
+                    acdb_id = vol / 20 + 101;
+                    break;
+                case SND_DEVICE_HEADSET:
+                case SND_DEVICE_NO_MIC_HEADSET:
+                    acdb_id = vol / 20 + 301;
+                    break;
+                case SND_DEVICE_SPEAKER:
+                    acdb_id = vol / 20 + 501;
+                    break;
+                default:
+                    break;
+            }
+        }
+    } else {
+        if (mode == MOD_PLAY) {
+            switch (device) {
+                case SND_DEVICE_HEADSET:
+                case SND_DEVICE_NO_MIC_HEADSET:
+                case SND_DEVICE_NO_MIC_HEADSET_BACK_MIC:
+                case SND_DEVICE_FM_HEADSET:
+                    acdb_id = ACDB_ID_HEADSET_PLAYBACK;
+                    break;
+                case SND_DEVICE_SPEAKER:
+                case SND_DEVICE_FM_SPEAKER:
+                case SND_DEVICE_SPEAKER_BACK_MIC:
+                    acdb_id = ACDB_ID_SPKR_PLAYBACK;
+                    if (alt_enable) {
+                        if (get_batt_temp(&batt_temp) == NO_ERROR) {
+                            if (batt_temp < 50)
+                                acdb_id = ACDB_ID_ALT_SPKR_PLAYBACK;
+                        }
+                    }
+                    break;
+                case SND_DEVICE_HEADSET_AND_SPEAKER:
+                case SND_DEVICE_HEADSET_AND_SPEAKER_BACK_MIC:
+                case SND_DEVICE_HEADPHONE_AND_SPEAKER:
+                    acdb_id = ACDB_ID_HEADSET_RINGTONE_PLAYBACK;
+                    break;
+                default:
+                    break;
+            }
+        } else if (mode == MOD_REC) {
+            switch (device) {
+                case SND_DEVICE_HEADSET:
+                case SND_DEVICE_FM_HEADSET:
+                case SND_DEVICE_FM_SPEAKER:
+                case SND_DEVICE_HEADSET_AND_SPEAKER:
+                    acdb_id = ACDB_ID_EXT_MIC_REC;
+                    break;
+                case SND_DEVICE_HANDSET:
+                case SND_DEVICE_NO_MIC_HEADSET:
+                case SND_DEVICE_SPEAKER:
+                    acdb_id = ACDB_ID_INT_MIC_REC;
+                    break;
+                case SND_DEVICE_SPEAKER_BACK_MIC:
+                case SND_DEVICE_NO_MIC_HEADSET_BACK_MIC:
+                case SND_DEVICE_HANDSET_BACK_MIC:
+                case SND_DEVICE_HEADSET_AND_SPEAKER_BACK_MIC:
+                    acdb_id = ACDB_ID_CAMCORDER;
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+    ALOGV("getACDB, return ID %d", acdb_id);
+    return acdb_id;
+}
+
+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 (mMode == AudioSystem::MODE_IN_CALL) {
+        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 {
+        if (checkOutputStandby()) {
+            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;
+            }
+        }
+    }
+    ALOGD("aic3254_ioctl: new_aic_rxmode %d cur_aic_rx %d", new_aic_rxmode, cur_aic_rx);
+    if (new_aic_rxmode != cur_aic_rx)
+        if (aic3254_ioctl(AIC3254_CONFIG_RX, new_aic_rxmode) >= 0)
+            cur_aic_rx = new_aic_rxmode;
+
+    ALOGD("aic3254_ioctl: new_aic_txmode %d cur_aic_tx %d", new_aic_txmode, cur_aic_tx);
+    if (new_aic_txmode != cur_aic_tx)
+        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) {
+#ifdef WITH_SPADE_DSP_PROFILE
+        if (support_htc_backmic) {
+            strcpy(name, "DualMic_Phone");
+            switch (device) {
+                case SND_DEVICE_HANDSET:
+                case SND_DEVICE_HANDSET_BACK_MIC:
+                case SND_DEVICE_HEADSET:
+                case SND_DEVICE_HEADSET_AND_SPEAKER:
+                case SND_DEVICE_HEADSET_AND_SPEAKER_BACK_MIC:
+                case SND_DEVICE_NO_MIC_HEADSET:
+                    strcat(name, "_EP");
+                    break;
+                case SND_DEVICE_SPEAKER:
+                    strcat(name, "_SPK");
+                    break;
+                default:
+                    break;
+            }
+        } else {
+            strcpy(name, "Original_Phone");
+        }
+#else
+        strcpy(name, "Original_Phone");
+        switch (device) {
+            case SND_DEVICE_HANDSET:
+            case SND_DEVICE_HANDSET_BACK_MIC:
+                strcat(name, "_REC");
+                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:
+                strcat(name, "_HP");
+                break;
+            case SND_DEVICE_SPEAKER:
+                strcat(name, "_SPK");
+                break;
+            default:
+                break;
+        }
+#endif
+    } else {
+#ifdef WITH_SPADE_DSP_PROFILE
+        if (mRecordState) {
+#else
+        if ((strcasecmp(mActiveAP, "Camcorder") == 0)) {
+            if (strlen(mEffect) != 0) {
+                strcpy(name, "Recording_");
+                strcat(name, mEffect);
+            } else
+                strcpy(name, "Original");
+        } else if (mRecordState) {
+#endif
+#ifdef WITH_SPADE_DSP_PROFILE
+            strcpy(name, "Original");
+#else
+            strcpy(name, "Original_Recording");
+#endif
+        } else if (strlen(mEffect) == 0 && !mEffectEnabled)
+           strcpy(name, "Original");
+        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*);
+
+    ALOGD("aic3254_ioctl()");
+
+    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;
+    }
+
+    ALOGD("aic3254_ioctl: try ioctl 0x%x with arg %d", cmd, argc);
+    rc = set_aic3254_ioctl(cmd, &argc);
+    if (rc < 0)
+        ALOGE("aic3254_ioctl failed");
+
+    return rc;
+}
+
+void AudioHardware::aic3254_powerdown() {
+    ALOGD("aic3254_powerdown");
+    int rc = aic3254_ioctl(AIC3254_POWERDOWN, 0);
+    if (rc < 0)
+        ALOGE("aic3254_powerdown failed");
+}
+
+int AudioHardware::aic3254_set_volume(int volume) {
+    ALOGD("aic3254_set_volume = %d", volume);
+
+    if (aic3254_ioctl(AIC3254_CONFIG_VOLUME_L, volume) < 0)
+        ALOGE("aic3254_set_volume: could not set aic3254 LEFT volume %d", volume);
+
+    int rc = aic3254_ioctl(AIC3254_CONFIG_VOLUME_R, volume);
+    if (rc < 0)
+        ALOGE("aic3254_set_volume: could not set aic3254 RIGHT volume %d", volume);
+    return rc;
+}
+#endif
+
+status_t AudioHardware::doRouting(AudioStreamInMSM72xx *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;
+            } 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;
+                }
+            } else {
+                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;
+                } else {
+                    ALOGI("Routing audio to Speakerphone\n");
+                    sndDevice = SND_DEVICE_SPEAKER;
+                }
+            }
+        }
+        // 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)) {
+            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);
+        }
+#ifdef QCOM_FM_ENABLED
+        else 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);
+        }
+#endif
+        else 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;
+            }
+        } 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);
+        } 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 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);
+        }
+#ifdef QCOM_FM_ENABLED
+         else 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);
+        }
+#endif
+    }
+
+    if (mDualMicEnabled && mMode == AudioSystem::MODE_IN_CALL) {
+        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;
+        }
+    }
+
+#ifdef SAMSUNG_AUDIO
+    if (mMode == AudioSystem::MODE_IN_CALL) {
+        if (sndDevice == SND_DEVICE_HANDSET) {
+            ALOGI("Routing audio to Call Handset\n");
+            sndDevice = SND_DEVICE_CALL_HANDSET;
+        } else if (sndDevice == SND_DEVICE_SPEAKER) {
+            ALOGI("Routing audio to Call Speaker\n");
+            sndDevice = SND_DEVICE_CALL_SPEAKER;
+        } else if (sndDevice == SND_DEVICE_HEADSET) {
+            ALOGI("Routing audio to Call Headset\n");
+            sndDevice = SND_DEVICE_CALL_HEADSET;
+        }
+    } else if (mMode == AudioSystem::MODE_IN_COMMUNICATION) {
+        if (sndDevice == SND_DEVICE_HANDSET) {
+            ALOGI("Routing audio to VOIP handset\n");
+            sndDevice = SND_DEVICE_VOIP_HANDSET;
+        } else if (sndDevice == SND_DEVICE_SPEAKER) {
+            ALOGI("Routing audio to VOIP speaker\n");
+            sndDevice = SND_DEVICE_VOIP_SPEAKER;
+        } else if (sndDevice == SND_DEVICE_HEADSET) {
+            ALOGI("Routing audio to VOIP headset\n");
+            sndDevice = SND_DEVICE_VOIP_HEADSET;
+        }
+    }
+#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 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;
+    }
+#endif
+
+    if (sndDevice != -1 && sndDevice != mCurSndDevice) {
+        ret = doAudioRouteOrMute(sndDevice);
+        mCurSndDevice = sndDevice;
+    }
+
+    return ret;
+}
+#ifdef QCOM_FM_ENABLED
+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(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 ");
+            return NO_ERROR;
+        }
+
+        Mutex::Autolock lock_1(mComboDeviceLock);
+
+        Routing_table* temp = NULL;
+
+        if (enableOrDisable == 1) {
+
+            if(enableDevice(DEVICE_SPEAKER_RX, 1)) {
+                ALOGE("enableDevice failed for device %d", DEVICE_SPEAKER_RX);
+                return -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("null check:fatal error:temp cannot be null");
+                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("null check:fatal error:temp cannot be null");
+                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;
+            }
+
+            if(enableDevice(DEVICE_SPEAKER_RX, 0)) {
+                ALOGE("enableDevice failed for device %d", DEVICE_SPEAKER_RX);
+                return -1;
+            }
+        }
+
+    }
+
+    return status;
+}
+
+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;
+    }
+    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);
+        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("Disabling device failed for device %d", DEVICE_FMRADIO_STEREO_TX);
+        }
+    }
+    deleteFromTable(FM_RADIO);
+#ifdef HTC_AUDIO
+    updateDeviceInfo(cur_rx, cur_tx, 0, 0);
+#else
+    updateDeviceInfo(cur_rx, cur_tx);
+#endif
+    return NO_ERROR;
+}
+#endif
+
+status_t AudioHardware::checkMicMute()
+{
+    Mutex::Autolock lock(mLock);
+    if (mMode != AudioSystem::MODE_IN_CALL) {
+        setMicMute_nosync(true);
+    }
+
+    return NO_ERROR;
+}
+
+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];
+}
+
+
+// ----------------------------------------------------------------------------
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+AudioHardware::AudioSessionOutMSM7xxx::AudioSessionOutMSM7xxx() :
+    mHardware(0), mStartCount(0), mRetryCount(0), mStandby(true), mDevices(0), mSessionId(-1)
+{
+}
+
+status_t AudioHardware::AudioSessionOutMSM7xxx::set(
+        AudioHardware* hw, uint32_t devices, int *pFormat, int32_t sessionId)
+{
+    int lFormat = pFormat ? *pFormat : 0;
+
+    mHardware = hw;
+    mDevices = devices;
+
+    if(sessionId >= 0) {
+        ALOGD("AudioSessionOutMSM7xxx::set() Adding LPA_DECODE Node to Table");
+
+        Mutex::Autolock lock(mDeviceSwitchLock);
+
+        addToTable(sessionId,cur_rx,INVALID_DEVICE,LPA_DECODE,true);
+
+        if(enableDevice(cur_rx, 1)) {
+            ALOGE("enableDevice failed for device cur_rx %d", cur_rx);
+            return 0;
+        }
+
+        ALOGV("msm_route_stream(PCM_PLAY,%d,%d,0)",sessionId,DEV_ID(cur_rx));
+        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));
+        }
+
+        Mutex::Autolock lock_1(mComboDeviceLock);
+
+        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;
+        }
+
+        mSessionId = sessionId;
+    }
+    return NO_ERROR;
+}
+
+AudioHardware::AudioSessionOutMSM7xxx::~AudioSessionOutMSM7xxx()
+{
+}
+
+status_t AudioHardware::AudioSessionOutMSM7xxx::standby()
+{
+    Routing_table* temp = NULL;
+    ALOGD("AudioSessionOutMSM7xxx::standby()");
+    status_t status = NO_ERROR;
+
+    temp = getNodeByStreamType(LPA_DECODE);
+
+    if(temp == NULL)
+        return NO_ERROR;
+
+    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);
+        return -1;
+    }
+    deleteFromTable(LPA_DECODE);
+    updateDeviceInfo(cur_rx, cur_tx);
+    mStandby = true;
+    return status;
+}
+
+bool AudioHardware::AudioSessionOutMSM7xxx::checkStandby()
+{
+    return mStandby;
+}
+
+
+status_t AudioHardware::AudioSessionOutMSM7xxx::setParameters(const String8& keyValuePairs)
+{
+    AudioParameter param = AudioParameter(keyValuePairs);
+    String8 key = String8(AudioParameter::keyRouting);
+    status_t status = NO_ERROR;
+    int device;
+    ALOGV("AudioSessionOutMSM7xxx::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::AudioSessionOutMSM7xxx::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("AudioSessionOutMSM7xxx::getParameters() %s", param.toString().string());
+    return param.toString();
+}
+
+status_t AudioHardware::AudioSessionOutMSM7xxx::getRenderPosition(uint32_t *dspFrames)
+{
+    //TODO: enable when supported by driver
+    return INVALID_OPERATION;
+}
+
+status_t AudioHardware::AudioSessionOutMSM7xxx::setVolume(float left, float right)
+{
+    float v = (left + right) / 2;
+    if (v < 0.0) {
+        ALOGW("AudioSessionOutMSM7xxx::setVolume(%f) under 0.0, assuming 0.0\n", v);
+        v = 0.0;
+    } else if (v > 1.0) {
+        ALOGW("AudioSessionOutMSM7xxx::setVolume(%f) over 1.0, assuming 1.0\n", v);
+        v = 1.0;
+    }
+
+    // Ensure to convert the log volume back to linear for LPA
+    float vol = v * 100;
+    ALOGV("AudioSessionOutMSM7xxx::setVolume(%f)\n", v);
+    ALOGV("Setting session volume to %f (available range is 0 to 100)\n", vol);
+
+    if(msm_set_volume(mSessionId, vol)) {
+        ALOGE("msm_set_volume(%d %f) failed errno = %d",mSessionId, vol,errno);
+        return -1;
+    }
+    ALOGV("msm_set_volume(%f) succeeded",vol);
+    return NO_ERROR;
+}
+
+#endif /* QCOM_TUNNEL_LPA_ENABLED */
+// ----------------------------------------------------------------------------
+
+AudioHardware::AudioStreamOutMSM72xx::AudioStreamOutMSM72xx() :
+    mHardware(0), mFd(-1), mStartCount(0), mRetryCount(0), mStandby(true), mDevices(0)
+{
+}
+
+status_t AudioHardware::AudioStreamOutMSM72xx::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::AudioStreamOutMSM72xx::~AudioStreamOutMSM72xx()
+{
+    if (mFd >= 0) close(mFd);
+}
+
+ssize_t AudioHardware::AudioStreamOutMSM72xx::write(const void* buffer, size_t bytes)
+{
+    // ALOGD("AudioStreamOutMSM72xx::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_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;
+            }
+            ALOGV("dec_id = %d\n",dec_id);
+            if(cur_rx == INVALID_DEVICE)
+                return 0;
+
+            Mutex::Autolock lock(mDeviceSwitchLock);
+
+#ifdef HTC_AUDIO
+            int snd_dev = mHardware->get_snd_dev();
+            if (support_aic3254)
+                mHardware->do_aic3254_control(snd_dev);
+#endif
+
+            ALOGV("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 HTC_AUDIO
+            uint32_t rx_acdb_id = mHardware->getACDB(MOD_PLAY, snd_dev);
+            updateACDB(cur_rx, cur_tx, rx_acdb_id, 0);
+#endif
+
+            ALOGV("msm_route_stream(PCM_PLAY,%d,%d,1)",dec_id,DEV_ID(cur_rx));
+            if(msm_route_stream(PCM_PLAY, dec_id, DEV_ID(cur_rx), 1)) {
+                ALOGE("msm_route_stream failed");
+                return 0;
+            }
+#ifdef QCOM_FM_ENABLED
+            Mutex::Autolock lock_1(mComboDeviceLock);
+
+            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){
+                    ALOGE("null check:fatal error:LpaNode cannot be null");
+                    return -1;
+                }
+                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::AudioStreamOutMSM72xx::standby()
+{
+    Routing_table* temp = NULL;
+    ALOGV("AudioStreamOutMSM72xx::standby()");
+    status_t status = NO_ERROR;
+
+    temp = getNodeByStreamType(PCM_PLAY);
+
+    if(temp == NULL)
+        return NO_ERROR;
+
+    ALOGV("Deroute pcm out 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);
+#ifdef HTC_AUDIO
+    updateDeviceInfo(cur_rx, cur_tx, 0, 0);
+#else
+    updateDeviceInfo(cur_rx, cur_tx);
+#endif
+
+    if (!mStandby && mFd >= 0) {
+        ::close(mFd);
+        mFd = -1;
+    }
+
+    mStandby = true;
+
+#ifdef HTC_AUDIO
+    if (support_aic3254)
+        mHardware->do_aic3254_control(mHardware->get_snd_dev());
+#endif
+
+    return status;
+}
+
+status_t AudioHardware::AudioStreamOutMSM72xx::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    result.append("AudioStreamOutMSM72xx::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::AudioStreamOutMSM72xx::checkStandby()
+{
+    return mStandby;
+}
+
+
+status_t AudioHardware::AudioStreamOutMSM72xx::setParameters(const String8& keyValuePairs)
+{
+    AudioParameter param = AudioParameter(keyValuePairs);
+    String8 key = String8(AudioParameter::keyRouting);
+    status_t status = NO_ERROR;
+    int device;
+    ALOGV("AudioStreamOutMSM72xx::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::AudioStreamOutMSM72xx::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("AudioStreamOutMSM72xx::getParameters() %s", param.toString().string());
+    return param.toString();
+}
+
+status_t AudioHardware::AudioStreamOutMSM72xx::getRenderPosition(uint32_t *dspFrames)
+{
+    //TODO: enable when supported by driver
+    return INVALID_OPERATION;
+}
+
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+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("AudioStreamOutDirect::set 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
+    if ((lFormat != format()) ||
+        (lChannels != channels()) ||
+        (lRate != sampleRate())) {
+        if (pFormat) *pFormat = format();
+        if (pChannels) *pChannels = channels();
+        if (pRate) *pRate = sampleRate();
+        ALOGE("  AudioStreamOutDirect::set return bad values\n");
+        return BAD_VALUE;
+    }
+
+    if (pFormat) *pFormat = lFormat;
+    if (pChannels) *pChannels = lChannels;
+    if (pRate) *pRate = lRate;
+
+    mDevices = devices;
+    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;
+    }
+
+    mHardware->mVoipOutActive = true;
+
+    if (mHardware->mVoipInActive)
+        mHardware->setupDeviceforVoipCall(true);
+
+    return NO_ERROR;
+}
+
+AudioHardware::AudioStreamOutDirect::~AudioStreamOutDirect()
+{
+    ALOGV("AudioStreamOutDirect destructor");
+    mHardware->mVoipOutActive = false;
+    standby();
+}
+
+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;
+    ALOGV("AudioStreamOutDirect::write(%p, %ld)", buffer, bytes);
+
+    if (mStandby) {
+        if(mHardware->mVoipFd >= 0) {
+            mFd = mHardware->mVoipFd;
+
+            mHardware->mVoipOutActive = true;
+            if (mHardware->mVoipInActive)
+                mHardware->setupDeviceforVoipCall(true);
+
+            mStandby = false;
+        } else {
+            //Routing Voice
+            if ( (cur_rx != INVALID_DEVICE) && (cur_tx != INVALID_DEVICE))
+            {
+                ALOGV("Starting voice 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;
+            }
+
+            // start Voice call
+            ALOGD("Starting voice call and UnMuting the call");
+            msm_start_voice();
+            msm_set_voice_tx_mute(0);
+            addToTable(0,cur_rx,cur_tx,VOICE_CALL,true);
+
+
+            // 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");
+            mvs_config.mvs_mode = MVS_MODE_PCM;
+            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;
+            }
+
+            mHardware->mVoipOutActive = true;
+            if (mHardware->mVoipInActive)
+                mHardware->setupDeviceforVoipCall(true);
+
+            // fill 2 buffers before AUDIO_START
+            mStartCount = AUDIO_HW_NUM_OUT_BUF;
+            mStandby = false;
+        }
+    }
+    struct q5v2_msm_audio_mvs_frame audio_mvs_frame;
+    audio_mvs_frame.frame_type = 0;
+    while (count) {
+        audio_mvs_frame.len = mBufferSize;
+        memcpy(&audio_mvs_frame.voc_pkt, p, mBufferSize);
+        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 -= mBufferSize;
+            p += mBufferSize;
+        } 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 = sizeof(audio_mvs_frame.voc_pkt);
+    return bytes;
+
+Error:
+ALOGE("  write Error \n");
+  //  mHardware->mLock.unlock();
+    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()");
+    Mutex::Autolock lock(mHardware->mVoipLock);
+    status_t status = NO_ERROR;
+
+    ALOGD("Voipin %d driver fd %d", mHardware->mVoipInActive, mHardware->mVoipFd);
+    mHardware->mVoipOutActive = false;
+    if (mHardware->mVoipFd >= 0 && !mHardware->mVoipInActive) {
+        ALOGE("mute and disbale device  ***\n");
+        //Mute and disable the device.
+        int ret = msm_set_voice_rx_vol(0);
+        if (ret <0)
+            ALOGE("Error %d setting volume\n", ret);
+
+        ret = msm_set_voice_tx_mute(1);
+        if (ret < 0)
+            ALOGE("Error %d setting mute\n", ret);
+
+        ret = msm_end_voice();
+        if (ret < 0)
+            ALOGE("Error %d ending voice\n", ret);
+
+        if (mHardware->mVoipFd >= 0) {
+            ret = ioctl(mHardware->mVoipFd, AUDIO_STOP, NULL);
+            ALOGE("MVS stop returned %d \n", ret);
+            ::close(mFd);
+            mFd = mHardware->mVoipFd = -1;
+            mHardware->setupDeviceforVoipCall(false);
+            ALOGD("MVS driver closed %d mFd %d", __LINE__, mHardware->mVoipFd);
+        }
+       //mHardware->checkMicMute();
+    }
+    else
+        ALOGE("Not closing MVS driver");
+    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;
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+AudioHardware::AudioStreamInMSM72xx::AudioStreamInMSM72xx() :
+    mHardware(0), mFd(-1), 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)
+{
+}
+
+status_t AudioHardware::AudioStreamInMSM72xx::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) &&
+#ifdef WITH_QCOM_SPEECH
+         (*pFormat != AudioSystem::AMR_NB) &&
+         (*pFormat != AudioSystem::EVRC) &&
+         (*pFormat != AudioSystem::QCELP) &&
+#endif
+         (*pFormat != AudioSystem::AAC)))
+    {
+        *pFormat = AUDIO_HW_IN_FORMAT;
+        return BAD_VALUE;
+    }
+
+    if((*pFormat == AudioSystem::AAC) && (*pChannels & (AudioSystem::CHANNEL_IN_VOICE_DNLINK |  AudioSystem::CHANNEL_IN_VOICE_UPLINK))) {
+        ALOGE("voice call recording in AAC format does not support");
+        return BAD_VALUE;
+    }
+
+    if (pRate == 0) {
+        return BAD_VALUE;
+    }
+    uint32_t rate = hw->getInputSampleRate(*pRate);
+    if (rate != *pRate) {
+        *pRate = rate;
+        return BAD_VALUE;
+    }
+
+    if (pChannels == 0 || (*pChannels & (AudioSystem::CHANNEL_IN_MONO | AudioSystem::CHANNEL_IN_STEREO)) == 0) {
+        *pChannels = AUDIO_HW_IN_CHANNELS;
+        return BAD_VALUE;
+    }
+
+    mHardware = hw;
+
+    ALOGV("AudioStreamInMSM72xx::set(%d, %d, %u)", *pFormat, *pChannels, *pRate);
+    if (mFd >= 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_a2dp_in", O_RDONLY);
+        if (status < 0) {
+            ALOGE("Cannot open /dev/msm_a2dp_in 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((*pChannels) & (AudioSystem::CHANNEL_IN_STEREO | AudioSystem::CHANNEL_IN_MONO));
+        config.sample_rate = *pRate;
+        config.buffer_size = bufferSize();
+        config.buffer_count = 2;
+        config.type = CODEC_TYPE_PCM;
+        status = ioctl(mFd, AUDIO_SET_CONFIG, &config);
+        if (status < 0) {
+            ALOGE("Cannot set config");
+            if (ioctl(mFd, 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(mFd, 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)
+    {
+        // open audio input device
+        status = ::open("/dev/msm_pcm_in", O_RDONLY);
+        if (status < 0) {
+            ALOGE("Cannot open /dev/msm_pcm_in 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((*pChannels) & (AudioSystem::CHANNEL_IN_STEREO | AudioSystem::CHANNEL_IN_MONO));
+        config.sample_rate = *pRate;
+        config.buffer_size = bufferSize();
+        config.buffer_count = 2;
+        config.type = CODEC_TYPE_PCM;
+        if (build_id[17] == '1') {//build 4.1
+           /*
+             Configure 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(*pRate>=44100)
+                config.buffer_size = 1024 * config.channel_count;
+            else
+                config.buffer_size = 512 * config.channel_count;
+        }
+        status = ioctl(mFd, AUDIO_SET_CONFIG, &config);
+        if (status < 0) {
+            ALOGE("Cannot set config");
+            if (ioctl(mFd, 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(mFd, 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;
+        if (mDevices == AudioSystem::DEVICE_IN_VOICE_CALL)
+         {
+            if ((mChannels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) &&
+                (mChannels & AudioSystem::CHANNEL_IN_VOICE_UPLINK)) {
+                 ALOGI("Recording Source: Voice Call Both Uplink and Downlink");
+                 voc_rec_cfg.rec_mode = VOC_REC_BOTH;
+            } else if (mChannels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
+                 ALOGI("Recording Source: Voice Call DownLink");
+                 voc_rec_cfg.rec_mode = VOC_REC_DOWNLINK;
+            } else if (mChannels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) {
+                 ALOGI("Recording Source: Voice Call UpLink");
+                 voc_rec_cfg.rec_mode = VOC_REC_UPLINK;
+            }
+            if (ioctl(mFd, AUDIO_SET_INCALL, &voc_rec_cfg))
+            {
+                ALOGE("Error: AUDIO_SET_INCALL failed\n");
+                goto  Error;
+            }
+        }
+        mSampleRate = config.sample_rate;
+        mBufferSize = config.buffer_size;
+    }
+#ifdef WITH_QCOM_SPEECH
+    else if (*pFormat == AudioSystem::EVRC)
+    {
+          ALOGI("Recording format: EVRC");
+          // open evrc input device
+          status = ::open(EVRC_DEVICE_IN, O_RDONLY);
+          if (status < 0) {
+              ALOGE("Cannot open evrc device for read");
+              goto Error;
+          }
+          mFd = status;
+          mDevices = devices;
+          mChannels = *pChannels;
+
+          if (mDevices == AudioSystem::DEVICE_IN_VOICE_CALL)
+          {
+              if ((mChannels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) &&
+                     (mChannels & AudioSystem::CHANNEL_IN_VOICE_UPLINK)) {
+                  ALOGI("Recording Source: Voice Call Both Uplink and Downlink");
+                  voc_rec_cfg.rec_mode = VOC_REC_BOTH;
+              } else if (mChannels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
+                  ALOGI("Recording Source: Voice Call DownLink");
+                  voc_rec_cfg.rec_mode = VOC_REC_DOWNLINK;
+              } else if (mChannels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) {
+                  ALOGI("Recording Source: Voice Call UpLink");
+                  voc_rec_cfg.rec_mode = VOC_REC_UPLINK;
+              }
+
+              if (ioctl(mFd, AUDIO_SET_INCALL, &voc_rec_cfg))
+              {
+                 ALOGE("Error: AUDIO_SET_INCALL failed\n");
+                 goto  Error;
+              }
+          }
+
+          /* Config param */
+          struct msm_audio_stream_config config;
+          if(ioctl(mFd, AUDIO_GET_STREAM_CONFIG, &config))
+          {
+            ALOGE(" Error getting buf config param AUDIO_GET_STREAM_CONFIG \n");
+            goto  Error;
+          }
+
+          ALOGV("The Config buffer size is %d", config.buffer_size);
+          ALOGV("The Config buffer count is %d", config.buffer_count);
+
+          mSampleRate =8000;
+          mFormat = *pFormat;
+          mBufferSize = 230;
+          struct msm_audio_evrc_enc_config evrc_enc_cfg;
+
+          if (ioctl(mFd, AUDIO_GET_EVRC_ENC_CONFIG, &evrc_enc_cfg))
+          {
+            ALOGE("Error: AUDIO_GET_EVRC_ENC_CONFIG failed\n");
+            goto  Error;
+          }
+
+          ALOGV("The Config cdma_rate is %d", evrc_enc_cfg.cdma_rate);
+          ALOGV("The Config min_bit_rate is %d", evrc_enc_cfg.min_bit_rate);
+          ALOGV("The Config max_bit_rate is %d", evrc_enc_cfg.max_bit_rate);
+
+          evrc_enc_cfg.min_bit_rate = 4;
+          evrc_enc_cfg.max_bit_rate = 4;
+
+          if (ioctl(mFd, AUDIO_SET_EVRC_ENC_CONFIG, &evrc_enc_cfg))
+          {
+            ALOGE("Error: AUDIO_SET_EVRC_ENC_CONFIG failed\n");
+            goto  Error;
+          }
+    }
+    else if (*pFormat == AudioSystem::QCELP)
+    {
+          ALOGI("Recording format: QCELP");
+          // open qcelp input device
+          status = ::open(QCELP_DEVICE_IN, O_RDONLY);
+          if (status < 0) {
+              ALOGE("Cannot open qcelp device for read");
+              goto Error;
+          }
+          mFd = status;
+          mDevices = devices;
+          mChannels = *pChannels;
+
+          if (mDevices == AudioSystem::DEVICE_IN_VOICE_CALL)
+          {
+              if ((mChannels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) &&
+                  (mChannels & AudioSystem::CHANNEL_IN_VOICE_UPLINK)) {
+                  ALOGI("Recording Source: Voice Call Both Uplink and Downlink");
+                  voc_rec_cfg.rec_mode = VOC_REC_BOTH;
+              } else if (mChannels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
+                  ALOGI("Recording Source: Voice Call DownLink");
+                  voc_rec_cfg.rec_mode = VOC_REC_DOWNLINK;
+              } else if (mChannels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) {
+                  ALOGI("Recording Source: Voice Call UpLink");
+                  voc_rec_cfg.rec_mode = VOC_REC_UPLINK;
+              }
+
+              if (ioctl(mFd, AUDIO_SET_INCALL, &voc_rec_cfg))
+              {
+                 ALOGE("Error: AUDIO_SET_INCALL failed\n");
+                 goto  Error;
+              }
+          }
+
+          /* Config param */
+          struct msm_audio_stream_config config;
+          if(ioctl(mFd, AUDIO_GET_STREAM_CONFIG, &config))
+          {
+            ALOGE(" Error getting buf config param AUDIO_GET_STREAM_CONFIG \n");
+            goto  Error;
+          }
+
+          ALOGV("The Config buffer size is %d", config.buffer_size);
+          ALOGV("The Config buffer count is %d", config.buffer_count);
+
+          mSampleRate =8000;
+          mFormat = *pFormat;
+          mBufferSize = 350;
+
+          struct msm_audio_qcelp_enc_config qcelp_enc_cfg;
+
+          if (ioctl(mFd, AUDIO_GET_QCELP_ENC_CONFIG, &qcelp_enc_cfg))
+          {
+            ALOGE("Error: AUDIO_GET_QCELP_ENC_CONFIG failed\n");
+            goto  Error;
+          }
+
+          ALOGV("The Config cdma_rate is %d", qcelp_enc_cfg.cdma_rate);
+          ALOGV("The Config min_bit_rate is %d", qcelp_enc_cfg.min_bit_rate);
+          ALOGV("The Config max_bit_rate is %d", qcelp_enc_cfg.max_bit_rate);
+
+          qcelp_enc_cfg.min_bit_rate = 4;
+          qcelp_enc_cfg.max_bit_rate = 4;
+
+          if (ioctl(mFd, AUDIO_SET_QCELP_ENC_CONFIG, &qcelp_enc_cfg))
+          {
+            ALOGE("Error: AUDIO_SET_QCELP_ENC_CONFIG failed\n");
+            goto  Error;
+          }
+    }
+    else if (*pFormat == AudioSystem::AMR_NB)
+    {
+          ALOGI("Recording format: AMR_NB");
+          // open amr_nb input device
+          status = ::open(AMRNB_DEVICE_IN, O_RDONLY);
+          if (status < 0) {
+              ALOGE("Cannot open amr_nb device for read");
+              goto Error;
+          }
+          mFd = status;
+          mDevices = devices;
+          mChannels = *pChannels;
+
+          if (mDevices == AudioSystem::DEVICE_IN_VOICE_CALL)
+          {
+              if ((mChannels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) &&
+                     (mChannels & AudioSystem::CHANNEL_IN_VOICE_UPLINK)) {
+                  ALOGI("Recording Source: Voice Call Both Uplink and Downlink");
+                  voc_rec_cfg.rec_mode = VOC_REC_BOTH;
+              } else if (mChannels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
+                  ALOGI("Recording Source: Voice Call DownLink");
+                  voc_rec_cfg.rec_mode = VOC_REC_DOWNLINK;
+              } else if (mChannels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) {
+                  ALOGI("Recording Source: Voice Call UpLink");
+                  voc_rec_cfg.rec_mode = VOC_REC_UPLINK;
+              }
+
+              if (ioctl(mFd, AUDIO_SET_INCALL, &voc_rec_cfg))
+              {
+                 ALOGE("Error: AUDIO_SET_INCALL failed\n");
+                 goto  Error;
+              }
+          }
+
+          /* Config param */
+          struct msm_audio_stream_config config;
+          if(ioctl(mFd, AUDIO_GET_STREAM_CONFIG, &config))
+          {
+            ALOGE(" Error getting buf config param AUDIO_GET_STREAM_CONFIG \n");
+            goto  Error;
+          }
+
+          ALOGV("The Config buffer size is %d", config.buffer_size);
+          ALOGV("The Config buffer count is %d", config.buffer_count);
+
+          mSampleRate =8000;
+          mFormat = *pFormat;
+          mBufferSize = 320;
+          struct msm_audio_amrnb_enc_config_v2 amr_nb_cfg;
+
+          if (ioctl(mFd, AUDIO_GET_AMRNB_ENC_CONFIG_V2, &amr_nb_cfg))
+          {
+            ALOGE("Error: AUDIO_GET_AMRNB_ENC_CONFIG_V2 failed\n");
+            goto  Error;
+          }
+
+          ALOGV("The Config band_mode is %d", amr_nb_cfg.band_mode);
+          ALOGV("The Config dtx_enable is %d", amr_nb_cfg.dtx_enable);
+          ALOGV("The Config frame_format is %d", amr_nb_cfg.frame_format);
+
+          amr_nb_cfg.band_mode = 7; /* Bit Rate 12.2 kbps MR122 */
+          amr_nb_cfg.dtx_enable= 0;
+          amr_nb_cfg.frame_format = 0; /* IF1 */
+
+          if (ioctl(mFd, AUDIO_SET_AMRNB_ENC_CONFIG_V2, &amr_nb_cfg))
+          {
+            ALOGE("Error: AUDIO_SET_AMRNB_ENC_CONFIG_V2 failed\n");
+            goto  Error;
+          }
+    }
+#endif
+    else if (*pFormat == AudioSystem::AAC)
+    {
+          ALOGI("Recording format: AAC");
+          // open aac input device
+          status = ::open(AAC_DEVICE_IN, O_RDWR);
+          if (status < 0) {
+              ALOGE("Cannot open aac device for read");
+              goto Error;
+          }
+          mFd = status;
+
+          struct msm_audio_stream_config config;
+          if(ioctl(mFd, AUDIO_GET_STREAM_CONFIG, &config))
+          {
+            ALOGE(" Error getting buf config param AUDIO_GET_STREAM_CONFIG \n");
+            goto  Error;
+          }
+
+          ALOGE("The Config buffer size is %d", config.buffer_size);
+          ALOGE("The Config buffer count is %d", config.buffer_count);
+
+
+          struct msm_audio_aac_enc_config aac_enc_cfg;
+          if (ioctl(mFd, AUDIO_GET_AAC_ENC_CONFIG, &aac_enc_cfg))
+          {
+            ALOGE("Error: AUDIO_GET_AAC_ENC_CONFIG failed\n");
+            goto  Error;
+          }
+
+          ALOGV("The Config channels is %d", aac_enc_cfg.channels);
+          ALOGV("The Config sample_rate is %d", aac_enc_cfg.sample_rate);
+          ALOGV("The Config bit_rate is %d", aac_enc_cfg.bit_rate);
+          ALOGV("The Config stream_format is %d", aac_enc_cfg.stream_format);
+
+          mDevices = devices;
+          mChannels = *pChannels;
+          aac_enc_cfg.sample_rate = mSampleRate = *pRate;
+          mFormat = *pFormat;
+          mBufferSize = 2048;
+          if (*pChannels & (AudioSystem::CHANNEL_IN_MONO))
+              aac_enc_cfg.channels =  1;
+          else if (*pChannels & (AudioSystem::CHANNEL_IN_STEREO))
+              aac_enc_cfg.channels =  2;
+          aac_enc_cfg.bit_rate = 128000;
+
+          ALOGV("Setting the Config channels is %d", aac_enc_cfg.channels);
+          ALOGV("Setting the Config sample_rate is %d", aac_enc_cfg.sample_rate);
+          ALOGV("Setting the Config bit_rate is %d", aac_enc_cfg.bit_rate);
+          ALOGV("Setting the Config stream_format is %d", aac_enc_cfg.stream_format);
+
+          if (ioctl(mFd, AUDIO_SET_AAC_ENC_CONFIG, &aac_enc_cfg))
+          {
+            ALOGE("Error: AUDIO_SET_AAC_ENC_CONFIG failed\n");
+            goto  Error;
+          }
+    }
+    //mHardware->setMicMute_nosync(false);
+    mState = AUDIO_INPUT_OPENED;
+#ifdef HTC_AUDIO
+    mHardware->set_mRecordState(true);
+#endif
+
+    if (!acoustic)
+        return NO_ERROR;
+
+    int (*msm72xx_set_audpre_params)(int, int);
+    msm72xx_set_audpre_params = (int (*)(int, int))::dlsym(acoustic, "msm72xx_set_audpre_params");
+    if ((*msm72xx_set_audpre_params) == 0) {
+        ALOGI("msm72xx_set_audpre_params not present");
+        return NO_ERROR;
+    }
+
+    int (*msm72xx_enable_audpre)(int, int, int);
+    msm72xx_enable_audpre = (int (*)(int, int, int))::dlsym(acoustic, "msm72xx_enable_audpre");
+    if ((*msm72xx_enable_audpre) == 0) {
+        ALOGI("msm72xx_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 = msm72xx_set_audpre_params(audpre_index, tx_iir_index);
+    if (status < 0)
+        ALOGE("Cannot set audpre parameters");
+
+    mAcoustics = acoustic_flags;
+    status = msm72xx_enable_audpre((int)acoustic_flags, audpre_index, tx_iir_index);
+    if (status < 0)
+        ALOGE("Cannot enable audpre");
+
+    return NO_ERROR;
+
+Error:
+    if (mFd >= 0) {
+        ::close(mFd);
+        mFd = -1;
+    }
+    return status;
+}
+
+AudioHardware::AudioStreamInMSM72xx::~AudioStreamInMSM72xx()
+{
+    ALOGV("AudioStreamInMSM72xx destructor");
+    standby();
+}
+
+ssize_t AudioHardware::AudioStreamInMSM72xx::read( void* buffer, ssize_t bytes)
+{
+    unsigned short dec_id = INVALID_DEVICE;
+    ALOGV("AudioStreamInMSM72xx::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(mFd, 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 failed for device %d",DEVICE_FMRADIO_STEREO_TX);
+                hw->mLock.unlock();
+                return -1;
+             }
+
+            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;
+            }
+            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(mFd, AUDIO_GET_SESSION_ID, &dec_id)) {
+                ALOGE("AUDIO_GET_SESSION_ID failed*********");
+                return -1;
+            }
+            ALOGV("dec_id = %d,cur_tx= %d",dec_id,cur_tx);
+            if(cur_tx == INVALID_DEVICE)
+                cur_tx = DEVICE_HANDSET_TX;
+
+            Mutex::Autolock lock(mDeviceSwitchLock);
+
+            if(enableDevice(cur_tx, 1)) {
+                ALOGE("enableDevice failed, device %d",cur_tx);
+                return -1;
+            }
+            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) {
+        // force routing to input device
+        mHardware->clearCurDevice();
+        mHardware->doRouting(this);
+#ifdef HTC_AUDIO
+        if (support_aic3254) {
+            int snd_dev = mHardware->get_snd_dev();
+            mHardware->aic3254_config(snd_dev);
+            mHardware->do_aic3254_control(snd_dev);
+        }
+#endif
+        if (ioctl(mFd, AUDIO_START, 0)) {
+            ALOGE("Error starting record");
+            standby();
+            return -1;
+        }
+        mState = AUDIO_INPUT_STARTED;
+    }
+
+    bytes = 0;
+    if(mFormat == AUDIO_HW_IN_FORMAT)
+    {
+        while (count) {
+            ssize_t bytesRead = ::read(mFd, buffer, count);
+            if (bytesRead >= 0) {
+                count -= bytesRead;
+                p += bytesRead;
+                bytes += bytesRead;
+                if(!mFirstread)
+                {
+                   mFirstread = true;
+                   break;
+                }
+            } else {
+                if (errno != EAGAIN) return bytesRead;
+                mRetryCount++;
+                ALOGW("EAGAIN - retrying");
+            }
+        }
+    }
+#ifdef WITH_QCOM_SPEECH
+    else if ((mFormat == AudioSystem::EVRC) || (mFormat == AudioSystem::QCELP) || (mFormat == AudioSystem::AMR_NB))
+    {
+        uint8_t readBuf[36];
+        uint8_t *dataPtr;
+        while (count) {
+            dataPtr = readBuf;
+            ssize_t bytesRead = ::read(mFd, readBuf, 36);
+            if (bytesRead >= 0) {
+                if (mFormat == AudioSystem::AMR_NB){
+                   amr_transcode(dataPtr,p);
+                   p += AMRNB_FRAME_SIZE;
+                   count -= AMRNB_FRAME_SIZE;
+                   bytes += AMRNB_FRAME_SIZE;
+                   if(!mFirstread)
+                   {
+                      mFirstread = true;
+                      break;
+                   }
+                }
+                else {
+                    dataPtr++;
+                    if (mFormat == AudioSystem::EVRC){
+                       memcpy(p, dataPtr, EVRC_FRAME_SIZE);
+                       p += EVRC_FRAME_SIZE;
+                       count -= EVRC_FRAME_SIZE;
+                       bytes += EVRC_FRAME_SIZE;
+                       if(!mFirstread)
+                       {
+                          mFirstread = true;
+                          break;
+                       }
+                    }
+                    else if (mFormat == AudioSystem::QCELP){
+                       memcpy(p, dataPtr, QCELP_FRAME_SIZE);
+                       p += QCELP_FRAME_SIZE;
+                       count -= QCELP_FRAME_SIZE;
+                       bytes += QCELP_FRAME_SIZE;
+                       if(!mFirstread)
+                       {
+                          mFirstread = true;
+                          break;
+                       }
+                    }
+                }
+
+            } else {
+                if (errno != EAGAIN) return bytesRead;
+                mRetryCount++;
+                ALOGW("EAGAIN - retrying");
+            }
+        }
+    }
+#endif
+    else if (mFormat == AudioSystem::AAC)
+    {
+        *((uint32_t*)recogPtr) = 0x51434F4D ;// ('Q','C','O', 'M') Number to identify format as AAC by higher layers
+        recogPtr++;
+        frameCountPtr = (uint16_t*)recogPtr;
+        *frameCountPtr = 0;
+        p += 3*sizeof(uint16_t);
+        count -= 3*sizeof(uint16_t);
+
+        while (count > 0) {
+            frameSizePtr = (uint16_t *)p;
+            p += sizeof(uint16_t);
+            if(!(count > 2)) break;
+            count -= sizeof(uint16_t);
+
+            ssize_t bytesRead = ::read(mFd, p, count);
+            if (bytesRead > 0) {
+                ALOGV("Number of Bytes read = %d", bytesRead);
+                count -= bytesRead;
+                p += bytesRead;
+                bytes += bytesRead;
+                ALOGV("Total Number of Bytes read = %d", bytes);
+
+                *frameSizePtr =  bytesRead;
+                (*frameCountPtr)++;
+                if(!mFirstread)
+                {
+                   mFirstread = true;
+                   break;
+                }
+                /*Typical frame size for AAC is around 250 bytes. So we have
+                 * taken the minimum buffer size as twice of this size i.e.
+                 * 512 to avoid short reads from driver */
+                if(count < 512)
+                {
+                   ALOGI("buffer passed to driver %d, is less than the min 512 bytes", count);
+                   break;
+                }
+            }
+            else if(bytesRead == 0)
+            {
+             ALOGI("Bytes Read = %d ,Buffer no longer sufficient",bytesRead);
+             break;
+            } else {
+                if (errno != EAGAIN) return bytesRead;
+                mRetryCount++;
+                ALOGW("EAGAIN - retrying");
+            }
+        }
+    }
+
+    if (mFormat == AudioSystem::AAC)
+         return aac_framesize;
+
+        return bytes;
+}
+
+status_t AudioHardware::AudioStreamInMSM72xx::standby()
+{
+    bool isDriverClosed = false;
+    ALOGD("AudioStreamInMSM72xx::standby()");
+    Routing_table* temp = NULL;
+    if (!mHardware) return -1;
+
+#ifdef HTC_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 (mFd >= 0) {
+            ::close(mFd);
+            mFd = -1;
+            ALOGV("driver closed");
+            isDriverClosed = true;
+        }
+        //mHardware->checkMicMute();
+        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("Disabling device failed for device %d", DEVICE_FMRADIO_STEREO_TX);
+        }
+    }
+    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){
+        ALOGD("Deroute pcm in stream");
+        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);
+#ifdef HTC_AUDIO
+        updateDeviceInfo(cur_rx, cur_tx, 0, 0);
+#else
+        updateDeviceInfo(cur_rx, cur_tx);
+#endif
+    }//mRecordingSession condition.
+    // restore output routing if necessary
+    mHardware->clearCurDevice();
+    mHardware->doRouting(this);
+    return NO_ERROR;
+}
+
+status_t AudioHardware::AudioStreamInMSM72xx::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    result.append("AudioStreamInMSM72xx::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::AudioStreamInMSM72xx::setParameters(const String8& keyValuePairs)
+{
+    AudioParameter param = AudioParameter(keyValuePairs);
+    String8 key = String8(AudioParameter::keyRouting);
+    status_t status = NO_ERROR;
+    int device;
+    ALOGV("AudioStreamInMSM72xx::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::AudioStreamInMSM72xx::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("AudioStreamInMSM72xx::getParameters() %s", param.toString().string());
+    return param.toString();
+}
+
+// getActiveInput_l() must be called with mLock held
+AudioHardware::AudioStreamInMSM72xx *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() > AudioStreamInMSM72xx::AUDIO_INPUT_CLOSED) {
+            return mInputs[i];
+        }
+    }
+
+    return NULL;
+}
+
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+status_t AudioHardware::setupDeviceforVoipCall(bool value)
+{
+
+    int mode = (value ? AudioSystem::MODE_IN_COMMUNICATION : AudioSystem::MODE_NORMAL);
+    if (setMode(mode) != NO_ERROR) {
+        ALOGV("setMode fails");
+        return UNKNOWN_ERROR;
+    }
+
+    if (setMicMute(!value) != NO_ERROR) {
+        ALOGV("MicMute fails");
+        return UNKNOWN_ERROR;
+    }
+
+    ALOGD("Device setup sucess for VOIP call");
+
+    return NO_ERROR;
+}
+
+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;
+    }
+    else {
+
+       ALOGV("Going to enable RX/TX device for voice stream");
+        // Routing Voice
+        if ( (cur_rx != INVALID_DEVICE) && (cur_tx != INVALID_DEVICE))
+        {
+            ALOGV("Starting voice 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))
+        {
+            ALOGI(" 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;
+        }
+
+        // start Voice call
+        ALOGD("Starting voice call and UnMuting the call");
+        msm_start_voice();
+        msm_set_voice_tx_mute(0);
+        addToTable(0,cur_rx,cur_tx,VOICE_CALL,true);
+
+        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");
+
+        // 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");
+        mvs_config.mvs_mode = MVS_MODE_PCM;
+        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;
+        }
+    }
+    mFormat =  *pFormat;
+    mChannels = *pChannels;
+    mSampleRate = *pRate;
+    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("AudioStreamInVoip::set return bad values\n");
+        return BAD_VALUE;
+    }
+
+    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;
+
+    ALOGV(" Set mVoipFd now\n");
+    mHardware->mVoipFd = mFd;
+    mHardware->mVoipInActive = true;
+
+    if (mHardware->mVoipOutActive)
+        mHardware->setupDeviceforVoipCall(true);
+
+    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");
+    mHardware->mVoipInActive = false;
+    standby();
+}
+
+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;
+
+    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
+      ALOGV("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 q5v2_msm_audio_mvs_frame audio_mvs_frame;
+        audio_mvs_frame.frame_type = 0;
+        while (count >= mBufferSize) {
+            audio_mvs_frame.len = mBufferSize;
+            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 mvs bytes \n", bytesRead);
+            if (bytesRead > 0) {
+                memcpy(buffer+totalBytesRead,&audio_mvs_frame.voc_pkt, mBufferSize);
+                count -= mBufferSize;
+                totalBytesRead += mBufferSize;
+                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()
+{
+    Routing_table* temp = NULL;
+    ALOGD("AudioStreamInVoip::standby");
+    Mutex::Autolock lock(mHardware->mVoipLock);
+    if (!mHardware) return -1;
+    ALOGE("VoipOut %d driver fd %d", mHardware->mVoipOutActive, mHardware->mVoipFd);
+    mHardware->mVoipInActive = false;
+    if (mState > AUDIO_INPUT_CLOSED && !mHardware->mVoipOutActive) {
+         ALOGE(" closing mvs driver\n");
+         //Mute and disable the device.
+         int ret = msm_set_voice_rx_vol(0);
+         if (ret <0)
+            ALOGE("Error %d setting volume\n", ret);
+         ret = msm_set_voice_tx_mute(1);
+         if (ret < 0)
+            ALOGE("Error %d setting mute\n", ret);
+         ret = msm_end_voice();
+         if (ret < 0)
+            ALOGE("Error %d ending voice\n", ret);
+         if (ret < 0)
+            ALOGE("Error %d closing mixer\n", ret);
+         if (mHardware->mVoipFd >= 0) {
+            ret = ioctl(mHardware->mVoipFd, AUDIO_STOP, NULL);
+            ALOGD("MVS stop returned %d %d %d\n", ret, __LINE__, mHardware->mVoipFd);
+            ::close(mFd);
+            mFd = mHardware->mVoipFd = -1;
+            mHardware->setupDeviceforVoipCall(false);
+            ALOGD("MVS driver closed %d mFd %d", __LINE__, mHardware->mVoipFd);
+        }
+        mState = AUDIO_INPUT_CLOSED;
+    }
+    else
+        ALOGE("Not closing MVS driver");
+    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)) {
+            ALOGV(" return BAD_VALUE ");
+            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;
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+extern "C" AudioHardwareInterface* createAudioHardware(void) {
+    return new AudioHardware();
+}
+
+#ifdef WITH_QCOM_SPEECH
+/*===========================================================================
+
+FUNCTION amrsup_frame_len
+
+DESCRIPTION
+  This function will determine number of bytes of AMR vocoder frame length
+based on the frame type and frame rate.
+
+DEPENDENCIES
+  None.
+
+RETURN VALUE
+  number of bytes of AMR frame
+
+SIDE EFFECTS
+  None.
+
+===========================================================================*/
+int amrsup_frame_len_bits(
+  amrsup_frame_type frame_type,
+  amrsup_mode_type amr_mode
+)
+{
+  int frame_len=0;
+
+
+  switch (frame_type)
+  {
+    case AMRSUP_SPEECH_GOOD :
+    case AMRSUP_SPEECH_DEGRADED :
+    case AMRSUP_ONSET :
+    case AMRSUP_SPEECH_BAD :
+      if (amr_mode >= AMRSUP_MODE_MAX)
+      {
+        frame_len = 0;
+      }
+      else
+      {
+        frame_len = amrsup_122_framing.len_a
+                    + amrsup_122_framing.len_b
+                    + amrsup_122_framing.len_c;
+      }
+      break;
+
+    case AMRSUP_SID_FIRST :
+    case AMRSUP_SID_UPDATE :
+    case AMRSUP_SID_BAD :
+      frame_len = AMR_CLASS_A_BITS_SID;
+      break;
+
+    case AMRSUP_NO_DATA :
+    case AMRSUP_SPEECH_LOST :
+    default :
+      frame_len = 0;
+  }
+
+  return frame_len;
+}
+
+/*===========================================================================
+
+FUNCTION amrsup_frame_len
+
+DESCRIPTION
+  This function will determine number of bytes of AMR vocoder frame length
+based on the frame type and frame rate.
+
+DEPENDENCIES
+  None.
+
+RETURN VALUE
+  number of bytes of AMR frame
+
+SIDE EFFECTS
+  None.
+
+===========================================================================*/
+int amrsup_frame_len(
+  amrsup_frame_type frame_type,
+  amrsup_mode_type amr_mode
+)
+{
+  int frame_len = amrsup_frame_len_bits(frame_type, amr_mode);
+
+  frame_len = (frame_len + 7) / 8;
+  return frame_len;
+}
+
+/*===========================================================================
+
+FUNCTION amrsup_tx_order
+
+DESCRIPTION
+  Use a bit ordering table to order bits from their original sequence.
+
+DEPENDENCIES
+  None.
+
+RETURN VALUE
+  None.
+
+SIDE EFFECTS
+  None.
+
+===========================================================================*/
+void amrsup_tx_order(
+  unsigned char *dst_frame,
+  int         *dst_bit_index,
+  unsigned char *src,
+  int         num_bits,
+  const unsigned short *order
+)
+{
+  unsigned long dst_mask = 0x00000080 >> ((*dst_bit_index) & 0x7);
+  unsigned char *dst = &dst_frame[((unsigned int) *dst_bit_index) >> 3];
+  unsigned long src_bit, src_mask;
+
+  /* Prepare to process all bits
+  */
+  *dst_bit_index += num_bits;
+  num_bits++;
+
+  while(--num_bits) {
+    /* Get the location of the bit in the input buffer */
+    src_bit  = (unsigned long ) *order++;
+    src_mask = 0x00000080 >> (src_bit & 0x7);
+
+    /* Set the value of the output bit equal to the input bit */
+    if (src[src_bit >> 3] & src_mask) {
+      *dst |= (unsigned char ) dst_mask;
+    }
+
+    /* Set the destination bit mask and increment pointer if necessary */
+    dst_mask >>= 1;
+    if (dst_mask == 0) {
+      dst_mask = 0x00000080;
+      dst++;
+    }
+  }
+} /* amrsup_tx_order */
+
+/*===========================================================================
+
+FUNCTION amrsup_if1_framing
+
+DESCRIPTION
+  Performs the transmit side framing function.  Generates AMR IF1 ordered data
+  from the vocoder packet and frame type.
+
+DEPENDENCIES
+  None.
+
+RETURN VALUE
+  number of bytes of encoded frame.
+  if1_frame : IF1-encoded frame.
+  if1_frame_info : holds frame information of IF1-encoded frame.
+
+SIDE EFFECTS
+  None.
+
+===========================================================================*/
+static int amrsup_if1_framing(
+  unsigned char              *vocoder_packet,
+  amrsup_frame_type          frame_type,
+  amrsup_mode_type           amr_mode,
+  unsigned char              *if1_frame,
+  amrsup_if1_frame_info_type *if1_frame_info
+)
+{
+  amrsup_frame_order_type *ordering_table;
+  int frame_len = 0;
+  int i;
+
+  if(amr_mode >= AMRSUP_MODE_MAX)
+  {
+    ALOGE("Invalid AMR_Mode : %d",amr_mode);
+    return 0;
+  }
+
+  /* Initialize IF1 frame data and info */
+  if1_frame_info->fqi = true;
+
+  if1_frame_info->amr_type = AMRSUP_CODEC_AMR_NB;
+
+  memset(if1_frame, 0,
+           amrsup_frame_len(AMRSUP_SPEECH_GOOD, AMRSUP_MODE_1220));
+
+
+  switch (frame_type)
+  {
+    case AMRSUP_SID_BAD:
+      if1_frame_info->fqi = false;
+      /* fall thru */
+
+    case AMRSUP_SID_FIRST:
+    case AMRSUP_SID_UPDATE:
+      /* Set frame type index */
+      if1_frame_info->frame_type_index
+      = AMRSUP_FRAME_TYPE_INDEX_AMR_SID;
+
+
+      /* ===== Encoding SID frame ===== */
+      /* copy the sid frame to class_a data */
+      for (i=0; i<5; i++)
+      {
+        if1_frame[i] = vocoder_packet[i];
+      }
+
+      /* Set the SID type : SID_FIRST: Bit 35 = 0, SID_UPDATE : Bit 35 = 1 */
+      if (frame_type == AMRSUP_SID_FIRST)
+      {
+        if1_frame[4] &= ~0x10;
+      }
+
+      if (frame_type == AMRSUP_SID_UPDATE)
+      {
+        if1_frame[4] |= 0x10;
+      }
+      else
+      {
+      /* Set the mode (Bit 36 - 38 = amr_mode with bits swapped)
+      */
+      if1_frame[4] |= (((unsigned char)amr_mode << 3) & 0x08)
+        | (((unsigned char)amr_mode << 1) & 0x04) | (((unsigned char)amr_mode >> 1) & 0x02);
+
+      frame_len = AMR_CLASS_A_BITS_SID;
+      }
+
+      break;
+
+
+    case AMRSUP_SPEECH_BAD:
+      if1_frame_info->fqi = false;
+      /* fall thru */
+
+    case AMRSUP_SPEECH_GOOD:
+      /* Set frame type index */
+
+        if1_frame_info->frame_type_index
+        = (amrsup_frame_type_index_type)(amr_mode);
+
+      /* ===== Encoding Speech frame ===== */
+      /* Clear num bits in frame */
+      frame_len = 0;
+
+      /* Select ordering table */
+      ordering_table =
+      (amrsup_frame_order_type*)&amrsup_122_framing;
+
+      amrsup_tx_order(
+        if1_frame,
+        &frame_len,
+        vocoder_packet,
+        ordering_table->len_a,
+        ordering_table->class_a
+      );
+
+      amrsup_tx_order(
+        if1_frame,
+        &frame_len,
+        vocoder_packet,
+        ordering_table->len_b,
+        ordering_table->class_b
+      );
+
+      amrsup_tx_order(
+        if1_frame,
+        &frame_len,
+        vocoder_packet,
+        ordering_table->len_c,
+        ordering_table->class_c
+      );
+
+
+      /* frame_len already updated with correct number of bits */
+      break;
+
+
+
+    default:
+      ALOGE("Unsupported frame type %d", frame_type);
+      /* fall thru */
+
+    case AMRSUP_NO_DATA:
+      /* Set frame type index */
+      if1_frame_info->frame_type_index = AMRSUP_FRAME_TYPE_INDEX_NO_DATA;
+
+      frame_len = 0;
+
+      break;
+  }  /* end switch */
+
+
+  /* convert bit length to byte length */
+  frame_len = (frame_len + 7) / 8;
+
+  return frame_len;
+}
+
+static void amr_transcode(unsigned char *src, unsigned char *dst)
+{
+   amrsup_frame_type frame_type_in = (amrsup_frame_type) *(src++);
+   amrsup_mode_type frame_rate_in = (amrsup_mode_type) *(src++);
+   amrsup_if1_frame_info_type frame_info_out;
+   unsigned char frameheader;
+
+   amrsup_if1_framing(src, frame_type_in, frame_rate_in, dst+1, &frame_info_out);
+   frameheader = (frame_info_out.frame_type_index << 3) + (frame_info_out.fqi << 2);
+   *dst = frameheader;
+
+   return;
+}
+#endif
+
+}; // namespace android
diff --git a/msm7x30/AudioHardware.h b/msm7x30/AudioHardware.h
new file mode 100644
index 0000000..9a5b7f5
--- /dev/null
+++ b/msm7x30/AudioHardware.h
@@ -0,0 +1,664 @@
+/*
+** Copyright 2008, The Android Open-Source Project
+** Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+** Copyright (c) 2011-2013, The CyanogenMod Project
+** Not a Contribution, Apache license notifications and license are retained
+** for attribution purposes only.
+**
+** 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/threads.h>
+#include <utils/SortedVector.h>
+
+#include <hardware_legacy/AudioHardwareBase.h>
+
+extern "C" {
+#include <linux/msm_audio.h>
+#include <linux/msm_audio_aac.h>
+#ifdef WITH_QCOM_SPEECH
+#include <linux/msm_audio_qcp.h>
+#include <linux/msm_audio_amrnb.h>
+#endif
+}
+
+namespace android_audio_legacy {
+using android::SortedVector;
+using android::Mutex;
+
+// ----------------------------------------------------------------------------
+// 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
+
+#ifdef HTC_AUDIO
+#define MOD_PLAY 1
+#define MOD_REC  2
+#define MOD_TX   3
+#define MOD_RX   4
+
+#define VOICE_VOLUME_MAX                  100  /* Maximum voice volume */
+
+#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_PLAYBACK          407
+#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
+#define ACDB_ID_ALT_SPKR_PLAYBACK         608
+#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];
+};
+
+struct msm_audio_stats {
+    uint32_t out_bytes;
+    uint32_t unused[3];
+};
+
+#ifdef WITH_QCOM_SPEECH
+/* AMR frame type definitions */
+typedef enum {
+  AMRSUP_SPEECH_GOOD,          /* Good speech frame              */
+  AMRSUP_SPEECH_DEGRADED,      /* Speech degraded                */
+  AMRSUP_ONSET,                /* onset                          */
+  AMRSUP_SPEECH_BAD,           /* Corrupt speech frame (bad CRC) */
+  AMRSUP_SID_FIRST,            /* First silence descriptor       */
+  AMRSUP_SID_UPDATE,           /* Comfort noise frame            */
+  AMRSUP_SID_BAD,              /* Corrupt SID frame (bad CRC)    */
+  AMRSUP_NO_DATA,              /* Nothing to transmit            */
+  AMRSUP_SPEECH_LOST,          /* Lost speech in downlink        */
+  AMRSUP_FRAME_TYPE_MAX
+} amrsup_frame_type;
+
+/* AMR frame mode (frame rate) definitions */
+typedef enum {
+  AMRSUP_MODE_0475,    /* 4.75 kbit /s */
+  AMRSUP_MODE_0515,    /* 5.15 kbit /s */
+  AMRSUP_MODE_0590,    /* 5.90 kbit /s */
+  AMRSUP_MODE_0670,    /* 6.70 kbit /s */
+  AMRSUP_MODE_0740,    /* 7.40 kbit /s */
+  AMRSUP_MODE_0795,    /* 7.95 kbit /s */
+  AMRSUP_MODE_1020,    /* 10.2 kbit /s */
+  AMRSUP_MODE_1220,    /* 12.2 kbit /s */
+  AMRSUP_MODE_MAX
+} amrsup_mode_type;
+
+/* The AMR classes
+*/
+typedef enum  {
+  AMRSUP_CLASS_A,
+  AMRSUP_CLASS_B,
+  AMRSUP_CLASS_C
+} amrsup_class_type;
+
+/* The maximum number of bits in each class */
+#define AMRSUP_CLASS_A_MAX 81
+#define AMRSUP_CLASS_B_MAX 405
+#define AMRSUP_CLASS_C_MAX 60
+
+/* The size of the buffer required to hold the vocoder frame */
+#define AMRSUP_VOC_FRAME_BYTES  \
+  ((AMRSUP_CLASS_A_MAX + AMRSUP_CLASS_B_MAX + AMRSUP_CLASS_C_MAX + 7) / 8)
+
+/* Size of each AMR class to hold one frame of AMR data */
+#define AMRSUP_CLASS_A_BYTES ((AMRSUP_CLASS_A_MAX + 7) / 8)
+#define AMRSUP_CLASS_B_BYTES ((AMRSUP_CLASS_B_MAX + 7) / 8)
+#define AMRSUP_CLASS_C_BYTES ((AMRSUP_CLASS_C_MAX + 7) / 8)
+
+
+/* Number of bytes for an AMR IF2 frame */
+#define AMRSUP_IF2_FRAME_BYTES 32
+
+/* Frame types for 4-bit frame type as in 3GPP TS 26.101 v3.2.0, Sec.4.1.1 */
+typedef enum {
+  AMRSUP_FRAME_TYPE_INDEX_0475    = 0,    /* 4.75 kbit /s    */
+  AMRSUP_FRAME_TYPE_INDEX_0515    = 1,    /* 5.15 kbit /s    */
+  AMRSUP_FRAME_TYPE_INDEX_0590    = 2,    /* 5.90 kbit /s    */
+  AMRSUP_FRAME_TYPE_INDEX_0670    = 3,    /* 6.70 kbit /s    */
+  AMRSUP_FRAME_TYPE_INDEX_0740    = 4,    /* 7.40 kbit /s    */
+  AMRSUP_FRAME_TYPE_INDEX_0795    = 5,    /* 7.95 kbit /s    */
+  AMRSUP_FRAME_TYPE_INDEX_1020    = 6,    /* 10.2 kbit /s    */
+  AMRSUP_FRAME_TYPE_INDEX_1220    = 7,    /* 12.2 kbit /s    */
+  AMRSUP_FRAME_TYPE_INDEX_AMR_SID = 8,    /* SID frame       */
+/* Frame types 9-11 are not supported */
+  AMRSUP_FRAME_TYPE_INDEX_NO_DATA = 15,   /* No data         */
+  AMRSUP_FRAME_TYPE_INDEX_MAX,
+  AMRSUP_FRAME_TYPE_INDEX_UNDEF = AMRSUP_FRAME_TYPE_INDEX_MAX
+} amrsup_frame_type_index_type;
+
+#define AMRSUP_FRAME_TYPE_INDEX_MASK         0x0F /* All frame types */
+#define AMRSUP_FRAME_TYPE_INDEX_SPEECH_MASK  0x07 /* Speech frame    */
+
+typedef enum {
+  AMRSUP_CODEC_AMR_NB,
+  AMRSUP_CODEC_AMR_WB,
+  AMRSUP_CODEC_MAX
+} amrsup_codec_type;
+
+/* IF1-encoded frame info */
+typedef struct {
+  amrsup_frame_type_index_type frame_type_index;
+  unsigned char fqi;    /* frame quality indicator: TRUE: good frame, FALSE: bad */
+  amrsup_codec_type amr_type;   /* AMR-NB or AMR-WB */
+} amrsup_if1_frame_info_type;
+
+#define AUDFADEC_AMR_FRAME_TYPE_MASK     0x78
+#define AUDFADEC_AMR_FRAME_TYPE_SHIFT    3
+#define AUDFADEC_AMR_FRAME_QUALITY_MASK  0x04
+
+#define AMR_CLASS_A_BITS_BAD   0
+
+#define AMR_CLASS_A_BITS_SID  39
+
+#define AMR_CLASS_A_BITS_122  81
+#define AMR_CLASS_B_BITS_122 103
+#define AMR_CLASS_C_BITS_122  60
+
+typedef struct {
+  int   len_a;
+  unsigned short *class_a;
+  int   len_b;
+  unsigned short *class_b;
+  int   len_c;
+  unsigned short *class_c;
+} amrsup_frame_order_type;
+#endif
+
+#ifdef HTC_AUDIO
+struct msm_bt_endpoint {
+    int tx;
+    int rx;
+    char name[64];
+};
+#endif
+
+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 2048                 // Default audio input buffer size
+#define AUDIO_HW_IN_FORMAT (AudioSystem::PCM_16_BIT)  // Default audio input sample format
+#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
+
+#ifdef WITH_QCOM_SPEECH
+/* ======================== 12.2 kbps mode ========================== */
+const unsigned short amrsup_bit_order_122_a[AMR_CLASS_A_BITS_122] = {
+     0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
+    10,  11,  12,  13,  14,  23,  15,  16,  17,  18,
+    19,  20,  21,  22,  24,  25,  26,  27,  28,  38,
+   141,  39, 142,  40, 143,  41, 144,  42, 145,  43,
+   146,  44, 147,  45, 148,  46, 149,  47,  97, 150,
+   200,  48,  98, 151, 201,  49,  99, 152, 202,  86,
+   136, 189, 239,  87, 137, 190, 240,  88, 138, 191,
+   241,  91, 194,  92, 195,  93, 196,  94, 197,  95,
+   198
+};
+
+const unsigned short amrsup_bit_order_122_b[AMR_CLASS_B_BITS_122] = {
+   /**/  29,  30,  31,  32,  33,  34,  35,  50, 100,
+   153, 203,  89, 139, 192, 242,  51, 101, 154, 204,
+    55, 105, 158, 208,  90, 140, 193, 243,  59, 109,
+   162, 212,  63, 113, 166, 216,  67, 117, 170, 220,
+    36,  37,  54,  53,  52,  58,  57,  56,  62,  61,
+    60,  66,  65,  64,  70,  69,  68, 104, 103, 102,
+   108, 107, 106, 112, 111, 110, 116, 115, 114, 120,
+   119, 118, 157, 156, 155, 161, 160, 159, 165, 164,
+   163, 169, 168, 167, 173, 172, 171, 207, 206, 205,
+   211, 210, 209, 215, 214, 213, 219, 218, 217, 223,
+   222, 221,  73,  72
+};
+
+
+const unsigned short amrsup_bit_order_122_c[AMR_CLASS_C_BITS_122] = {
+   /* ------------- */  71,  76,  75,  74,  79,  78,
+    77,  82,  81,  80,  85,  84,  83, 123, 122, 121,
+   126, 125, 124, 129, 128, 127, 132, 131, 130, 135,
+   134, 133, 176, 175, 174, 179, 178, 177, 182, 181,
+   180, 185, 184, 183, 188, 187, 186, 226, 225, 224,
+   229, 228, 227, 232, 231, 230, 235, 234, 233, 238,
+   237, 236,  96, 199
+};
+
+
+const amrsup_frame_order_type amrsup_122_framing = {
+  AMR_CLASS_A_BITS_122,
+  (unsigned short *) amrsup_bit_order_122_a,
+  AMR_CLASS_B_BITS_122,
+  (unsigned short *) amrsup_bit_order_122_b,
+  AMR_CLASS_C_BITS_122,
+  (unsigned short *) amrsup_bit_order_122_c
+};
+#endif
+
+// ----------------------------------------------------------------------------
+
+using android_audio_legacy::AudioHardwareBase;
+using android_audio_legacy::AudioStreamOut;
+using android_audio_legacy::AudioStreamIn;
+using android_audio_legacy::AudioSystem;
+using android_audio_legacy::AudioHardwareInterface;
+
+class AudioHardware : public  AudioHardwareBase
+{
+    class AudioStreamOutMSM72xx;
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+    class AudioSessionOutMSM7xxx;
+#endif /* QCOM_TUNNEL_LPA_ENABLED */
+    class AudioStreamInMSM72xx;
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+    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,
+                            //    audio_output_flags_t flags,
+                                int *format=0,
+                                uint32_t *channels=0,
+                                uint32_t *sampleRate=0,
+                                status_t *status=0);
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+    virtual AudioStreamOut* openOutputSession(
+                                uint32_t devices,
+                                int *format=0,
+                                status_t *status=0,
+                                int sessionId=-1,
+                                uint32_t samplingRate=0,
+                                uint32_t channels=0);
+#endif /* QCOM_TUNNEL_LPA_ENABLED */
+
+    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);
+    status_t setupDeviceforVoipCall(bool value);
+
+private:
+
+#ifdef HTC_AUDIO
+    status_t    doAudioRouteOrMuteHTC(uint32_t device);
+#endif
+    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();
+    status_t    doRouting(AudioStreamInMSM72xx *input);
+#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
+#ifdef HTC_AUDIO
+    status_t    get_mMode();
+    status_t    set_mRecordState(bool onoff);
+    status_t    get_mRecordState();
+    status_t    get_snd_dev();
+    uint32_t    getACDB(int mode, 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();
+    int         aic3254_set_volume(int volume);
+#endif
+    AudioStreamInMSM72xx*   getActiveInput_l();
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+    AudioStreamInVoip* getActiveVoipInput_l();
+#endif
+    FILE *fp;
+
+    class AudioStreamOutMSM72xx : public AudioStreamOut {
+    public:
+                            AudioStreamOutMSM72xx();
+        virtual             ~AudioStreamOutMSM72xx();
+                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 WITH_QCOM_VOIP_OVER_MVS
+    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 { ALOGE(" AudioStreamOutDirect: sampleRate\n"); return 8000; }
+        // must be 32-bit aligned - driver only seems to like 4800
+        virtual size_t      bufferSize() const { ALOGE(" AudioStreamOutDirect: bufferSize\n"); return 320; }
+        virtual uint32_t    channels() const {ALOGD(" AudioStreamOutDirect: channels\n"); return mChannels; }
+        virtual int         format() const {ALOGE(" AudioStreamOutDirect: format\n"); 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;
+                int         mSessionId;
+                uint32_t    mChannels;
+                uint32_t    mSampleRate;
+                size_t      mBufferSize;
+                int         mFormat;
+
+    };
+#endif
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+    class AudioSessionOutMSM7xxx : public AudioStreamOut {
+    public:
+                            AudioSessionOutMSM7xxx();
+        virtual             ~AudioSessionOutMSM7xxx();
+                status_t    set(AudioHardware* mHardware,
+                                uint32_t devices,
+                                int *pFormat,
+                                int32_t sessionId);
+        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::MP3; }
+        virtual uint32_t    latency() const { return 0; }
+        virtual status_t    setVolume(float left, float right);
+        virtual ssize_t     write(const void* buffer, size_t bytes) {return 0;};
+        virtual status_t    standby();
+        virtual status_t    dump(int fd, const Vector<String16>& args) {return 0;};
+                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         mStartCount;
+                int         mRetryCount;
+                bool        mStandby;
+                uint32_t    mDevices;
+                int         mSessionId;
+    };
+#endif /* QCOM_TUNNEL_LPA_ENABLED */
+
+    class AudioStreamInMSM72xx : public AudioStreamIn {
+    public:
+        enum input_state {
+            AUDIO_INPUT_CLOSED,
+            AUDIO_INPUT_OPENED,
+            AUDIO_INPUT_STARTED
+        };
+
+                            AudioStreamInMSM72xx();
+        virtual             ~AudioStreamInMSM72xx();
+                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;}
+
+    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;
+    };
+
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+    class AudioStreamInVoip : public AudioStreamInMSM72xx  { //*/ AudioStreamIn {
+    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 { ALOGE("\n AudioStreamInVoip mBufferSize %d  ",mBufferSize); return mBufferSize; } //320; }
+        virtual uint32_t    channels() const {ALOGD(" AudioStreamInVoip: channels %d \n",mChannels); return mChannels; }
+        virtual int         format() const { ALOGE("\n AudioStreamInVoip mFormat %d",mFormat); return mFormat; }//AUDIO_HW_IN_FORMAT; }
+        virtual uint32_t    sampleRate() const { ALOGE("\n AudioStreamInVoip mSampleRate %d ",mSampleRate); return mSampleRate;} //8000; }
+        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; }
+
+    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;
+                int         mSessionId;
+    };
+#endif
+            static const uint32_t inputSamplingRates[];
+            bool        mInit;
+            bool        mMicMute;
+            int         mFmFd;
+            bool        mBluetoothNrec;
+            bool        mBluetoothVGS;
+            uint32_t    mBluetoothId;
+            float       mVoiceVolume;
+#ifdef HTC_AUDIO
+            bool        mHACSetting;
+            uint32_t    mBluetoothIdTx;
+            uint32_t    mBluetoothIdRx;
+            msm_bt_endpoint *mBTEndpoints;
+            int         mNumBTEndpoints;
+            int         mNoiseSuppressionState;
+            bool        mRecordState;
+            char        mCurDspProfile[22];
+            bool        mEffectEnabled;
+            char        mActiveAP[10];
+            char        mEffect[10];
+#endif
+            AudioStreamOutMSM72xx*  mOutput;
+            SortedVector <AudioStreamInMSM72xx*>   mInputs;
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+            AudioStreamOutDirect*  mDirectOutput;
+#endif
+            int mCurSndDevice;
+            int m7xsnddriverfd;
+            bool    mDualMicEnabled;
+            int     mTtyMode;
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+            SortedVector <AudioStreamInVoip*>   mVoipInputs;
+#endif
+
+            friend class AudioStreamInMSM72xx;
+            Mutex       mLock;
+#ifdef WITH_QCOM_VOIP_OVER_MVS
+            int mVoipFd;
+            bool mVoipInActive;
+            bool mVoipOutActive;
+            Mutex mVoipLock;
+            int mVoipSession;
+#endif
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_MSM72XX_H
diff --git a/msm7x30/AudioPolicyManager.cpp b/msm7x30/AudioPolicyManager.cpp
new file mode 100644
index 0000000..f6076da
--- /dev/null
+++ b/msm7x30/AudioPolicyManager.cpp
@@ -0,0 +1,2184 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2012-2013, The Linux Foundation. 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 LOG_NDDEBUG 0
+
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+// A device mask for all audio input devices that are considered "virtual" when evaluating
+// active inputs in getActiveInput()
+#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL  AUDIO_DEVICE_IN_REMOTE_SUBMIX
+// A device mask for all audio output devices that are considered "remote" when evaluating
+// active output devices in isStreamActiveRemotely()
+#define APM_AUDIO_OUT_DEVICE_REMOTE_ALL  AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+
+#include <utils/Log.h>
+
+#include "AudioPolicyManager.h"
+#include <hardware/audio_effect.h>
+#include <hardware/audio.h>
+#include <hardware_legacy/audio_policy_conf.h>
+#include <math.h>
+#include <media/mediarecorder.h>
+#include <stdio.h>
+#include <cutils/properties.h>
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManager
+// ----------------------------------------------------------------------------
+
+AudioParameter param;
+
+void AudioPolicyManager::setStrategyMute(routing_strategy strategy,
+                                             bool on,
+                                             audio_io_handle_t output,
+                                             int delayMs,
+                                             audio_devices_t device)
+{
+    ALOGVV("setStrategyMute() strategy %d, mute %d, output %d", strategy, on, output);
+    for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+        if (getStrategy((AudioSystem::stream_type)stream) == strategy) {
+            setStreamMute(stream, on, output, delayMs, device);
+        }
+    }
+}
+
+void AudioPolicyManager::releaseOutput(audio_io_handle_t output)
+{
+    ALOGV("releaseOutput() %d", output);
+    ssize_t index = mOutputs.indexOfKey(output);
+    if (index < 0) {
+        ALOGW("releaseOutput() releasing unknown output %d", output);
+        return;
+    }
+
+#ifdef AUDIO_POLICY_TEST
+    int testIndex = testOutputIndex(output);
+    if (testIndex != 0) {
+        AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+        if (outputDesc->isActive()) {
+            mpClientInterface->closeOutput(output);
+            delete mOutputs.valueAt(index);
+            mOutputs.removeItem(output);
+            mTestOutputs[testIndex] = 0;
+        }
+        return;
+    }
+#endif //AUDIO_POLICY_TEST
+
+    AudioOutputDescriptor *desc = mOutputs.valueAt(index);
+    if (desc->mFlags & AudioSystem::OUTPUT_FLAG_DIRECT) {
+        if ((desc->mDirectOpenCount <= 0) && !(desc->mFlags & AUDIO_OUTPUT_FLAG_LPA || desc->mFlags & AUDIO_OUTPUT_FLAG_TUNNEL ||
+                desc->mFlags & AUDIO_OUTPUT_FLAG_VOIP_RX)) {
+            ALOGW("releaseOutput() invalid open count %d for output %d",
+                                                              desc->mDirectOpenCount, output);
+            return;
+        }
+        if ((--desc->mDirectOpenCount == 0) || ((desc->mFlags & AUDIO_OUTPUT_FLAG_LPA || desc->mFlags & AUDIO_OUTPUT_FLAG_TUNNEL ||
+                desc->mFlags & AUDIO_OUTPUT_FLAG_VOIP_RX))) {
+            ALOGV("releaseOutput() closing output");
+            closeOutput(output);
+        }
+    }
+
+}
+
+uint32_t AudioPolicyManager::checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc,
+                                                       audio_devices_t prevDevice,
+                                                       uint32_t delayMs)
+{
+    // mute/unmute strategies using an incompatible device combination
+    // if muting, wait for the audio in pcm buffer to be drained before proceeding
+    // if unmuting, unmute only after the specified delay
+    if (outputDesc->isDuplicated()) {
+        return 0;
+    }
+
+    uint32_t muteWaitMs = 0;
+    audio_devices_t device = outputDesc->device();
+    bool shouldMute = (outputDesc->isActive()) &&
+                    (AudioSystem::popCount(device) >= 2);
+    // temporary mute output if device selection changes to avoid volume bursts due to
+    // different per device volumes
+    bool tempMute = (outputDesc->isActive()) && (device != prevDevice);
+
+    for (size_t i = 0; i < NUM_STRATEGIES; i++) {
+        audio_devices_t curDevice = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/);
+        bool mute = shouldMute && (curDevice & device) && (curDevice != device);
+        bool doMute = false;
+
+        if (mute && !outputDesc->mStrategyMutedByDevice[i]) {
+            doMute = true;
+            outputDesc->mStrategyMutedByDevice[i] = true;
+        } else if (!mute && outputDesc->mStrategyMutedByDevice[i]){
+            doMute = true;
+            outputDesc->mStrategyMutedByDevice[i] = false;
+        }
+        if (doMute || tempMute) {
+            for (size_t j = 0; j < mOutputs.size(); j++) {
+                AudioOutputDescriptor *desc = mOutputs.valueAt(j);
+                if ((desc->supportedDevices() & outputDesc->supportedDevices())
+                        == AUDIO_DEVICE_NONE) {
+                    continue;
+                }
+                audio_io_handle_t curOutput = mOutputs.keyAt(j);
+                ALOGVV("checkDeviceMuteStrategies() %s strategy %d (curDevice %04x) on output %d",
+                      mute ? "muting" : "unmuting", i, curDevice, curOutput);
+                setStrategyMute((routing_strategy)i, mute, curOutput, mute ? 0 : delayMs);
+                if (desc->isStrategyActive((routing_strategy)i)) {
+                    // do tempMute only for current output
+                    if (tempMute && (desc == outputDesc)) {
+                        setStrategyMute((routing_strategy)i, true, curOutput);
+                        setStrategyMute((routing_strategy)i, false, curOutput,
+                                            desc->latency() * ((desc->mFlags & AUDIO_OUTPUT_FLAG_LPA) ? 4 : 2),
+                                            device);
+                    }
+                    if ((tempMute && (desc == outputDesc)) || mute) {
+                        if (muteWaitMs < desc->latency()) {
+                            muteWaitMs = desc->latency();
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // FIXME: should not need to double latency if volume could be applied immediately by the
+    // audioflinger mixer. We must account for the delay between now and the next time
+    // the audioflinger thread for this output will process a buffer (which corresponds to
+    // one buffer size, usually 1/2 or 1/4 of the latency).
+    muteWaitMs *= 2;
+    // wait for the PCM output buffers to empty before proceeding with the rest of the command
+    if (muteWaitMs > delayMs) {
+        muteWaitMs -= delayMs;
+        usleep(muteWaitMs * 1000);
+        return muteWaitMs;
+    }
+    return 0;
+}
+
+void AudioPolicyManager::setStreamMute(int stream,
+                                           bool on,
+                                           audio_io_handle_t output,
+                                           int delayMs,
+                                           audio_devices_t device)
+{
+    StreamDescriptor &streamDesc = mStreams[stream];
+    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    if (device == AUDIO_DEVICE_NONE) {
+        device = outputDesc->device();
+    }
+
+    ALOGVV("setStreamMute() stream %d, mute %d, output %d, mMuteCount %d device %04x",
+          stream, on, output, outputDesc->mMuteCount[stream], device);
+
+    if (on) {
+        if (outputDesc->mMuteCount[stream] > 0) {
+            ALOGV("setStreamMute() muting already muted stream!");
+            return;
+        }
+        if (outputDesc->mMuteCount[stream] == 0) {
+            if (streamDesc.mCanBeMuted &&
+                    ((stream != AudioSystem::ENFORCED_AUDIBLE) ||
+                     (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_NONE))) {
+                checkAndSetVolume(stream, 0, output, device, delayMs);
+            }
+        }
+        // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored
+        outputDesc->mMuteCount[stream]++;
+    } else {
+        if (outputDesc->mMuteCount[stream] == 0) {
+            ALOGV("setStreamMute() unmuting non muted stream!");
+            return;
+        }
+        if (--outputDesc->mMuteCount[stream] == 0) {
+            checkAndSetVolume(stream,
+                              streamDesc.getVolumeIndex(device),
+                              output,
+                              device,
+                              delayMs);
+        }
+    }
+}
+
+
+status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t 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 (!audio_is_output_device(device) && !audio_is_input_device(device)) 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 (audio_is_output_device(device)) {
+
+        //Use QCOM's a2dp and usb audio solution, no need to check here
+        /*if (!mHasA2dp && audio_is_a2dp_device(device)) {
+            ALOGE("setDeviceConnectionState() invalid A2DP device: %x", device);
+            return BAD_VALUE;
+        }
+        if (!mHasUsb && audio_is_usb_device(device)) {
+            ALOGE("setDeviceConnectionState() invalid USB audio device: %x", device);
+            return BAD_VALUE;
+        }*/
+        if (!mHasRemoteSubmix && audio_is_remote_submix_device((audio_devices_t)device)) {
+            ALOGE("setDeviceConnectionState() invalid remote submix audio device: %x", device);
+            return BAD_VALUE;
+        }
+
+        // save a copy of the opened output descriptors before any output is opened or closed
+        // by checkOutputsForDevice(). This will be needed by checkOutputForAllStrategies()
+        mPreviousOutputs = mOutputs;
+        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(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);
+
+            if (audio_is_a2dp_device(device)) {
+               AudioParameter param;
+               param.add(String8("a2dp_connected"), String8("true"));
+               mpClientInterface->setParameters(0, param.toString());
+            }
+            if ( audio_is_usb_device(device)) {
+               AudioParameter param;
+               param.add(String8("usb_connected"), String8("true"));
+               mpClientInterface->setParameters(0, param.toString());
+            }
+            if (!outputs.isEmpty()) {
+                String8 paramStr;
+                if (audio_is_a2dp_device(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 (audio_is_bluetooth_sco_device(device)) {
+                    // handle SCO device connection
+                    mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+                } else if (audio_is_usb_device(device)) {
+                    // handle USB device connection
+                    mUsbCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+                    paramStr = mUsbCardAndDevice;
+                }
+                // not currently handling multiple simultaneous submixes: ignoring remote submix
+                //   case and address
+                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(device, state, outputs);
+            if (audio_is_a2dp_device(device)) {
+                // handle A2DP device disconnection
+                mA2dpDeviceAddress = "";
+                mA2dpSuspended = false;
+
+                AudioParameter param;
+                param.add(String8("a2dp_connected"), String8("false"));
+                mpClientInterface->setParameters(0, param.toString());
+
+            } else if (audio_is_bluetooth_sco_device(device)) {
+                // handle SCO device disconnection
+                mScoDeviceAddress = "";
+            } else if (audio_is_usb_device(device)) {
+                // handle USB device disconnection
+                mUsbCardAndDevice = "";
+
+                AudioParameter param;
+                param.add(String8("usb_connected"), String8("false"));
+                mpClientInterface->setParameters(0, param.toString());
+            }
+            // not currently handling multiple simultaneous submixes: ignoring remote submix
+            //   case and address
+            } break;
+
+        default:
+            ALOGE("setDeviceConnectionState() invalid state: %x", state);
+            return BAD_VALUE;
+        }
+
+        checkA2dpSuspend();
+        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) {
+                    closeOutput(outputs[i]);
+                }
+            }
+        }
+
+        updateDevicesAndOutputs();
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+        if (state == AudioSystem::DEVICE_STATE_AVAILABLE &&
+                audio_is_a2dp_device(device) &&
+                (mAvailableOutputDevices & AUDIO_DEVICE_OUT_PROXY)) {
+            ALOGV("Delay the proxy device open");
+            return NO_ERROR;
+        }
+#endif
+
+        audio_devices_t newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/);
+#ifdef QCOM_FM_ENABLED
+        if(device == AUDIO_DEVICE_OUT_FM) {
+            if (state == AudioSystem::DEVICE_STATE_AVAILABLE) {
+                ALOGV("setDeviceConnectionState() changeRefCount Inc");
+                mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::FM, 1);
+                newDevice = (audio_devices_t)(AudioPolicyManagerBase::getNewDevice(mPrimaryOutput, false) | AUDIO_DEVICE_OUT_FM);
+            }
+            else {
+                ALOGV("setDeviceConnectionState() changeRefCount Dec");
+                mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::FM, -1);
+            }
+
+            AudioParameter param = AudioParameter();
+            param.addInt(String8(AudioParameter::keyHandleFm), (int)newDevice);
+            ALOGV("setDeviceConnectionState() setParameters handle_fm");
+            mpClientInterface->setParameters(mPrimaryOutput, param.toString());
+        }
+#endif
+        for (int i = mOutputs.size() -1; i >= 0; i--) {
+            audio_devices_t newDevice = getNewDevice(mOutputs.keyAt(i), true /*fromCache*/);
+#ifdef QCOM_ANC_HEADSET_ENABLED
+            if(device == AUDIO_DEVICE_OUT_ANC_HEADPHONE ||
+               device == AUDIO_DEVICE_OUT_ANC_HEADSET) {
+                if(newDevice == 0){
+                    newDevice = getDeviceForStrategy(STRATEGY_MEDIA, false);
+                }
+            }
+#endif
+            setOutputDevice(mOutputs.keyAt(i),
+                            getNewDevice(mOutputs.keyAt(i), true /*fromCache*/),
+                            true,
+                            0);
+        }
+
+        if (device == AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+            device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+        } else if (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO ||
+                   device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET ||
+                   device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
+            device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+        } else if(device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET){
+            device = AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET;
+#ifdef QCOM_ANC_HEADSET_ENABLED
+        } else if(device == AUDIO_DEVICE_OUT_ANC_HEADSET){
+               device = AUDIO_DEVICE_IN_ANC_HEADSET; //wait for actual ANC device
+#endif
+        } else {
+            return NO_ERROR;
+        }
+    }
+    // handle input devices
+    if (audio_is_input_device(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 = mAvailableInputDevices | (device & ~AUDIO_DEVICE_BIT_IN);
+            }
+            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 != AUDIO_DEVICE_NONE) && (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;
+}
+
+AudioSystem::device_connection_state AudioPolicyManager::getDeviceConnectionState(audio_devices_t device,
+                                                  const char *device_address)
+{
+    AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE;
+    String8 address = String8(device_address);
+    if (audio_is_output_device(device)) {
+        if (device & mAvailableOutputDevices) {
+            if (audio_is_a2dp_device(device) &&
+                ((address != "" && mA2dpDeviceAddress != address))) {
+                return state;
+            }
+            if (audio_is_bluetooth_sco_device(device) &&
+                address != "" && mScoDeviceAddress != address) {
+                return state;
+            }
+            if (audio_is_usb_device(device) &&
+                ((address != "" && mUsbCardAndDevice != address))) {
+                ALOGE("getDeviceConnectionState() invalid device: %x", device);
+                return state;
+            }
+            if (audio_is_remote_submix_device((audio_devices_t)device) && !mHasRemoteSubmix) {
+                return state;
+            }
+            state = AudioSystem::DEVICE_STATE_AVAILABLE;
+        }
+    } else if (audio_is_input_device(device)) {
+        if (device & mAvailableInputDevices) {
+            state = AudioSystem::DEVICE_STATE_AVAILABLE;
+        }
+    }
+
+    return state;
+}
+
+void AudioPolicyManager::setPhoneState(int state)
+{
+    ALOGV("setPhoneState() state %d", state);
+    audio_devices_t newDevice = AUDIO_DEVICE_NONE;
+    if (state < 0 || state >= AudioSystem::NUM_MODES) {
+        ALOGW("setPhoneState() invalid state %d", state);
+        return;
+    }
+
+    if (state == mPhoneState ) {
+        ALOGW("setPhoneState() setting same state %d", state);
+        return;
+    }
+
+    // if leaving call state, handle special case of active streams
+    // pertaining to sonification strategy see handleIncallSonification()
+    if (isInCall()) {
+        ALOGV("setPhoneState() in call state management: new state is %d", state);
+        for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+            handleIncallSonification(stream, false, true);
+        }
+    }
+
+    // store previous phone state for management of sonification strategy below
+    int oldState = mPhoneState;
+    mPhoneState = state;
+    bool force = false;
+
+    // are we entering or starting a call
+    if (!isStateInCall(oldState) && isStateInCall(state)) {
+        ALOGV("  Entering call in setPhoneState()");
+        // force routing command to audio hardware when starting a call
+        // even if no device change is needed
+        force = true;
+    } else if (isStateInCall(oldState) && !isStateInCall(state)) {
+        ALOGV("  Exiting call in setPhoneState()");
+        // force routing command to audio hardware when exiting a call
+        // even if no device change is needed
+        force = true;
+    } else if (isStateInCall(state) && (state != oldState)) {
+        ALOGV("  Switching between telephony and VoIP in setPhoneState()");
+        // force routing command to audio hardware when switching between telephony and VoIP
+        // even if no device change is needed
+        force = true;
+    }
+
+    // check for device and output changes triggered by new phone state
+    // Need to update A2DP suspend first then getNewDevice(from cache)
+    checkA2dpSuspend();
+    checkOutputForAllStrategies();
+    updateDevicesAndOutputs();
+    newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/);
+
+    AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mPrimaryOutput);
+
+    // force routing command to audio hardware when ending call
+    // even if no device change is needed
+    if (isStateInCall(oldState) && newDevice == AUDIO_DEVICE_NONE) {
+        newDevice = hwOutputDesc->device();
+    }
+
+    int delayMs = 0;
+    if (state == AUDIO_MODE_IN_CALL &&
+#ifdef QCOM_CSDCLIENT_ENABLED
+        platform_is_Fusion3() &&
+#endif
+        oldState == AUDIO_MODE_RINGTONE) {
+        delayMs = 40;
+    }
+
+    if (isStateInCall(state)) {
+        nsecs_t sysTime = systemTime();
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+            // mute media and sonification strategies and delay device switch by the largest
+            // latency of any output where either strategy is active.
+            // This avoid sending the ring tone or music tail into the earpiece or headset.
+            if ((desc->isStrategyActive(STRATEGY_MEDIA,
+                                     SONIFICATION_HEADSET_MUSIC_DELAY,
+                                     sysTime) ||
+                    desc->isStrategyActive(STRATEGY_SONIFICATION,
+                                         SONIFICATION_HEADSET_MUSIC_DELAY,
+                                         sysTime)) &&
+                    (delayMs < (int)desc->mLatency*2)) {
+                delayMs = desc->mLatency*2;
+            }
+            setStrategyMute(STRATEGY_MEDIA, true, mOutputs.keyAt(i));
+            setStrategyMute(STRATEGY_MEDIA, false, mOutputs.keyAt(i), MUTE_TIME_MS,
+                getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/));
+            setStrategyMute(STRATEGY_SONIFICATION, true, mOutputs.keyAt(i));
+            setStrategyMute(STRATEGY_SONIFICATION, false, mOutputs.keyAt(i), MUTE_TIME_MS,
+                getDeviceForStrategy(STRATEGY_SONIFICATION, true /*fromCache*/));
+        }
+    }
+
+    // change routing is necessary
+    setOutputDevice(mPrimaryOutput, newDevice, force, delayMs);
+
+    //update device for all non-primary outputs
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        audio_io_handle_t output = mOutputs.keyAt(i);
+        if (output != mPrimaryOutput) {
+            newDevice = getNewDevice(output, false /*fromCache*/);
+            setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE));
+        }
+    }
+
+    // if entering in call state, handle special case of active streams
+    // pertaining to sonification strategy see handleIncallSonification()
+    if (isStateInCall(state)) {
+        ALOGV("setPhoneState() in call state management: new state is %d", state);
+        for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+            handleIncallSonification(stream, true, true);
+        }
+    }
+
+    // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE
+    if (state == AudioSystem::MODE_RINGTONE &&
+        isStreamActive(AudioSystem::MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY)) {
+        mLimitRingtoneVolume = true;
+    } else {
+        mLimitRingtoneVolume = false;
+    }
+}
+
+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;
+        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;
+    case AudioSystem::FOR_SYSTEM:
+        if (config != AudioSystem::FORCE_NONE &&
+            config != AudioSystem::FORCE_SYSTEM_ENFORCED) {
+            ALOGW("setForceUse() invalid config %d for FOR_SYSTEM", 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();
+    updateDevicesAndOutputs();
+    for (int i = mOutputs.size() -1; i >= 0; i--) {
+        audio_io_handle_t output = mOutputs.keyAt(i);
+        audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/);
+        setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE));
+        if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) {
+            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 != AUDIO_DEVICE_NONE) && (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_io_handle_t AudioPolicyManager::getOutput(AudioSystem::stream_type stream,
+                                    uint32_t samplingRate,
+                                    uint32_t format,
+                                    uint32_t channelMask,
+                                    AudioSystem::output_flags flags)
+{
+    audio_io_handle_t output = 0;
+    uint32_t latency = 0;
+    routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream);
+    audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
+    ALOGV("getOutput() stream %d, samplingRate %d, format %d, channelMask %x, flags %x",
+          stream, samplingRate, format, channelMask, flags);
+
+#ifdef AUDIO_POLICY_TEST
+    if (mCurOutput != 0) {
+        ALOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channelMask %x, mDirectOutput %d",
+                mCurOutput, mTestSamplingRate, mTestFormat, mTestChannels, mDirectOutput);
+
+        if (mTestOutputs[mCurOutput] == 0) {
+            ALOGV("getOutput() opening test output");
+            AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(NULL);
+            outputDesc->mDevice = mTestDevice;
+            outputDesc->mSamplingRate = mTestSamplingRate;
+            outputDesc->mFormat = mTestFormat;
+            outputDesc->mChannelMask = mTestChannels;
+            outputDesc->mLatency = mTestLatencyMs;
+            outputDesc->mFlags = (audio_output_flags_t)(mDirectOutput ? AudioSystem::OUTPUT_FLAG_DIRECT : 0);
+            outputDesc->mRefCount[stream] = 0;
+            mTestOutputs[mCurOutput] = mpClientInterface->openOutput(0, &outputDesc->mDevice,
+                                            &outputDesc->mSamplingRate,
+                                            &outputDesc->mFormat,
+                                            &outputDesc->mChannelMask,
+                                            &outputDesc->mLatency,
+                                            outputDesc->mFlags);
+            if (mTestOutputs[mCurOutput]) {
+                AudioParameter outputCmd = AudioParameter();
+                outputCmd.addInt(String8("set_id"),mCurOutput);
+                mpClientInterface->setParameters(mTestOutputs[mCurOutput],outputCmd.toString());
+                addOutput(mTestOutputs[mCurOutput], outputDesc);
+            }
+        }
+        return mTestOutputs[mCurOutput];
+    }
+#endif //AUDIO_POLICY_TEST
+
+    // open a direct output if required by specified parameters
+    IOProfile *profile = getProfileForDirectOutput(device,
+                                                   samplingRate,
+                                                   format,
+                                                   channelMask,
+                                                   (audio_output_flags_t)flags);
+    if (profile != NULL) {
+        AudioOutputDescriptor *outputDesc = NULL;
+
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+            if (!desc->isDuplicated() && (profile == desc->mProfile)) {
+                outputDesc = desc;
+                // reuse direct output if currently open and configured with same parameters
+                if ((samplingRate == outputDesc->mSamplingRate) &&
+                        (format == outputDesc->mFormat) &&
+                        (channelMask == outputDesc->mChannelMask)) {
+                    outputDesc->mDirectOpenCount++;
+                    ALOGV("getOutput() reusing direct output %d", output);
+                    return mOutputs.keyAt(i);
+                }
+            }
+        }
+
+        // close direct output if currently open and configured with different parameters
+        if (outputDesc != NULL) {
+            closeOutput(outputDesc->mId);
+        }
+        outputDesc = new AudioOutputDescriptor(profile);
+        outputDesc->mDevice = device;
+        outputDesc->mSamplingRate = samplingRate;
+        outputDesc->mFormat = (audio_format_t)format;
+        outputDesc->mChannelMask = (audio_channel_mask_t)channelMask;
+        outputDesc->mLatency = 0;
+        outputDesc->mFlags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT);;
+        outputDesc->mRefCount[stream] = 0;
+        outputDesc->mStopTime[stream] = 0;
+        outputDesc->mDirectOpenCount = 1;
+        output = mpClientInterface->openOutput(profile->mModule->mHandle,
+                                        &outputDesc->mDevice,
+                                        &outputDesc->mSamplingRate,
+                                        &outputDesc->mFormat,
+                                        &outputDesc->mChannelMask,
+                                        &outputDesc->mLatency,
+                                        outputDesc->mFlags);
+
+        // only accept an output with the requested parameters
+        if (output == 0 ||
+            (samplingRate != 0 && samplingRate != outputDesc->mSamplingRate) ||
+            (format != 0 && format != outputDesc->mFormat) ||
+            (channelMask != 0 && channelMask != outputDesc->mChannelMask)) {
+            ALOGV("getOutput() failed opening direct output: output %d samplingRate %d %d,"
+                    "format %d %d, channelMask %04x %04x", output, samplingRate,
+                    outputDesc->mSamplingRate, format, outputDesc->mFormat, channelMask,
+                    outputDesc->mChannelMask);
+            if (output != 0) {
+                mpClientInterface->closeOutput(output);
+            }
+            delete outputDesc;
+            return 0;
+        }
+        addOutput(output, outputDesc);
+        mPreviousOutputs = mOutputs;
+        ALOGV("getOutput() returns new direct output %d", output);
+        return output;
+    }
+
+    // ignoring channel mask due to downmix capability in mixer
+
+    // open a non direct output
+
+    // get which output is suitable for the specified stream. The actual routing change will happen
+    // when startOutput() will be called
+    SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
+
+    output = selectOutput(outputs, flags);
+
+    ALOGW_IF((output ==0), "getOutput() could not find output for stream %d, samplingRate %d,"
+            "format %d, channels %x, flags %x", stream, samplingRate, format, channelMask, flags);
+
+    ALOGV("getOutput() returns output %d", output);
+
+    return output;
+}
+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 newDevice = getNewDevice(output, false /*fromCache*/);
+        routing_strategy strategy = getStrategy(stream);
+        bool shouldWait = (strategy == STRATEGY_SONIFICATION) ||
+                            (strategy == STRATEGY_SONIFICATION_RESPECTFUL);
+        uint32_t waitMs = 0;
+        uint32_t muteWaitMs = 0;
+        bool force = false;
+        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.
+                uint32_t latency = desc->latency();
+                if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) {
+                    waitMs = latency;
+                }
+            }
+        }
+
+#ifdef QCOM_FM_ENABLED
+        if(stream == AudioSystem::FM && output == getA2dpOutput()) {
+            muteWaitMs = setOutputDevice(output, newDevice, true);
+        } else
+#endif
+        {
+            muteWaitMs = setOutputDevice(output, newDevice, force);
+        }
+
+        // handle special case for sonification while in call
+        if (isInCall()) {
+            handleIncallSonification(stream, true, false);
+        }
+
+        // apply volume rules for current stream and device if necessary
+        checkAndSetVolume(stream,
+                          mStreams[stream].getVolumeIndex(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);
+        }
+    } else {
+        // handle special case for sonification while in call
+        if (isInCall()) {
+            handleIncallSonification(stream, true, false);
+        }
+    }
+    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) {
+            outputDesc->mStopTime[stream] = systemTime();
+
+            if ((outputDesc->mRefCount[AUDIO_STREAM_RING]!= 0) && (stream == AUDIO_STREAM_VOICE_CALL)) {
+                 // When AUDIO_STREAM_RING is present, Send Mute on RING
+                 // if it gets stopOutput on  AUDIO_STREAM_VOICE_CALL
+                 setStreamMute(AudioSystem::RING, true, mPrimaryOutput);
+            }
+
+            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->isActive() &&
+                        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;
+    }
+}
+
+
+audio_io_handle_t AudioPolicyManager::getInput(int inputSource,
+                                    uint32_t samplingRate,
+                                    uint32_t format,
+                                    uint32_t channelMask,
+                                    AudioSystem::audio_in_acoustics acoustics)
+{
+    audio_io_handle_t input = 0;
+    audio_devices_t device = getDeviceForInputSource(inputSource);
+
+    ALOGV("getInput() inputSource %d, samplingRate %d, format %d, channelMask %x, acoustics %x",
+          inputSource, samplingRate, format, channelMask, acoustics);
+
+    if (device == AUDIO_DEVICE_NONE) {
+        ALOGW("getInput() could not find device for inputSource %d", inputSource);
+        return 0;
+    }
+
+    // adapt channel selection to input source
+    switch(inputSource) {
+    case AUDIO_SOURCE_VOICE_UPLINK:
+        channelMask |= AudioSystem::CHANNEL_IN_VOICE_UPLINK;
+        break;
+    case AUDIO_SOURCE_VOICE_DOWNLINK:
+        channelMask |= AudioSystem::CHANNEL_IN_VOICE_DNLINK;
+        break;
+    case AUDIO_SOURCE_VOICE_CALL:
+        channelMask |= (AudioSystem::CHANNEL_IN_VOICE_UPLINK | AudioSystem::CHANNEL_IN_VOICE_DNLINK);
+        break;
+    default:
+        break;
+    }
+
+    IOProfile *profile = getInputProfile(device,
+                                         samplingRate,
+                                         format,
+                                         channelMask);
+    if (profile == NULL) {
+        ALOGW("getInput() could not find profile for device %04x, samplingRate %d, format %d,"
+                "channelMask %04x",
+                device, samplingRate, format, channelMask);
+        return 0;
+    }
+
+    if (profile->mModule->mHandle == 0) {
+        ALOGE("getInput(): HW module %s not opened", profile->mModule->mName);
+        return 0;
+    }
+
+    AudioInputDescriptor *inputDesc = new AudioInputDescriptor(profile);
+
+    inputDesc->mInputSource = inputSource;
+    inputDesc->mDevice = device;
+    inputDesc->mSamplingRate = samplingRate;
+    inputDesc->mFormat = (audio_format_t)format;
+    inputDesc->mChannelMask = (audio_channel_mask_t)channelMask;
+    inputDesc->mRefCount = 0;
+    input = mpClientInterface->openInput(profile->mModule->mHandle,
+                                    &inputDesc->mDevice,
+                                    &inputDesc->mSamplingRate,
+                                    &inputDesc->mFormat,
+                                    &inputDesc->mChannelMask);
+
+    // only accept input with the exact requested set of parameters
+    if (input == 0 ||
+        (samplingRate != inputDesc->mSamplingRate) ||
+        (format != inputDesc->mFormat) ||
+        (channelMask != inputDesc->mChannelMask)) {
+        ALOGV("getInput() failed opening input: samplingRate %d, format %d, channelMask %d",
+                samplingRate, format, channelMask);
+        if (input != 0) {
+            mpClientInterface->closeInput(input);
+        }
+        delete inputDesc;
+        return 0;
+    }
+    mInputs.add(input, inputDesc);
+    return input;
+}
+
+/*
+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);
+
+/*
+#ifdef AUDIO_POLICY_TEST
+    if (mTestInput == 0)
+#endif //AUDIO_POLICY_TEST
+    {
+        // refuse 2 active AudioRecord clients at the same time
+        if (getActiveInput() != 0) {
+            ALOGW("startInput() input %d failed: other input already started", input);
+            return INVALID_OPERATION;
+        }
+    }
+*/
+    audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+    if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
+        inputDesc->mDevice = newDevice;
+    }
+    AudioParameter param = AudioParameter();
+    param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice);
+
+    param.addInt(String8(AudioParameter::keyInputSource), (int)inputDesc->mInputSource);
+
+    // 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);
+
+    //to pass on if camcorder mode is enabled to HAL
+    int camcorder_enabled = inputDesc->mInputSource == AUDIO_SOURCE_CAMCORDER ? 1 : 0;
+    param.addInt(String8("camcorder_mode"), camcorder_enabled);
+
+    mpClientInterface->setParameters(input, param.toString());
+
+    inputDesc->mRefCount = 1;
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::stopInput(audio_io_handle_t input)
+{
+    ALOGV("stopInput() input %d", input);
+    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);
+        mpClientInterface->setParameters(input, param.toString());
+        setOutputDevice(mPrimaryOutput, getNewDevice(mPrimaryOutput, true), true);
+        inputDesc->mRefCount = 0;
+        return NO_ERROR;
+    }
+}
+
+
+status_t AudioPolicyManager::setStreamVolumeIndex(AudioSystem::stream_type stream,
+                                                      int index,
+                                                      audio_devices_t device)
+{
+
+    if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) {
+        return BAD_VALUE;
+    }
+    if (!audio_is_output_device(device)) {
+        return BAD_VALUE;
+    }
+
+    // Force max volume if stream cannot be muted
+    if (!mStreams[stream].mCanBeMuted) index = mStreams[stream].mIndexMax;
+
+    ALOGV("setStreamVolumeIndex() stream %d, device %04x, index %d",
+          stream, device, index);
+
+    // if device is AUDIO_DEVICE_OUT_DEFAULT set default value and
+    // clear all device specific values
+    if ((device == AUDIO_DEVICE_OUT_DEFAULT) && (AUDIO_DEVICE_OUT_DEFAULT != AUDIO_DEVICE_OUT_SPEAKER))  {
+        mStreams[stream].mIndexCur.clear();
+    }
+    mStreams[stream].mIndexCur.add(device, index);
+
+    // compute and apply stream volume on all outputs according to connected device
+    status_t status = NO_ERROR;
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        audio_devices_t curDevice =
+                getDeviceForVolume(mOutputs.valueAt(i)->device());
+        if (device == curDevice) {
+            status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice);
+            if (volStatus != NO_ERROR) {
+                status = volStatus;
+            }
+        }
+    }
+    return status;
+}
+
+
+status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
+                                                       AudioSystem::device_connection_state state,
+                                                       SortedVector<audio_io_handle_t>& outputs)
+{
+    AudioOutputDescriptor *desc;
+
+    if (state == AudioSystem::DEVICE_STATE_AVAILABLE) {
+        // first list already open outputs that can be routed to this device
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            desc = mOutputs.valueAt(i);
+            if (!desc->isDuplicated() && (desc->mProfile->mSupportedDevices & device)) {
+                ALOGV("checkOutputsForDevice(): adding opened output %d", mOutputs.keyAt(i));
+                outputs.add(mOutputs.keyAt(i));
+            }
+        }
+        // then look for output profiles that can be routed to this device
+        SortedVector<IOProfile *> profiles;
+        for (size_t i = 0; i < mHwModules.size(); i++)
+        {
+            if (mHwModules[i]->mHandle == 0) {
+                continue;
+            }
+            for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
+            {
+                if (mHwModules[i]->mOutputProfiles[j]->mSupportedDevices & device) {
+                    ALOGV("checkOutputsForDevice(): adding profile %d from module %d", j, i);
+                    profiles.add(mHwModules[i]->mOutputProfiles[j]);
+                }
+            }
+        }
+
+        if (profiles.isEmpty() && outputs.isEmpty()) {
+            ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
+            return BAD_VALUE;
+        }
+
+        // open outputs for matching profiles if needed. Direct outputs are also opened to
+        // query for dynamic parameters and will be closed later by setDeviceConnectionState()
+        for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
+            IOProfile *profile = profiles[profile_index];
+
+            // nothing to do if one output is already opened for this profile
+            size_t j;
+            for (j = 0; j < mOutputs.size(); j++) {
+                desc = mOutputs.valueAt(j);
+                if (!desc->isDuplicated() && desc->mProfile == profile) {
+                    break;
+                }
+            }
+            if (j != mOutputs.size()) {
+                continue;
+            }
+
+            ALOGV("opening output for device %08x", device);
+            desc = new AudioOutputDescriptor(profile);
+            desc->mDevice = device;
+            audio_io_handle_t output = 0;
+            if (!(desc->mFlags & AUDIO_OUTPUT_FLAG_LPA || desc->mFlags & AUDIO_OUTPUT_FLAG_TUNNEL ||
+                desc->mFlags & AUDIO_OUTPUT_FLAG_VOIP_RX)) {
+                output =  mpClientInterface->openOutput(profile->mModule->mHandle,
+                                                        &desc->mDevice,
+                                                        &desc->mSamplingRate,
+                                                        &desc->mFormat,
+                                                        &desc->mChannelMask,
+                                                        &desc->mLatency,
+                                                        desc->mFlags);
+            }
+            if (output != 0) {
+                if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
+                    String8 reply;
+                    char *value;
+                    if (profile->mSamplingRates[0] == 0) {
+                        reply = mpClientInterface->getParameters(output,
+                                                String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
+                        ALOGV("checkOutputsForDevice() direct output sup sampling rates %s",
+                                  reply.string());
+                        value = strpbrk((char *)reply.string(), "=");
+                        if (value != NULL) {
+                            loadSamplingRates(value, profile);
+                        }
+                    }
+                    if (profile->mFormats[0] == 0) {
+                        reply = mpClientInterface->getParameters(output,
+                                                       String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
+                        ALOGV("checkOutputsForDevice() direct output sup formats %s",
+                                  reply.string());
+                        value = strpbrk((char *)reply.string(), "=");
+                        if (value != NULL) {
+                            loadFormats(value, profile);
+                        }
+                    }
+                    if (profile->mChannelMasks[0] == 0) {
+                        reply = mpClientInterface->getParameters(output,
+                                                      String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
+                        ALOGV("checkOutputsForDevice() direct output sup channel masks %s",
+                                  reply.string());
+                        value = strpbrk((char *)reply.string(), "=");
+                        if (value != NULL) {
+                            loadOutChannels(value + 1, profile);
+                        }
+                    }
+                    if (((profile->mSamplingRates[0] == 0) &&
+                             (profile->mSamplingRates.size() < 2)) ||
+                         ((profile->mFormats[0] == 0) &&
+                             (profile->mFormats.size() < 2)) ||
+                         ((profile->mFormats[0] == 0) &&
+                             (profile->mChannelMasks.size() < 2))) {
+                        ALOGW("checkOutputsForDevice() direct output missing param");
+                        mpClientInterface->closeOutput(output);
+                        output = 0;
+                    } else {
+                        addOutput(output, desc);
+                    }
+                } else {
+                    audio_io_handle_t duplicatedOutput = 0;
+                    // add output descriptor
+                    addOutput(output, desc);
+                    // set initial stream volume for device
+                    applyStreamVolumes(output, device, 0, true);
+
+                    //TODO: configure audio effect output stage here
+
+                    // open a duplicating output thread for the new output and the primary output
+                    duplicatedOutput = mpClientInterface->openDuplicateOutput(output,
+                                                                              mPrimaryOutput);
+                    if (duplicatedOutput != 0) {
+                        // add duplicated output descriptor
+                        AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor(NULL);
+                        dupOutputDesc->mOutput1 = mOutputs.valueFor(mPrimaryOutput);
+                        dupOutputDesc->mOutput2 = mOutputs.valueFor(output);
+                        dupOutputDesc->mSamplingRate = desc->mSamplingRate;
+                        dupOutputDesc->mFormat = desc->mFormat;
+                        dupOutputDesc->mChannelMask = desc->mChannelMask;
+                        dupOutputDesc->mLatency = desc->mLatency;
+                        addOutput(duplicatedOutput, dupOutputDesc);
+                        applyStreamVolumes(duplicatedOutput, device, 0, true);
+                    } else {
+                        ALOGW("checkOutputsForDevice() could not open dup output for %d and %d",
+                                mPrimaryOutput, output);
+                        mpClientInterface->closeOutput(output);
+                        mOutputs.removeItem(output);
+                        output = 0;
+                    }
+                }
+            }
+            if (output == 0) {
+                ALOGW("checkOutputsForDevice() could not open output for device %x", device);
+                delete desc;
+                profiles.removeAt(profile_index);
+                profile_index--;
+            } else {
+                outputs.add(output);
+                ALOGV("checkOutputsForDevice(): adding output %d", output);
+            }
+        }
+
+        if (profiles.isEmpty()) {
+            ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
+            return BAD_VALUE;
+        }
+    } else {
+        // check if one opened output is not needed any more after disconnecting one device
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            desc = mOutputs.valueAt(i);
+            if (!desc->isDuplicated() &&
+                    !(desc->mProfile->mSupportedDevices & mAvailableOutputDevices)) {
+                ALOGV("checkOutputsForDevice(): disconnecting adding output %d", mOutputs.keyAt(i));
+                outputs.add(mOutputs.keyAt(i));
+            }
+        }
+        for (size_t i = 0; i < mHwModules.size(); i++)
+        {
+            if (mHwModules[i]->mHandle == 0) {
+                continue;
+            }
+            for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
+            {
+                IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
+                if ((profile->mSupportedDevices & device) &&
+                        (profile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
+                    ALOGV("checkOutputsForDevice(): clearing direct output profile %d on module %d",
+                          j, i);
+                    if (profile->mSamplingRates[0] == 0) {
+                        profile->mSamplingRates.clear();
+                        profile->mSamplingRates.add(0);
+                    }
+                    if (profile->mFormats[0] == 0) {
+                        profile->mFormats.clear();
+                        profile->mFormats.add((audio_format_t)0);
+                    }
+                    if (profile->mChannelMasks[0] == 0) {
+                        profile->mChannelMasks.clear();
+                        profile->mChannelMasks.add((audio_channel_mask_t)0);
+                    }
+                }
+            }
+        }
+    }
+    return NO_ERROR;
+}
+
+audio_devices_t AudioPolicyManager::getNewDevice(audio_io_handle_t output, bool fromCache)
+{
+    audio_devices_t device = AUDIO_DEVICE_NONE;
+
+    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    AudioOutputDescriptor *primaryOutputDesc = mOutputs.valueFor(mPrimaryOutput);
+    // check the following by order of priority to request a routing change if necessary:
+    // 1: the strategy enforced audible is active on the output:
+    //      use device for strategy enforced audible
+    // 2: we are in call or the strategy phone is active on the output:
+    //      use device for strategy phone
+    // 3: the strategy sonification is active on the output:
+    //      use device for strategy sonification
+    // 4: the strategy "respectful" sonification is active on the output:
+    //      use device for strategy "respectful" sonification
+    // 5: the strategy media is active on the output:
+    //      use device for strategy media
+    // 6: the strategy DTMF is active on the output:
+    //      use device for strategy DTMF
+    if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE)) {
+        device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
+    } else if (isInCall() ||
+                    outputDesc->isStrategyActive(STRATEGY_PHONE)) {
+        device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
+    } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION)) {
+        device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
+    } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION_RESPECTFUL)) {
+        device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache);
+    } else if (outputDesc->isStrategyActive(STRATEGY_MEDIA)) {
+        device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache);
+    } else if (outputDesc->isStrategyActive(STRATEGY_DTMF)) {
+        device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
+    }
+
+    ALOGV("getNewDevice() selected device %x", device);
+    return device;
+}
+
+AudioPolicyManager::routing_strategy AudioPolicyManager::getStrategy(
+        AudioSystem::stream_type stream) {
+    // stream to strategy mapping
+    switch (stream) {
+    case AudioSystem::VOICE_CALL:
+    case AudioSystem::BLUETOOTH_SCO:
+        return STRATEGY_PHONE;
+    case AudioSystem::RING:
+    case AudioSystem::ALARM:
+        return STRATEGY_SONIFICATION;
+    case AudioSystem::NOTIFICATION:
+        return STRATEGY_SONIFICATION_RESPECTFUL;
+    case AudioSystem::DTMF:
+        return STRATEGY_DTMF;
+    default:
+        ALOGE("unknown stream type");
+    case AudioSystem::SYSTEM:
+        // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
+        // while key clicks are played produces a poor result
+    case AudioSystem::TTS:
+    case AudioSystem::MUSIC:
+#ifdef QCOM_FM_ENABLED
+    case AudioSystem::FM:
+#endif
+        return STRATEGY_MEDIA;
+    case AudioSystem::ENFORCED_AUDIBLE:
+        return STRATEGY_ENFORCED_AUDIBLE;
+    }
+}
+audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy,
+                                                             bool fromCache)
+{
+    uint32_t device = AUDIO_DEVICE_NONE;
+
+    if (fromCache) {
+        ALOGVV("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 (isStreamActiveRemotely(AudioSystem::MUSIC,
+                SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+            // while media is playing on a remote device, use the the sonification behavior.
+            // Note that we test this usecase before testing if media is playing because
+            //   the isStreamActive() method only informs about the activity of a stream, not
+            //   if it's for local playback. Note also that we use the same delay between both tests
+            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 & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+                if (device) break;
+            }
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+            if (device) break;
+            device = mAvailableOutputDevices & AUDIO_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 (!isInCall())
+            {
+                if ((mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+                        !mA2dpSuspended) {
+                    device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+                    if (device) break;
+                    device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+                    if (device) break;
+                }
+            }
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+            if (device) break;
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
+            if (device) break;
+#ifdef QCOM_ANC_HEADSET_ENABLED
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANC_HEADPHONE;
+            if (device) break;
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANC_HEADSET;
+            if (device) break;
+#endif
+            if (mPhoneState != AudioSystem::MODE_IN_CALL) {
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+                if (device) break;
+            }
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+            if (device) break;
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_EARPIECE;
+            if (device) break;
+            device = mDefaultOutputDevice;
+            if (device == AUDIO_DEVICE_NONE) {
+                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 (!isInCall() &&
+                    (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+                    !mA2dpSuspended) {
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+                if (device) break;
+            }
+            if (mPhoneState != AudioSystem::MODE_IN_CALL) {
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+                if (device) break;
+            }
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+            if (device) break;
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+            if (device) break;
+            device = mDefaultOutputDevice;
+            if (device == AUDIO_DEVICE_NONE) {
+                ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER");
+            }
+            break;
+        }
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
+        if (mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM) {
+            if (mForceUse[AudioSystem::FOR_MEDIA] == AudioSystem::FORCE_SPEAKER) {
+                device &= ~(AUDIO_DEVICE_OUT_WIRED_HEADSET);
+                device &= ~(AUDIO_DEVICE_OUT_WIRED_HEADPHONE);
+                device &= ~(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET);
+                device |= AUDIO_DEVICE_OUT_SPEAKER;
+            }
+        }
+#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) ||
+                (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_SYSTEM_ENFORCED)) {
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+            if (device == AUDIO_DEVICE_NONE) {
+                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: {
+        uint32_t device2 = AUDIO_DEVICE_NONE;
+        if (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_SPEAKER) {
+            if (strategy != STRATEGY_SONIFICATION) {
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+                // no sonification on WFD sink
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_PROXY;
+#else
+                // no sonification on remote submix (e.g. WFD)
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+#endif
+            }
+            if ((device2 == AUDIO_DEVICE_NONE) &&
+                    (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+                    !mA2dpSuspended) {
+                if (device2 == AUDIO_DEVICE_NONE) {
+                    device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+                }
+                if (device2 == AUDIO_DEVICE_NONE) {
+                    device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+                }
+                if (device2 == AUDIO_DEVICE_NONE) {
+                    device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+                }
+            }
+            if (device2 == AUDIO_DEVICE_NONE) {
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+            }
+            if (device2 == AUDIO_DEVICE_NONE) {
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
+            }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+            if (device2 == AUDIO_DEVICE_NONE) {
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANC_HEADPHONE;
+            }
+            if (device2 == AUDIO_DEVICE_NONE) {
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANC_HEADSET;
+            }
+#endif
+            if (device2 == AUDIO_DEVICE_NONE) {
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+            }
+            if (device2 == AUDIO_DEVICE_NONE) {
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+            }
+            if (device2 == AUDIO_DEVICE_NONE) {
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+            }
+            if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) {
+                // no sonification on aux digital (e.g. HDMI)
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+            }
+            if (device2 == AUDIO_DEVICE_NONE) {
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+            }
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
+            if (device2 == AUDIO_DEVICE_NONE) {
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM_TX;
+            }
+#endif
+            if (device2 == AUDIO_DEVICE_NONE) {
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+            }
+
+            // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
+            // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
+            device |= device2;
+            if (!device) {
+                device = mDefaultOutputDevice;
+            }
+            if (device == AUDIO_DEVICE_NONE) {
+                ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA");
+            }
+
+        } else {
+            //AudioSystem::FORCE_SPEAKER for STRATEGY_MEDIA
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+        }
+
+        if (isInCall()) {
+            // when in call, get the device for Phone strategy
+            device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/);
+        }
+
+        } break;
+
+    default:
+        ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
+        break;
+    }
+
+    ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
+    return device;
+}
+
+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;
+    }
+    // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
+    // output profile
+    if ((device != AUDIO_DEVICE_NONE) &&
+            ((device & outputDesc->mProfile->mSupportedDevices) == 0)) {
+        return 0;
+    }
+
+    // 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 != AUDIO_DEVICE_NONE) {
+        outputDesc->mDevice = device;
+    }
+    muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+
+    // Do not change the routing if:
+    //  - the requested device is AUDIO_DEVICE_NONE
+    //  - 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 == AUDIO_DEVICE_NONE) || ((device == prevDevice) && !force)) {
+        ALOGV("setOutputDevice() setting same device %04x or null device for output %d", device, output);
+        return muteWaitMs;
+    }
+    if (device == prevDevice) {
+        ALOGV("setOutputDevice() Call routing with same device with zero delay ");
+        delayMs = 0;
+    }
+    ALOGV("setOutputDevice() changing device:%x",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;
+}
+
+audio_devices_t AudioPolicyManager::getDeviceForInputSource(int inputSource)
+{
+    uint32_t device = AUDIO_DEVICE_NONE;
+
+    switch (inputSource) {
+    case AUDIO_SOURCE_VOICE_UPLINK:
+      if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {
+          device = AUDIO_DEVICE_IN_VOICE_CALL;
+          break;
+      }
+      // FALL THROUGH
+
+    case AUDIO_SOURCE_DEFAULT:
+    case AUDIO_SOURCE_MIC:
+    case AUDIO_SOURCE_VOICE_RECOGNITION:
+        if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO &&
+            mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+            device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+        } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+            device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+#ifdef QCOM_ANC_HEADSET_ENABLED
+        } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_ANC_HEADSET) {
+            device = AUDIO_DEVICE_IN_ANC_HEADSET;
+#endif
+        } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET) {
+            device = AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET;
+        } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+        }
+        break;
+    case AUDIO_SOURCE_VOICE_COMMUNICATION:
+        device = AUDIO_DEVICE_IN_COMMUNICATION;
+        break;
+    case AUDIO_SOURCE_CAMCORDER:
+        if (mAvailableInputDevices & AUDIO_DEVICE_IN_BACK_MIC) {
+            device = AUDIO_DEVICE_IN_BACK_MIC;
+        } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+            device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+        } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+            device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+        } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_AUX_DIGITAL) {
+            device = AUDIO_DEVICE_IN_AUX_DIGITAL;
+        } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+        }
+        break;
+    case AUDIO_SOURCE_VOICE_DOWNLINK:
+    case AUDIO_SOURCE_VOICE_CALL:
+        if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {
+            device = AUDIO_DEVICE_IN_VOICE_CALL;
+        }
+        break;
+    case AUDIO_SOURCE_REMOTE_SUBMIX:
+        if (mAvailableInputDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
+            device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+        }
+        break;
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
+   case AUDIO_SOURCE_FM_RX:
+        device = AUDIO_DEVICE_IN_FM_RX;
+        break;
+    case AUDIO_SOURCE_FM_RX_A2DP:
+        device = AUDIO_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 device;
+}
+
+
+
+
+audio_devices_t AudioPolicyManager::getDeviceForVolume(audio_devices_t device)
+{
+    if (device == AUDIO_DEVICE_NONE) {
+        // this happens when forcing a route update and no track is active on an output.
+        // In this case the returned category is not important.
+        device =  AUDIO_DEVICE_OUT_SPEAKER;
+    } else if (AudioSystem::popCount(device) > 1) {
+        // Multiple device selection is either:
+        //  - speaker + one other device: give priority to speaker in this case.
+        //  - one A2DP device + another device: happens with duplicated output. In this case
+        // retain the device on the A2DP output as the other must not correspond to an active
+        // selection if not the speaker.
+        if (device & AUDIO_DEVICE_OUT_SPEAKER) {
+            device = AUDIO_DEVICE_OUT_SPEAKER;
+        } else if ((device & AUDIO_DEVICE_OUT_WIRED_HEADSET) != 0) {
+            device = AUDIO_DEVICE_OUT_WIRED_HEADSET;
+        } else if ((device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) != 0) {
+            device = AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+        } else {
+            device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
+        }
+    }
+
+    ALOGW_IF(AudioSystem::popCount(device) != 1,
+            "getDeviceForVolume() invalid device combination: %08x",
+            device);
+
+    return device;
+}
+
+AudioPolicyManager::device_category AudioPolicyManager::getDeviceCategory(audio_devices_t device)
+{
+    switch(getDeviceForVolume(device)) {
+        case AUDIO_DEVICE_OUT_EARPIECE:
+            return DEVICE_CATEGORY_EARPIECE;
+        case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+        case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+        case AUDIO_DEVICE_OUT_ANC_HEADSET:
+        case AUDIO_DEVICE_OUT_ANC_HEADPHONE:
+        case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
+        case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+        case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
+        case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+#if defined(QCOM_FM_ENABLED) || defined(STE_FM)
+        case AUDIO_DEVICE_OUT_FM:
+#endif
+            return DEVICE_CATEGORY_HEADSET;
+        case AUDIO_DEVICE_OUT_SPEAKER:
+        case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+        case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+        case AUDIO_DEVICE_OUT_AUX_DIGITAL:
+        case AUDIO_DEVICE_OUT_USB_ACCESSORY:
+        case AUDIO_DEVICE_OUT_USB_DEVICE:
+        case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
+        case AUDIO_DEVICE_OUT_PROXY:
+        default:
+            return DEVICE_CATEGORY_SPEAKER;
+    }
+}
+
+bool AudioPolicyManager::isDirectOutput(audio_io_handle_t 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->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+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);
+        // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is
+        // enabled
+        if (stream == AudioSystem::BLUETOOTH_SCO) {
+            mpClientInterface->setStreamVolume(AudioSystem::VOICE_CALL, volume, output, 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);
+    }
+
+    if (stream == AudioSystem::VOICE_CALL ||
+        stream == AudioSystem::BLUETOOTH_SCO) {
+        float voiceVolume;
+        // Force voice volume to max for bluetooth SCO as volume is managed by the headset
+        if (stream == AudioSystem::VOICE_CALL) {
+            voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
+        } else {
+            voiceVolume = 1.0;
+        }
+
+        voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
+
+        // Force voice volume to max when Vgs is set for bluetooth SCO as volume is managed by the headset
+        if (stream == AudioSystem::BLUETOOTH_SCO) {
+            String8 key ("bt_headset_vgs");
+            mpClientInterface->getParameters(output,key);
+            AudioParameter result(mpClientInterface->getParameters(0,key));
+            int value;
+            if (result.getInt(String8("isVGS"),value) == NO_ERROR) {
+                ALOGV("Use BT-SCO Voice Volume");
+                voiceVolume = 1.0;
+            }
+        }
+
+        if (voiceVolume != mLastVoiceVolume && (output == mPrimaryOutput ||
+            isDirectOutput(output))) {
+            mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
+            mLastVoiceVolume = voiceVolume;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+
+void AudioPolicyManager::checkA2dpSuspend()
+{
+
+    // suspend A2DP output if:
+    //      (NOT already suspended) &&
+    //      ((SCO device is connected &&
+    //       (forced usage for communication || for record is SCO))) ||
+    //      (phone state is ringing || in call)
+    //
+    // restore A2DP output if:
+    //      (Already suspended) &&
+    //      ((SCO device is NOT connected ||
+    //       (forced usage NOT for communication && NOT for record is SCO))) &&
+    //      (phone state is NOT ringing && NOT in call)
+    //
+    if (mA2dpSuspended) {
+        if (((mScoDeviceAddress == "") ||
+             ((mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO) &&
+              (mForceUse[AudioSystem::FOR_RECORD] != AudioSystem::FORCE_BT_SCO))) ||
+             ((mPhoneState != AudioSystem::MODE_IN_CALL) &&
+              (mPhoneState != AudioSystem::MODE_RINGTONE))) {
+
+            mA2dpSuspended = false;
+        }
+    } else {
+        if (((mScoDeviceAddress != "") &&
+             ((mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
+              (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO))) &&
+             ((mPhoneState == AudioSystem::MODE_IN_CALL) ||
+              (mPhoneState == AudioSystem::MODE_RINGTONE))) {
+
+            mA2dpSuspended = true;
+        }
+    }
+}
+
+audio_io_handle_t AudioPolicyManager::getA2dpOutput()
+{
+    return 0;
+}
+
+//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;
+    }
+}
+
+
+AudioPolicyManagerBase::IOProfile *AudioPolicyManager::getProfileForDirectOutput(
+                                                               audio_devices_t device,
+                                                               uint32_t samplingRate,
+                                                               uint32_t format,
+                                                               uint32_t channelMask,
+                                                               audio_output_flags_t flags)
+{
+    if( !((flags & AUDIO_OUTPUT_FLAG_LPA)   ||
+          (flags & AUDIO_OUTPUT_FLAG_TUNNEL)||
+          (flags & AUDIO_OUTPUT_FLAG_VOIP_RX)) )
+        flags = AUDIO_OUTPUT_FLAG_DIRECT;
+
+    for (size_t i = 0; i < mHwModules.size(); i++) {
+        if (mHwModules[i]->mHandle == 0) {
+            continue;
+        }
+        for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) {
+           AudioPolicyManagerBase::IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
+           if (isCompatibleProfile(profile, device, samplingRate, format,
+                                           channelMask,
+                                           flags)) {
+               if (mAvailableOutputDevices & profile->mSupportedDevices) {
+                   return mHwModules[i]->mOutputProfiles[j];
+               }
+           }
+        }
+    }
+    return 0;
+}
+
+bool AudioPolicyManager::isCompatibleProfile(AudioPolicyManagerBase::IOProfile *profile,
+                                             audio_devices_t device,
+                                             uint32_t samplingRate,
+                                             uint32_t format,
+                                             uint32_t channelMask,
+                                            audio_output_flags_t flags)
+{
+    if ((profile->mSupportedDevices & device) != device) {
+        return false;
+    }
+    if (profile->mFlags != flags) {
+        return false;
+    }
+    if (samplingRate != 0) {
+        size_t i;
+        for (i = 0; i < profile->mSamplingRates.size(); i++)
+        {
+            if (profile->mSamplingRates[i] == samplingRate) {
+                break;
+            }
+        }
+        if (i == profile->mSamplingRates.size()) {
+            return false;
+        }
+    }
+    if (format != 0) {
+        size_t i;
+        for (i = 0; i < profile->mFormats.size(); i++)
+        {
+            if (profile->mFormats[i] == format) {
+                break;
+            }
+        }
+        if (i == profile->mFormats.size()) {
+            return false;
+        }
+    }
+    if (channelMask != 0) {
+        size_t i;
+       for (i = 0; i < profile->mChannelMasks.size(); i++)
+        {
+            if (profile->mChannelMasks[i] == channelMask) {
+                break;
+            }
+        }
+        if (i == profile->mChannelMasks.size()) {
+            return false;
+        }
+    }
+    ALOGD(" profile found: device %x, flags %x, samplingrate %d,\
+            format %x, channelMask %d",
+            device, flags, samplingRate, format, channelMask);
+    return true;
+}
+
+bool AudioPolicyManager::platform_is_Fusion3()
+{
+    char platform[128], baseband[128], baseband_arch[128];
+    property_get("ro.board.platform", platform, "");
+    property_get("ro.baseband", baseband, "");
+    property_get("ro.baseband.arch", baseband_arch, "");
+    if (!strcmp("msm8960", platform) && (!strcmp("mdm", baseband) || !strcmp("mdm", baseband_arch)))
+        return true;
+    else
+        return false;
+}
+
+extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+{
+    return new AudioPolicyManager(clientInterface);
+}
+
+extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface)
+{
+    delete interface;
+}
+
+
+}; // namespace android
diff --git a/msm7x30/AudioPolicyManager.h b/msm7x30/AudioPolicyManager.h
new file mode 100644
index 0000000..f0f0237
--- /dev/null
+++ b/msm7x30/AudioPolicyManager.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2012-2013, The Linux Foundation. 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(audio_devices_t device,
+                                                          AudioSystem::device_connection_state state,
+                                                          const char *device_address);
+        uint32_t checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc,
+                                           audio_devices_t prevDevice,
+                                           uint32_t delayMs);
+
+	void setStrategyMute(routing_strategy strategy,
+						 bool on,
+						 audio_io_handle_t output,
+						 int delayMs = 0,
+						 audio_devices_t device = (audio_devices_t)0);
+	void setStreamMute(int stream, bool on, audio_io_handle_t output,
+						int delayMs = 0,
+						audio_devices_t device = (audio_devices_t)0);
+
+        virtual AudioSystem::device_connection_state getDeviceConnectionState(audio_devices_t device,
+                                                                              const char *device_address);
+        virtual void setPhoneState(int state);
+        virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
+        virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream,
+                                            uint32_t samplingRate = 0,
+                                            uint32_t format = AudioSystem::FORMAT_DEFAULT,
+                                            uint32_t channels = 0,
+                                            AudioSystem::output_flags flags =
+                                                    AudioSystem::OUTPUT_FLAG_INDIRECT);
+        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 releaseOutput(audio_io_handle_t output);
+        virtual audio_io_handle_t getInput(int inputSource,
+                                            uint32_t samplingRate,
+                                            uint32_t format,
+                                            uint32_t channels,
+                                            AudioSystem::audio_in_acoustics acoustics);
+
+        // indicates to the audio policy manager that the input starts being used.
+        virtual status_t startInput(audio_io_handle_t input);
+
+        // indicates to the audio policy manager that the input stops being used.
+        virtual status_t stopInput(audio_io_handle_t input);
+        virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream,
+                                              int index,
+                                              audio_devices_t device);
+protected:
+        // return the strategy corresponding to a given stream type
+        static routing_strategy getStrategy(AudioSystem::stream_type stream);
+
+        // 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 determine 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 updateDevicesAndOutputs() is called.
+        virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy,
+                                                     bool fromCache = true);
+
+        // change the route of the specified output. Returns the number of ms we have slept to
+        // allow new routing to take effect in certain cases.
+        uint32_t setOutputDevice(audio_io_handle_t output,
+                             audio_devices_t device,
+                             bool force = false,
+                             int delayMs = 0);
+
+        // select input device corresponding to requested audio source
+        virtual audio_devices_t getDeviceForInputSource(int inputSource);
+
+        // 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);
+
+
+        // when a device is connected, checks if an open output can be routed
+        // to this device. If none is open, tries to open one of the available outputs.
+        // Returns an output suitable to this device or 0.
+        // when a device is disconnected, checks if an output is not used any more and
+        // returns its handle if any.
+        // transfers the audio tracks and effects from one output thread to another accordingly.
+        status_t checkOutputsForDevice(audio_devices_t device,
+                                       AudioSystem::device_connection_state state,
+                                       SortedVector<audio_io_handle_t>& outputs);
+        // manages A2DP output suspend/restore according to phone state and BT SCO usage
+        void checkA2dpSuspend();
+
+        // returns the A2DP output handle if it is open or 0 otherwise
+        audio_io_handle_t getA2dpOutput();
+
+        // returns true if give output is direct output
+        bool isDirectOutput(audio_io_handle_t output);
+
+        virtual AudioPolicyManagerBase::IOProfile* getProfileForDirectOutput(
+                                                     audio_devices_t device,
+                                                     uint32_t samplingRate,
+                                                     uint32_t format,
+                                                     uint32_t channelMask,
+                                                     audio_output_flags_t flags);
+        bool    isCompatibleProfile(AudioPolicyManagerBase::IOProfile *profile,
+                                    audio_devices_t device,
+                                    uint32_t samplingRate,
+                                    uint32_t format,
+                                    uint32_t channelMask,
+                                    audio_output_flags_t flags);
+        // selects the most appropriate device on output for current state
+        // must be called every time a condition that affects the device choice for a given output is
+        // changed: connected device, phone state, force use, output start, output stop..
+        // see getDeviceForStrategy() for the use of fromCache parameter
+
+        audio_devices_t getNewDevice(audio_io_handle_t output, bool fromCache);
+
+
+        // returns the category the device belongs to with regard to volume curve management
+        static device_category getDeviceCategory(audio_devices_t device);
+
+        // extract one device relevant for volume control from multiple device selection
+        static audio_devices_t getDeviceForVolume(audio_devices_t device);
+        // true is current platform implements a back microphone
+        virtual bool hasBackMicrophone() const { return false; }
+        // true is current platform supports suplication of notifications and ringtones over A2DP output
+        virtual bool a2dpUsedForSonification() const { return true; }
+
+private:
+
+        void handleNotificationRoutingForStream(AudioSystem::stream_type stream);
+        bool platform_is_Fusion3();
+};
+};
diff --git a/msm7x30/audio_hw_hal.cpp b/msm7x30/audio_hw_hal.cpp
new file mode 100644
index 0000000..5e65fe3
--- /dev/null
+++ b/msm7x30/audio_hw_hal.cpp
@@ -0,0 +1,750 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The CyanogenMod Project
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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.msm7x30"
+//#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;
+};
+
+enum {
+    HAL_API_REV_1_0,
+    HAL_API_REV_2_0,
+    HAL_API_REV_NUM
+} hal_api_rev;
+static uint32_t audio_device_conv_table[][HAL_API_REV_NUM] =
+{
+    /* output devices */
+    { AudioSystem::DEVICE_OUT_EARPIECE, AUDIO_DEVICE_OUT_EARPIECE },
+    { AudioSystem::DEVICE_OUT_SPEAKER, AUDIO_DEVICE_OUT_SPEAKER },
+    { AudioSystem::DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_OUT_WIRED_HEADSET },
+    { AudioSystem::DEVICE_OUT_WIRED_HEADPHONE, AUDIO_DEVICE_OUT_WIRED_HEADPHONE },
+    { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO, AUDIO_DEVICE_OUT_BLUETOOTH_SCO },
+    { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET },
+    { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT },
+    { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP },
+    { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES },
+    { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER },
+    { AudioSystem::DEVICE_OUT_AUX_DIGITAL, AUDIO_DEVICE_OUT_AUX_DIGITAL },
+    { AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET },
+    { AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET },
+    { AudioSystem::DEVICE_OUT_DEFAULT, AUDIO_DEVICE_OUT_DEFAULT },
+    /* input devices */
+    { AudioSystem::DEVICE_IN_COMMUNICATION, AUDIO_DEVICE_IN_COMMUNICATION },
+    { AudioSystem::DEVICE_IN_AMBIENT, AUDIO_DEVICE_IN_AMBIENT },
+    { AudioSystem::DEVICE_IN_BUILTIN_MIC, AUDIO_DEVICE_IN_BUILTIN_MIC },
+    { AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET },
+    { AudioSystem::DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_WIRED_HEADSET },
+    { AudioSystem::DEVICE_IN_AUX_DIGITAL, AUDIO_DEVICE_IN_AUX_DIGITAL },
+    { AudioSystem::DEVICE_IN_VOICE_CALL, AUDIO_DEVICE_IN_VOICE_CALL },
+    { AudioSystem::DEVICE_IN_BACK_MIC, AUDIO_DEVICE_IN_BACK_MIC },
+    { AudioSystem::DEVICE_IN_DEFAULT, AUDIO_DEVICE_IN_DEFAULT },
+};
+
+static uint32_t convert_audio_device(uint32_t from_device, int from_rev, int to_rev)
+{
+    const uint32_t k_num_devices = sizeof(audio_device_conv_table)/sizeof(uint32_t)/HAL_API_REV_NUM;
+    uint32_t to_device = AUDIO_DEVICE_NONE;
+    uint32_t in_bit = 0;
+
+    if (from_rev != HAL_API_REV_1_0) {
+        in_bit = from_device & AUDIO_DEVICE_BIT_IN;
+        from_device &= ~AUDIO_DEVICE_BIT_IN;
+    }
+
+    while (from_device) {
+        uint32_t i = 31 - __builtin_clz(from_device);
+        uint32_t cur_device = (1 << i) | in_bit;
+
+        for (i = 0; i < k_num_devices; i++) {
+            if (audio_device_conv_table[i][from_rev] == cur_device) {
+                to_device |= audio_device_conv_table[i][to_rev];
+                break;
+            }
+        }
+        from_device &= ~cur_device;
+    }
+    return to_device;
+}
+/** 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 (audio_channel_mask_t) 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);
+    int val;
+    String8 s8 = String8(kvpairs);
+    AudioParameter parms = AudioParameter(String8(kvpairs));
+
+    if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) {
+        val = convert_audio_device(val, HAL_API_REV_2_0, HAL_API_REV_1_0);
+        parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING));
+        parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val);
+        s8 = parms.toString();
+    }
+    return out->qcom_out->setParameters(s8);
+}
+
+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;
+    int val;
+    s8 = out->qcom_out->getParameters(String8(keys));
+    AudioParameter parms = AudioParameter(s8);
+    if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) {
+        val = convert_audio_device(val, HAL_API_REV_1_0, HAL_API_REV_2_0);
+        parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING));
+        parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val);
+        s8 = parms.toString();
+    }
+    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_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)
+{
+    return -EINVAL;
+}
+
+/** 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 (audio_channel_mask_t) 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);
+    int val;
+    AudioParameter parms = AudioParameter(String8(kvpairs));
+    String8 s8 = String8(kvpairs);
+
+    if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) {
+        val = convert_audio_device(val, HAL_API_REV_2_0, HAL_API_REV_1_0);
+        parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING));
+        parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val);
+        s8 = parms.toString();
+    }
+    return in->qcom_in->setParameters(s8);
+}
+
+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;
+    int val;
+    s8 = in->qcom_in->getParameters(String8(keys));
+    AudioParameter parms = AudioParameter(s8);
+    if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) {
+        val = convert_audio_device(val, HAL_API_REV_1_0, HAL_API_REV_2_0);
+        parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING));
+        parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val);
+        s8 = parms.toString();
+    }
+    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 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((int)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);
+    uint8_t channelCount = popcount(config->channel_mask);
+    return qadev->hwif->getInputBufferSize(config->sample_rate,config->format,channelCount);
+}
+
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+static int adev_open_output_session(struct audio_hw_device *dev,
+                                   uint32_t devices,
+                                   int *format,
+                                   int sessionId,
+                                   uint32_t samplingRate,
+                                   uint32_t channels,
+                                   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;
+
+    devices = convert_audio_device(devices, HAL_API_REV_2_0, HAL_API_REV_1_0);
+    status = static_cast<audio_output_flags_t> (flags);
+
+    out->qcom_out = qadev->hwif->openOutputSession(devices, format,&status,sessionId,samplingRate,channels);
+    if (!out->qcom_out) {
+        ret = status;
+        goto err_open;
+    }
+
+    out->stream.common.standby = out_standby;
+    out->stream.common.set_parameters = out_set_parameters;
+    out->stream.set_volume = out_set_volume;
+
+    *stream_out = &out->stream;
+    return 0;
+
+err_open:
+    free(out);
+    *stream_out = NULL;
+    return ret;
+}
+#endif /* QCOM_TUNNEL_LPA_ENABLED */
+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;
+
+    devices = convert_audio_device(devices, HAL_API_REV_2_0, HAL_API_REV_1_0);
+    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;
+
+    *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,
+                                  struct audio_config *config,
+                                  struct 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;
+
+    devices = convert_audio_device(devices, HAL_API_REV_2_0, HAL_API_REV_1_0);
+    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_2_0;
+    qadev->device.common.module = const_cast<hw_module_t*>(module);
+    qadev->device.common.close = qcom_adev_close;
+
+    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;
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+    qadev->device.open_output_session = adev_open_output_session;
+#endif /* QCOM_TUNNEL_LPA_ENABLED */
+    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,
+            module_api_version:  AUDIO_DEVICE_API_VERSION_1_0,
+            hal_api_version: HARDWARE_HAL_API_VERSION,
+            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/msm7x30/audio_policy_hal.cpp b/msm7x30/audio_policy_hal.cpp
new file mode 100644
index 0000000..f494d23
--- /dev/null
+++ b/msm7x30/audio_policy_hal.cpp
@@ -0,0 +1,469 @@
+/*
+ * Copyright (c) 2012-2013, The Linux Foundation. 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 "qcom_audio_policy_hal"
+//#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 {
+
+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(
+                    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(
+                    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);
+}
+
+    /* indicate a change in ringer mode */
+static void ap_set_ringer_mode(struct audio_policy *pol, uint32_t mode,
+                               uint32_t mask)
+{
+    // deprecated, never called
+}
+
+    /* 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();
+}
+
+
+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 bool ap_is_stream_active_remotely(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->isStreamActiveRemotely((int) stream, in_past_ms);
+}
+
+static bool ap_is_source_active(const struct audio_policy *pol, audio_source_t source)
+{
+    const struct qcom_audio_policy *qap = to_cqap(pol);
+    return qap->apm->isSourceActive(source);
+}
+
+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_ringer_mode = ap_set_ringer_mode;
+    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;
+    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.is_stream_active_remotely = ap_is_stream_active_remotely;
+    qap->policy.is_source_active = ap_is_source_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: "The Linux Foundation",
+            methods: &qcom_ap_module_methods,
+            dso : NULL,
+            reserved : {0},
+        },
+    },
+};
+
+}; // extern "C"
+
+}; // namespace android_audio_legacy
diff --git a/msm7x30/control.h b/msm7x30/control.h
new file mode 100644
index 0000000..3eb69fd
--- /dev/null
+++ b/msm7x30/control.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2009, The Android Open-Source Project
+ * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2013, 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_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 int 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);
+
+__END_DECLS
+
+#endif
diff --git a/msm7x30/initialize_audcal7x30.h b/msm7x30/initialize_audcal7x30.h
new file mode 100644
index 0000000..bf547ff
--- /dev/null
+++ b/msm7x30/initialize_audcal7x30.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2009, The Android Open-Source Project
+ * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2013, 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_AUDIO_CALIBRATION
+#define __MSM_AUDIO_CALIBRATION
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern void audcal_initialize(void);
+extern void audcal_deinitialize(void);
+
+__END_DECLS
+
+#endif
diff --git a/msm8660/Android.mk b/msm8660/Android.mk
new file mode 100644
index 0000000..3cb487b
--- /dev/null
+++ b/msm8660/Android.mk
@@ -0,0 +1,135 @@
+#AUDIO_POLICY_TEST := true
+#ENABLE_AUDIO_DUMP := true
+
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+  common_cflags += -DWITH_A2DP
+endif
+
+ifeq ($(BOARD_HAVE_QCOM_FM),true)
+  common_cflags += -DQCOM_FM_ENABLED
+endif
+
+ifneq ($(BOARD_QCOM_TUNNEL_LPA_ENABLED),false)
+  common_cflags += -DQCOM_TUNNEL_LPA_ENABLED
+endif
+
+ifeq ($(BOARD_QCOM_VOIP_ENABLED),true)
+  common_cflags += -DQCOM_VOIP_ENABLED
+endif
+
+ifeq ($(BOARD_QCOM_TUNNEL_PLAYBACK_ENABLED),true)
+  common_cflags += -DTUNNEL_PLAYBACK
+endif
+
+ifeq ($(BOARD_USES_QCOM_HARDWARE),true)
+  common_cflags += -DQCOM_ACDB_ENABLED
+endif
+
+ifeq ($(BOARD_HAVE_SAMSUNG_AUDIO),true)
+  common_cflags += -DSAMSUNG_AUDIO
+endif
+
+ifeq ($(BOARD_HAVE_SONY_AUDIO),true)
+  common_cflags += -DSONY_AUDIO
+endif
+
+ifeq ($(BOARD_HAVE_BACK_MIC_CAMCORDER),true)
+  common_cflags += -DBACK_MIC_CAMCORDER
+endif
+
+
+include $(CLEAR_VARS)
+
+LOCAL_ARM_MODE := arm
+LOCAL_CFLAGS := -D_POSIX_SOURCE
+
+LOCAL_SRC_FILES := \
+    AudioHardware.cpp \
+    audio_hw_hal.cpp
+
+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
+
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
+LOCAL_CFLAGS += $(common_cflags)
+
+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
+
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
+LOCAL_C_INCLUDES += hardware/libhardware_legacy/audio
+
+LOCAL_CFLAGS += $(common_cflags)
+
+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..0eb599a
--- /dev/null
+++ b/msm8660/AudioHardware.cpp
@@ -0,0 +1,6389 @@
+/*
+** Copyright 2008, The Android Open-Source Project
+** Copyright (c) 2011-2013, The Linux Foundation. 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
+#ifdef QCOM_VOIP_ENABLED
+#include <linux/msm_audio_mvs.h>
+#endif
+#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 VOIPRATE_KEY "voip_rate"
+
+#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
+    ALOGV("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;
+    }
+    ALOGV("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), mVoipInActive(false), mVoipOutActive(false), mDirectOutput(0), mVoipBitRate(0),
+    mDirectOutrefCnt(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)
+{
+     audio_output_flags_t flags = static_cast<audio_output_flags_t> (*status);
+
+     ALOGD("AudioHardware::openOutputStream devices %x format %d channels %d samplerate %d flags %d",
+        devices, *format, *channels, *sampleRate, flags);
+
+    { // scope for the lock
+        status_t lStatus;
+
+        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))
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+                    && !(flags & AUDIO_OUTPUT_FLAG_TUNNEL)
+#endif /* QCOM_TUNNEL_LPA_ENABLED */
+                    && !(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;
+                   mDirectOutrefCnt++;
+                   mLock.unlock();
+                   if (mVoipInActive)
+                       setupDeviceforVoipCall(true);
+                   mLock.lock();
+                   ALOGV(" \n set sucessful for AudioStreamOutDirect");
+               } else {
+                   ALOGE(" \n set Failed for AudioStreamOutDirect");
+                   delete out;
+               }
+            }
+            else {
+                mDirectOutrefCnt++;
+                ALOGE(" \n AudioHardware::AudioStreamOutDirect is already open refcnt %d", mDirectOutrefCnt);
+            }
+            return mDirectOutput;
+        } else
+#endif
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+	    if (flags & AUDIO_OUTPUT_FLAG_LPA) {
+			status_t err = BAD_VALUE;
+            // create new output LPA stream
+            AudioSessionOutLPA* out = new AudioSessionOutLPA(this, devices, *format, *channels,*sampleRate,0,&err);
+            if(err != NO_ERROR) {
+                delete out;
+                out = NULL;
+            }
+            if (status) *status = err;
+            mOutputLPA = out;
+            return mOutputLPA;
+
+        } else
+#endif
+#ifdef TUNNEL_PLAYBACK
+        if (flags & AUDIO_OUTPUT_FLAG_TUNNEL) {
+            status_t err = BAD_VALUE;
+            // create new Tunnel output stream
+            AudioSessionOutTunnel* out = new AudioSessionOutTunnel(this, devices, *format, *channels,*sampleRate,0,&err);
+            if(err != NO_ERROR) {
+                delete out;
+                out = NULL;
+            }
+            if (status) *status = err;
+            mOutputTunnel = out;
+            return mOutputTunnel;
+        } else
+#endif /*TUNNEL_PLAYBACK*/
+        {
+            // 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) {
+    ALOGD("closeOutputStream called");
+
+    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
+#ifdef TUNNEL_PLAYBACK
+        && (mOutputTunnel!= out)
+#endif /*TUNNEL_PLAYBACK*/
+       && (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) {
+        mDirectOutrefCnt--;
+        if (mDirectOutrefCnt <= 0) {
+            ALOGV(" deleting  mDirectOutput \n");
+            delete mDirectOutput;
+            mDirectOutput = 0;
+        }
+    }
+#endif
+    else if (mOutputLPA == out) {
+	    ALOGV(" deleting  mOutputLPA \n");
+        delete mOutputLPA;
+        mOutputLPA = 0;
+	}
+#ifdef TUNNEL_PLAYBACK
+    else if (mOutputTunnel == out) {
+        ALOGD("Closing Tunnel Output");
+        delete mOutputTunnel;
+        mOutputTunnel = 0;
+    }
+#endif /*TUNNEL_PLAYBACK*/
+}
+
+AudioStreamIn* AudioHardware::openInputStream(
+        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status,
+        AudioSystem::audio_in_acoustics acoustic_flags)
+{
+    ALOGD("AudioHardware::openInputStream devices %x format %d channels %d samplerate %d in_p=%x lin_p=%x in_v=%x lin_v=%x",
+        devices, *format, *channels, *sampleRate, AUDIO_DEVICE_IN_VOICE_CALL, AudioSystem::DEVICE_IN_VOICE_CALL, AUDIO_DEVICE_IN_COMMUNICATION, AudioSystem::DEVICE_IN_COMMUNICATION);
+
+    // 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) && (*sampleRate <= AUDIO_HW_VOIP_SAMPLERATE_16K)) {
+        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();
+        if (mVoipOutActive) {
+            inVoip->mSetupDevice = true;
+            setupDeviceforVoipCall(true);
+        }
+        return inVoip;
+    } else
+#endif /*QCOM_VOIP_ENABLED*/
+    {
+       if ( (mMode == AudioSystem::MODE_IN_CALL) &&
+            (getInputSampleRate(*sampleRate) > AUDIO_HW_IN_SAMPLERATE) &&
+            (*format == AUDIO_HW_IN_FORMAT) )
+        {
+              ALOGE("PCM recording, in a voice call, with sample rate more than 8K not supported \
+                   re-configure with 8K and try software re-sampler ");
+              *status = -EINVAL;
+              *sampleRate = AUDIO_HW_IN_SAMPLERATE;
+              mLock.unlock();
+              return 0;
+        }
+        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 /*QCOM_VOIP_ENABLED*/
+    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)) {